Core
Agents as code
Provision and govern agents from your pipeline — create one, grant its tools, bound its capabilities, gate risky actions, set a budget, and attach a golden-suite eval. Read the whole config back to diff against your desired state.
Create an agent#
instructions must be at least 10 characters; modelProfileId is optional (discover ids with listModelProfiles).
const agent = await bahini.createAgent({
key: "ticket-triage",
name: "Ticket Triage",
role: "Support triage assistant",
instructions: "Classify inbound tickets by urgency and draft a first reply.",
});
// → { id, key, name }Grant tools#
setAgentToolsis set-equality — it grants what's missing and revokes the rest. grantAgentTool / revokeAgentTool are the additive single-key forms. Discover valid keys with listTools.
await bahini.setAgentTools(agent.id, ["http.request", "documents.search"]);
// → { added, removed, unchanged, skipped }Bound its capabilities#
Capability scope is fail-closed. Restrict which hosts http.request may reach, deny tools outright, and fence storage to key prefixes.
await bahini.setAgentCapabilityScope(agent.id, {
allowedHttpDomains: ["api.stripe.com", "hooks.slack.com"],
deniedTools: ["storage.delete"],
storageKeyPrefixes: ["triage/"],
});Gate risky actions#
await bahini.setAgentApprovalPolicy(agent.id, {
approvalGatedTools: ["email.send", "http.request"],
});Set a budget#
Hard ceilings — the run halts when it crosses one.
await bahini.setAgentBudget(agent.id, {
maxIterations: 12,
maxTokens: 200_000,
maxDurationMs: 120_000,
maxConsecutiveErrors: 3,
});Attach a golden suite#
Declare the quality bar as data. Each case is a set of expectations (contains / equals / regex / numeric / shape, JSON-path aware). Run the agent, then read getRunEval for the verdict — a CI gate.
await bahini.setAgentGoldenSuite(agent.id, [
{
name: "classifies urgent",
expectations: [{ path: "$.priority", equals: "urgent" }],
},
]);Read & apply whole configs#
getAgentConfig(agentId)
One call returns tools + capability scope + approval policy + response format + guardrails + budget + golden suite — the canonical snapshot to diff against your desired IaC state.
const config = await bahini.getAgentConfig(agent.id);applyAgentConfig(agentId, config)
The write side. Only the surfaces you pass are touched; each goes through its own endpoint, so a failure on one is collected in errors and the rest still apply. Assert on the result in your pipeline.
const { applied, errors } = await bahini.applyAgentConfig(agent.id, {
tools: ["http.request"],
capabilityScope: { allowedHttpDomains: ["api.stripe.com"] },
budget: { maxIterations: 12 },
});
if (errors.length) throw new Error(JSON.stringify(errors));updateAgent(id, { status: 'ARCHIVED' }) is the IaC teardown primitive; 'PAUSED' stops it from running, 'ACTIVE' re-enables it.