Authentication and enablement
Requires a workspace Postgres integration. Host, port, database, user, password, SSL, and optional schema are injected from that integration (x-exclude-from-llm). Enable the tool on the agent and bind the integration.
Inputs
query(required): SELECT only. Example:SELECT * FROM users WHERE status = 'active' LIMIT 10.query_params(object, pinned queries only): values for the query’s named placeholders. Supplied by the agent per call — it is not a configurable field and does not appear in the tool’s configuration dialog. It is offered to the agent only whenqueryis pinned to a statement containing placeholders — see below.
Pinned queries with named parameters
Instead of letting the agent write the SQL on every run, set the tool’s Query field in its configuration dialog to a fixed statement that addresses its values by name:query_params object whose keys are exactly the
placeholders that query declares, and the agent only supplies values:
query_params, and query_params is
offered only when a pinned query declares some — so a query the agent writes itself is
passed to the database exactly as written. Prefer this over a
model-authored query for any lookup that runs in production: the SQL is reviewed once,
at configuration time, instead of being regenerated on every task.
Notes:
- Placeholder names use
:name. A::typecast is a cast, not a placeholder, so:org_id::uuidbinds one value and casts it. - Repeat a name to reuse the same value:
WHERE name = :n OR alias = :nbinds once. - Declare types in the SQL (
:amount::numeric) rather than in the value — values are sent as text and cast server-side. - Placeholders substitute values, never table or column names, and cannot supply a
list to
IN (...). Use= ANY(:ids::uuid[])for a list — and because every value is scalar text, pass the Postgres array literal as a string ("{id1,id2}"), not a JSON array. A JSON array is rejected. - A placeholder cannot appear inside an array subscript. A colon between brackets is
read as a slice separator, so
arr[lo:hi]stays a slice rather than becoming a parameter namedhi. - Named and ordinal (
$1) placeholders cannot be mixed in one query. - Maximum 64 distinct placeholders.
Output
Structured rows plus:query— the SQL as authored, with its:namelabels intact. This is what the task feed renders, so a lookup that returned nothing can still be read against the values it was meant to filter on.query_bound— the statement actually sent, with placeholders replaced by$1,$2…query_param_keys— the placeholder names that were bound. The values are never reported: they are customer document data and do not belong in a rendered feed item.param_count,row_count,truncated,columns,rows.
content for generate_file.
Limits and side effects
- Non-SELECT statements are rejected.
- Read-only by design; use
postgres_upsert(separate tool) to write. - Returns at most
max_rowsrows (default and maximum 3000);truncatedreports when the limit was hit.
Expected errors
- Missing/invalid integration credentials.
- Non-SELECT
query. - A placeholder in the pinned query with no value in
query_params, or aquery_paramskey that is not a placeholder in the query (both name the offending key and list the placeholders the query expects, so the agent can retry). - A
query_paramsvalue that is an object or an array (numbers and booleans are accepted and sent as text). - A pinned query mixing
:namedand$1placeholders, or declaring more than 64 placeholders. Both are rejected when the tool is saved, and again at run time. - A query declaring placeholders on a call that supplied no
query_paramsat all — reported with the placeholder names, rather than reaching the database with:namemarkers intact. - SQL error from the database (surfaced as a tool error, not a panic).