Skip to content

Add Snowflake integration pack#656

Open
santoshkumarradha wants to merge 9 commits into
mainfrom
codex/snowflake-integration-architecture
Open

Add Snowflake integration pack#656
santoshkumarradha wants to merge 9 commits into
mainfrom
codex/snowflake-integration-architecture

Conversation

@santoshkumarradha

Copy link
Copy Markdown
Member

Summary

Adds the first Snowflake integration pack with two separate surfaces:

  • a built-in control-plane snowflake trigger source for Snowflake event-table/custom-query polling
  • an optional Docker-hostable Go capability node that registers Snowflake skills/reasoners for cross-node calls

This keeps ingress in the control plane while keeping data/API capabilities modular, deployable, and callable from any AgentField SDK.

Developer Experience

Trigger side

Operators configure Snowflake from Integrations -> Snowflake -> Connect or through POST /api/v1/triggers.

The target node/reasoner must already be registered. The trigger stores only a secret env-var reference, for example SNOWFLAKE_PAT; the PAT value stays in the control-plane environment.

Example config shape:

{
  "mode": "event_table_poll",
  "account_url": "https://<account>.snowflakecomputing.com",
  "database": "AGENTFIELD_TEST",
  "schema": "PUBLIC",
  "table": "AGENTFIELD_EVENTS",
  "warehouse": "AGENTFIELD_WH",
  "role": "AGENTFIELD_TEST_ROLE",
  "interval_seconds": 30,
  "max_batch_size": 100
}

The source persists inbound event history, dedupes by EVENT_ID, normalizes payload/provenance, and dispatches to the selected reasoner.

Node side

Users deploy the optional Snowflake node as a Go binary in Docker. It registers as a normal AgentField node, for example snowflake-prod.

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_LISTEN=:8012 \
  -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=AGENTFIELD_TEST \
  -e SNOWFLAKE_SCHEMA=PUBLIC \
  -e SNOWFLAKE_WAREHOUSE=AGENTFIELD_WH \
  -e SNOWFLAKE_ROLE=AGENTFIELD_TEST_ROLE \
  agentfield-snowflake-node:latest

Other nodes then call it through AgentField:

result, err := a.Call(ctx, "snowflake-prod.query_readonly", map[string]any{
  "sql": "SELECT EVENT_ID, EVENT_TYPE FROM AGENTFIELD_EVENTS LIMIT 10",
})
result = await app.call("snowflake-prod.semantic_ask", input={
    "question": "What changed in revenue yesterday?"
})

Included Capabilities

  • query_readonly
  • describe_table
  • search_columns
  • cortex_analyst_message
  • cortex_search_query
  • cortex_complete
  • semantic_ask
  • explain_result
  • investigate_metric_change

Prompt-backed reasoners load prompts from SNOWFLAKE_PROMPTS_FILE or packaged defaults, so prompt behavior is not hardcoded into the binary.

Implementation Notes

  • Registers control-plane/internal/sources/snowflake through the built-in source registry.
  • Adds Snowflake UI metadata, icon, and trigger-dialog defaults using existing UI components/design tokens.
  • Adds integrations/snowflake contracts, manifest, Dockerfile, prompt defaults, docs, and e2e harnesses.
  • SQL API support includes PAT auth header and 202 Accepted polling.
  • Trigger polling normalizes Snowflake timestamp watermarks using TO_VARCHAR(..., 'YYYY-MM-DD"T"HH24:MI:SS.FF9') and TO_TIMESTAMP_NTZ(...); this was verified against a real Snowflake account after the first live smoke uncovered Snowflake JSON timestamp serialization behavior.

Validation

  • go test ./internal/sources/snowflake ./internal/sources/all
  • go test ./... in integrations/snowflake/node
  • go test ./... in integrations/snowflake/e2e/caller-node
  • go test ./... in integrations/snowflake/e2e/fake-snowflake
  • YAML parse for all Snowflake manifests/prompts
  • npm run build in control-plane/web/client
  • Docker image build for the Snowflake node
  • Multi-node e2e smoke with AgentField control plane + caller node + Docker Snowflake node + fake Snowflake API
  • Live Snowflake smoke using a scoped PAT:
    • direct SQL API auth succeeded
    • Docker node query_readonly succeeded through AgentField
    • control-plane Snowflake trigger polled and dispatched existing event rows
    • row inserted after trigger startup was picked up and dispatched with its own workflow id

Safety / Scope

  • Default SQL capability is read-only and denies DDL/DML/COPY/CALL/PUT/GET/role switching.
  • Secrets are referenced by env var; secret values are not stored in trigger config.
  • No real Snowflake token, account id, username, or smoke-test row ids are included in the diff.
  • This PR is intentionally draft for product/API review before merge.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

📊 Coverage gate

Thresholds from .coverage-gate.toml: per-surface ≥ 84%, aggregate ≥ 85%, max per-surface regression ≤ 1.0 pp, max aggregate regression ≤ 0.50 pp.

Surface Current Baseline Δ
control-plane 87.10% 87.40% ↓ -0.30 pp 🟡
sdk-go 92.00% 92.00% → +0.00 pp 🟢
sdk-python 93.73% 93.73% ↑ +0.00 pp 🟢
sdk-typescript 90.44% 90.42% ↑ +0.02 pp 🟢
web-ui 84.83% 84.79% ↑ +0.04 pp 🟡
aggregate 85.67% 85.75% ↓ -0.08 pp 🟡

✅ Gate passed

No surface regressed past the allowed threshold and the aggregate stayed above the floor.

@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

📐 Patch coverage gate

Threshold: 80% on lines this PR touches vs origin/main (from .coverage-gate.toml:thresholds.min_patch).

Surface Touched lines Patch coverage Status
control-plane 414 87.00%
sdk-go 0 ➖ no changes
sdk-python 0 ➖ no changes
sdk-typescript 0 ➖ no changes
web-ui 6 83.00%

✅ Patch gate passed

Every surface whose lines were touched by this PR has patch coverage at or above the threshold.

Comment thread control-plane/internal/sources/snowflake/snowflake.go Fixed
Comment thread control-plane/internal/sources/snowflake/snowflake.go Fixed
@santoshkumarradha santoshkumarradha marked this pull request as ready for review June 12, 2026 18:25
@santoshkumarradha santoshkumarradha requested review from a team and AbirAbbas as code owners June 12, 2026 18:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants