Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 36 additions & 2 deletions apps/dev-playground/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {
serving,
WRITE_ACTIONS,
} from "@databricks/appkit";
import { agents, createAgent, tool } from "@databricks/appkit/beta";
import {
agents,
createAgent,
DatabricksAdapter,
tool,
} from "@databricks/appkit/beta";
import { WorkspaceClient } from "@databricks/sdk-experimental";
import { z } from "zod";
import { lakebaseExamples } from "./lakebase-examples-plugin";
Expand Down Expand Up @@ -68,6 +73,35 @@ const helper = createAgent({
},
});

// Supervisor API demo agent. The Databricks AI Gateway executes hosted
// tools server-side; declare them via `createAgent({ tools })` like any
// other agent tool — the agents plugin classifies the tagged record and
// routes it to the adapter via AgentInput.extensions. Import
// `supervisorTools` from '@databricks/appkit/beta' and uncomment an
// entry below to give the model real powers.
//
// `createAgent({ model })` accepts an adapter promise, so the factory's
// host/credential resolution is awaited lazily on first dispatch (via
// `resolveAdapter` in the agents plugin). A misconfigured workspace will
// surface at first chat request, not at module init.
const supervisor = createAgent({
instructions:
"You are an assistant powered by the Databricks Supervisor API.",
model: DatabricksAdapter.fromSupervisorApi({
model: "databricks-claude-sonnet-4-5",
}),
tools: () => ({
// nyc: supervisorTools.genieSpace({
// id: "01ABCDEF12345678",
// description: "NYC taxi trip records and zones",
// }),
// add: supervisorTools.ucFunction({
// name: "main.default.add",
// description: "Adds two integers and returns the sum.",
// }),
}),
});

