Snowflake
Poll Snowflake event tables and expose Snowflake SQL and Cortex as AgentField capabilities.
Snowflake has two OSS surfaces:
- A built-in control-plane source named
snowflakefor event-table or custom-query polling. - An optional deployable Snowflake node that exposes governed data capabilities through
app.call.
Trigger Source
Use event_table_poll when Snowflake alerts or tasks write rows into an AGENTFIELD_EVENTS table.
{
"mode": "event_table_poll",
"account_url": "https://<account>.snowflakecomputing.com",
"database": "OBSERVABILITY",
"schema": "AGENTFIELD",
"table": "AGENTFIELD_EVENTS",
"warehouse": "AGENTFIELD_WH",
"role": "AGENTFIELD_ROLE",
"interval_seconds": 30,
"max_batch_size": 100
}Set the trigger secret env var to a Snowflake programmatic access token, usually SNOWFLAKE_PAT. The secret value stays in the control-plane environment; trigger config stores only the env-var name.
The source also supports custom_query_poll for a read-only query that returns EVENT_ID, EVENT_TYPE, PAYLOAD, and OCCURRED_AT.
Event Table
CREATE TABLE IF NOT EXISTS AGENTFIELD_EVENTS (
EVENT_ID STRING DEFAULT UUID_STRING(),
EVENT_TYPE STRING NOT NULL,
PAYLOAD VARIANT NOT NULL,
OCCURRED_AT TIMESTAMP_LTZ DEFAULT CURRENT_TIMESTAMP(),
CONSUMED_AT TIMESTAMP_LTZ
);The source normalizes each row into an AgentField event and deduplicates by EVENT_ID.
Reasoners receive the normalized payload under event and dispatch metadata under _meta:
{
"event": {
"event_id": "evt_123",
"event_type": "snowflake.alert.example",
"occurred_at": "2026-06-15T10:30:00Z",
"payload": { "source_table": "OBSERVABILITY.PUBLIC.REQUESTS" },
"snowflake": {
"account_url": "https://<account>.snowflakecomputing.com",
"database": "OBSERVABILITY",
"schema": "AGENTFIELD",
"table": "AGENTFIELD_EVENTS",
"query_id": "<statement-handle>"
}
},
"_meta": {
"source": "snowflake",
"event_type": "snowflake.alert.example",
"idempotency_key": "evt_123"
}
}Capability Node
Deploy the optional node when agents need to query Snowflake or call Cortex from other AgentField nodes.
docker run --name agentfield-snowflake \
-p 8012:8012 \
-e AGENTFIELD_SERVER=http://host.docker.internal:8080 \
-e AGENTFIELD_NODE_ID=snowflake-prod \
-e SNOWFLAKE_NODE_PUBLIC_URL=http://localhost:8012 \
-e SNOWFLAKE_ACCOUNT_URL=https://<account>.snowflakecomputing.com \
-e SNOWFLAKE_PAT=<programmatic-access-token> \
-e SNOWFLAKE_DATABASE=OBSERVABILITY \
-e SNOWFLAKE_SCHEMA=AGENTFIELD \
-e SNOWFLAKE_WAREHOUSE=AGENTFIELD_WH \
agentfield-snowflake-node:latestCall it from any SDK:
result = await app.call("snowflake-prod.semantic_ask", input={
"question": "What changed in revenue yesterday?"
})The node registers these callable reasoners. Their descriptions come from the OSS package manifest and node registration code.
| Capability | Description | Input | Output |
|---|---|---|---|
health | Report Snowflake node configuration health. | {} | status, node_id, prompt source/version, default Cortex model, Snowflake defaults. |
query_readonly | Run a guarded read-only Snowflake SQL statement. | sql; optional database, schema, warehouse, role, max_rows, timeout_seconds. | query_id, columns, rows, row_count, truncated, provenance. |
describe_table | Describe a Snowflake table or view. | object or table. | Query-style table metadata rows plus provenance. |
search_columns | Search Snowflake INFORMATION_SCHEMA columns. | query; optional database, schema, limit. | Matching column rows plus query provenance. |
cortex_analyst_message | Call Snowflake Cortex Analyst. | question; optional semantic_model, semantic_model_file, semantic_view, conversation. | answer, raw response, snowflake_request_id. |
cortex_search_query | Query a Cortex Search service. | service, query; optional database, schema, columns, filter, limit. | results, raw response, service name, snowflake_request_id. |
cortex_complete | Call Snowflake Cortex model inference. | model, prompt; optional system, max_tokens, temperature. | text, model, snowflake_request_id, optional usage. |
semantic_ask | Answer a data question using semantic context and configured prompts. | question; optional semantic model/view/context or model. | answer, model/query id when used, prompt source/keys, or NEEDS_REVIEW. |
explain_result | Explain a query result with configured caveat policy. | result or result_preview; optional question, model. | answer, model/query id, prompt source, or NEEDS_REVIEW. |
investigate_metric_change | Plan a bounded metric-change investigation. | metric_name, time_window. | status, rendered prompt, recommended follow-up calls, prompt source. |
Typical DX is to let an event trigger a domain reasoner, then call the Snowflake node only for data work:
@app.reasoner()
async def investigate_snowflake_alert(input: dict):
event = input["event"]
answer = await app.call("snowflake-prod.semantic_ask", input={
"question": f"Explain {event['event_type']} with the latest warehouse context",
"semantic_model": "finance_metrics",
})
return {"event_id": event["event_id"], "analysis": answer}Guardrails
- Default SQL capability is read-only.
- DDL, DML,
COPY,CALL,PUT,GET, and role switching are denied by default. - Prompt-backed reasoners load prompts from
SNOWFLAKE_PROMPTS_FILEor packaged defaults, not hardcoded customer behavior.