@databricks/appkit 0.62.0 → 0.64.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +2 -2
- package/dist/appkit/package.js +1 -1
- package/dist/core/agent/agent-dirs.js +14 -0
- package/dist/core/agent/agent-dirs.js.map +1 -0
- package/dist/core/agent/create-agent.d.ts +5 -7
- package/dist/core/agent/create-agent.d.ts.map +1 -1
- package/dist/core/agent/create-agent.js +28 -7
- package/dist/core/agent/create-agent.js.map +1 -1
- package/dist/core/agent/load-agents.d.ts.map +1 -1
- package/dist/core/agent/load-agents.js +4 -4
- package/dist/core/agent/load-agents.js.map +1 -1
- package/dist/core/agent/load-code-agents.js +115 -0
- package/dist/core/agent/load-code-agents.js.map +1 -0
- package/dist/core/agent/types.d.ts +20 -6
- package/dist/core/agent/types.d.ts.map +1 -1
- package/dist/core/agent/types.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts +35 -4
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js +144 -38
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/tool-approval-gate.js.map +1 -1
- package/dist/shared/src/agent.d.ts +1 -1
- package/dist/tsdown/index.d.ts +58 -0
- package/dist/tsdown/index.d.ts.map +1 -0
- package/dist/tsdown/index.js +71 -0
- package/dist/tsdown/index.js.map +1 -0
- package/docs/api/appkit/Function.createAgent.md +1 -3
- package/docs/api/appkit/Interface.AgentDefinition.md +12 -1
- package/docs/api/appkit/Interface.AgentsPluginConfig.md +6 -15
- package/docs/api/appkit/TypeAlias.AgentEvent.md +1 -1
- package/docs/api/appkit/Variable.agents.md +1 -1
- package/docs/api/appkit.md +46 -46
- package/docs/plugins/agents.md +85 -21
- package/docs/plugins/testing.md +2 -2
- package/llms.txt +2 -2
- package/package.json +5 -1
- package/sbom.cdx.json +1 -1
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { readdirSync } from "node:fs";
|
|
3
|
+
|
|
4
|
+
//#region src/tsdown/index.ts
|
|
5
|
+
const SERVER_ENTRY = "server/server.ts";
|
|
6
|
+
const AGENT_ENTRY = "server/agents/*/agent.ts";
|
|
7
|
+
/** AppKit default: keep anything resolving outside the project out of the bundle. */
|
|
8
|
+
const defaultExternal = (id) => /^[^./]/.test(id) || id.includes("/node_modules/");
|
|
9
|
+
function toEntryArray(entry) {
|
|
10
|
+
if (entry === void 0) return [];
|
|
11
|
+
return Array.isArray(entry) ? entry : [entry];
|
|
12
|
+
}
|
|
13
|
+
/** True when `server/agents/` holds at least one `<id>/agent.ts` (a code agent). */
|
|
14
|
+
function hasCodeAgents(cwd) {
|
|
15
|
+
const root = path.join(cwd, "server", "agents");
|
|
16
|
+
try {
|
|
17
|
+
return readdirSync(root, { withFileTypes: true }).some((e) => {
|
|
18
|
+
if (!e.isDirectory() && !e.isSymbolicLink()) return false;
|
|
19
|
+
try {
|
|
20
|
+
return readdirSync(path.join(root, e.name)).includes("agent.ts");
|
|
21
|
+
} catch {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
} catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/** AppKit's base server config, with the agent entry + `clean` only when needed. */
|
|
30
|
+
function baseConfig(codeAgents) {
|
|
31
|
+
return {
|
|
32
|
+
entry: [SERVER_ENTRY, ...codeAgents ? [AGENT_ENTRY] : []],
|
|
33
|
+
unbundle: true,
|
|
34
|
+
external: defaultExternal,
|
|
35
|
+
outExtensions: () => ({ js: ".js" }),
|
|
36
|
+
...codeAgents ? { clean: true } : {}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The server tsdown config, merging AppKit's required wiring with `overrides`.
|
|
41
|
+
*
|
|
42
|
+
* Object overrides merge with intent, not a blind spread:
|
|
43
|
+
* - `entry` is UNIONed — the agent glob can't be dropped by an override;
|
|
44
|
+
* - `external` is COMPOSED — the caller's predicate runs alongside AppKit's;
|
|
45
|
+
* - every other key wins.
|
|
46
|
+
* A function override instead receives the computed base and returns the final
|
|
47
|
+
* config, for callers that need full control (including removing the glob).
|
|
48
|
+
*
|
|
49
|
+
* The agent entry + `clean` are included only when `server/agents/` actually
|
|
50
|
+
* holds code agents, so the same call works for every app. Pass
|
|
51
|
+
* `opts.codeAgents` to force that decision (e.g. a non-standard layout).
|
|
52
|
+
*/
|
|
53
|
+
function appkitServerConfig(overrides = {}, opts = {}) {
|
|
54
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
55
|
+
const base = baseConfig(opts.codeAgents ?? hasCodeAgents(cwd));
|
|
56
|
+
if (typeof overrides === "function") return overrides(base);
|
|
57
|
+
const baseEntries = toEntryArray(base.entry);
|
|
58
|
+
const entry = [...baseEntries, ...toEntryArray(overrides.entry).filter((e) => !baseEntries.includes(e))];
|
|
59
|
+
const userExternal = overrides.external;
|
|
60
|
+
const external = userExternal ? (id) => defaultExternal(id) || userExternal(id) : defaultExternal;
|
|
61
|
+
return {
|
|
62
|
+
...base,
|
|
63
|
+
...overrides,
|
|
64
|
+
entry,
|
|
65
|
+
external
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { appkitServerConfig };
|
|
71
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/tsdown/index.ts"],"sourcesContent":["import { readdirSync } from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * `@databricks/appkit/tsdown` — the server build preset.\n *\n * A scaffolded app's `tsdown.server.config.ts` is a single line:\n *\n * ```ts\n * import { appkitServerConfig } from \"@databricks/appkit/tsdown\";\n * export default appkitServerConfig();\n * ```\n *\n * so the agent-discovery build wiring lives in the package and reaches existing\n * apps on upgrade, instead of being hand-maintained in every scaffold. The\n * returned object is a plain tsdown config (no `defineConfig` wrapper needed).\n *\n * This module is intentionally dependency-free (only `node:` builtins) — it is\n * loaded at build time and must not pull in the runtime SDK.\n */\n\n/** The tsdown options this preset sets. A structural subset of tsdown's config. */\nexport interface ServerBuildConfig {\n entry?: string | string[];\n unbundle?: boolean;\n clean?: boolean;\n external?: (id: string) => boolean;\n outExtensions?: () => { js: string };\n tsconfig?: string;\n /** Any other tsdown option passes through untouched. */\n [key: string]: unknown;\n}\n\n/**\n * Overrides accepted by {@link appkitServerConfig}: either a partial config\n * (merged — `entry` is unioned, `external` composed, other keys win) or a\n * function that receives AppKit's computed base config for full control.\n */\nexport type ServerConfigOverrides =\n | ServerBuildConfig\n | ((base: ServerBuildConfig) => ServerBuildConfig);\n\nconst SERVER_ENTRY = \"server/server.ts\";\nconst AGENT_ENTRY = \"server/agents/*/agent.ts\";\n\n/** AppKit default: keep anything resolving outside the project out of the bundle. */\nconst defaultExternal = (id: string): boolean =>\n /^[^./]/.test(id) || id.includes(\"/node_modules/\");\n\nfunction toEntryArray(entry: string | string[] | undefined): string[] {\n if (entry === undefined) return [];\n return Array.isArray(entry) ? entry : [entry];\n}\n\n/** True when `server/agents/` holds at least one `<id>/agent.ts` (a code agent). */\nfunction hasCodeAgents(cwd: string): boolean {\n const root = path.join(cwd, \"server\", \"agents\");\n try {\n return readdirSync(root, { withFileTypes: true }).some((e) => {\n if (!e.isDirectory() && !e.isSymbolicLink()) return false;\n try {\n return readdirSync(path.join(root, e.name)).includes(\"agent.ts\");\n } catch {\n return false;\n }\n });\n } catch {\n return false;\n }\n}\n\n/** AppKit's base server config, with the agent entry + `clean` only when needed. */\nfunction baseConfig(codeAgents: boolean): ServerBuildConfig {\n return {\n entry: [SERVER_ENTRY, ...(codeAgents ? [AGENT_ENTRY] : [])],\n unbundle: true,\n external: defaultExternal,\n outExtensions: () => ({ js: \".js\" }),\n ...(codeAgents ? { clean: true } : {}),\n };\n}\n\n/**\n * The server tsdown config, merging AppKit's required wiring with `overrides`.\n *\n * Object overrides merge with intent, not a blind spread:\n * - `entry` is UNIONed — the agent glob can't be dropped by an override;\n * - `external` is COMPOSED — the caller's predicate runs alongside AppKit's;\n * - every other key wins.\n * A function override instead receives the computed base and returns the final\n * config, for callers that need full control (including removing the glob).\n *\n * The agent entry + `clean` are included only when `server/agents/` actually\n * holds code agents, so the same call works for every app. Pass\n * `opts.codeAgents` to force that decision (e.g. a non-standard layout).\n */\nexport function appkitServerConfig(\n overrides: ServerConfigOverrides = {},\n opts: { cwd?: string; codeAgents?: boolean } = {},\n): ServerBuildConfig {\n const cwd = opts.cwd ?? process.cwd();\n const codeAgents = opts.codeAgents ?? hasCodeAgents(cwd);\n const base = baseConfig(codeAgents);\n\n if (typeof overrides === \"function\") return overrides(base);\n\n const baseEntries = toEntryArray(base.entry);\n const entry = [\n ...baseEntries,\n ...toEntryArray(overrides.entry).filter((e) => !baseEntries.includes(e)),\n ];\n\n const userExternal = overrides.external;\n const external = userExternal\n ? (id: string): boolean => defaultExternal(id) || userExternal(id)\n : defaultExternal;\n\n return { ...base, ...overrides, entry, external };\n}\n"],"mappings":";;;;AA0CA,MAAM,eAAe;AACrB,MAAM,cAAc;;AAGpB,MAAM,mBAAmB,OACvB,SAAS,KAAK,GAAG,IAAI,GAAG,SAAS,iBAAiB;AAEpD,SAAS,aAAa,OAAgD;AACpE,KAAI,UAAU,OAAW,QAAO,EAAE;AAClC,QAAO,MAAM,QAAQ,MAAM,GAAG,QAAQ,CAAC,MAAM;;;AAI/C,SAAS,cAAc,KAAsB;CAC3C,MAAM,OAAO,KAAK,KAAK,KAAK,UAAU,SAAS;AAC/C,KAAI;AACF,SAAO,YAAY,MAAM,EAAE,eAAe,MAAM,CAAC,CAAC,MAAM,MAAM;AAC5D,OAAI,CAAC,EAAE,aAAa,IAAI,CAAC,EAAE,gBAAgB,CAAE,QAAO;AACpD,OAAI;AACF,WAAO,YAAY,KAAK,KAAK,MAAM,EAAE,KAAK,CAAC,CAAC,SAAS,WAAW;WAC1D;AACN,WAAO;;IAET;SACI;AACN,SAAO;;;;AAKX,SAAS,WAAW,YAAwC;AAC1D,QAAO;EACL,OAAO,CAAC,cAAc,GAAI,aAAa,CAAC,YAAY,GAAG,EAAE,CAAE;EAC3D,UAAU;EACV,UAAU;EACV,sBAAsB,EAAE,IAAI,OAAO;EACnC,GAAI,aAAa,EAAE,OAAO,MAAM,GAAG,EAAE;EACtC;;;;;;;;;;;;;;;;AAiBH,SAAgB,mBACd,YAAmC,EAAE,EACrC,OAA+C,EAAE,EAC9B;CACnB,MAAM,MAAM,KAAK,OAAO,QAAQ,KAAK;CAErC,MAAM,OAAO,WADM,KAAK,cAAc,cAAc,IAAI,CACrB;AAEnC,KAAI,OAAO,cAAc,WAAY,QAAO,UAAU,KAAK;CAE3D,MAAM,cAAc,aAAa,KAAK,MAAM;CAC5C,MAAM,QAAQ,CACZ,GAAG,aACH,GAAG,aAAa,UAAU,MAAM,CAAC,QAAQ,MAAM,CAAC,YAAY,SAAS,EAAE,CAAC,CACzE;CAED,MAAM,eAAe,UAAU;CAC/B,MAAM,WAAW,gBACZ,OAAwB,gBAAgB,GAAG,IAAI,aAAa,GAAG,GAChE;AAEJ,QAAO;EAAE,GAAG;EAAM,GAAG;EAAW;EAAO;EAAU"}
|
|
@@ -5,9 +5,7 @@ function createAgent(def: AgentDefinition): AgentDefinition;
|
|
|
5
5
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
-
Pure factory for agent definitions
|
|
9
|
-
|
|
10
|
-
The returned value is a plain `AgentDefinition` — no adapter construction, no side effects. Register it with `agents({ agents: { name: def } })` or run it standalone via `runAgent(def, input)`.
|
|
8
|
+
Pure factory for agent definitions: cycle-detects the sub-agent graph and returns the same object, stamped with a non-enumerable AGENT\_BRAND so discovery recognizes it. Safe at module top-level; no adapter is built. Don't `Object.freeze` the definition before passing it in — the brand is written onto the argument.
|
|
11
9
|
|
|
12
10
|
## Parameters[](#parameters "Direct link to Parameters")
|
|
13
11
|
|
|
@@ -24,6 +24,17 @@ Override the plugin's baseSystemPrompt for this agent only.
|
|
|
24
24
|
|
|
25
25
|
***
|
|
26
26
|
|
|
27
|
+
### default?[](#default "Direct link to default?")
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
optional default: boolean;
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Marks this agent as the default one chosen when a client doesn't name an agent. Mirrors markdown frontmatter `default: true`. When several agents set it, a code (discovered) agent wins over a markdown one, then the lowest id; an explicit `agents({ defaultAgent })` always overrides it. Defaults to `false`.
|
|
35
|
+
|
|
36
|
+
***
|
|
37
|
+
|
|
27
38
|
### ephemeral?[](#ephemeral "Direct link to ephemeral?")
|
|
28
39
|
|
|
29
40
|
```ts
|
|
@@ -96,7 +107,7 @@ optional name: string;
|
|
|
96
107
|
|
|
97
108
|
```
|
|
98
109
|
|
|
99
|
-
Stable identifier for the agent. **Optional and informational** — when the definition is registered via `agents: { foo: def }` (code) or lives at `
|
|
110
|
+
Stable identifier for the agent. **Optional and informational** — when the definition is registered via `agents: { foo: def }` (code) or lives at `server/agents/<id>/agent.md` (markdown), the **registry key always wins** and `name` is ignored. The agent will be reachable as `foo` (or `<id>`) regardless of what this field contains.
|
|
100
111
|
|
|
101
112
|
Set `name` when:
|
|
102
113
|
|
|
@@ -15,14 +15,16 @@ Base configuration interface for AppKit plugins
|
|
|
15
15
|
|
|
16
16
|
## Properties[](#properties "Direct link to Properties")
|
|
17
17
|
|
|
18
|
-
### agents
|
|
18
|
+
### ~~agents?~~[](#agents "Direct link to agents")
|
|
19
19
|
|
|
20
20
|
```ts
|
|
21
21
|
optional agents: Record<string, AgentDefinition>;
|
|
22
22
|
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
#### Deprecated[](#deprecated "Direct link to Deprecated")
|
|
26
|
+
|
|
27
|
+
Put each code agent in its own folder under `server/agents/<id>/agent.ts` (`export default createAgent({ ... })`); it is discovered automatically at startup and the call collapses to `agents({ ... })` with no map. Still honored for backward compatibility (emits a one-time deprecation warning) but will be removed in a future minor. If both discovery and this map define the same id, discovery wins and the map entry is ignored.
|
|
26
28
|
|
|
27
29
|
***
|
|
28
30
|
|
|
@@ -36,7 +38,7 @@ optional approval: {
|
|
|
36
38
|
|
|
37
39
|
```
|
|
38
40
|
|
|
39
|
-
Human-in-the-loop approval gate for mutating tool calls. When enabled (the default), the agents plugin emits an `appkit.approval_pending` SSE event before executing any tool whose annotation flags it as mutating — `effect: "write" | "update" | "destructive"` (preferred) or the legacy `destructive: true` boolean — and waits for a `POST /
|
|
41
|
+
Human-in-the-loop approval gate for mutating tool calls. When enabled (the default), the agents plugin emits an `appkit.approval_pending` SSE event before executing any tool whose annotation flags it as mutating — `effect: "write" | "update" | "destructive"` (preferred) or the legacy `destructive: true` boolean — and waits for a `POST /api/agents/approve` decision from the same user who initiated the stream. A missing decision after `timeoutMs` auto-denies the call.
|
|
40
42
|
|
|
41
43
|
#### requireForDestructive?[](#requirefordestructive "Direct link to requireForDestructive?")
|
|
42
44
|
|
|
@@ -89,7 +91,7 @@ optional defaultAgent: string;
|
|
|
89
91
|
|
|
90
92
|
```
|
|
91
93
|
|
|
92
|
-
Agent used when clients don't specify one.
|
|
94
|
+
Agent used when clients don't specify one. Precedence: this value, else a code agent with `default: true`, else a markdown agent with `default: true`, else the first-registered agent.
|
|
93
95
|
|
|
94
96
|
***
|
|
95
97
|
|
|
@@ -107,17 +109,6 @@ Default model for agents that don't specify their own (in code or frontmatter).
|
|
|
107
109
|
|
|
108
110
|
***
|
|
109
111
|
|
|
110
|
-
### dir?[](#dir "Direct link to dir?")
|
|
111
|
-
|
|
112
|
-
```ts
|
|
113
|
-
optional dir: string | false;
|
|
114
|
-
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable.
|
|
118
|
-
|
|
119
|
-
***
|
|
120
|
-
|
|
121
112
|
### host?[](#host "Direct link to host?")
|
|
122
113
|
|
|
123
114
|
```ts
|
|
@@ -296,4 +296,4 @@ type: "approval_pending";
|
|
|
296
296
|
|
|
297
297
|
```
|
|
298
298
|
|
|
299
|
-
Emitted by the agents plugin (not adapters) when a mutating tool call is awaiting human approval — fires for tools annotated with `effect: "write" | "update" | "destructive"` (preferred) or the legacy `destructive: true` boolean. Clients should render an approval prompt and POST to `/
|
|
299
|
+
Emitted by the agents plugin (not adapters) when a mutating tool call is awaiting human approval — fires for tools annotated with `effect: "write" | "update" | "destructive"` (preferred) or the legacy `destructive: true` boolean. Clients should render an approval prompt and POST to `/api/agents/approve` with the matching `approvalId` and a `decision` of `approve` or `deny`.
|
|
@@ -5,7 +5,7 @@ const agents: ToPlugin<typeof AgentsPlugin, AgentsPluginConfig, string>;
|
|
|
5
5
|
|
|
6
6
|
```
|
|
7
7
|
|
|
8
|
-
Plugin factory for the agents plugin.
|
|
8
|
+
Plugin factory for the agents plugin. Discovers agents from `server/agents/<id>/agent.{ts,md}` by default (markdown still in `config/agents/` is read as a deprecated fallback), resolves toolkits/tools from registered plugins, exposes the `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable).
|
|
9
9
|
|
|
10
10
|
## Example[](#example "Direct link to Example")
|
|
11
11
|
|
package/docs/api/appkit.md
CHANGED
|
@@ -124,52 +124,52 @@ Documentation merge entry for Typedoc — combines the stable `@databricks/appki
|
|
|
124
124
|
|
|
125
125
|
## Variables[](#variables "Direct link to Variables")
|
|
126
126
|
|
|
127
|
-
| Variable | Description
|
|
128
|
-
| ------------------------------------------------------------------------------------------ |
|
|
129
|
-
| [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin.
|
|
130
|
-
| [aiSearch](./docs/api/appkit/Variable.aiSearch.md) | -
|
|
131
|
-
| [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data.
|
|
132
|
-
| [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace
|
|
133
|
-
| [SUPERVISOR\_EXTENSION\_KEY](./docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md) | Namespace key under which the adapter reads its hosted-tool payload from [AgentInput.extensions](./docs/api/appkit/Interface.AgentInput.md#extensions). Exported so the agents plugin and standalone `runAgent` (the producers) can write under the same key the adapter reads.
|
|
134
|
-
| [supervisorTools](./docs/api/appkit/Variable.supervisorTools.md) | Concise factories for declaring Supervisor API tools.
|
|
135
|
-
| [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data.
|
|
127
|
+
| Variable | Description |
|
|
128
|
+
| ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
129
|
+
| [agents](./docs/api/appkit/Variable.agents.md) | Plugin factory for the agents plugin. Discovers agents from `server/agents/<id>/agent.{ts,md}` by default (markdown still in `config/agents/` is read as a deprecated fallback), resolves toolkits/tools from registered plugins, exposes the `appkit.agents.*` runtime API and mounts `POST /invocations` and `POST /responses` (aliased non-streaming invoke endpoints) plus `POST /chat` (streaming, HITL-capable). |
|
|
130
|
+
| [aiSearch](./docs/api/appkit/Variable.aiSearch.md) | - |
|
|
131
|
+
| [READ\_ACTIONS](./docs/api/appkit/Variable.READ_ACTIONS.md) | Actions that only read data. |
|
|
132
|
+
| [sql](./docs/api/appkit/Variable.sql.md) | SQL helper namespace |
|
|
133
|
+
| [SUPERVISOR\_EXTENSION\_KEY](./docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md) | Namespace key under which the adapter reads its hosted-tool payload from [AgentInput.extensions](./docs/api/appkit/Interface.AgentInput.md#extensions). Exported so the agents plugin and standalone `runAgent` (the producers) can write under the same key the adapter reads. |
|
|
134
|
+
| [supervisorTools](./docs/api/appkit/Variable.supervisorTools.md) | Concise factories for declaring Supervisor API tools. |
|
|
135
|
+
| [WRITE\_ACTIONS](./docs/api/appkit/Variable.WRITE_ACTIONS.md) | Actions that mutate data. |
|
|
136
136
|
|
|
137
137
|
## Functions[](#functions "Direct link to Functions")
|
|
138
138
|
|
|
139
|
-
| Function | Description
|
|
140
|
-
| -------------------------------------------------------------------------------------------- |
|
|
141
|
-
| [agentIdFromMarkdownPath](./docs/api/appkit/Function.agentIdFromMarkdownPath.md) | Derives the logical agent id from a markdown path. When the file is named `agent.md`, the id is the parent directory name (folder-based layout); otherwise the id is the file stem (e.g. legacy single-file paths).
|
|
142
|
-
| [appKitServingTypesPlugin](./docs/api/appkit/Function.appKitServingTypesPlugin.md) | Vite plugin to generate TypeScript types for AppKit serving endpoints. Fetches OpenAPI schemas from Databricks and generates a .d.ts with ServingEndpointRegistry module augmentation.
|
|
143
|
-
| [appKitTypesPlugin](./docs/api/appkit/Function.appKitTypesPlugin.md) | Vite plugin to generate types for AppKit queries. Calls generateFromEntryPoint under the hood.
|
|
144
|
-
| [createAgent](./docs/api/appkit/Function.createAgent.md) | Pure factory for agent definitions
|
|
145
|
-
| [createApp](./docs/api/appkit/Function.createApp.md) | Bootstraps AppKit with the provided configuration.
|
|
146
|
-
| [createLakebasePool](./docs/api/appkit/Function.createLakebasePool.md) | Create a Lakebase pool with appkit's logger integration. Telemetry automatically uses appkit's OpenTelemetry configuration via global registry.
|
|
147
|
-
| [createLakebasePoolManager](./docs/api/appkit/Function.createLakebasePoolManager.md) | Create a pool manager that maintains per-key Lakebase connection pools.
|
|
148
|
-
| [createWorkspaceClient](./docs/api/appkit/Function.createWorkspaceClient.md) | Construct an AppKit workspace client.
|
|
149
|
-
| [defineTool](./docs/api/appkit/Function.defineTool.md) | Defines a single tool entry for a plugin's internal registry.
|
|
150
|
-
| [executeFromRegistry](./docs/api/appkit/Function.executeFromRegistry.md) | Validates tool-call arguments against the entry's schema and invokes its handler. On validation failure, returns an LLM-friendly error string (matching the behavior of `tool()`) rather than throwing, so the model can self-correct on its next turn.
|
|
151
|
-
| [extractServingEndpoints](./docs/api/appkit/Function.extractServingEndpoints.md) | Extract serving endpoint config from a server file by AST-parsing it. Looks for `serving({ endpoints: { alias: { env: "..." }, ... } })` calls and extracts the endpoint alias names and their environment variable mappings.
|
|
152
|
-
| [findServerFile](./docs/api/appkit/Function.findServerFile.md) | Find the server entry file by checking candidate paths in order.
|
|
153
|
-
| [fromSupervisorApi](./docs/api/appkit/Function.fromSupervisorApi.md) | Creates an [AgentAdapter](./docs/api/appkit/Interface.AgentAdapter.md) backed by the Databricks AI Gateway Responses API (`/ai-gateway/mlflow/v1/responses`).
|
|
154
|
-
| [functionToolToDefinition](./docs/api/appkit/Function.functionToolToDefinition.md) | -
|
|
155
|
-
| [generateDatabaseCredential](./docs/api/appkit/Function.generateDatabaseCredential.md) | Generate OAuth credentials for Postgres database connection using the proper Postgres API.
|
|
156
|
-
| [getExecutionContext](./docs/api/appkit/Function.getExecutionContext.md) | Get the current execution context.
|
|
157
|
-
| [getLakebaseOrmConfig](./docs/api/appkit/Function.getLakebaseOrmConfig.md) | Get Lakebase connection configuration for ORMs that don't accept pg.Pool directly.
|
|
158
|
-
| [getLakebasePgConfig](./docs/api/appkit/Function.getLakebasePgConfig.md) | Get Lakebase connection configuration for PostgreSQL clients.
|
|
159
|
-
| [getPluginManifest](./docs/api/appkit/Function.getPluginManifest.md) | Loads and validates the manifest from a plugin constructor. Normalizes string type/permission to strict ResourceType/ResourcePermission.
|
|
160
|
-
| [getResourceRequirements](./docs/api/appkit/Function.getResourceRequirements.md) | Gets the resource requirements from a plugin's manifest.
|
|
161
|
-
| [getUsernameWithApiLookup](./docs/api/appkit/Function.getUsernameWithApiLookup.md) | Resolves the PostgreSQL username for a Lakebase connection.
|
|
162
|
-
| [getWorkspaceClient](./docs/api/appkit/Function.getWorkspaceClient.md) | Get workspace client from config or SDK default auth chain
|
|
163
|
-
| [isFunctionTool](./docs/api/appkit/Function.isFunctionTool.md) | -
|
|
164
|
-
| [isHostedTool](./docs/api/appkit/Function.isHostedTool.md) | -
|
|
165
|
-
| [isSQLTypeMarker](./docs/api/appkit/Function.isSQLTypeMarker.md) | Type guard to check if a value is a SQL type marker
|
|
166
|
-
| [isSupervisorTool](./docs/api/appkit/Function.isSupervisorTool.md) | Type guard for [HostedSupervisorTool](./docs/api/appkit/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.
|
|
167
|
-
| [isToolkitEntry](./docs/api/appkit/Function.isToolkitEntry.md) | Type guard for `ToolkitEntry` — used by the agents plugin to differentiate toolkit references from inline tools in a mixed `tools` record.
|
|
168
|
-
| [loadAgentFromFile](./docs/api/appkit/Function.loadAgentFromFile.md) | Loads a single markdown agent file and resolves its frontmatter against registered plugin toolkits + ambient tool library.
|
|
169
|
-
| [loadAgentsFromDir](./docs/api/appkit/Function.loadAgentsFromDir.md) | Scans a directory for one subdirectory per agent, each containing `agent.md` (frontmatter + body). Produces an `AgentDefinition` record keyed by agent id (folder name). Throws on frontmatter errors or unresolved references. Returns an empty map if the directory does not exist.
|
|
170
|
-
| [mcpServer](./docs/api/appkit/Function.mcpServer.md) | Factory for declaring a custom MCP server tool.
|
|
171
|
-
| [parseTextToolCalls](./docs/api/appkit/Function.parseTextToolCalls.md) | Parses text-based tool calls from model output.
|
|
172
|
-
| [resolveHostedTools](./docs/api/appkit/Function.resolveHostedTools.md) | -
|
|
173
|
-
| [runAgent](./docs/api/appkit/Function.runAgent.md) | Standalone agent execution without `createApp`. Resolves the adapter, binds inline tools, and drives the adapter's `run()` loop to completion.
|
|
174
|
-
| [tool](./docs/api/appkit/Function.tool.md) | Factory for defining function tools with Zod schemas.
|
|
175
|
-
| [toolsFromRegistry](./docs/api/appkit/Function.toolsFromRegistry.md) | Produces the `AgentToolDefinition[]` a ToolProvider exposes to the LLM, deriving `parameters` JSON Schema from each entry's Zod schema.
|
|
139
|
+
| Function | Description |
|
|
140
|
+
| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| [agentIdFromMarkdownPath](./docs/api/appkit/Function.agentIdFromMarkdownPath.md) | Derives the logical agent id from a markdown path. When the file is named `agent.md`, the id is the parent directory name (folder-based layout); otherwise the id is the file stem (e.g. legacy single-file paths). |
|
|
142
|
+
| [appKitServingTypesPlugin](./docs/api/appkit/Function.appKitServingTypesPlugin.md) | Vite plugin to generate TypeScript types for AppKit serving endpoints. Fetches OpenAPI schemas from Databricks and generates a .d.ts with ServingEndpointRegistry module augmentation. |
|
|
143
|
+
| [appKitTypesPlugin](./docs/api/appkit/Function.appKitTypesPlugin.md) | Vite plugin to generate types for AppKit queries. Calls generateFromEntryPoint under the hood. |
|
|
144
|
+
| [createAgent](./docs/api/appkit/Function.createAgent.md) | Pure factory for agent definitions: cycle-detects the sub-agent graph and returns the same object, stamped with a non-enumerable AGENT\_BRAND so discovery recognizes it. Safe at module top-level; no adapter is built. Don't `Object.freeze` the definition before passing it in — the brand is written onto the argument. |
|
|
145
|
+
| [createApp](./docs/api/appkit/Function.createApp.md) | Bootstraps AppKit with the provided configuration. |
|
|
146
|
+
| [createLakebasePool](./docs/api/appkit/Function.createLakebasePool.md) | Create a Lakebase pool with appkit's logger integration. Telemetry automatically uses appkit's OpenTelemetry configuration via global registry. |
|
|
147
|
+
| [createLakebasePoolManager](./docs/api/appkit/Function.createLakebasePoolManager.md) | Create a pool manager that maintains per-key Lakebase connection pools. |
|
|
148
|
+
| [createWorkspaceClient](./docs/api/appkit/Function.createWorkspaceClient.md) | Construct an AppKit workspace client. |
|
|
149
|
+
| [defineTool](./docs/api/appkit/Function.defineTool.md) | Defines a single tool entry for a plugin's internal registry. |
|
|
150
|
+
| [executeFromRegistry](./docs/api/appkit/Function.executeFromRegistry.md) | Validates tool-call arguments against the entry's schema and invokes its handler. On validation failure, returns an LLM-friendly error string (matching the behavior of `tool()`) rather than throwing, so the model can self-correct on its next turn. |
|
|
151
|
+
| [extractServingEndpoints](./docs/api/appkit/Function.extractServingEndpoints.md) | Extract serving endpoint config from a server file by AST-parsing it. Looks for `serving({ endpoints: { alias: { env: "..." }, ... } })` calls and extracts the endpoint alias names and their environment variable mappings. |
|
|
152
|
+
| [findServerFile](./docs/api/appkit/Function.findServerFile.md) | Find the server entry file by checking candidate paths in order. |
|
|
153
|
+
| [fromSupervisorApi](./docs/api/appkit/Function.fromSupervisorApi.md) | Creates an [AgentAdapter](./docs/api/appkit/Interface.AgentAdapter.md) backed by the Databricks AI Gateway Responses API (`/ai-gateway/mlflow/v1/responses`). |
|
|
154
|
+
| [functionToolToDefinition](./docs/api/appkit/Function.functionToolToDefinition.md) | - |
|
|
155
|
+
| [generateDatabaseCredential](./docs/api/appkit/Function.generateDatabaseCredential.md) | Generate OAuth credentials for Postgres database connection using the proper Postgres API. |
|
|
156
|
+
| [getExecutionContext](./docs/api/appkit/Function.getExecutionContext.md) | Get the current execution context. |
|
|
157
|
+
| [getLakebaseOrmConfig](./docs/api/appkit/Function.getLakebaseOrmConfig.md) | Get Lakebase connection configuration for ORMs that don't accept pg.Pool directly. |
|
|
158
|
+
| [getLakebasePgConfig](./docs/api/appkit/Function.getLakebasePgConfig.md) | Get Lakebase connection configuration for PostgreSQL clients. |
|
|
159
|
+
| [getPluginManifest](./docs/api/appkit/Function.getPluginManifest.md) | Loads and validates the manifest from a plugin constructor. Normalizes string type/permission to strict ResourceType/ResourcePermission. |
|
|
160
|
+
| [getResourceRequirements](./docs/api/appkit/Function.getResourceRequirements.md) | Gets the resource requirements from a plugin's manifest. |
|
|
161
|
+
| [getUsernameWithApiLookup](./docs/api/appkit/Function.getUsernameWithApiLookup.md) | Resolves the PostgreSQL username for a Lakebase connection. |
|
|
162
|
+
| [getWorkspaceClient](./docs/api/appkit/Function.getWorkspaceClient.md) | Get workspace client from config or SDK default auth chain |
|
|
163
|
+
| [isFunctionTool](./docs/api/appkit/Function.isFunctionTool.md) | - |
|
|
164
|
+
| [isHostedTool](./docs/api/appkit/Function.isHostedTool.md) | - |
|
|
165
|
+
| [isSQLTypeMarker](./docs/api/appkit/Function.isSQLTypeMarker.md) | Type guard to check if a value is a SQL type marker |
|
|
166
|
+
| [isSupervisorTool](./docs/api/appkit/Function.isSupervisorTool.md) | Type guard for [HostedSupervisorTool](./docs/api/appkit/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. |
|
|
167
|
+
| [isToolkitEntry](./docs/api/appkit/Function.isToolkitEntry.md) | Type guard for `ToolkitEntry` — used by the agents plugin to differentiate toolkit references from inline tools in a mixed `tools` record. |
|
|
168
|
+
| [loadAgentFromFile](./docs/api/appkit/Function.loadAgentFromFile.md) | Loads a single markdown agent file and resolves its frontmatter against registered plugin toolkits + ambient tool library. |
|
|
169
|
+
| [loadAgentsFromDir](./docs/api/appkit/Function.loadAgentsFromDir.md) | Scans a directory for one subdirectory per agent, each containing `agent.md` (frontmatter + body). Produces an `AgentDefinition` record keyed by agent id (folder name). Throws on frontmatter errors or unresolved references. Returns an empty map if the directory does not exist. |
|
|
170
|
+
| [mcpServer](./docs/api/appkit/Function.mcpServer.md) | Factory for declaring a custom MCP server tool. |
|
|
171
|
+
| [parseTextToolCalls](./docs/api/appkit/Function.parseTextToolCalls.md) | Parses text-based tool calls from model output. |
|
|
172
|
+
| [resolveHostedTools](./docs/api/appkit/Function.resolveHostedTools.md) | - |
|
|
173
|
+
| [runAgent](./docs/api/appkit/Function.runAgent.md) | Standalone agent execution without `createApp`. Resolves the adapter, binds inline tools, and drives the adapter's `run()` loop to completion. |
|
|
174
|
+
| [tool](./docs/api/appkit/Function.tool.md) | Factory for defining function tools with Zod schemas. |
|
|
175
|
+
| [toolsFromRegistry](./docs/api/appkit/Function.toolsFromRegistry.md) | Produces the `AgentToolDefinition[]` a ToolProvider exposes to the LLM, deriving `parameters` JSON Schema from each entry's Zod schema. |
|
package/docs/plugins/agents.md
CHANGED
|
@@ -4,7 +4,7 @@ Beta plugin
|
|
|
4
4
|
|
|
5
5
|
This plugin is currently **beta**. APIs may change between minor releases. Import from `@databricks/appkit/beta`. See [Plugin Stability Tiers](./docs/plugins/stability.md).
|
|
6
6
|
|
|
7
|
-
The `agents` plugin turns a Databricks AppKit app into an AI-agent host. It
|
|
7
|
+
The `agents` plugin turns a Databricks AppKit app into an AI-agent host. It discovers agent definitions from disk — one folder per agent under `server/agents/`, holding either `agent.md` (markdown) or `agent.ts` (code) — and exposes them at `POST /invocations` and `POST /responses` (non-streaming, aliases) alongside `POST /chat` (streaming) and routes for thread management, cancellation, and HITL approval. In every case the agent's id is its folder name; there's no map to maintain and no id to restate.
|
|
8
8
|
|
|
9
9
|
This page covers the full lifecycle. For the hand-written primitives (`tool()`, `mcpServer()`), see [tools](./docs/plugins/server.md).
|
|
10
10
|
|
|
@@ -36,14 +36,15 @@ That alone gives you a live HTTP server with `POST /invocations` (and its alias
|
|
|
36
36
|
|
|
37
37
|
## Level 1: drop a markdown agent package[](#level-1-drop-a-markdown-agent-package "Direct link to Level 1: drop a markdown agent package")
|
|
38
38
|
|
|
39
|
-
Each agent lives in its own
|
|
39
|
+
Each agent lives in its own folder under `server/agents/` with entry file `agent.md`. A folder is an agent only if it holds an entry file (`agent.md` or `agent.ts`); a folder without one is skipped, so per-agent asset folders like `skills/` sit beside the entry.
|
|
40
40
|
|
|
41
41
|
```text
|
|
42
42
|
my-app/
|
|
43
|
-
server
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
43
|
+
server/
|
|
44
|
+
server.ts
|
|
45
|
+
agents/
|
|
46
|
+
assistant/
|
|
47
|
+
agent.md
|
|
47
48
|
|
|
48
49
|
```
|
|
49
50
|
|
|
@@ -61,13 +62,17 @@ Use the available tools to query data, browse files, and help users.
|
|
|
61
62
|
|
|
62
63
|
On startup the plugin:
|
|
63
64
|
|
|
64
|
-
1. Discovers
|
|
65
|
+
1. Discovers `server/agents/assistant/agent.md` and registers agent id `assistant`.
|
|
65
66
|
2. Parses the YAML frontmatter and markdown body as the agent's `instructions`.
|
|
66
|
-
3. Resolves the adapter from `endpoint` (or falls back to `
|
|
67
|
+
3. Resolves the adapter from `endpoint` (or falls back to `DATABRICKS_SERVING_ENDPOINT_NAME`).
|
|
67
68
|
4. Mounts the agent at the default name (`assistant`).
|
|
68
69
|
|
|
69
70
|
The agent starts with **no tools**. Tools are opt-in — declare them in frontmatter (Level 2 below) or opt into auto-inherit explicitly with `agents({ autoInheritTools: { file: true } })`. See "Auto-inherit posture" further down for what that costs and why it's off by default.
|
|
70
71
|
|
|
72
|
+
Migrating from `config/agents/`
|
|
73
|
+
|
|
74
|
+
Earlier versions kept markdown agents under `config/agents/<id>/agent.md`. That location is still read as a deprecated fallback (one-time warning on boot); move each folder to `server/agents/<id>/agent.md` so every agent — markdown and code — lives in one place.
|
|
75
|
+
|
|
71
76
|
Requests land at `POST /invocations` (or its alias `POST /responses`) with an OpenAI Responses-compatible body. These endpoints run the agent to completion and return a single JSON response — no SSE. Streaming clients should use `POST /chat`. Every tool call runs through `asUser(req)` so SQL executes as the requesting user, file access respects Unity Catalog ACLs, and telemetry spans are created automatically.
|
|
72
77
|
|
|
73
78
|
No HITL on `/invocations` and `/responses`
|
|
@@ -102,12 +107,14 @@ When any `tools:` is declared the auto-inherit default is turned off — the age
|
|
|
102
107
|
|
|
103
108
|
## Level 3: code-defined agents[](#level-3-code-defined-agents "Direct link to Level 3: code-defined agents")
|
|
104
109
|
|
|
110
|
+
Code agents live one-per-folder under `server/agents/`, with entry file `agent.ts` (mirroring markdown's `agent.md`). The entry exports a created agent and its **id is the folder name** (`server/agents/support/agent.ts` → `support`). Nothing restates the id.
|
|
111
|
+
|
|
105
112
|
```ts
|
|
106
|
-
|
|
107
|
-
import {
|
|
113
|
+
// server/agents/support/agent.ts
|
|
114
|
+
import { createAgent, tool } from "@databricks/appkit/beta";
|
|
108
115
|
import { z } from "zod";
|
|
109
116
|
|
|
110
|
-
|
|
117
|
+
export default createAgent({ // id derived from folder name: "support"
|
|
111
118
|
instructions: "You help customers with data and files.",
|
|
112
119
|
model: "databricks-claude-sonnet-4-5", // string sugar
|
|
113
120
|
tools(plugins) {
|
|
@@ -123,17 +130,40 @@ const support = createAgent({
|
|
|
123
130
|
},
|
|
124
131
|
});
|
|
125
132
|
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The `agents` plugin discovers these files at startup — no registration, no map:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
// server/server.ts
|
|
139
|
+
import { analytics, createApp, files, server } from "@databricks/appkit";
|
|
140
|
+
import { agents } from "@databricks/appkit/beta";
|
|
141
|
+
|
|
126
142
|
await createApp({
|
|
127
|
-
plugins: [server(), analytics(), files(), agents(
|
|
143
|
+
plugins: [server(), analytics(), files(), agents()], // no agent map, no import
|
|
128
144
|
});
|
|
129
145
|
|
|
130
146
|
```
|
|
131
147
|
|
|
148
|
+
Discovery imports each `server/agents/<id>/agent.ts` — the source `.ts` under `tsx` in dev, and the compiled `dist/agents/<id>/agent.js` in a production build (built output wins over source, independent of `NODE_ENV`). Because the production server is bundled and only imports things reachable from `server/server.ts`, the template's `tsdown` config lists `server/agents/*/agent.ts` as build entries so `dist/agents/*/agent.js` are emitted for the scan — that wiring is what lets a dropped-in folder survive the prod bundle. (Markdown `agent.md` is read from source in both dev and prod — it's data, not compiled.) The root is always `server/agents` — there is no config option to relocate it; markdown still under `config/agents/` is read as a deprecated fallback (one-time warning).
|
|
149
|
+
|
|
150
|
+
Built output shadows source in dev
|
|
151
|
+
|
|
152
|
+
Because compiled output wins over source, a stale `dist/agents` / `build/agents` left over from a previous `npm run build` will be picked up by `npm run dev` instead of your live `server/agents/*.ts`, so edits appear ignored. **Delete the build dir** if a code agent seems frozen — a rebuild only swaps in a newer snapshot, so only deleting it restores live-from-source dev reload. Markdown is always read from source, so `agent.md` edits are never shadowed.
|
|
153
|
+
|
|
154
|
+
The entry may `export default createAgent({...})` or export a single named created agent; either way the id is the folder name. A folder whose entry exports no created agent (or has no `agent.ts`/`agent.md` at all) is skipped. Mark one agent as the default with `createAgent({ default: true })` (mirrors markdown frontmatter `default: true`); an explicit `agents({ defaultAgent })` still wins.
|
|
155
|
+
|
|
132
156
|
Code-defined agents start with no tools by default. The function form `tools(plugins) => Record<string, AgentTool>` is the primary way to pull in plugin tools: each plugin registered in `createApp({ plugins: [...] })` shows up on the `plugins` parameter, and you call `.toolkit(opts?)` on it to get a spread-friendly record. The runtime invokes the function once at agent setup and caches the result — every plugin is mentioned exactly once (in `createApp`), with no held variables or marker imports.
|
|
133
157
|
|
|
134
|
-
Inline `tool({...})` calls live in the same record. `name` is optional — the agents plugin overrides it with the record key (`get_weather` above).
|
|
158
|
+
Inline `tool({...})` calls live in the same record. Their `name` is optional — the agents plugin overrides it with the record key (`get_weather` above).
|
|
135
159
|
|
|
136
|
-
|
|
160
|
+
Auto-inherit is **off for both origins by default** — a markdown or code agent with no declared `tools:` gets an empty tool index. Opt an origin in explicitly with `agents({ autoInheritTools: { file: true } })` (or `{ code: true }`, or `true` for both).
|
|
161
|
+
|
|
162
|
+
Deprecated: the `agents({ agents: { ... } })` map
|
|
163
|
+
|
|
164
|
+
Passing a hand-built agent map still works and is honored for backward compatibility, but it emits a one-time deprecation warning and will be removed in a future minor. It restates each agent's id (once in `createAgent`, once as the map key); discovery from `server/agents/` removes both the map and the restatement. Migrate by moving each `createAgent(...)` into its own `server/agents/<id>/agent.ts` (default or single named export) and dropping the map. If a discovered agent and a map entry share an id, discovery wins and the map entry is ignored (with a one-time warning). (Inline sub-agents — `createAgent({ agents: { ... } })` on a definition — are unaffected; only the plugin-level map is deprecated.)
|
|
165
|
+
|
|
166
|
+
Some examples further down still pass agents inline via this map for snippet brevity — in a real app each of those `createAgent(...)` definitions lives in its own `server/agents/<id>/agent.ts` and needs no map.
|
|
137
167
|
|
|
138
168
|
### Scoping tools in code[](#scoping-tools-in-code "Direct link to Scoping tools in code")
|
|
139
169
|
|
|
@@ -170,16 +200,16 @@ const supervisor = createAgent({
|
|
|
170
200
|
agents: { researcher, writer }, // exposed as agent-researcher, agent-writer
|
|
171
201
|
});
|
|
172
202
|
|
|
203
|
+
// server/agents/{supervisor,researcher,writer}/agent.ts — one folder each
|
|
204
|
+
export default supervisor;
|
|
205
|
+
|
|
173
206
|
await createApp({
|
|
174
|
-
plugins: [
|
|
175
|
-
server(),
|
|
176
|
-
agents({ agents: { supervisor, researcher, writer } }),
|
|
177
|
-
],
|
|
207
|
+
plugins: [server(), agents()], // discovered from server/agents/
|
|
178
208
|
});
|
|
179
209
|
|
|
180
210
|
```
|
|
181
211
|
|
|
182
|
-
Each key in `agents: {...}` on an `AgentDefinition` becomes an `agent-<key>` tool on the parent. When invoked, the agents plugin runs the child's adapter with a fresh message list (no shared thread state) and returns the aggregated text. Cycles are rejected at load
|
|
212
|
+
Put `supervisor`, `researcher`, and `writer` in their own `server/agents/<id>/agent.ts` folders (default export each) — a markdown parent can also delegate to a code child in a sibling folder via `agents: [helper]` frontmatter. Each key in `agents: {...}` on an `AgentDefinition` becomes an `agent-<key>` tool on the parent. When invoked, the agents plugin runs the child's adapter with a fresh message list (no shared thread state) and returns the aggregated text. Cycles in a code agent's inline `agents: {}` graph are rejected at load (`createAgent`); markdown `agents:` delegation rejects self-references at load and bounds deeper cycles at runtime via `limits.maxSubAgentDepth`.
|
|
183
213
|
|
|
184
214
|
## Level 5: standalone (no `createApp`)[](#level-5-standalone-no-createapp "Direct link to level-5-standalone-no-createapp")
|
|
185
215
|
|
|
@@ -229,6 +259,36 @@ const result = await runAgent(classifier, {
|
|
|
229
259
|
|
|
230
260
|
MCP hosted tools (`mcpServer(...)`) still require `agents()` (they need a live MCP client). Supervisor-API hosted tools (`supervisorTools.*`), by contrast, **work in standalone `runAgent`** — the adapter has everything it needs to execute them server-side. This makes batch-eval / CI use of supervisor agents possible without `createApp`. 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.
|
|
231
261
|
|
|
262
|
+
## Adding agents to an existing app[](#adding-agents-to-an-existing-app "Direct link to Adding agents to an existing app")
|
|
263
|
+
|
|
264
|
+
Already have an app and want to add agents? What you touch depends on the kind:
|
|
265
|
+
|
|
266
|
+
**Markdown agents** — just the plugin. Drop `server/agents/<id>/agent.md`, add `agents()` to your `plugins`, done. Markdown is read from source at runtime in both dev and prod, so there is no build change.
|
|
267
|
+
|
|
268
|
+
**Code agents** (`server/agents/<id>/agent.ts`) — also update your server build so a production bundle emits them. Code agents aren't imported anywhere, so a build that only compiles `server/server.ts` never produces `dist/agents/*/agent.js`, and a bundled `npm run build` + start would discover **zero** code agents.
|
|
269
|
+
|
|
270
|
+
Dev hides this
|
|
271
|
+
|
|
272
|
+
`npm run dev` (tsx) imports the `.ts` source directly, so code agents work there with no build change — the gap only appears in a bundled build. If you add code agents but forget the build change, the plugin warns at startup (and names the fix) rather than failing silently.
|
|
273
|
+
|
|
274
|
+
The one-line fix is to adopt the build preset:
|
|
275
|
+
|
|
276
|
+
```ts
|
|
277
|
+
// tsdown.server.config.ts
|
|
278
|
+
import { appkitServerConfig } from '@databricks/appkit/tsdown';
|
|
279
|
+
|
|
280
|
+
export default appkitServerConfig();
|
|
281
|
+
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
`appkitServerConfig()` auto-detects `server/agents/` and adds the entry glob + `clean` only when code agents exist; pass overrides as `appkitServerConfig({ external, define, ... })`, or a function `appkitServerConfig((base) => ({ ...base }))` for full control. It's also the last time you touch this file — future build-wiring changes ship with the package. If you'd rather keep a hand-written config, add the entries yourself:
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
entry: ['server/server.ts', 'server/agents/*/agent.ts'],
|
|
288
|
+
clean: true,
|
|
289
|
+
|
|
290
|
+
```
|
|
291
|
+
|
|
232
292
|
## Managed agents: the Supervisor API adapter[](#managed-agents-the-supervisor-api-adapter "Direct link to Managed agents: the Supervisor API adapter")
|
|
233
293
|
|
|
234
294
|
`DatabricksAdapter.fromSupervisorApi` (beta) is the zero-config way to run an agent: instead of provisioning and pointing at a model-serving endpoint, you run the agentic loop in the Databricks workspace by targeting the 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.
|
|
@@ -361,8 +421,8 @@ Some hosted tool kinds return their final assistant text without incremental `ou
|
|
|
361
421
|
|
|
362
422
|
```ts
|
|
363
423
|
agents({
|
|
364
|
-
|
|
365
|
-
agents?: Record<string, AgentDefinition>,
|
|
424
|
+
// Agents live under server/agents/<id>/ (fixed root). config/agents is read as a deprecated fallback.
|
|
425
|
+
agents?: Record<string, AgentDefinition>, // DEPRECATED — use server/agents/<id>/ discovery
|
|
366
426
|
defaultAgent?: string,
|
|
367
427
|
defaultModel?: AgentAdapter | Promise<AgentAdapter> | string,
|
|
368
428
|
tools?: Record<string, AgentTool>,
|
|
@@ -381,6 +441,7 @@ agents({
|
|
|
381
441
|
maxConcurrentStreamsPerUser?: number, // default: 5
|
|
382
442
|
maxToolCalls?: number, // default: 50
|
|
383
443
|
maxSubAgentDepth?: number, // default: 3
|
|
444
|
+
toolCallTimeoutMs?: number, // default: 300_000 (5 min)
|
|
384
445
|
},
|
|
385
446
|
})
|
|
386
447
|
|
|
@@ -538,6 +599,7 @@ agents({
|
|
|
538
599
|
maxConcurrentStreamsPerUser: 5, // HTTP 429 + Retry-After when exceeded
|
|
539
600
|
maxToolCalls: 50, // aborts the run if the budget is exhausted
|
|
540
601
|
maxSubAgentDepth: 3, // rejects sub-agent recursion beyond this
|
|
602
|
+
toolCallTimeoutMs: 300_000, // per-tool-call timeout (5 min; cold SQL/Genie headroom)
|
|
541
603
|
},
|
|
542
604
|
});
|
|
543
605
|
|
|
@@ -567,8 +629,10 @@ appkit.agents.getThreads(userId); // list user's threads
|
|
|
567
629
|
| `model` | string | Same as `endpoint`; either works. |
|
|
568
630
|
| `tools` | array | Unified tool list. Entries are `plugin:<name>` / `plugin:<name>: [t1, t2]` / `plugin:<name>: { only, except, rename, prefix }` for plugin tools, or a bare `<key>` resolved against `agents({ tools: {...} })` for ambient tools. See "Level 2: scope tools in frontmatter" above for examples. |
|
|
569
631
|
| `default` | boolean | First agent id (sorted order) with `default: true` becomes the default agent. |
|
|
632
|
+
| `agents` | array | Sub-agent ids (sibling folders) to delegate to; each becomes an `agent-<id>` tool. Resolves against other markdown and code agents. |
|
|
570
633
|
| `maxSteps` | number | Adapter max-step hint. |
|
|
571
634
|
| `maxTokens` | number | Adapter max-token hint. |
|
|
635
|
+
| `generationParams` | object | Adapter generation params (e.g. `temperature`, `top_p`) passed through when AppKit builds the adapter. |
|
|
572
636
|
| `baseSystemPrompt` | false \| string | Per-agent override. `false` disables the AppKit base prompt. |
|
|
573
637
|
| `ephemeral` | boolean | If `true`, the thread created for a chat request against this agent is deleted from `ThreadStore` after the stream finishes. Use for stateless one-shot agents (e.g. autocomplete) so history does not accumulate or contaminate future calls. Defaults to `false`. |
|
|
574
638
|
|
package/docs/plugins/testing.md
CHANGED
|
@@ -49,7 +49,7 @@ const mock = createTestPluginContext({
|
|
|
49
49
|
`attach()` wires the context to a plugin the production way: it seeds an in-memory cache (if AppKit hasn't already initialized one), then calls the plugin's `attachContext`, which rebuilds telemetry and flips `isReady` to `true`. Await it before exercising any handler that reads `this.context`, `this.cache`, or gates on `isReady`:
|
|
50
50
|
|
|
51
51
|
```ts
|
|
52
|
-
const plugin = new MyAgentPlugin({
|
|
52
|
+
const plugin = new MyAgentPlugin({});
|
|
53
53
|
await mock.attach(plugin);
|
|
54
54
|
|
|
55
55
|
```
|
|
@@ -222,7 +222,7 @@ To test a plugin that dispatches cross-plugin tool calls, register fake provider
|
|
|
222
222
|
|
|
223
223
|
```ts
|
|
224
224
|
const mock = createTestPluginContext({ analytics: { query: [{ n: 1 }] } });
|
|
225
|
-
const plugin = new MyAgentPlugin({
|
|
225
|
+
const plugin = new MyAgentPlugin({});
|
|
226
226
|
await mock.attach(plugin);
|
|
227
227
|
|
|
228
228
|
// `obo` sets the forwarded identity headers `asUser` needs — without them the
|