Skip to content
Integrations
Integrations

Snowflake

Poll Snowflake event tables and expose Snowflake SQL and Cortex as AgentField capabilities.

Snowflake connect dialog with event table polling config

Snowflake has two OSS surfaces:

  • A built-in control-plane source named snowflake for 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:latest

Call 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.

CapabilityDescriptionInputOutput
healthReport Snowflake node configuration health.{}status, node_id, prompt source/version, default Cortex model, Snowflake defaults.
query_readonlyRun 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_tableDescribe a Snowflake table or view.object or table.Query-style table metadata rows plus provenance.
search_columnsSearch Snowflake INFORMATION_SCHEMA columns.query; optional database, schema, limit.Matching column rows plus query provenance.
cortex_analyst_messageCall Snowflake Cortex Analyst.question; optional semantic_model, semantic_model_file, semantic_view, conversation.answer, raw response, snowflake_request_id.
cortex_search_queryQuery a Cortex Search service.service, query; optional database, schema, columns, filter, limit.results, raw response, service name, snowflake_request_id.
cortex_completeCall Snowflake Cortex model inference.model, prompt; optional system, max_tokens, temperature.text, model, snowflake_request_id, optional usage.
semantic_askAnswer 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_resultExplain 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_changePlan 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_FILE or packaged defaults, not hardcoded customer behavior.