Managing agents#
An agent is a row in aidb.agents , created with
aidb.create_agent() . Nothing runs until you call Invoking agents —
creating an agent just stores its configuration.
SELECT aidb.create_agent(
name => db_helper,
instructions => You are a helpful assistant that answers questions about this database. Be concise.,
model => my_gpt,
tools => ARRAY[run_sql_query], -- optional; tool names from aidb.tools. Default: NULL (no tools)
delegates => NULL, -- optional; names of other agents to delegate to. Default: NULL (no delegation)
role => NULL, -- optional; Postgres role tool calls run as. Default: NULL (run as the calling role)
output_type => NULL, -- optional; structured output schema from aidb.output_type(). Default: NULL (plain-text answer)
input_token_budget => NULL, -- optional; input token cap per agent_converse call. Default: NULL (no limit)
output_token_budget => NULL, -- optional; output token cap per agent_converse call. Default: NULL (no limit)
max_iterations => NULL, -- optional; reasoning-round cap per call. Default: NULL (a hard ceiling of 25 always applies)
timeout => NULL, -- optional; wall-clock seconds cap per call. Default: NULL (300 seconds applied at runtime)
budget_strategy => attempt_complete, -- optional; behavior when a budget is exceeded. Default: attempt_complete
preset => NULL -- optional; reserved for future use, has no effect today. Default: NULL
);
Returns no rows on success. On failure (for example, the name is already
taken), it returns a single row with an error column set — it never
raises, so a batch of create_agent calls can’t abort partway
through:
SELECT * FROM aidb.create_agent(db_helper, Be helpful., my_gpt);
__OUTPUT__
error
- -----------------------------------
agent db_helper already exists
(1 row)
Choosing a model#
model must name an already-registered Choosing a model that’s capable
of generating text and following instructions. Embedding, reranking,
OCR, and multimodal-embedding providers (bert_local ,
openai_embeddings , nim_reranking , clip_local , and so on)
can’t back an agent at all, and t5_local is rejected outright since
it has no instruction-following or system-prompt support. Every other
text-generation provider works, split into two tiers by tool-calling
quality:
Preferred — these send real, provider-native tool-call requests:
openai_responses(+openai_responses_azure)anthropic_messages(+anthropic_messages_azure/anthropic_messages_bedrock)llamacpp_generate
Supported — these work, but AIDB simulates tool calling by describing the available tools in the prompt text and parsing a tool call back out of the model’s plain-text reply:
openai_completionscompletions(any other OpenAI-Chat-Completions-compatible endpoint)nim_completionsopenrouter_chatgeminillama_instruct_local
See Tool calling and structured output for more on the preferred/supported distinction. The
model doesn’t need to exist yet when you call create_agent — only
agent_converse requires it to be resolvable.
Tools and delegates#
tools is an array of names from the Tools reference (aidb.tools )
the agent is allowed to call; delegates is an array of names of
other agents it may Delegation . Both are validated against
aidb.tools /aidb.agents at create_agent /update_agent
time — an unknown name is rejected immediately rather than surfacing
later inside agent_converse . Omit either for an agent with no tools
or no delegates.
SELECT aidb.create_agent(
name => help_desk,
instructions => Help users with general questions, delegating data questions to a specialist.,
model => my_gpt,
tools => ARRAY[run_sql_query],
delegates => ARRAY[sql_specialist]
);
Permissions#
By default, an agent’s tool calls run as whichever Postgres role calls
agent_converse . Pass role to pin an agent to a specific role
instead — for example, to give it narrower table permissions than the
calling application user has. The caller must already be a member of
that role (pg_has_role(..., 'MEMBER') ); create_agent
/update_agent reject an agent configured with a role you don’t
belong to.
SELECT aidb.create_agent(
name => readonly_reporter,
instructions => Answer questions about sales data. Never modify data.,
model => my_gpt,
tools => ARRAY[run_sql_query],
role => reporting_role
);
Structured output#
By default, agent_converse ’s answer is plain text. To get back
structured JSON instead, build a schema with aidb.output_type() and
aidb.output_field() :
SELECT aidb.create_agent(
name => sentiment_tagger,
instructions => Classify the sentiment of the given text.,
model => my_gpt,
output_type => aidb.output_type(
aidb.output_field(sentiment, TEXT, One of: positive, negative, neutral),
aidb.output_field(confidence, FLOAT)
)
);
aidb.output_field() ’s description argument is optional. A
call-time output_type argument to agent_converse overrides the
agent’s configured schema for that one call only.
Budgets, iterations, and timeouts#
input_token_budget , output_token_budget , max_iterations ,
and timeout (seconds) cap how much a single agent_converse call
can cost and how long it can run; budget_strategy controls what
happens when a budget is exceeded. All are optional — see Budgets and limits
for the full behavior, since it’s a property of how a conversation runs,
not of the agent’s static configuration.
SELECT aidb.create_agent(
name => cost_capped_helper,
instructions => Answer questions about the orders table.,
model => my_gpt,
input_token_budget => 20000, -- INTEGER; input tokens allowed per agent_converse call
output_token_budget => 2000, -- INTEGER; output tokens allowed per agent_converse call
max_iterations => 10, -- INTEGER; reasoning rounds allowed per call (a hard ceiling of 25 always applies)
timeout => 60, -- INTEGER; wall-clock seconds allowed per call
budget_strategy => error -- TEXT; one of ignore, error, summarize, attempt_complete
);
Updating and deleting agents#
aidb.update_agent() takes the same fields as create_agent , all
optional — only the fields you pass change; everything else keeps its
current value:
SELECT aidb.update_agent(db_helper, model => my_new_gpt, max_iterations => 15);
There’s no dedicated “list agents” function — aidb.agents is a
normal table, so SELECT * FROM aidb.agents lists them. See
Agents reference for its full column list.
aidb.delete_agent() removes an agent by name:
SELECT aidb.delete_agent(db_helper);
If the agent has any conversation history, this fails by default (its
internal task records are referenced by foreign key) — pass
force => true to delete that internal history alongside the agent.
The conversation transcript itself is untouched either way and remains
readable with Retrieving conversations even after the agent that produced it has
been deleted.
SELECT aidb.delete_agent(db_helper, force => true);
!!!note create_agent /update_agent also accept a preset
argument (for example, 'text_to_sql' ). It’s stored on the agent but
doesn’t currently change its behavior — reserved for future use.