Skip to content

feat(appkit): add DatabricksAdapter.fromAiGateway for gateway chat completions - #605

Merged
MarioCadenas merged 5 commits into
mainfrom
feat/agents-ai-gateway
Sep 28, 2026
Merged

MarioCadenas merged 5 commits into
mainfrom
feat/agents-ai-gateway

Conversation

@MarioCadenas

@MarioCadenas MarioCadenas commented Sep 25, 2026 •

Copy link
Copy Markdown
Collaborator

What

Lets AppKit agents consume models through the Databricks AI Gateway Chat Completions endpoint (/ai-gateway/mlflow/v1/chat/completions), naming the model in the request body (a UC system.* name, e.g. system.ai.claude-opus-5-5) instead of a per-endpoint URL. This is the migration path off the legacy databricks-* serving-endpoint names.

Two commits:

  1. fromAiGateway adapter — DatabricksAdapter.fromAiGateway({ model }) explicit factory.
  2. Automatic routing — a string model that starts with system. resolves to the gateway; anything else resolves to Model Serving as before. So the common case needs no factory:
createAgent({
  instructions: "…",
  model: "system.ai.claude-opus-5-5",   // -> AI Gateway automatically
});

createAgent({
  instructions: "…",
  model: "my-custom-endpoint",          // -> /serving-endpoints/my-custom-endpoint/invocations
});

How

The gateway speaks the same OpenAI Chat Completions wire format the adapter already used, so the change is deliberately small:

  • connectors/serving/client.ts — new streamAiGateway(): hard-codes the gateway path, forces stream: true (mirrors the existing stream() serving helper; keeps streamPath's @internal hard-coded-path contract).
  • agents/databricks.ts — optional model on the adapter options, injected into the body only when set; fromAiGateway factory; and adapterFromModelString() — the single decision point that both string-model resolution sites now share (plugins/agents/agents.ts + core/agent/run-agent.ts), so they can't drift.

Everything else is reused unchanged: the multi-step tool loop, SSE parsing, dot→__ tool-name mapping, thought-signature pass-through, DoS caps, generation params.

Non-breaking

  • model is set on the request body only on the gateway path; fromModelServing / fromServingEndpoint requests are byte-identical to before (test-pinned).
  • Serving-endpoint names are [a-zA-Z0-9_-] (no dots), so the system. prefix never matches an existing endpoint name — no current string changes routing. A system.* string never worked as a serving-endpoint name anyway.
  • Escape hatch: to force a system.* name onto a serving endpoint, pass a pre-built DatabricksAdapter.fromServingEndpoint(...) as the agent's model.

Verification

  • Live against the dogfood gateway: /ai-gateway/mlflow/v1/chat/completions 200s, model-in-body works (system.ai.claude-opus-5-5 → global.anthropic.claude-opus-5-5), streaming SSE + tool-calling return in the exact choices[0].delta / tool_calls[] shape the adapter parses.
  • Tests: adapter + agents-plugin + core-agent suites green (465 passed). New tests cover: gateway path + model in body; serving path leaves model out; and the system.* vs non-system routing split.
  • Typecheck: no new errors introduced (pre-existing baseline red is in unrelated genie / sql-warehouse / mock-workspace-client files only).

This pull request and its description were written by Isaac.

…mpletions

Route agents through the Databricks AI Gateway Chat Completions
endpoint (/ai-gateway/mlflow/v1/chat/completions), naming the model in
the request body (e.g. system.ai.claude-opus-5-5) instead of in the URL.
Reuses the existing Chat Completions tool loop and SSE parsing unchanged.

Additive and non-breaking: the serving-endpoint path (fromModelServing,
fromServingEndpoint, bare-string model) never sets a body model, so its
request is byte-identical to before.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

📦 Bundle size report

Compared against bundle-size-baseline.json (main).

@databricks/appkit

npm tarball (packed): 1.2 MB (+3.6 KB) — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 1.2 MB (+3.4 KB) 426 KB (+1.0 KB)
Type declarations 446 KB (+2.4 KB) 162 KB (+674 B)
Source maps 2.3 MB (+7.2 KB) 799 KB (+2.0 KB)
Other 11 KB 3.7 KB
Total 4.0 MB (+13 KB) 1.4 MB (+3.7 KB)
Per-entry composition (own code — deps external (as shipped))
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
. 96 KB 2.5 KB 98 KB external 314 KB
./beta 93 KB (+170 B) 480 B (+23 B) 94 KB (+193 B) external 281 KB (+540 B)
./testing 38 KB 30 KB 69 KB external 201 KB
./tsdown 520 B 0 B 520 B external 813 B
./type-generator 23 KB 0 B 23 KB external 65 KB

Chunks:

Entry Chunk Load Size (gz)
. index.js initial 92 KB
. utils.js initial 4.0 KB
. remote-tunnel-manager.js lazy 2.5 KB
./beta beta.js initial 77 KB
./beta stream-manager.js initial 5.8 KB
./beta databricks.js initial 3.3 KB
./beta wide-event-emitter.js initial 3.2 KB
./beta configuration.js initial 2.3 KB
./beta service-context.js initial 1.3 KB
./beta client.js initial 434 B
./beta client-options.js initial 219 B
./beta supervisor-api.js lazy 192 B
./beta databricks.js lazy 165 B
./beta index.js lazy 123 B
./testing manifest.js initial 26 KB
./testing index.js initial 10.0 KB
./testing wide-event-emitter.js initial 2.9 KB
./testing index.js lazy 26 KB
./testing remote-tunnel-manager.js lazy 2.5 KB
./testing utils.js lazy 1.2 KB
./tsdown index.js initial 520 B
./type-generator index.js initial 23 KB

@databricks/appkit-ui

npm tarball (packed): 350 KB — gzipped download (dist + bin; excludes release-only docs/NOTICE).

dist raw gzip
JS (runtime) 395 KB 132 KB
Type declarations 229 KB 84 KB
Source maps 766 KB 253 KB
CSS 16 KB 3.2 KB
Total 1.4 MB 472 KB
Per-entry composition (consumer bundle — deps bundled, peerDeps external)
Entry Initial (gz) Lazy (gz) Total (gz) node_modules (min) Own code (min)
./js 5.3 KB 49 KB 55 KB 208 KB 14 KB
./js/beta 20 B 0 B 20 B 0 B 0 B
./react 432 KB 49 KB 481 KB 1.3 MB 177 KB
./react/beta 1.0 KB 0 B 1.0 KB 0 B 1.9 KB

Chunks:

Entry Chunk Load Size (gz)
./js index.js initial 5.2 KB
./js chunk initial 120 B
./js apache-arrow lazy 49 KB
./js/beta beta.js initial 20 B
./react index.js initial 430 KB
./react tslib initial 2.1 KB
./react apache-arrow lazy 49 KB
./react/beta beta.js initial 1.0 KB

@github-actions

github-actions Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

🤖 AppKit PR bot

🔬 Run evals

Start an eval for this PR from the evals-monitor app: Go to Evals Monitor →

📦 Try this PR's app template

Scaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh auth login — and the Databricks CLI):