/*
* Smart-Dashboard agents.
*
Expand Down Expand Up @@ -385,7 +419,7 @@ createApp({
}),
serving(),
agents({
agents: { helper, sql_analyst, dashboard_pilot },
agents: { helper, sql_analyst, dashboard_pilot, supervisor },
// `query` (markdown dispatcher) + `sql_analyst` + `dashboard_pilot`
// wire the /smart-dashboard route. `insights` and `anomaly` are
// ephemeral markdown agents auto-fired by the route's AgentSidebar.
Expand Down
37 changes: 37 additions & 0 deletions docs/docs/api/appkit/Class.DatabricksAdapter.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,40 @@ serving surface — no bespoke `fetch()` + `authenticate()` plumbing.
#### Returns

`Promise`\<`DatabricksAdapter`\>

***

### fromSupervisorApi()

```ts
static fromSupervisorApi(options: SupervisorApiAdapterOptions): Promise<SupervisorApiAdapter>;
```

Discoverability shim for the Supervisor API adapter. Returns a
import("./supervisor-api").SupervisorApiAdapter, NOT a
DatabricksAdapter — the two are separate classes (different
wire formats, different lifecycle). Surfaced here so application
developers see a single `DatabricksAdapter.from*` autocomplete root.

Dynamic-imports `./supervisor-api` to avoid forming a load-time cycle:
both files share `connectors/serving/client.ts`.

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `options` | [`SupervisorApiAdapterOptions`](Interface.SupervisorApiAdapterOptions.md) |

#### Returns

`Promise`\<[`SupervisorApiAdapter`](Class.SupervisorApiAdapter.md)\>

#### Example

```ts
import { DatabricksAdapter } from "@databricks/appkit/beta";

const model = await DatabricksAdapter.fromSupervisorApi({
model: "databricks-claude-sonnet-4-5",
});
```
141 changes: 141 additions & 0 deletions docs/docs/api/appkit/Class.SupervisorApiAdapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Class: SupervisorApiAdapter

Adapter that calls the Databricks AI Gateway Responses API
(`/ai-gateway/mlflow/v1/responses`).

Streams SSE events in the OpenAI Responses API wire format and maps them
to the AppKit `AgentEvent` protocol. Tool execution is handled
server-side, so the adapter ignores the agents-plugin tool index.

Authentication is handled via the Databricks SDK credential chain — the
same mechanism used by `DatabricksAdapter.fromModelServing`. The transport
is injected via [SupervisorApiAdapterCtorOptions.streamBody](Interface.SupervisorApiAdapterCtorOptions.md#streambody); the
[fromSupervisorApi](Function.fromSupervisorApi.md) factory wires it through the SDK's
`apiClient.request({ raw: true })`.

Set `DEBUG=appkit:agents:supervisor-api` to log the outbound request
shape (model, instructions length, input shape, tool count) and to be
notified when the recovery path engages (no incremental deltas, text
pulled from `response.completed.output[]`). The no-delta warning includes
a per-turn event-type histogram and the SA-reported status/error/
incomplete_details, so it's already actionable without DEBUG.

Tools are not configured on the adapter. Declare them via
`createAgent({ tools: () => ({ key: supervisorTools.genieSpace({...}) }) })`
(or markdown frontmatter referencing an ambient `supervisorTools.*` entry);
the agents plugin / standalone `runAgent` aggregates hosted-supervisor
entries and routes them to the adapter via
`AgentInput.extensions[SUPERVISOR_EXTENSION_KEY]`. Advanced callers
invoking `adapter.run(...)` directly populate that key themselves.

## Example

```ts
import { createApp, createAgent } from "@databricks/appkit";
import {
agents,
DatabricksAdapter,
supervisorTools,
} from "@databricks/appkit/beta";

await createApp({
plugins: [
agents({
agents: {
assistant: createAgent({
instructions: "You are a helpful assistant.",
model: DatabricksAdapter.fromSupervisorApi({
model: "databricks-claude-sonnet-4",
}),
tools: () => ({
nyc: supervisorTools.genieSpace({
id: "01ABCDEF12345678",
description: "NYC taxi trip records and zones",
}),
}),
}),
},
}),
],
});
```

## Implements

- [`AgentAdapter`](Interface.AgentAdapter.md)

## Constructors

### Constructor

```ts
new SupervisorApiAdapter(options: SupervisorApiAdapterCtorOptions): SupervisorApiAdapter;
```

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `options` | [`SupervisorApiAdapterCtorOptions`](Interface.SupervisorApiAdapterCtorOptions.md) |

#### Returns

`SupervisorApiAdapter`

## Properties

### acceptsExtensions

```ts
readonly acceptsExtensions: readonly ["databricks.supervisor"];
```

Capability negotiation: the adapter reads its hosted-tool payload
from [AgentInput.extensions](Interface.AgentInput.md#extensions) under [SUPERVISOR\_EXTENSION\_KEY](Variable.SUPERVISOR_EXTENSION_KEY.md).
The agents plugin uses this list to warn at registration when the tool
index produces extensions the adapter wouldn't consume.

#### Implementation of

[`AgentAdapter`](Interface.AgentAdapter.md).[`acceptsExtensions`](Interface.AgentAdapter.md#acceptsextensions)

***

### consumesInputTools

```ts
readonly consumesInputTools: false = false;
```

Capability negotiation: the adapter does not consume `input.tools`.
Tool execution is owned by the Databricks AI Gateway server-side, so
any function tools or local sub-agents declared on this agent would
be silently dropped — the agents plugin warns at registration when
that combination is detected.

#### Implementation of

[`AgentAdapter`](Interface.AgentAdapter.md).[`consumesInputTools`](Interface.AgentAdapter.md#consumesinputtools)

## Methods

### run()

```ts
run(input: AgentInput, context: AgentRunContext): AsyncGenerator<AgentEvent, void, unknown>;
```

#### Parameters

| Parameter | Type |
| ------ | ------ |
| `input` | [`AgentInput`](Interface.AgentInput.md) |
| `context` | [`AgentRunContext`](Interface.AgentRunContext.md) |

#### Returns

`AsyncGenerator`\<[`AgentEvent`](TypeAlias.AgentEvent.md), `void`, `unknown`\>

#### Implementation of

[`AgentAdapter`](Interface.AgentAdapter.md).[`run`](Interface.AgentAdapter.md#run)
73 changes: 73 additions & 0 deletions docs/docs/api/appkit/Function.fromSupervisorApi.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# Function: fromSupervisorApi()

```ts
function fromSupervisorApi(options: SupervisorApiAdapterOptions): Promise<SupervisorApiAdapter>;
```

Creates an [AgentAdapter](Interface.AgentAdapter.md) backed by the Databricks AI Gateway
Responses API (`/ai-gateway/mlflow/v1/responses`).

Uses the SDK's default credential chain for auth (reads DATABRICKS_HOST,
DATABRICKS_TOKEN, OAuth config, etc.). Tools are declared on the agent
(via `createAgent({ tools })`), not on this factory.

Application code should prefer the
[DatabricksAdapter.fromSupervisorApi](Class.DatabricksAdapter.md#fromsupervisorapi) static — it delegates here
and keeps a single `DatabricksAdapter.from*` autocomplete root for all
Databricks-backed adapters. This free function is the implementation
behind the static and remains exported for callers that want to import
it directly without pulling in [DatabricksAdapter](Class.DatabricksAdapter.md).

## Parameters

| Parameter | Type |
| ------ | ------ |
| `options` | [`SupervisorApiAdapterOptions`](Interface.SupervisorApiAdapterOptions.md) |

## Returns

`Promise`\<[`SupervisorApiAdapter`](Class.SupervisorApiAdapter.md)\>

## Example

```ts
import { createApp, createAgent } from "@databricks/appkit";
import {
agents,
DatabricksAdapter,
supervisorTools,
} from "@databricks/appkit/beta";

await createApp({
plugins: [
agents({
agents: {
assistant: createAgent({
instructions: "You are a helpful assistant.",
model: DatabricksAdapter.fromSupervisorApi({
model: "databricks-claude-sonnet-4",
}),
tools: () => ({
nyc: supervisorTools.genieSpace({
id: "01ABCDEF12345678",
description: "NYC taxi trip records and zones",
}),
}),
}),
},
}),
],
});
```

## Remarks

⚠ When passing your own `workspaceClient`, see the warning on
[SupervisorApiAdapterOptions.workspaceClient](Interface.SupervisorApiAdapterOptions.md#workspaceclient) — the client is
captured once and reused, so per-request OBO clients would leak
identity across requests.

## See

[DatabricksAdapter.fromSupervisorApi](Class.DatabricksAdapter.md#fromsupervisorapi) — the recommended
application-facing entry point.
20 changes: 20 additions & 0 deletions docs/docs/api/appkit/Function.isSupervisorTool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Function: isSupervisorTool()

```ts
function isSupervisorTool(value: unknown): value is HostedSupervisorTool;
```

Type guard for [HostedSupervisorTool](Interface.HostedSupervisorTool.md). Used by the agents plugin
(`buildToolIndex`) and standalone `runAgent` (`classifyTool`) to route
supervisor-hosted tools to the extensions payload rather than the
adapter's `tools` array.

## Parameters

| Parameter | Type |
| ------ | ------ |
| `value` | `unknown` |

## Returns

`value is HostedSupervisorTool`
29 changes: 29 additions & 0 deletions docs/docs/api/appkit/Interface.AgentAdapter.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,34 @@
# Interface: AgentAdapter

## Properties

### acceptsExtensions?

```ts
readonly optional acceptsExtensions: readonly string[];
```

Extension keys this adapter consumes from [AgentInput.extensions](Interface.AgentInput.md#extensions).
The agents plugin (and standalone `runAgent`) warns at registration
if the tool index produces extensions whose keys aren't listed here.

Adapters that don't read extensions can omit this field.

***

### consumesInputTools?

```ts
readonly optional consumesInputTools: boolean;
```

Whether the adapter consumes tools from `input.tools`. Defaults to
true. Adapters whose tool execution happens elsewhere (e.g. the
Supervisor API, where SA owns the tool loop server-side) declare
false; the agents plugin warns at registration if the agent declares
function tools or local sub-agents alongside such an adapter, since
those tools would never reach the model.

## Methods

### run()
Expand Down
17 changes: 17 additions & 0 deletions docs/docs/api/appkit/Interface.AgentInput.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

## Properties

### extensions?

```ts
optional extensions: Readonly<Record<string, unknown>>;
```

Adapter-specific opaque payloads, keyed by adapter namespace. The
shared contract intentionally does not enumerate keys — see each
adapter's docs for which keys it reads and the shape of each value.

The agents plugin and standalone `runAgent` populate this from the
agent's tool index when entries declare an adapter-side spec (e.g.
Supervisor API hosted tools). Adapters that don't read extensions
should leave it untouched.

***

### messages

```ts
Expand Down
Loading
Loading