Skip to content

Commit 2db7108

Browse files
committed
feat(appkit): supervisor api adapter
1 parent 4ee02ce commit 2db7108

9 files changed

Lines changed: 1704 additions & 16 deletions

File tree

apps/dev-playground/server/index.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,12 @@ import {
1111
serving,
1212
WRITE_ACTIONS,
1313
} from "@databricks/appkit";
14-
import { agents, createAgent, tool } from "@databricks/appkit/beta";
14+
import {
15+
agents,
16+
createAgent,
17+
fromSupervisorApi,
18+
tool,
19+
} from "@databricks/appkit/beta";
1520
import { WorkspaceClient } from "@databricks/sdk-experimental";
1621
import { z } from "zod";
1722
import { lakebaseExamples } from "./lakebase-examples-plugin";
@@ -68,6 +73,33 @@ const helper = createAgent({
6873
},
6974
});
7075

76+
// Supervisor API demo agent. Tools are configured on the adapter (the SA
77+
// endpoint executes them server-side), not on the createAgent definition.
78+
// Uncomment a `supervisorTools.*` entry (and import 'supervisorTools' from
79+
// '@databricks/appkit/beta') to give the model real powers.
80+
//
81+
// We `await` the factory at module init so a misconfigured workspace
82+
// (missing host, bad credentials) fails fast with a clear error here
83+
// instead of as an unhandled rejection. Top-level await is fine in this
84+
// ESM module.
85+
const supervisor = createAgent({
86+
instructions:
87+
"You are an assistant powered by the Databricks Supervisor API.",
88+
model: fromSupervisorApi({
89+
model: "databricks-claude-sonnet-4-5",
90+
tools: [
91+
// supervisorTools.genieSpace(
92+
// "01ABCDEF12345678",
93+
// "NYC taxi trip records and zones",
94+
// ),
95+
// supervisorTools.ucFunction(
96+
// "main.default.add",
97+
// "Adds two integers and returns the sum.",
98+
// ),
99+
],
100+
}),
101+
});
102+
71103
/*
72104
* Smart-Dashboard agents.
73105
*
@@ -385,7 +417,7 @@ createApp({
385417
}),
386418
serving(),
387419
agents({
388-
agents: { helper, sql_analyst, dashboard_pilot },
420+
agents: { helper, sql_analyst, dashboard_pilot, supervisor },
389421
// `query` (markdown dispatcher) + `sql_analyst` + `dashboard_pilot`
390422
// wire the /smart-dashboard route. `insights` and `anomaly` are
391423
// ephemeral markdown agents auto-fired by the route's AgentSidebar.

docs/docs/plugins/agents.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ This page covers the full lifecycle. For the hand-written primitives (`tool()`,
1616
The agents plugin drives the LLM over Server-Sent Events. Foundation Model APIs (Claude, Llama, GPT, etc.) and other chat-style endpoints support streaming and work out of the box. Custom model endpoints that return a single JSON response (e.g. typical `sklearn` or MLflow `pyfunc` deployments) do **not** stream — pointing an agent at one will fail with "Response body is null — streaming not supported" on the first turn. If you list a serving endpoint in `apps init`, pick one whose model implements the chat-completions streaming protocol; the agents plugin reads its name from `DATABRICKS_SERVING_ENDPOINT_NAME` whenever an agent doesn't pin `model:` itself.
1717

1818
For the non-streaming path against a custom endpoint, use the `serving` plugin's `/invoke` route with `useServingInvoke` instead.
19+
20+
Or skip serving-endpoint setup entirely with the managed [Supervisor API adapter](#managed-agents-the-supervisor-api-adapter) (beta) — no endpoint to pick, no `DATABRICKS_SERVING_ENDPOINT_NAME`, just SDK credentials.
1921
:::
2022

2123
## Install
@@ -217,6 +219,79 @@ const result = await runAgent(classifier, {
217219

218220
Hosted tools (MCP) are still `agents()`-only since they require the live MCP client. Plugin tool dispatch in standalone mode runs as the service principal (no OBO) and **bypasses the agents-plugin approval gate** — treat standalone runAgent as a trusted-prompt environment (CI, batch eval, internal scripts), not as an exposed user-facing surface.
219221

222+
## Managed agents: the Supervisor API adapter
223+
224+
`fromSupervisorApi` (beta) is the zero-config way to back an agent: instead of provisioning and pointing at a model-serving endpoint, you target the Databricks AI Gateway Responses API (`/ai-gateway/mlflow/v1/responses`), which runs the LLM — and any hosted tools — as a managed service on Databricks. No `DATABRICKS_SERVING_ENDPOINT_NAME`, no stream-capability check, no JS tool plumbing for the common cases.
225+
226+
The minimal agent is one extra line versus a markdown agent:
227+
228+
```ts
229+
import { createApp, createAgent } from "@databricks/appkit";
230+
import { agents, fromSupervisorApi } from "@databricks/appkit/beta";
231+
232+
await createApp({
233+
plugins: [
234+
agents({
235+
agents: {
236+
assistant: createAgent({
237+
instructions: "You are a helpful assistant.",
238+
model: fromSupervisorApi({ model: "databricks-claude-sonnet-4-5" }),
239+
}),
240+
},
241+
}),
242+
],
243+
});
244+
```
245+
246+
`createAgent({ model })` already accepts adapters and adapter promises in addition to the model-name string used in earlier examples, so you can drop the factory result straight in. `fromSupervisorApi` resolves credentials through the SDK chain (`DATABRICKS_HOST`, OAuth, PAT, …); pass `workspaceClient` to reuse an existing client.
247+
248+
### Hosted tools
249+
250+
Expose Genie spaces, Unity Catalog functions/connections, Knowledge Assistants, or other AppKit apps to the model by listing them on the adapter — execution stays server-side, you write no tool code:
251+
252+
```ts
253+
import { fromSupervisorApi, supervisorTools } from "@databricks/appkit/beta";
254+
255+
const model = fromSupervisorApi({
256+
model: "databricks-claude-sonnet-4-5",
257+
tools: [
258+
supervisorTools.genieSpace(
259+
"01ABCDEF12345678",
260+
"NYC taxi trip records and zones",
261+
),
262+
supervisorTools.ucFunction(
263+
"main.default.add",
264+
"Adds two integers and returns the sum.",
265+
),
266+
],
267+
});
268+
```
269+
270+
`description` is **required and non-empty** — the LLM uses it to route between tools, so two Genie spaces both labelled "Genie space" will be indistinguishable.
271+
272+
| Factory | Tool kind | Identifier |
273+
|---|---|---|
274+
| `supervisorTools.genieSpace(id, description)` | Genie space | space id |
275+
| `supervisorTools.ucFunction(name, description)` | Unity Catalog function | three-part name |
276+
| `supervisorTools.knowledgeAssistant(id, description)` | Knowledge Assistant | assistant id |
277+
| `supervisorTools.app(name, description)` | Databricks App | app name |
278+
| `supervisorTools.ucConnection(name, description)` | UC connection | connection name |
279+
280+
### What does *not* apply to Supervisor-API agents
281+
282+
The managed runtime owns its own tool execution, so the adapter intentionally **ignores the agents-plugin tool index**. For any agent whose `model:` is a Supervisor adapter:
283+
284+
- Tools wired via markdown `tools:` or the `tools(plugins)` function form are not exposed to the model — declare hosted tools via `fromSupervisorApi({ tools: […] })` instead.
285+
- The **human-in-the-loop approval gate** does not fire (tool calls never enter the Node process; `effect: "destructive"` annotations on plugin tools are irrelevant here).
286+
- `limits.maxToolCalls` is not enforced (the managed runtime accounts for its own calls).
287+
- Per-call **OBO** does not apply to hosted tools; they run with the credentials the managed runtime uses for the target resource.
288+
289+
Standard-adapter agents and Supervisor-API agents can coexist in the same `agents({ agents: { … } })` map and can be composed as sub-agents (Level 4) — only the agent whose `model:` points at a Supervisor adapter is exempt from the items above.
290+
291+
:::note Recovery path for non-streaming tool turns
292+
Some hosted tool kinds return their final assistant text without incremental `output_text.delta` events. The adapter has a recovery path that pulls the text out of `response.completed.output[]` so the turn is not silently empty. Set `DEBUG=appkit:agents:supervisor-api` to log the per-turn event-type histogram if you want to verify which path a turn took.
293+
:::
294+
220295
## Configuration reference
221296

222297
```ts

0 commit comments

Comments
 (0)