gh run download 36422423929 -R databricks/appkit -n appkit-template-0.78.0-pr.0f7fbf2-feat-agents-ai-gateway-605 -D appkit-pr-605 \
  && unzip -o "appkit-pr-605/appkit-template-0.78.0-pr.0f7fbf2-feat-agents-ai-gateway-605.zip" -d "appkit-pr-605" \
  && databricks apps init --template "appkit-pr-605"

The template pins @databricks/appkit and @databricks/appkit-ui to tarballs built from this branch, so the scaffolded app runs against this PR's code.

Add adapterFromModelString(), the single decision point both string-model
resolution sites (agents plugin + standalone runAgent) now share: a
`system.*` UC model name (e.g. system.ai.claude-opus-5-5) resolves to the
AI Gateway; any other string (serving-endpoint names like
databricks-claude-sonnet-4-5, or custom endpoints) resolves to Model Serving.

Non-breaking: serving-endpoint names are [a-zA-Z0-9_-] (no dots), so the
`system.` prefix never matches an existing endpoint name. To force a
`system.*` name onto a serving endpoint, pass a pre-built adapter as the
agent's model.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
MarioCadenas and others added 3 commits September 28, 2026 13:53
…ateway routing

The no-model default path resolved DATABRICKS_SERVING_ENDPOINT_NAME inside
fromModelServing(), always building a serving-endpoint URL — so a `system.*`
value (e.g. system.ai.claude-opus-4-6) 404'd instead of reaching the AI
Gateway. Read the env default into the resolver's `source` so it flows through
adapterFromModelString() like an explicit string model, in both the agents
plugin and standalone runAgent.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
… demo

Points the autocomplete agent's `endpoint` at system.ai.gemini-3-5-flash-lite
so the reference app exercises the new AI Gateway routing (a system.* string
resolves to /ai-gateway/mlflow/v1/chat/completions).

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
Regenerated API reference for the new fromAiGateway factory.

Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: MarioCadenas <MarioCadenas@users.noreply.github.com>
@MarioCadenas
MarioCadenas marked this pull request as ready for review September 28, 2026 13:41
@MarioCadenas
MarioCadenas requested a review from a team as a code owner September 28, 2026 13:41
@MarioCadenas
MarioCadenas requested a review from ditadi September 28, 2026 13:41
@MarioCadenas
MarioCadenas merged commit c49beb3 into main Sep 28, 2026
10 checks passed
@MarioCadenas
MarioCadenas deleted the feat/agents-ai-gateway branch September 28, 2026 13:52
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