name: 06-appkit-serving-wiring
description: >
Wire a Databricks Model Serving or Agent endpoint into an existing AppKit project
using the Serving plugin. Covers endpoint registration, app.yaml resource binding,
streaming and invoke React hooks, conversation state management, agent response
mapping, and server-side proxy patterns. PRD-independent patterns that apply to
any AppKit + Serving app. Use after registering the Serving plugin via
04-appkit-plugin-add. Triggers on "wire agent", "agent endpoint", "serving plugin",
"agent UI", "chat interface", "connect agent", "model serving", "useServingStream",
"useServingInvoke", "agent chat", "wire serving", "serving wiring".
license: Apache-2.0
compatibility: Requires Serving plugin registered via 04-appkit-plugin-add, Node.js v22+, Databricks CLI >= 0.295.0
allowed-tools: Bash(databricks:) Bash(npm:) Bash(curl:) Bash(node:) Read
clients: [ide_cli, genie_code]
bundle_resource: apps
deploy_verb: apps_deploy
deploy_note: >
Serving wiring is source editing (server.ts plugin config, React hooks, optional proxy routes) —
client-agnostic. IDE: databricks serving-endpoints get/query --profile $PROFILE for verification,
npm run build gates locally, then databricks apps deploy --profile $PROFILE. Genie Code: run
serving-endpoints get/query via runDatabricksCli (read-tier, omit --profile); local npm run build
gates are an IDE convenience (skip — platform builds server-side); deploy per 03-appkit-deploy
(runDatabricksCli or SDK fallback). Verify the deployed app via browser or the OAuth-session test —
auth token + raw Bearer curl is hard-blocked on Genie Code.
coverage: full
metadata:
author: prashanth subrahmanyam
version: "1.1.0"
domain: apps
role: serving-wiring
standalone: false
last_verified: "2026-06-02"
volatility: medium
upstream_sources:
- name: "databricks-agent-skills/databricks-model-serving"
repo: "databricks/databricks-agent-skills"
paths:
- "skills/databricks-model-serving/SKILL.md"
relationship: "extended"
last_synced: "2026-04-27"
sync_commit: "manifest-v2-2026-04-22"
- name: "databricks-agent-skills/databricks-apps"
repo: "databricks/databricks-agent-skills"
paths:
- "skills/databricks-apps/SKILL.md"
relationship: "extended"
last_synced: "2026-04-27"
sync_commit: "manifest-v2-2026-04-22"
Wire Serving Endpoint into AppKit
Connect a Databricks Model Serving or Agent endpoint to an AppKit app using the Serving plugin. Build streaming chat UIs, single-shot query interfaces, or server-side proxy routes that post-process agent responses.
When to Use
- Wiring a deployed Agent or Model Serving endpoint into an AppKit app
- Building a streaming chat interface for a conversational agent
- Adding a single-shot inference call to a page (classification, summarization, etc.)
- Post-processing agent responses server-side before sending to the frontend
Not for registering the plugin. Use 04-appkit-plugin-add with references/plugin-serving.md to install and configure the Serving plugin first.
Not for deploying. Use 03-appkit-deploy after wiring is complete.
Not for deploying the agent itself. The agent endpoint must already exist on Databricks Model Serving.
Before You Begin
Prerequisites — verify these before proceeding:
- Agent endpoint is deployed on Databricks Model Serving and in
READYstate - The Serving plugin is registered in
server/server.ts(via04-appkit-plugin-add) - Endpoint added as an app resource with
CAN_QUERYpermission (via Databricks Apps UI orapp.yamlresources) app.yamlhasDATABRICKS_SERVING_ENDPOINT_NAMEwithvalueFrom: serving-endpointnpm run buildpasses with the Serving plugin importedservingexport is available in your installed AppKit version (see 04-appkit-plugin-add/SKILL.md Step 1b). Iftypeof require('@databricks/appkit').serving === "undefined", stop here — read references/custom-proxy-fallback.md and skip Step 3.
Upstream docs (always check for latest):
npx @databricks/appkit docs "serving"
Key architectural difference from Lakebase wiring: The Serving plugin auto-registers HTTP routes (
/api/serving/:alias/invokeand/api/serving/:alias/stream) via the plugin lifecycle — like the Genie plugin. You do NOT needserver.extend()to create routes for basic invoke/stream calls. Useserver.extend()only when you need a custom server-side proxy route that post-processes the agent's response (Step 6).
Working in Genie Code (client routing)
All the code in this skill — plugin config, hooks, proxy routes — is written the same way on both clients. Only the toolchain commands and the deployed-app verification differ. $APP_NAME / $PROFILE / endpoint name resolve from .vibecoding-state.md when a prior phase wrote it (don't re-derive). Apply these substitutions:
| IDE/CLI (as written) | Genie Code substitution |
|---|---|
databricks serving-endpoints get/query … --profile $PROFILE (Step 1) |
run via runDatabricksCli (read-tier, pre-approved), omit --profile |
npm run build gates (Steps 3, 8) — "You MUST run npm run build" |
IDE-only convenience — no local Node toolchain. Skip; the platform builds server-side on deploy and surfaces errors in databricks apps logs <name> |
npm run dev |
not available (and blocked pre-deploy: serving() needs platform-injected env) — verify on the deployed app |
npx @databricks/appkit docs "serving" |
npx absent (P9) — WebFetch https://databricks.github.io/appkit/docs/plugins/serving |
databricks auth token + curl -H "Authorization: Bearer …" (Steps 9b/9c) |
hard-blocked / raw Bearer rejected by the Apps OAuth gate → use browser (open the app URL, test chat) or the 3-hop OAuth requests.Session() test in 03-appkit-deploy |
databricks apps deploy … (Step 9a) |
see the 03-appkit-deploy deploy-routing contract (runDatabricksCli, else SDK w.apps.deploy(... SNAPSHOT)) |
Paths are relative to apps_lakebase/$APP_NAME — inside your git-cloned workshop project (artifact_root) on Genie Code, never the read-only .assistant/skills copy and never /tmp. See skills/genie-code-environment for the full manifest.
Decision Defaults
When multiple approaches are valid, use these defaults. Override only if the use case demands it.
| Decision | Default | Rationale |
|---|---|---|
| Streaming or invoke? | useServingStream for agent chat; useServingInvoke for single-shot |
Agents are typically slow — streaming gives progressive UX feedback |
| Single or multiple endpoints? | Single (reads DATABRICKS_SERVING_ENDPOINT_NAME) |
Multi-endpoint via endpoints: {} config is an advanced pattern |
| Chat UI pattern | Scrollable message list + input box + streaming indicator | Most agent UIs are conversational |
| Conversation state | Client-side useState<Message[]> array |
useServingStream is stateless; the app must manage history |
| Agent response mapping | Show raw text by default | Not all agents return structured data; see references/agent-response-mapping.md for structured patterns |
| OBO auth | Always (AppKit default) | Per-user CAN_QUERY enforcement on the serving endpoint |
| Timeout | 120000ms (2 minutes) | Agent endpoints may be slow; configurable via serving({ timeout }) |
npm run dev before deploy? |
No — npm run build only |
Serving plugin may throw ConfigurationError when env vars are not set |
| Check endpoint schema first? | Yes — verify streaming support | Endpoints without an OpenAPI streaming schema produce chunk: unknown |
Step 1: Verify Endpoint Access
Confirm the serving endpoint is reachable and in READY state before writing any code.
1a. Check Endpoint Status
databricks serving-endpoints get <endpoint-name> --profile $PROFILE --output json | jq '.state'
Expected output includes "ready": "READY". If the endpoint is not ready, wait for it to finish provisioning before proceeding.
1b. Test with a Sample Query
databricks serving-endpoints query <endpoint-name> \
--profile $PROFILE \
--input '{"messages": [{"role": "user", "content": "Hello"}]}'
If this returns a valid response, the endpoint is accessible and the agent is functional.
1c. Automated Test Script
bash apps_lakebase/skills/06-appkit-serving-wiring/scripts/test-serving-endpoint.sh \
--endpoint-name <endpoint-name> --profile $PROFILE
Gate: The endpoint responds with READY status and returns a non-empty response to the sample query.
Step 2: Configure app.yaml
2a. Add the Serving Endpoint as an App Resource
The endpoint must be registered as a resource in the Databricks Apps UI or in the app.yaml resources section:
- Resource key:
serving-endpoint(default) - Permission:
CAN_QUERY - Requirement: Endpoint must be in
READYstate
If using the Databricks Apps UI: navigate to your app's settings, add a Model Serving Endpoint resource, select the endpoint, and grant CAN_QUERY.
2b. Add the Environment Variable
env:
- name: DATABRICKS_SERVING_ENDPOINT_NAME
valueFrom: serving-endpoint
Critical — env var name mismatch: The Databricks Apps platform injects
SERVING_ENDPOINT=<name>via the resource binding, but the AppKit Serving plugin readsDATABRICKS_SERVING_ENDPOINT_NAME. You MUST explicitly declare the env var inapp.yamlwith the nameDATABRICKS_SERVING_ENDPOINT_NAMEand usevalueFrom: serving-endpointso the platform maps the resource value to the name the plugin expects.
2c. Local Development (.env)
For local dev, set the env var directly:
DATABRICKS_SERVING_ENDPOINT_NAME=<your-endpoint-name>
Local dev also requires Databricks authentication (CLI profile or DATABRICKS_HOST + DATABRICKS_TOKEN in .env).
Gate: app.yaml contains the DATABRICKS_SERVING_ENDPOINT_NAME env var with valueFrom: serving-endpoint.
Step 3: Register in server/server.ts
If
servingis undefined in your installed AppKit version, stop here and read references/custom-proxy-fallback.md instead of proceeding with Step 3. The bundler will silently accept a nonexistentservingimport and fail at client build or runtime.
3a. Single Endpoint (Default)
import { createApp, server, serving } from "@databricks/appkit";
await createApp({
plugins: [
server(),
serving(),
],
});
With no configuration, the plugin reads DATABRICKS_SERVING_ENDPOINT_NAME from the environment and registers it under the default alias. Routes are auto-registered at /api/serving/invoke and /api/serving/stream.
3b. Multiple Endpoints with Aliases
await createApp({
plugins: [
server(),
serving({
endpoints: {
agent: { env: "DATABRICKS_SERVING_ENDPOINT_NAME" },
classifier: { env: "DATABRICKS_CLASSIFIER_ENDPOINT_NAME" },
},
timeout: 120000,
}),
],
});
Each alias gets its own route pair: /api/serving/agent/invoke, /api/serving/agent/stream, etc.
3c. Targeting a Specific Model
If the endpoint serves multiple models, bypass traffic routing:
serving({
endpoints: {
agent: {
env: "DATABRICKS_SERVING_ENDPOINT_NAME",
servedModel: "my-agent-v2",
},
},
});
Unlike Lakebase wiring, no
server.extend()routes are needed here. The plugin auto-registers the HTTP endpoints. Theserver.extend()pattern is only needed if you want a custom proxy route (Step 6).
Gate: npm run build passes with the serving() plugin imported and configured.
Step 4: Wire Frontend — Streaming Chat
You MUST read references/chat-ui-patterns.md for the full conversation state management pattern before building a chat UI.
4a. Basic Streaming Hook
import { useServingStream } from "@databricks/appkit-ui/react";
function AgentChat() {
const { stream, chunks, streaming, error, reset } = useServingStream(
{ messages: [{ role: "user", content: userInput }] },
{
alias: "agent",
onComplete: (finalChunks) => {
console.log("Agent done:", finalChunks.length, "chunks");
},
},
);
return (
<>
<button onClick={stream} disabled={streaming}>Ask Agent</button>
<button onClick={reset}>Clear</button>
{chunks.map((c, i) => <pre key={i}>{JSON.stringify(c)}</pre>)}
{error && <p className="text-red-600">{error}</p>}
</>
);
}
4b. Conversation State Management
useServingStream is stateless — it doesn't track history across calls. For multi-turn chat, manage messages in useState and pass the full array on each request:
const [messages, setMessages] = useState<{ role: string; content: string }[]>([]);
const { stream, chunks, streaming, error, reset } = useServingStream(
{
messages: [
...messages,
{ role: "user", content: currentInput },
],
},
{
alias: "agent",
onComplete: (finalChunks) => {
const text = finalChunks
.map((c: any) => c.choices?.[0]?.delta?.content ?? "")
.join("");
setMessages((prev) => [
...prev,
{ role: "user", content: currentInput },
{ role: "assistant", content: text },
]);
reset();
},
},
);
Key rules:
- Pass the full conversation history on every call so the agent has context
- Append the assistant message in
onComplete, not during streaming - Call
reset()after capturing the response to clear chunks for the next turn - For long conversations, consider a sliding window to stay within token limits
Request body timing: The first argument to
useServingStreamis the request body sent whenstream()is called. Verify the hook re-reads this argument at call time, not at mount time. If the messages array appears stale (always sends the initial empty array), use auseRefto hold current messages — see references/chat-ui-patterns.md for theuseReffallback pattern. Test multi-turn early: send two messages and confirm the second request includes the first exchange.
4c. Streaming Chunk Format
Databricks emits streaming chunks in two different shapes depending on how the endpoint was deployed:
- Databricks Responses API (agents deployed via
databricks.agents.deploy()withResponsesAgent):{ type: "response.output_text.delta", delta: "..." } - OpenAI Chat Completion (custom Model Serving, OpenAI-compatible pyfunc):
chunk.choices[0].delta.content
A parser that reads only choices[0].delta.content will silently produce empty output against a Responses-API endpoint. Before writing the parser, read references/sse-format-patterns.md for the curl pre-deploy format test and a dual-format parser you can copy directly.
Minimal dual-format extractor (use against both endpoint types):
function extractDelta(chunk: any): string {
if (chunk.type === "response.output_text.delta") return chunk.delta ?? "";
return chunk.choices?.[0]?.delta?.content ?? "";
}
For the full SSE reader (buffering, [DONE] handling, unknown-chunk warnings, and the curl pre-deploy format test), read references/sse-format-patterns.md.
Gate: The streaming chat component renders in the browser with npm run build succeeding. Full runtime testing happens after deployment (Step 9).
Step 5: Wire Frontend — Invoke (Optional)
For single-shot queries where streaming is unnecessary:
import { useServingInvoke } from "@databricks/appkit-ui/react";
function AgentQuery() {
const { invoke, data, loading, error } = useServingInvoke(
{ messages: [{ role: "user", content: "Summarize Q3 sales" }] },
{ alias: "agent" },
);
return (
<>
<button onClick={invoke} disabled={loading}>Run</button>
{data && <pre>{JSON.stringify(data, null, 2)}</pre>}
{error && <p className="text-red-600">{error}</p>}
</>
);
}
useServingInvoke returns typed data when the endpoint has an OpenAPI response schema. The invoke() function returns a promise with the response data (or null on error), so you can also await it.
Gate: npm run build passes.
Step 6: Server-Side Proxy (Optional)
Use server.extend() when you need to post-process agent responses before sending them to the frontend — e.g., extracting structured data from tool calls, adding business logic, or chaining with other plugins.
6a. Proxy Route Pattern
const AppKit = await createApp({
plugins: [server({ autoStart: false }), serving()],
});
AppKit.server.extend((app) => {
app.post("/api/ask-agent", async (req, res) => {
try {
const result = await AppKit.serving("agent")
.asUser(req)
.invoke({ messages: req.body.messages });
// Post-process the result here (see Step 7)
res.json(result);
} catch (err) {
console.warn(`[Serving] /api/ask-agent error: ${err}`);
res.status(500).json({ error: "Agent request failed" });
}
});
});
await AppKit.server.start();
Gotcha —
autoStart: falseis required when usingserver.extend(). Without it, the server starts beforeextend()runs and routes are never registered. Same pattern as Lakebase wiring.
Local dev note: In development mode (
NODE_ENV=development), if.asUser(req)is called without a user token (nox-forwarded-access-tokenheader), AppKit logs a warning and skips user impersonation — the operation runs with default credentials instead. This is expected behavior during local development; the warning is not an error.
6b. Streaming Proxy
app.post("/api/ask-agent/stream", async (req, res) => {
res.setHeader("Content-Type", "text/event-stream");
res.setHeader("Cache-Control", "no-cache");
try {
for await (const chunk of AppKit.serving("agent").asUser(req).stream({
messages: req.body.messages,
})) {
res.write(`data: ${JSON.stringify(chunk)}\n\n`);
}
res.write("data: [DONE]\n\n");
res.end();
} catch (err) {
res.write(`data: ${JSON.stringify({ error: String(err) })}\n\n`);
res.end();
}
});
Gate: npm run build passes with the extended server routes.
6c. Custom Proxy Fallback (When serving Is Not Exported)
If the Step 1b check in 04-appkit-plugin-add returned typeof serving === "undefined", replace Steps 3–5 with a custom proxy. The full pattern lives in references/custom-proxy-fallback.md; the three pieces agents most commonly get wrong are inlined here.
Auth — use config.authenticate(headers), NOT config.getToken():
import { getExecutionContext } from "@databricks/appkit";
async function getServingHeaders() {
const ctx = getExecutionContext();
const config = ctx.client.config;
await config.ensureResolved();
const host = (config.host ?? "").replace(/\/$/, "");
const h = new Headers();
await config.authenticate(h);
h.set("Content-Type", "application/json");
const out: Record<string, string> = {};
h.forEach((v, k) => { out[k] = v; });
return { host, headers: out };
}
Anti-patterns that will fail at deploy time:
config.getToken()— method does not exist on AppKitConfig.process.env.DATABRICKS_HOSTdirectly — may lackhttps://; useconfig.hostinstead.
Payload — transform messages → input:
function buildAgentPayload(body: any, stream = false) {
return {
input: body.messages ?? body.input ?? [],
...(stream ? { stream: true } : {}),
...(body.context ? { context: body.context } : {}),
};
}
Sending {messages: ...} directly produces 400: Model is missing inputs ['input'].
Routes: mirror the plugin surface (/api/serving/invoke, /api/serving/stream) so the frontend hooks in Step 4 work unchanged. See references/custom-proxy-fallback.md for the full Express handlers including SSE passthrough.
Gate: npm run build passes with the custom proxy routes.
Step 7: Map Agent Output to Structured UI (Optional)
You MUST read references/agent-response-mapping.md before implementing this step. It covers three patterns:
- Structured Output Schema — endpoint defines an output schema;
useServingInvokereturns typed data - Tool Results Extraction — agent uses tools that return JSON/tabular data; extract and map server-side
- Text Parsing — regex extraction from free-text responses (last resort)
This step generalizes the mapper pattern from agentic-framework/agents/agent-ui-wiring-prompt.md, where booking agent Genie results were mapped to Listing objects. The reference file provides PRD-independent templates.
Choose based on your agent's output:
| Agent Output Type | Pattern | Where |
|---|---|---|
| Typed JSON (OpenAPI schema) | Pattern 1 | Frontend only |
| Tool call results (SQL, API) | Pattern 2 | Server proxy (Step 6) + frontend |
| Free text with embedded data | Pattern 3 | Server proxy (Step 6) + frontend |
| Conversational text only | Skip this step | Frontend (Step 4 or 5) |
Step 8: Build Gate
You MUST run npm run build and fix all errors before proceeding to deployment.
cd apps_lakebase/$APP_NAME
npm run build
This validates all TypeScript, imports, and bundling without executing the code.
Do NOT run
npm run devat this step if you haven't deployed yet. Theserving()plugin may throwConfigurationErrorwhenDATABRICKS_SERVING_ENDPOINT_NAMEis not set. These env vars are injected by the platform after the serving endpoint resource is bound. Usenpm run buildonly for local validation. Runtime testing withnpm run devis available after deployment or after configuring.envwith connection details.
What to Verify at This Step
- Zero TypeScript errors
- All
@databricks/appkitand@databricks/appkit-uiimports resolve serving()plugin configuration compiles- Frontend hooks (
useServingStream,useServingInvoke) compile with correct types - Any
server.extend()routes (Step 6) compile
Step 9: Deploy and Test
9a. Deploy
Use 03-appkit-deploy to deploy the app:
databricks apps deploy --profile $PROFILE
9b. Verify Auto-Registered Endpoints
After deployment, test the Serving plugin's auto-registered endpoints:
APP_URL=$(databricks apps get $APP_NAME --profile $PROFILE --output json | jq -r '.url')
TOKEN=$(databricks auth token --profile $PROFILE --output json | jq -r '.access_token')
curl -s -X POST "${APP_URL}/api/serving/invoke" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d '{"messages": [{"role": "user", "content": "Hello"}]}' | jq .
For named aliases, use /api/serving/<alias>/invoke instead.
Client note — Genie Code: this
auth token+ raw Bearercurldoes not work (auth tokenhard-blocked; AppKit's OAuth gate rejects raw Bearer → 401). Verify instead via browser (open the app URL and test the chat UI) or the 3-hop OAuthrequests.Session()pattern in03-appkit-deploy"Testing Deployed App APIs", then assert ondatabricks apps logs <name>.
9c. Automated Test
bash apps_lakebase/skills/06-appkit-serving-wiring/scripts/test-serving-endpoint.sh \
--base-url "$APP_URL" \
--alias "default"
9d. Verify Frontend
Open the app URL in a browser and test:
- The chat input accepts a message
- Streaming responses appear progressively
- Conversation history persists across turns
- Error states display correctly when the agent fails
- A domain-specific data question returns data (not just a greeting). If the agent greets but returns nothing for a question that should hit a tool / Genie / SQL (e.g., "how many bookings last month?"), the tool-calling path is broken. AI Playground may still work because it uses OBO; the app's SP does not. Check Genie Space / warehouse / UC grants via 09-simple-agent-scaffold/references/post-deploy-permissions.md.
Gate: The agent responds to queries via the deployed app's UI and API endpoints.
Gotchas (Summary)
Detailed callouts are embedded inline at the relevant step. This table is a compact reference.
| Gotcha | Fix | Step |
|---|---|---|
Serving plugin crashes without DATABRICKS_SERVING_ENDPOINT_NAME |
Expected before first deploy; use npm run build only |
3, 8 |
Platform injects SERVING_ENDPOINT but AppKit reads DATABRICKS_SERVING_ENDPOINT_NAME |
Name the env var explicitly in app.yaml with valueFrom: serving-endpoint |
2 |
Streaming chunks typed as unknown when endpoint lacks OpenAPI streaming schema |
Use useServingInvoke instead, or cast chunks after logging shape |
4 |
useServingStream is stateless — no built-in conversation history |
Manage message array in useState; pass full history on each call |
4 |
Endpoint not in READY state |
Verify via databricks serving-endpoints get <name> before wiring |
1 |
autoStart: true on hooks fires on mount |
Only use for demo/single-shot; omit for interactive chat | 4, 5 |
Custom server.extend() routes need autoStart: false on server() plugin |
Same pattern as Lakebase wiring — call AppKit.server.start() after extend |
6 |
| Type generation fails silently when endpoint env var not set | Generated types fall back to unknown; endpoint still usable, just untyped |
3 |
| 403 on invoke/stream endpoints | User lacks CAN_QUERY on the serving endpoint; verify app resource binding |
2, 9 |
npm run dev crashes without env vars |
Use npm run build only before first deploy; after deploy, configure .env |
8 |
| Agent timeout (no response within 120s) | Increase timeout in serving() config or simplify the prompt |
3 |
400: Model is missing inputs ['input'] when calling agent endpoint |
Payload sent {"messages":[...]} but agent expects {"input":[...]}. The plugin normalizes this; a custom proxy must transform — see references/custom-proxy-fallback.md |
3, 6c |
| Stream returns 200, UI stays blank | Parser reads choices[0].delta.content but endpoint emits Databricks Responses API (type: "response.output_text.delta"). Use dual parser from references/sse-format-patterns.md |
4 |
TypeError: Failed to parse URL when calling endpoint from a custom proxy |
Using process.env.DATABRICKS_HOST which may lack https://. Use config.host from getExecutionContext().client.config — see references/custom-proxy-fallback.md |
6c |
TypeError: config.getToken is not a function in custom proxy auth |
AppKit Config does not expose getToken(). Use await config.authenticate(headers) — see references/custom-proxy-fallback.md |
6c |
serving export missing in older AppKit versions |
Run Step 1b check (node -e ...) BEFORE importing; fall back to Step 6c custom proxy if undefined |
3, 6c |
Anti-Patterns (Things Agents Reach For That Fail)
| Anti-Pattern | Why It Fails | Correct Approach |
|---|---|---|
Import serving without verifying the export |
tsdown bundles silently; fails only at tsc/runtime | Run Step 1b node -e check first |
Guess the SDK auth API (getToken, raw env vars) |
AppKit Config exposes only authenticate(headers) |
Step 6c getServingHeaders |
Forward {messages:...} straight to an Agent endpoint |
Agent expects {input:...} at top level |
Step 6c buildAgentPayload |
Parse only choices[0].delta.content |
Databricks Responses API emits response.output_text.delta |
Step 4c dual parser |
rm -f package-lock.json && npm install to "fix" deps |
Picks up local proxy URLs, breaks platform install | --package-lock-only, or delete and let platform resolve |
| Delete the app to "start fresh" | New SP loses ownership of Lakebase schemas | Fix the deploy; DROP+recreate schemas only as last resort |
| Ship after one "Hello" response | Tool-calling path may still be broken | Test a real domain question before declaring done |
Quick Reference
| Task | Command / Pattern |
|---|---|
| Check live Serving docs | npx @databricks/appkit docs "serving" |
| Check endpoint status | databricks serving-endpoints get <name> --profile $PROFILE |
| Build gate | npm run build (must pass with zero errors) |
| Test invoke endpoint (after deploy) | curl -s -X POST "$APP_URL/api/serving/invoke" -H "Content-Type: application/json" -H "Authorization: Bearer $TOKEN" -d '{"messages":[{"role":"user","content":"Hello"}]}' |
| Test with script (after deploy) | bash apps_lakebase/skills/06-appkit-serving-wiring/scripts/test-serving-endpoint.sh --base-url "$APP_URL" |
| Frontend streaming hook | useServingStream({ messages }, { alias: "agent" }) |
| Frontend invoke hook | useServingInvoke({ messages }, { alias: "agent" }) |
| Server-side invoke | AppKit.serving("agent").asUser(req).invoke({ messages }) |
| Server-side stream | for await (const chunk of AppKit.serving("agent").stream({ messages })) |
See Also
- Upstream platform skills:
databricks-model-servinganddatabricks-apps(both tracked inupstream_sources). - AppKit Serving plugin docs: databricks.github.io/appkit/docs/plugins/serving