AgentFieldintegrations

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.

The OSS package is in integrations/snowflake. The node image is built from integrations/snowflake/node/Dockerfile, which expects the repository root as the Docker build context; the package also includes a docker-compose.example.yml.

git clone https://github.com/Agent-Field/agentfield.git
cd agentfield
docker build \
  -f integrations/snowflake/node/Dockerfile \
  -t agentfield-snowflake-node:latest \
  .
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.