@databricks/appkit 0.48.0 → 0.50.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.
Files changed (51) hide show
  1. package/CLAUDE.md +11 -1
  2. package/dist/agents/databricks.d.ts +24 -7
  3. package/dist/agents/databricks.d.ts.map +1 -1
  4. package/dist/agents/databricks.js +25 -0
  5. package/dist/agents/databricks.js.map +1 -1
  6. package/dist/agents/supervisor-api.d.ts +362 -0
  7. package/dist/agents/supervisor-api.d.ts.map +1 -0
  8. package/dist/agents/supervisor-api.js +498 -0
  9. package/dist/agents/supervisor-api.js.map +1 -0
  10. package/dist/appkit/package.js +1 -1
  11. package/dist/beta.d.ts +2 -1
  12. package/dist/beta.js +2 -1
  13. package/dist/connectors/serving/client.d.ts +24 -0
  14. package/dist/connectors/serving/client.d.ts.map +1 -0
  15. package/dist/connectors/serving/client.js +34 -14
  16. package/dist/connectors/serving/client.js.map +1 -1
  17. package/dist/core/agent/run-agent.d.ts.map +1 -1
  18. package/dist/core/agent/run-agent.js +51 -2
  19. package/dist/core/agent/run-agent.js.map +1 -1
  20. package/dist/core/agent/types.d.ts +19 -3
  21. package/dist/core/agent/types.d.ts.map +1 -1
  22. package/dist/core/agent/types.js.map +1 -1
  23. package/dist/plugins/agents/agents.d.ts.map +1 -1
  24. package/dist/plugins/agents/agents.js +65 -5
  25. package/dist/plugins/agents/agents.js.map +1 -1
  26. package/dist/registry/manifest-loader.d.ts +1 -1
  27. package/dist/shared/src/agent.d.ts +28 -0
  28. package/dist/shared/src/agent.d.ts.map +1 -1
  29. package/dist/stream/index.js +1 -0
  30. package/dist/stream/sse-reader.js +86 -0
  31. package/dist/stream/sse-reader.js.map +1 -0
  32. package/docs/api/appkit/Class.DatabricksAdapter.md +34 -0
  33. package/docs/api/appkit/Class.SupervisorApiAdapter.md +121 -0
  34. package/docs/api/appkit/Function.fromSupervisorApi.md +63 -0
  35. package/docs/api/appkit/Function.isSupervisorTool.md +18 -0
  36. package/docs/api/appkit/Interface.AgentAdapter.md +24 -0
  37. package/docs/api/appkit/Interface.AgentInput.md +13 -0
  38. package/docs/api/appkit/Interface.HostedSupervisorTool.md +21 -0
  39. package/docs/api/appkit/Interface.SupervisorApiAdapterOptions.md +38 -0
  40. package/docs/api/appkit/Interface.SupervisorExtension.md +12 -0
  41. package/docs/api/appkit/Interface.WorkspaceClientLike.md +67 -0
  42. package/docs/api/appkit/TypeAlias.AgentTool.md +3 -2
  43. package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +167 -0
  44. package/docs/api/appkit/TypeAlias.SupervisorTool.md +45 -0
  45. package/docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md +8 -0
  46. package/docs/api/appkit/Variable.supervisorTools.md +176 -0
  47. package/docs/api/appkit.md +118 -108
  48. package/docs/plugins/agents.md +136 -6
  49. package/llms.txt +11 -1
  50. package/package.json +1 -1
  51. package/sbom.cdx.json +1 -1
@@ -39,34 +39,54 @@ async function invoke(client, endpointName, body) {
39
39
  });
40
40
  }
41
41
  /**
42
- * Returns the raw SSE byte stream from a serving endpoint.
43
- * No parsing is performed — bytes are passed through as-is.
42
+ * POSTs `body` as JSON to an arbitrary workspace API path and returns the raw
43
+ * SSE byte stream. No parsing is performed — bytes are passed through as-is.
44
44
  *
45
- * Uses the SDK's low-level `apiClient.request({ raw: true })` because
46
- * the high-level `servingEndpoints.query()` returns `Promise<QueryEndpointResponse>`
47
- * and does not support SSE streaming.
45
+ * Uses the SDK's low-level `apiClient.request({ raw: true })` so callers
46
+ * inherit URL resolution, the SDK credential chain (PAT/OAuth/OIDC), and
47
+ * any future retries/telemetry baked into the SDK transport.
48
+ *
49
+ * When `signal` is provided it is bridged to the SDK's `Context` /
50
+ * `CancellationToken` so aborts cancel the outbound HTTP request.
51
+ *
52
+ * @internal
53
+ *
54
+ * Not part of the public AppKit surface. `path` is passed through to the
55
+ * SDK without any allowlist — exposing this to user-controlled input would
56
+ * turn it into workspace-credentialled SSRF (CWE-918). Internal callers
57
+ * must hard-code the path (or build it from a closed enum). New callers
58
+ * inside the package: keep this constraint, and do not re-export from
59
+ * `beta.ts` or any other entry point.
48
60
  */
49
- async function stream(client, endpointName, body, signal) {
50
- const { stream: _stream, ...cleanBody } = body;
51
- logger.debug("Streaming from endpoint %s", endpointName);
61
+ async function streamPath(client, path, body, signal) {
62
+ logger.debug("Streaming from path %s", path);
52
63
  const context = signal ? new Context({ cancellationToken: cancellationTokenFromAbortSignal(signal) }) : void 0;
53
64
  const response = await client.apiClient.request({
54
- path: `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,
65
+ path,
55
66
  method: "POST",
56
67
  headers: new Headers({
57
68
  "Content-Type": "application/json",
58
69
  Accept: "text/event-stream"
59
70
  }),
60
- payload: {
61
- ...cleanBody,
62
- stream: true
63
- },
71
+ payload: body,
64
72
  raw: true
65
73
  }, context);
66
74
  if (!response.contents) throw new Error("Response body is null — streaming not supported");
67
75
  return response.contents;
68
76
  }
77
+ /**
78
+ * Returns the raw SSE byte stream from a serving endpoint. Thin wrapper over
79
+ * {@link streamPath} that handles serving-specific URL encoding and forces
80
+ * `stream: true` in the payload.
81
+ */
82
+ async function stream(client, endpointName, body, signal) {
83
+ const { stream: _stream, ...cleanBody } = body;
84
+ return streamPath(client, `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`, {
85
+ ...cleanBody,
86
+ stream: true
87
+ }, signal);
88
+ }
69
89
 
70
90
  //#endregion
71
- export { invoke, stream };
91
+ export { invoke, stream, streamPath };
72
92
  //# sourceMappingURL=client.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {\n CancellationToken,\n serving,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { Context } from \"@databricks/sdk-experimental\";\nimport { createLogger } from \"../../logging/logger\";\n\nconst logger = createLogger(\"connectors:serving\");\n\n/**\n * Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so\n * `apiClient.request` can abort the outbound HTTP request (and stop pulling\n * the SSE body) when the agent run is cancelled.\n */\nfunction cancellationTokenFromAbortSignal(\n signal: AbortSignal,\n): CancellationToken {\n const listeners = new Set<() => void>();\n const fire = () => {\n for (const cb of listeners) {\n try {\n cb();\n } catch {\n // ignore listener failures — abort must stay best-effort\n }\n }\n };\n signal.addEventListener(\"abort\", fire, { passive: true });\n\n return {\n get isCancellationRequested() {\n return signal.aborted;\n },\n onCancellationRequested(callback: (e?: unknown) => unknown) {\n listeners.add(callback as () => void);\n if (signal.aborted) {\n void callback();\n }\n },\n };\n}\n\n/**\n * Invokes a serving endpoint using the SDK's high-level query API.\n * Returns a typed QueryEndpointResponse.\n */\nexport async function invoke(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n): Promise<serving.QueryEndpointResponse> {\n // Strip `stream` from the body — the connector controls this\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Invoking endpoint %s\", endpointName);\n\n return client.servingEndpoints.query({\n name: endpointName,\n ...cleanBody,\n } as serving.QueryEndpointInput);\n}\n\n/**\n * Returns the raw SSE byte stream from a serving endpoint.\n * No parsing is performed — bytes are passed through as-is.\n *\n * Uses the SDK's low-level `apiClient.request({ raw: true })` because\n * the high-level `servingEndpoints.query()` returns `Promise<QueryEndpointResponse>`\n * and does not support SSE streaming.\n */\nexport async function stream(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Streaming from endpoint %s\", endpointName);\n\n const context = signal\n ? new Context({\n cancellationToken: cancellationTokenFromAbortSignal(signal),\n })\n : undefined;\n\n const response = (await client.apiClient.request(\n {\n path: `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,\n method: \"POST\",\n headers: new Headers({\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n }),\n payload: { ...cleanBody, stream: true },\n raw: true,\n },\n context,\n )) as { contents: ReadableStream<Uint8Array> };\n\n if (!response.contents) {\n throw new Error(\"Response body is null — streaming not supported\");\n }\n\n return response.contents;\n}\n"],"mappings":";;;;AAQA,MAAM,SAAS,aAAa,qBAAqB;;;;;;AAOjD,SAAS,iCACP,QACmB;CACnB,MAAM,4BAAY,IAAI,KAAiB;CACvC,MAAM,aAAa;AACjB,OAAK,MAAM,MAAM,UACf,KAAI;AACF,OAAI;UACE;;AAKZ,QAAO,iBAAiB,SAAS,MAAM,EAAE,SAAS,MAAM,CAAC;AAEzD,QAAO;EACL,IAAI,0BAA0B;AAC5B,UAAO,OAAO;;EAEhB,wBAAwB,UAAoC;AAC1D,aAAU,IAAI,SAAuB;AACrC,OAAI,OAAO,QACT,CAAK,UAAU;;EAGpB;;;;;;AAOH,eAAsB,OACpB,QACA,cACA,MACwC;CAExC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,wBAAwB,aAAa;AAElD,QAAO,OAAO,iBAAiB,MAAM;EACnC,MAAM;EACN,GAAG;EACJ,CAA+B;;;;;;;;;;AAWlC,eAAsB,OACpB,QACA,cACA,MACA,QACqC;CACrC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,8BAA8B,aAAa;CAExD,MAAM,UAAU,SACZ,IAAI,QAAQ,EACV,mBAAmB,iCAAiC,OAAO,EAC5D,CAAC,GACF;CAEJ,MAAM,WAAY,MAAM,OAAO,UAAU,QACvC;EACE,MAAM,sBAAsB,mBAAmB,aAAa,CAAC;EAC7D,QAAQ;EACR,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,QAAQ;GACT,CAAC;EACF,SAAS;GAAE,GAAG;GAAW,QAAQ;GAAM;EACvC,KAAK;EACN,EACD,QACD;AAED,KAAI,CAAC,SAAS,SACZ,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAO,SAAS"}
1
+ {"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {\n CancellationToken,\n serving,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { Context } from \"@databricks/sdk-experimental\";\nimport { createLogger } from \"../../logging/logger\";\n\nconst logger = createLogger(\"connectors:serving\");\n\n/**\n * Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so\n * `apiClient.request` can abort the outbound HTTP request (and stop pulling\n * the SSE body) when the agent run is cancelled.\n */\nfunction cancellationTokenFromAbortSignal(\n signal: AbortSignal,\n): CancellationToken {\n const listeners = new Set<() => void>();\n const fire = () => {\n for (const cb of listeners) {\n try {\n cb();\n } catch {\n // ignore listener failures — abort must stay best-effort\n }\n }\n };\n signal.addEventListener(\"abort\", fire, { passive: true });\n\n return {\n get isCancellationRequested() {\n return signal.aborted;\n },\n onCancellationRequested(callback: (e?: unknown) => unknown) {\n listeners.add(callback as () => void);\n if (signal.aborted) {\n void callback();\n }\n },\n };\n}\n\n/**\n * Structural shape of a Databricks SDK client we need for the low-level\n * `apiClient.request` call. Lets `streamPath` be reused by adapters that\n * don't want a hard dependency on the concrete `WorkspaceClient` type.\n */\nexport interface ApiClientLike {\n apiClient: {\n request(\n options: Record<string, unknown>,\n context?: unknown,\n ): Promise<unknown>;\n };\n}\n\n/**\n * Transport shim shared by the agent adapters: given a request body, returns\n * the raw SSE byte stream from a serving / AI-gateway endpoint. Injected at\n * adapter construction time so callers can swap in the workspace SDK (the\n * factory paths via {@link streamPath}), a bare `fetch` (a reverse proxy /\n * mock), or a test fake.\n */\nexport type StreamBody = (\n body: Record<string, unknown>,\n signal?: AbortSignal,\n) => Promise<ReadableStream<Uint8Array>>;\n\n/**\n * Invokes a serving endpoint using the SDK's high-level query API.\n * Returns a typed QueryEndpointResponse.\n */\nexport async function invoke(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n): Promise<serving.QueryEndpointResponse> {\n // Strip `stream` from the body — the connector controls this\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Invoking endpoint %s\", endpointName);\n\n return client.servingEndpoints.query({\n name: endpointName,\n ...cleanBody,\n } as serving.QueryEndpointInput);\n}\n\n/**\n * POSTs `body` as JSON to an arbitrary workspace API path and returns the raw\n * SSE byte stream. No parsing is performed — bytes are passed through as-is.\n *\n * Uses the SDK's low-level `apiClient.request({ raw: true })` so callers\n * inherit URL resolution, the SDK credential chain (PAT/OAuth/OIDC), and\n * any future retries/telemetry baked into the SDK transport.\n *\n * When `signal` is provided it is bridged to the SDK's `Context` /\n * `CancellationToken` so aborts cancel the outbound HTTP request.\n *\n * @internal\n *\n * Not part of the public AppKit surface. `path` is passed through to the\n * SDK without any allowlist — exposing this to user-controlled input would\n * turn it into workspace-credentialled SSRF (CWE-918). Internal callers\n * must hard-code the path (or build it from a closed enum). New callers\n * inside the package: keep this constraint, and do not re-export from\n * `beta.ts` or any other entry point.\n */\nexport async function streamPath(\n client: ApiClientLike,\n path: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n logger.debug(\"Streaming from path %s\", path);\n\n const context = signal\n ? new Context({\n cancellationToken: cancellationTokenFromAbortSignal(signal),\n })\n : undefined;\n\n const response = (await client.apiClient.request(\n {\n path,\n method: \"POST\",\n headers: new Headers({\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n }),\n payload: body,\n raw: true,\n },\n context,\n )) as { contents: ReadableStream<Uint8Array> | null };\n\n if (!response.contents) {\n throw new Error(\"Response body is null — streaming not supported\");\n }\n\n return response.contents;\n}\n\n/**\n * Returns the raw SSE byte stream from a serving endpoint. Thin wrapper over\n * {@link streamPath} that handles serving-specific URL encoding and forces\n * `stream: true` in the payload.\n */\nexport async function stream(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n const { stream: _stream, ...cleanBody } = body;\n return streamPath(\n client as unknown as ApiClientLike,\n `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,\n { ...cleanBody, stream: true },\n signal,\n );\n}\n"],"mappings":";;;;AAQA,MAAM,SAAS,aAAa,qBAAqB;;;;;;AAOjD,SAAS,iCACP,QACmB;CACnB,MAAM,4BAAY,IAAI,KAAiB;CACvC,MAAM,aAAa;AACjB,OAAK,MAAM,MAAM,UACf,KAAI;AACF,OAAI;UACE;;AAKZ,QAAO,iBAAiB,SAAS,MAAM,EAAE,SAAS,MAAM,CAAC;AAEzD,QAAO;EACL,IAAI,0BAA0B;AAC5B,UAAO,OAAO;;EAEhB,wBAAwB,UAAoC;AAC1D,aAAU,IAAI,SAAuB;AACrC,OAAI,OAAO,QACT,CAAK,UAAU;;EAGpB;;;;;;AAiCH,eAAsB,OACpB,QACA,cACA,MACwC;CAExC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,wBAAwB,aAAa;AAElD,QAAO,OAAO,iBAAiB,MAAM;EACnC,MAAM;EACN,GAAG;EACJ,CAA+B;;;;;;;;;;;;;;;;;;;;;;AAuBlC,eAAsB,WACpB,QACA,MACA,MACA,QACqC;AACrC,QAAO,MAAM,0BAA0B,KAAK;CAE5C,MAAM,UAAU,SACZ,IAAI,QAAQ,EACV,mBAAmB,iCAAiC,OAAO,EAC5D,CAAC,GACF;CAEJ,MAAM,WAAY,MAAM,OAAO,UAAU,QACvC;EACE;EACA,QAAQ;EACR,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,QAAQ;GACT,CAAC;EACF,SAAS;EACT,KAAK;EACN,EACD,QACD;AAED,KAAI,CAAC,SAAS,SACZ,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAO,SAAS;;;;;;;AAQlB,eAAsB,OACpB,QACA,cACA,MACA,QACqC;CACrC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAC1C,QAAO,WACL,QACA,sBAAsB,mBAAmB,aAAa,CAAC,eACvD;EAAE,GAAG;EAAW,QAAQ;EAAM,EAC9B,OACD"}
@@ -1 +1 @@
1
- {"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"mappings":";;;;;;UA4BiB,aAAA;;EAEf,QAAA,WAAmB,OAAA;;EAEnB,MAAA,GAAS,WAAA;EAJmB;;;;;;;EAY5B,OAAA,GAAU,UAAA,CAAW,iBAAA;AAAA;AAAA,UAGN,cAAA;EAXf;EAaA,IAAA;EALA;EAOA,MAAA,EAAQ,UAAA;AAAA;;;AAJV;;;;;;;;;AAmCA;;;;;;;;;;;;;;;;;iBAAsB,QAAA,CACpB,GAAA,EAAK,eAAA,EACL,KAAA,EAAO,aAAA,GACN,OAAA,CAAQ,cAAA"}
1
+ {"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"mappings":";;;;;;UAoCiB,aAAA;;EAEf,QAAA,WAAmB,OAAA;;EAEnB,MAAA,GAAS,WAAA;EAJmB;;;;;;;EAY5B,OAAA,GAAU,UAAA,CAAW,iBAAA;AAAA;AAAA,UAGN,cAAA;EAXf;EAaA,IAAA;EALA;EAOA,MAAA,EAAQ,UAAA;AAAA;;;AAJV;;;;;;;;;AAmCA;;;;;;;;;;;;;;;;;iBAAsB,QAAA,CACpB,GAAA,EAAK,eAAA,EACL,KAAA,EAAO,aAAA,GACN,OAAA,CAAQ,cAAA"}
@@ -1,3 +1,5 @@
1
+ import { createLogger } from "../../logging/logger.js";
2
+ import { SUPERVISOR_EXTENSION_KEY, isSupervisorTool } from "../../agents/supervisor-api.js";
1
3
  import { consumeAdapterStream } from "./consume-adapter-stream.js";
2
4
  import { createPluginsProxy } from "./plugins-map.js";
3
5
  import { resolveToolkitFromProvider } from "./toolkit-resolver.js";
@@ -7,6 +9,7 @@ import { isToolkitEntry } from "./types.js";
7
9
  import { randomUUID } from "node:crypto";
8
10
 
9
11
  //#region src/core/agent/run-agent.ts
12
+ const logger = createLogger("agent:run-agent");
10
13
  /**
11
14
  * Standalone agent execution without `createApp`. Resolves the adapter, binds
12
15
  * inline tools, and drives the adapter's `run()` loop to completion.
@@ -44,7 +47,8 @@ async function runAgentInternal(def, input, providerCache) {
44
47
  const adapter = await resolveAdapter(def);
45
48
  const messages = normalizeMessages(input.messages, def.instructions);
46
49
  const toolIndex = buildStandaloneToolIndex(def, input.plugins ?? [], providerCache);
47
- const tools = Array.from(toolIndex.values()).map((e) => e.def);
50
+ const tools = Array.from(toolIndex.values()).filter((e) => e.kind !== "hosted-supervisor").map((e) => e.def);
51
+ warnOnCapabilityMismatch(def.name ?? "<anonymous>", adapter, toolIndex);
48
52
  const signal = input.signal;
49
53
  const executeTool = async (name, args) => {
50
54
  const entry = toolIndex.get(name);
@@ -59,6 +63,7 @@ async function runAgentInternal(def, input, providerCache) {
59
63
  };
60
64
  return (await runAgentInternal(entry.agentDef, subInput, providerCache)).text;
61
65
  }
66
+ if (entry.kind === "hosted-supervisor") throw new Error(`runAgent: tool "${name}" is a hosted-supervisor tool, executed server-side by the Databricks AI Gateway. It must not be invoked from the Node process.`);
62
67
  throw new Error(`runAgent: tool "${name}" is a ${entry.kind} tool. Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).`);
63
68
  };
64
69
  const events = [];
@@ -67,7 +72,8 @@ async function runAgentInternal(def, input, providerCache) {
67
72
  messages,
68
73
  tools,
69
74
  threadId: randomUUID(),
70
- signal
75
+ signal,
76
+ extensions: buildStandaloneExtensions(toolIndex)
71
77
  }, {
72
78
  executeTool,
73
79
  signal
@@ -228,9 +234,52 @@ function classifyTool(key, tool, providerCache) {
228
234
  name: key
229
235
  }
230
236
  };
237
+ if (isSupervisorTool(tool)) return {
238
+ kind: "hosted-supervisor",
239
+ spec: tool.spec,
240
+ def: {
241
+ name: key,
242
+ description: supervisorToolDescription(tool.spec),
243
+ parameters: {
244
+ type: "object",
245
+ properties: {}
246
+ }
247
+ }
248
+ };
231
249
  if (isHostedTool(tool)) throw new Error(`runAgent: tool "${key}" is a hosted tool (type="${tool.type}") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`);
232
250
  throw new Error(`runAgent: unrecognized tool shape at key "${key}"`);
233
251
  }
252
+ /** Mirrors `agents.ts`'s `supervisorToolDescription`. */
253
+ function supervisorToolDescription(spec) {
254
+ switch (spec.type) {
255
+ case "genie_space": return spec.genie_space.description;
256
+ case "uc_function": return spec.uc_function.description;
257
+ case "knowledge_assistant": return spec.knowledge_assistant.description;
258
+ case "app": return spec.app.description;
259
+ case "uc_connection": return spec.uc_connection.description;
260
+ }
261
+ }
262
+ /** Mirrors `agents.ts`'s `buildAdapterExtensions`. */
263
+ function buildStandaloneExtensions(toolIndex) {
264
+ const supervisorSpecs = [];
265
+ for (const entry of toolIndex.values()) if (entry.kind === "hosted-supervisor") supervisorSpecs.push(entry.spec);
266
+ if (supervisorSpecs.length === 0) return void 0;
267
+ return { [SUPERVISOR_EXTENSION_KEY]: { hostedTools: supervisorSpecs } };
268
+ }
269
+ /**
270
+ * Mirrors the agents-plugin capability warning so standalone `runAgent`
271
+ * produces the same diagnostic when adapter capabilities don't match the
272
+ * tool index. Warn-not-throw: doesn't abort batch evals.
273
+ */
274
+ function warnOnCapabilityMismatch(agentName, adapter, toolIndex) {
275
+ const accepted = new Set(adapter.acceptsExtensions ?? []);
276
+ const hostedSupervisorKeys = [];
277
+ const inputToolKeys = [];
278
+ for (const [key, entry] of toolIndex) if (entry.kind === "hosted-supervisor") hostedSupervisorKeys.push(key);
279
+ else inputToolKeys.push(key);
280
+ if (hostedSupervisorKeys.length > 0 && !accepted.has(SUPERVISOR_EXTENSION_KEY)) logger.warn(`Agent '${agentName}' declares hosted-supervisor tools (${hostedSupervisorKeys.join(", ")}) but its model adapter does not accept the 'databricks.supervisor' extension. Pair them with \`DatabricksAdapter.fromSupervisorApi(...)\`, or remove them.`);
281
+ if (adapter.consumesInputTools === false && inputToolKeys.length > 0) logger.warn(`Agent '${agentName}' declares function tools / sub-agents (${inputToolKeys.join(", ")}) but its model adapter does not consume input.tools. These tools will not be exposed to the model.`);
282
+ }
234
283
  function providerCacheLookup(pluginName, cache) {
235
284
  const cached = cache.get(pluginName);
236
285
  if (cached) return cached;
@@ -1 +1 @@
1
- {"version":3,"file":"run-agent.js","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n AgentAdapter,\n AgentEvent,\n AgentToolDefinition,\n Message,\n PluginConstructor,\n PluginData,\n ToolProvider,\n} from \"shared\";\nimport { consumeAdapterStream } from \"./consume-adapter-stream\";\nimport { createPluginsProxy } from \"./plugins-map\";\nimport { resolveToolkitFromProvider } from \"./toolkit-resolver\";\nimport {\n type FunctionTool,\n functionToolToDefinition,\n isFunctionTool,\n} from \"./tools/function-tool\";\nimport { isHostedTool } from \"./tools/hosted-tools\";\nimport type {\n AgentDefinition,\n AgentTool,\n AgentTools,\n Plugins,\n PluginToolkitProvider,\n} from \"./types\";\nimport { isToolkitEntry } from \"./types\";\n\nexport interface RunAgentInput {\n /** Seed messages for the run. Either a single user string or a full message list. */\n messages: string | Message[];\n /** Abort signal for cancellation. */\n signal?: AbortSignal;\n /**\n * Optional plugin list. Required when `def.tools` is the function form\n * `(plugins) => Record<string, AgentTool>` and the function dereferences\n * any plugins. `runAgent` constructs a fresh instance per plugin and\n * dispatches tool calls against it as the service principal (no OBO —\n * there is no HTTP request in standalone mode).\n */\n plugins?: PluginData<PluginConstructor, unknown, string>[];\n}\n\nexport interface RunAgentResult {\n /** Aggregated text output from all `message_delta` events. */\n text: string;\n /** Every event the adapter yielded, in order. Useful for inspection/tests. */\n events: AgentEvent[];\n}\n\n/**\n * Standalone agent execution without `createApp`. Resolves the adapter, binds\n * inline tools, and drives the adapter's `run()` loop to completion.\n *\n * Limitations vs. running through the agents() plugin:\n * - **No OBO and no approval gate** — there is no HTTP request, so plugin\n * tools run as the service principal. The agents-plugin approval gate\n * that prompts for human confirmation on `effect: \"write\" | \"update\" |\n * \"destructive\"` tools is also absent. LLM-controlled tool arguments\n * flow straight through to the SP. Treat standalone runAgent as a\n * trusted-prompt environment (CI, batch eval, internal scripts) — not\n * as an exposed user-facing surface.\n * - **Hosted tools (MCP) are not supported** — they require a live MCP\n * client that only exists inside the agents plugin's lifecycle.\n * `runAgent` rejects them at index-build time with a clear error.\n * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested\n * `runAgent` calls with no shared thread state. Plugin instances ARE\n * shared across the recursion (same cache as the parent).\n * - **Plugin tools** (used inside the function form via\n * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via\n * `RunAgentInput`. Each plugin in that array is constructed once,\n * `attachContext({})` and `await setup()` are called eagerly, and the\n * resulting instance is shared across the top-level run and all\n * sub-agent recursions. Plugins whose `setup()` requires runtime that\n * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,\n * `PluginContext`) throw at standalone-init time with a clear \"use\n * createApp instead\" message — not mid-stream.\n */\nexport async function runAgent(\n def: AgentDefinition,\n input: RunAgentInput,\n): Promise<RunAgentResult> {\n // Single shared cache for the whole call graph: parent + every nested\n // sub-agent dispatch share constructed plugin instances. Without this,\n // each nested `runAgent` would build its own cache, re-instantiate every\n // plugin, and silently diverge in-instance state between parent and child\n // (e.g. query result caches, connection pools).\n const providerCache = new Map<string, ToolProvider>();\n await initStandalonePlugins(input.plugins ?? [], providerCache);\n return runAgentInternal(def, input, providerCache);\n}\n\nasync function runAgentInternal(\n def: AgentDefinition,\n input: RunAgentInput,\n providerCache: Map<string, ToolProvider>,\n): Promise<RunAgentResult> {\n const adapter = await resolveAdapter(def);\n const messages = normalizeMessages(input.messages, def.instructions);\n const toolIndex = buildStandaloneToolIndex(\n def,\n input.plugins ?? [],\n providerCache,\n );\n const tools = Array.from(toolIndex.values()).map((e) => e.def);\n\n const signal = input.signal;\n\n const executeTool = async (name: string, args: unknown): Promise<unknown> => {\n const entry = toolIndex.get(name);\n if (!entry) throw new Error(`Unknown tool: ${name}`);\n if (entry.kind === \"function\") {\n return entry.tool.execute(args as Record<string, unknown>);\n }\n if (entry.kind === \"toolkit\") {\n return entry.provider.executeAgentTool(\n entry.localName,\n args as Record<string, unknown>,\n signal,\n );\n }\n if (entry.kind === \"subagent\") {\n const subInput: RunAgentInput = {\n messages:\n typeof args === \"object\" &&\n args !== null &&\n typeof (args as { input?: unknown }).input === \"string\"\n ? (args as { input: string }).input\n : JSON.stringify(args),\n signal,\n plugins: input.plugins,\n };\n // Reuse the same `providerCache` so sub-agent plugin tools dispatch\n // through the same instances the parent constructed.\n const res = await runAgentInternal(\n entry.agentDef,\n subInput,\n providerCache,\n );\n return res.text;\n }\n throw new Error(\n `runAgent: tool \"${name}\" is a ${entry.kind} tool. ` +\n \"Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).\",\n );\n };\n\n const events: AgentEvent[] = [];\n\n const stream = adapter.run(\n {\n messages,\n tools,\n threadId: randomUUID(),\n signal,\n },\n { executeTool, signal },\n );\n\n // Shared accumulation rule (deltas append, `message` replaces). The\n // `events` array is filled via the `onEvent` side effect so callers that\n // inspect the raw stream still get the full record.\n const text = await consumeAdapterStream(stream, {\n signal,\n onEvent: (event) => {\n events.push(event);\n },\n });\n\n return { text, events };\n}\n\n/**\n * Eagerly construct every plugin in `input.plugins`, run the standard\n * AppKit lifecycle (`attachContext({})` + `await setup()`), and populate\n * `cache`. Failures here surface BEFORE any adapter work — mid-stream\n * `getWorkspaceClient is not initialised`-style errors become a clear\n * startup failure naming the plugin and pointing the user at `createApp`.\n *\n * Plugins that don't need runtime context (no overridden `setup`, or one\n * that doesn't dereference `createApp`-only state) initialise cleanly and\n * standalone runAgent works as documented. Plugins like analytics/files\n * that depend on `WorkspaceClient` will throw the underlying error wrapped\n * with the migration hint.\n */\nasync function initStandalonePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n cache: Map<string, ToolProvider>,\n): Promise<void> {\n for (const data of plugins) {\n if (cache.has(data.name)) continue;\n const instance = new data.plugin({\n ...(data.config ?? {}),\n name: data.name,\n });\n if (!isStandaloneToolProvider(instance)) {\n throw new Error(\n `runAgent: plugin '${data.name}' is not a ToolProvider ` +\n \"(missing getAgentTools/executeAgentTool). Only ToolProvider plugins \" +\n \"are supported in standalone runAgent.\",\n );\n }\n if (\n typeof (instance as { attachContext?: unknown }).attachContext ===\n \"function\"\n ) {\n try {\n (\n instance as { attachContext: (deps: Record<string, unknown>) => void }\n ).attachContext({});\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' attachContext() failed in ` +\n \"standalone mode. This plugin probably depends on createApp's \" +\n \"runtime (WorkspaceClient, ServiceContext, PluginContext). Run \" +\n \"via createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n if (typeof (instance as { setup?: unknown }).setup === \"function\") {\n try {\n await (instance as { setup: () => Promise<void> | void }).setup();\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' setup() failed in standalone ` +\n \"mode. This plugin probably depends on createApp's runtime \" +\n \"(WorkspaceClient, ServiceContext, PluginContext). Run via \" +\n \"createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n cache.set(data.name, instance);\n }\n}\n\nasync function resolveAdapter(def: AgentDefinition): Promise<AgentAdapter> {\n const { model } = def;\n if (!model) {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing();\n }\n if (typeof model === \"string\") {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing(model);\n }\n return await model;\n}\n\nfunction normalizeMessages(\n input: string | Message[],\n instructions: string,\n): Message[] {\n const systemMessage: Message = {\n id: \"system\",\n role: \"system\",\n content: instructions,\n createdAt: new Date(),\n };\n if (typeof input === \"string\") {\n return [\n systemMessage,\n {\n id: randomUUID(),\n role: \"user\",\n content: input,\n createdAt: new Date(),\n },\n ];\n }\n return [systemMessage, ...input];\n}\n\ntype StandaloneEntry =\n | {\n kind: \"function\";\n def: AgentToolDefinition;\n tool: FunctionTool;\n }\n | {\n kind: \"subagent\";\n def: AgentToolDefinition;\n agentDef: AgentDefinition;\n }\n | {\n kind: \"toolkit\";\n def: AgentToolDefinition;\n provider: ToolProvider;\n pluginName: string;\n localName: string;\n }\n | {\n kind: \"hosted\";\n def: AgentToolDefinition;\n };\n\n/**\n * Resolves `def.tools` (object or function form) and `def.agents`\n * (sub-agents) into a flat dispatch index. The function form is invoked\n * once per call against a {@link Plugins} map drawn from the shared\n * `providerCache` populated by {@link initStandalonePlugins}. Missing\n * references throw a named \"not registered\" error via the proxy.\n */\nfunction buildStandaloneToolIndex(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Map<string, StandaloneEntry> {\n const index = new Map<string, StandaloneEntry>();\n const tools = resolveDefTools(def, plugins, providerCache);\n\n for (const [key, tool] of Object.entries(tools)) {\n index.set(key, classifyTool(key, tool, providerCache));\n }\n\n for (const [childKey, child] of Object.entries(def.agents ?? {})) {\n const toolName = `agent-${childKey}`;\n index.set(toolName, {\n kind: \"subagent\",\n agentDef: { ...child, name: child.name ?? childKey },\n def: {\n name: toolName,\n description:\n child.instructions.slice(0, 120) ||\n `Delegate to the ${childKey} sub-agent`,\n parameters: {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"Message to send to the sub-agent.\",\n },\n },\n required: [\"input\"],\n },\n },\n });\n }\n\n return index;\n}\n\n/**\n * Resolves `def.tools` to a plain record. The function form is invoked\n * with a typed {@link Plugins} map drawn from the pre-populated\n * `providerCache`; each `plugins.foo.toolkit(opts)` lookup hits the cache\n * directly (no construction at toolkit-call time).\n */\nfunction resolveDefTools(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): AgentTools {\n if (typeof def.tools !== \"function\") {\n return def.tools ?? {};\n }\n const pluginsMap = buildStandalonePluginsMap(plugins, providerCache);\n try {\n return def.tools(pluginsMap);\n } catch (err) {\n const name = def.name ?? \"<anonymous>\";\n throw new Error(\n `runAgent: agent '${name}' tools(plugins) callback threw: ${\n err instanceof Error ? err.message : String(err)\n }`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n}\n\n/**\n * Builds the typed {@link Plugins} map passed to the function form of\n * `def.tools` in standalone mode. Reads pre-constructed instances from\n * `providerCache` (populated eagerly by {@link initStandalonePlugins})\n * and wraps the result in a Proxy so unknown plugin names produce a\n * named \"not registered, Available: ...\" error instead of bubbling up a\n * generic `TypeError: Cannot read properties of undefined`.\n */\nfunction buildStandalonePluginsMap(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Plugins {\n const out: Record<string, PluginToolkitProvider> = {};\n for (const data of plugins) {\n const provider = providerCache.get(data.name);\n if (!provider) continue; // initStandalonePlugins should have set this\n out[data.name] = {\n toolkit: (opts) => resolveToolkitFromProvider(data.name, provider, opts),\n };\n }\n return createPluginsProxy(out, \"runAgent: tools(plugins)\");\n}\n\nfunction classifyTool(\n key: string,\n tool: AgentTool,\n providerCache: Map<string, ToolProvider>,\n): StandaloneEntry {\n if (isToolkitEntry(tool)) {\n // Toolkit entries inside the function form's returned record carry the\n // provider name they came from, so we can resolve the provider on\n // demand and dispatch through it. The cache is shared with the\n // pluginsMap path so the same instance is reused.\n const provider = providerCacheLookup(tool.pluginName, providerCache);\n return {\n kind: \"toolkit\",\n provider,\n pluginName: tool.pluginName,\n localName: tool.localName,\n def: { ...tool.def, name: key },\n };\n }\n if (isFunctionTool(tool)) {\n return {\n kind: \"function\",\n tool,\n def: { ...functionToolToDefinition(tool), name: key },\n };\n }\n if (isHostedTool(tool)) {\n // Hosted tools (e.g. MCP `mcpServer(...)`) need a live MCP client that\n // only exists inside the agents plugin's lifecycle. In standalone\n // `runAgent` they would have errored at dispatch time with a confusing\n // mid-conversation failure; reject them up front so misconfiguration\n // surfaces before the adapter sees the tool list.\n throw new Error(\n `runAgent: tool \"${key}\" is a hosted tool (type=\"${tool.type}\") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`,\n );\n }\n throw new Error(`runAgent: unrecognized tool shape at key \"${key}\"`);\n}\n\nfunction providerCacheLookup(\n pluginName: string,\n cache: Map<string, ToolProvider>,\n): ToolProvider {\n const cached = cache.get(pluginName);\n if (cached) return cached;\n const available = Array.from(cache.keys()).join(\", \") || \"(none)\";\n throw new Error(\n `runAgent: tool refers to plugin '${pluginName}', but no instance was ` +\n \"initialised for that name. Add it to RunAgentInput.plugins, or — if \" +\n \"this came from a hand-rolled ToolkitEntry — go through \" +\n `plugins[name].toolkit() instead. Available: ${available}.`,\n );\n}\n\n/**\n * Lightweight `ToolProvider` shape check used by standalone `runAgent`.\n *\n * Distinct from `core/plugin-context.isToolProvider` which also requires\n * `asUser` (request-scoped, only meaningful when running inside `createApp`\n * with a live HTTP context). Standalone plugins are constructed without a\n * `WorkspaceClient` and have no request to scope to, so checking only the\n * two `ToolProvider` methods is the right narrowing here.\n */\nfunction isStandaloneToolProvider(value: unknown): value is ToolProvider {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.getAgentTools === \"function\" &&\n typeof obj.executeAgentTool === \"function\"\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-agent.js","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n AgentAdapter,\n AgentEvent,\n AgentToolDefinition,\n Message,\n PluginConstructor,\n PluginData,\n ToolProvider,\n} from \"shared\";\nimport {\n isSupervisorTool,\n SUPERVISOR_EXTENSION_KEY,\n type SupervisorTool,\n} from \"../../agents/supervisor-api\";\nimport { createLogger } from \"../../logging/logger\";\nimport { consumeAdapterStream } from \"./consume-adapter-stream\";\nimport { createPluginsProxy } from \"./plugins-map\";\nimport { resolveToolkitFromProvider } from \"./toolkit-resolver\";\nimport {\n type FunctionTool,\n functionToolToDefinition,\n isFunctionTool,\n} from \"./tools/function-tool\";\nimport { isHostedTool } from \"./tools/hosted-tools\";\nimport type {\n AgentDefinition,\n AgentTool,\n AgentTools,\n Plugins,\n PluginToolkitProvider,\n} from \"./types\";\nimport { isToolkitEntry } from \"./types\";\n\nconst logger = createLogger(\"agent:run-agent\");\n\nexport interface RunAgentInput {\n /** Seed messages for the run. Either a single user string or a full message list. */\n messages: string | Message[];\n /** Abort signal for cancellation. */\n signal?: AbortSignal;\n /**\n * Optional plugin list. Required when `def.tools` is the function form\n * `(plugins) => Record<string, AgentTool>` and the function dereferences\n * any plugins. `runAgent` constructs a fresh instance per plugin and\n * dispatches tool calls against it as the service principal (no OBO —\n * there is no HTTP request in standalone mode).\n */\n plugins?: PluginData<PluginConstructor, unknown, string>[];\n}\n\nexport interface RunAgentResult {\n /** Aggregated text output from all `message_delta` events. */\n text: string;\n /** Every event the adapter yielded, in order. Useful for inspection/tests. */\n events: AgentEvent[];\n}\n\n/**\n * Standalone agent execution without `createApp`. Resolves the adapter, binds\n * inline tools, and drives the adapter's `run()` loop to completion.\n *\n * Limitations vs. running through the agents() plugin:\n * - **No OBO and no approval gate** — there is no HTTP request, so plugin\n * tools run as the service principal. The agents-plugin approval gate\n * that prompts for human confirmation on `effect: \"write\" | \"update\" |\n * \"destructive\"` tools is also absent. LLM-controlled tool arguments\n * flow straight through to the SP. Treat standalone runAgent as a\n * trusted-prompt environment (CI, batch eval, internal scripts) — not\n * as an exposed user-facing surface.\n * - **Hosted tools (MCP) are not supported** — they require a live MCP\n * client that only exists inside the agents plugin's lifecycle.\n * `runAgent` rejects them at index-build time with a clear error.\n * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested\n * `runAgent` calls with no shared thread state. Plugin instances ARE\n * shared across the recursion (same cache as the parent).\n * - **Plugin tools** (used inside the function form via\n * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via\n * `RunAgentInput`. Each plugin in that array is constructed once,\n * `attachContext({})` and `await setup()` are called eagerly, and the\n * resulting instance is shared across the top-level run and all\n * sub-agent recursions. Plugins whose `setup()` requires runtime that\n * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,\n * `PluginContext`) throw at standalone-init time with a clear \"use\n * createApp instead\" message — not mid-stream.\n */\nexport async function runAgent(\n def: AgentDefinition,\n input: RunAgentInput,\n): Promise<RunAgentResult> {\n // Single shared cache for the whole call graph: parent + every nested\n // sub-agent dispatch share constructed plugin instances. Without this,\n // each nested `runAgent` would build its own cache, re-instantiate every\n // plugin, and silently diverge in-instance state between parent and child\n // (e.g. query result caches, connection pools).\n const providerCache = new Map<string, ToolProvider>();\n await initStandalonePlugins(input.plugins ?? [], providerCache);\n return runAgentInternal(def, input, providerCache);\n}\n\nasync function runAgentInternal(\n def: AgentDefinition,\n input: RunAgentInput,\n providerCache: Map<string, ToolProvider>,\n): Promise<RunAgentResult> {\n const adapter = await resolveAdapter(def);\n const messages = normalizeMessages(input.messages, def.instructions);\n const toolIndex = buildStandaloneToolIndex(\n def,\n input.plugins ?? [],\n providerCache,\n );\n // Hosted-supervisor entries are routed via `extensions`, not as callable\n // tools — exclude their placeholder `def` from the wire `tools` array.\n const tools = Array.from(toolIndex.values())\n .filter((e) => e.kind !== \"hosted-supervisor\")\n .map((e) => e.def);\n\n warnOnCapabilityMismatch(def.name ?? \"<anonymous>\", adapter, toolIndex);\n\n const signal = input.signal;\n\n const executeTool = async (name: string, args: unknown): Promise<unknown> => {\n const entry = toolIndex.get(name);\n if (!entry) throw new Error(`Unknown tool: ${name}`);\n if (entry.kind === \"function\") {\n return entry.tool.execute(args as Record<string, unknown>);\n }\n if (entry.kind === \"toolkit\") {\n return entry.provider.executeAgentTool(\n entry.localName,\n args as Record<string, unknown>,\n signal,\n );\n }\n if (entry.kind === \"subagent\") {\n const subInput: RunAgentInput = {\n messages:\n typeof args === \"object\" &&\n args !== null &&\n typeof (args as { input?: unknown }).input === \"string\"\n ? (args as { input: string }).input\n : JSON.stringify(args),\n signal,\n plugins: input.plugins,\n };\n // Reuse the same `providerCache` so sub-agent plugin tools dispatch\n // through the same instances the parent constructed.\n const res = await runAgentInternal(\n entry.agentDef,\n subInput,\n providerCache,\n );\n return res.text;\n }\n if (entry.kind === \"hosted-supervisor\") {\n // Defense-in-depth: should never fire. The placeholder def is\n // filtered out of `tools` above, so the model never sees a callable\n // schema for hosted-supervisor entries. If we ever reach here, the\n // model was somehow handed the def and tried to invoke it directly.\n throw new Error(\n `runAgent: tool \"${name}\" is a hosted-supervisor tool, executed server-side by the Databricks AI Gateway. It must not be invoked from the Node process.`,\n );\n }\n throw new Error(\n `runAgent: tool \"${name}\" is a ${entry.kind} tool. ` +\n \"Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).\",\n );\n };\n\n const events: AgentEvent[] = [];\n\n const stream = adapter.run(\n {\n messages,\n tools,\n threadId: randomUUID(),\n signal,\n extensions: buildStandaloneExtensions(toolIndex),\n },\n { executeTool, signal },\n );\n\n // Shared accumulation rule (deltas append, `message` replaces). The\n // `events` array is filled via the `onEvent` side effect so callers that\n // inspect the raw stream still get the full record.\n const text = await consumeAdapterStream(stream, {\n signal,\n onEvent: (event) => {\n events.push(event);\n },\n });\n\n return { text, events };\n}\n\n/**\n * Eagerly construct every plugin in `input.plugins`, run the standard\n * AppKit lifecycle (`attachContext({})` + `await setup()`), and populate\n * `cache`. Failures here surface BEFORE any adapter work — mid-stream\n * `getWorkspaceClient is not initialised`-style errors become a clear\n * startup failure naming the plugin and pointing the user at `createApp`.\n *\n * Plugins that don't need runtime context (no overridden `setup`, or one\n * that doesn't dereference `createApp`-only state) initialise cleanly and\n * standalone runAgent works as documented. Plugins like analytics/files\n * that depend on `WorkspaceClient` will throw the underlying error wrapped\n * with the migration hint.\n */\nasync function initStandalonePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n cache: Map<string, ToolProvider>,\n): Promise<void> {\n for (const data of plugins) {\n if (cache.has(data.name)) continue;\n const instance = new data.plugin({\n ...(data.config ?? {}),\n name: data.name,\n });\n if (!isStandaloneToolProvider(instance)) {\n throw new Error(\n `runAgent: plugin '${data.name}' is not a ToolProvider ` +\n \"(missing getAgentTools/executeAgentTool). Only ToolProvider plugins \" +\n \"are supported in standalone runAgent.\",\n );\n }\n if (\n typeof (instance as { attachContext?: unknown }).attachContext ===\n \"function\"\n ) {\n try {\n (\n instance as { attachContext: (deps: Record<string, unknown>) => void }\n ).attachContext({});\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' attachContext() failed in ` +\n \"standalone mode. This plugin probably depends on createApp's \" +\n \"runtime (WorkspaceClient, ServiceContext, PluginContext). Run \" +\n \"via createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n if (typeof (instance as { setup?: unknown }).setup === \"function\") {\n try {\n await (instance as { setup: () => Promise<void> | void }).setup();\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' setup() failed in standalone ` +\n \"mode. This plugin probably depends on createApp's runtime \" +\n \"(WorkspaceClient, ServiceContext, PluginContext). Run via \" +\n \"createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n cache.set(data.name, instance);\n }\n}\n\nasync function resolveAdapter(def: AgentDefinition): Promise<AgentAdapter> {\n const { model } = def;\n if (!model) {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing();\n }\n if (typeof model === \"string\") {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing(model);\n }\n return await model;\n}\n\nfunction normalizeMessages(\n input: string | Message[],\n instructions: string,\n): Message[] {\n const systemMessage: Message = {\n id: \"system\",\n role: \"system\",\n content: instructions,\n createdAt: new Date(),\n };\n if (typeof input === \"string\") {\n return [\n systemMessage,\n {\n id: randomUUID(),\n role: \"user\",\n content: input,\n createdAt: new Date(),\n },\n ];\n }\n return [systemMessage, ...input];\n}\n\ntype StandaloneEntry =\n | {\n kind: \"function\";\n def: AgentToolDefinition;\n tool: FunctionTool;\n }\n | {\n kind: \"subagent\";\n def: AgentToolDefinition;\n agentDef: AgentDefinition;\n }\n | {\n kind: \"toolkit\";\n def: AgentToolDefinition;\n provider: ToolProvider;\n pluginName: string;\n localName: string;\n }\n | {\n kind: \"hosted\";\n def: AgentToolDefinition;\n }\n | {\n /**\n * Adapter-side hosted tool. Standalone `runAgent` accepts these\n * (unlike MCP hosted tools, which need a live MCP client) because\n * the adapter has everything it needs to execute them server-side:\n * the spec travels via `AgentInput.extensions` and the SA endpoint\n * runs the tool loop. Enables batch-eval / CI use of supervisor\n * agents without `createApp`.\n */\n kind: \"hosted-supervisor\";\n def: AgentToolDefinition;\n spec: SupervisorTool;\n };\n\n/**\n * Resolves `def.tools` (object or function form) and `def.agents`\n * (sub-agents) into a flat dispatch index. The function form is invoked\n * once per call against a {@link Plugins} map drawn from the shared\n * `providerCache` populated by {@link initStandalonePlugins}. Missing\n * references throw a named \"not registered\" error via the proxy.\n */\nfunction buildStandaloneToolIndex(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Map<string, StandaloneEntry> {\n const index = new Map<string, StandaloneEntry>();\n const tools = resolveDefTools(def, plugins, providerCache);\n\n for (const [key, tool] of Object.entries(tools)) {\n index.set(key, classifyTool(key, tool, providerCache));\n }\n\n for (const [childKey, child] of Object.entries(def.agents ?? {})) {\n const toolName = `agent-${childKey}`;\n index.set(toolName, {\n kind: \"subagent\",\n agentDef: { ...child, name: child.name ?? childKey },\n def: {\n name: toolName,\n description:\n child.instructions.slice(0, 120) ||\n `Delegate to the ${childKey} sub-agent`,\n parameters: {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"Message to send to the sub-agent.\",\n },\n },\n required: [\"input\"],\n },\n },\n });\n }\n\n return index;\n}\n\n/**\n * Resolves `def.tools` to a plain record. The function form is invoked\n * with a typed {@link Plugins} map drawn from the pre-populated\n * `providerCache`; each `plugins.foo.toolkit(opts)` lookup hits the cache\n * directly (no construction at toolkit-call time).\n */\nfunction resolveDefTools(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): AgentTools {\n if (typeof def.tools !== \"function\") {\n return def.tools ?? {};\n }\n const pluginsMap = buildStandalonePluginsMap(plugins, providerCache);\n try {\n return def.tools(pluginsMap);\n } catch (err) {\n const name = def.name ?? \"<anonymous>\";\n throw new Error(\n `runAgent: agent '${name}' tools(plugins) callback threw: ${\n err instanceof Error ? err.message : String(err)\n }`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n}\n\n/**\n * Builds the typed {@link Plugins} map passed to the function form of\n * `def.tools` in standalone mode. Reads pre-constructed instances from\n * `providerCache` (populated eagerly by {@link initStandalonePlugins})\n * and wraps the result in a Proxy so unknown plugin names produce a\n * named \"not registered, Available: ...\" error instead of bubbling up a\n * generic `TypeError: Cannot read properties of undefined`.\n */\nfunction buildStandalonePluginsMap(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Plugins {\n const out: Record<string, PluginToolkitProvider> = {};\n for (const data of plugins) {\n const provider = providerCache.get(data.name);\n if (!provider) continue; // initStandalonePlugins should have set this\n out[data.name] = {\n toolkit: (opts) => resolveToolkitFromProvider(data.name, provider, opts),\n };\n }\n return createPluginsProxy(out, \"runAgent: tools(plugins)\");\n}\n\nfunction classifyTool(\n key: string,\n tool: AgentTool,\n providerCache: Map<string, ToolProvider>,\n): StandaloneEntry {\n if (isToolkitEntry(tool)) {\n // Toolkit entries inside the function form's returned record carry the\n // provider name they came from, so we can resolve the provider on\n // demand and dispatch through it. The cache is shared with the\n // pluginsMap path so the same instance is reused.\n const provider = providerCacheLookup(tool.pluginName, providerCache);\n return {\n kind: \"toolkit\",\n provider,\n pluginName: tool.pluginName,\n localName: tool.localName,\n def: { ...tool.def, name: key },\n };\n }\n if (isFunctionTool(tool)) {\n return {\n kind: \"function\",\n tool,\n def: { ...functionToolToDefinition(tool), name: key },\n };\n }\n // Supervisor-API hosted tools work in standalone mode: the adapter\n // executes them server-side via `AgentInput.extensions`, no MCP client\n // required. Must come BEFORE the `isHostedTool` MCP rejection — the two\n // predicates classify disjoint values (`isSupervisorTool` matches the\n // `__kind` tag; `isHostedTool` matches the wire-format `type` field),\n // but the placement makes the intent explicit.\n if (isSupervisorTool(tool)) {\n return {\n kind: \"hosted-supervisor\",\n spec: tool.spec,\n def: {\n name: key,\n description: supervisorToolDescription(tool.spec),\n parameters: { type: \"object\", properties: {} },\n },\n };\n }\n if (isHostedTool(tool)) {\n // Hosted tools (e.g. MCP `mcpServer(...)`) need a live MCP client that\n // only exists inside the agents plugin's lifecycle. In standalone\n // `runAgent` they would have errored at dispatch time with a confusing\n // mid-conversation failure; reject them up front so misconfiguration\n // surfaces before the adapter sees the tool list.\n throw new Error(\n `runAgent: tool \"${key}\" is a hosted tool (type=\"${tool.type}\") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`,\n );\n }\n throw new Error(`runAgent: unrecognized tool shape at key \"${key}\"`);\n}\n\n/** Mirrors `agents.ts`'s `supervisorToolDescription`. */\nfunction supervisorToolDescription(spec: SupervisorTool): string {\n switch (spec.type) {\n case \"genie_space\":\n return spec.genie_space.description;\n case \"uc_function\":\n return spec.uc_function.description;\n case \"knowledge_assistant\":\n return spec.knowledge_assistant.description;\n case \"app\":\n return spec.app.description;\n case \"uc_connection\":\n return spec.uc_connection.description;\n }\n}\n\n/** Mirrors `agents.ts`'s `buildAdapterExtensions`. */\nfunction buildStandaloneExtensions(\n toolIndex: Map<string, StandaloneEntry>,\n): Readonly<Record<string, unknown>> | undefined {\n const supervisorSpecs: SupervisorTool[] = [];\n for (const entry of toolIndex.values()) {\n if (entry.kind === \"hosted-supervisor\") {\n supervisorSpecs.push(entry.spec);\n }\n }\n if (supervisorSpecs.length === 0) return undefined;\n return {\n [SUPERVISOR_EXTENSION_KEY]: { hostedTools: supervisorSpecs },\n };\n}\n\n/**\n * Mirrors the agents-plugin capability warning so standalone `runAgent`\n * produces the same diagnostic when adapter capabilities don't match the\n * tool index. Warn-not-throw: doesn't abort batch evals.\n */\nfunction warnOnCapabilityMismatch(\n agentName: string,\n adapter: AgentAdapter,\n toolIndex: Map<string, StandaloneEntry>,\n): void {\n const accepted = new Set(adapter.acceptsExtensions ?? []);\n\n const hostedSupervisorKeys: string[] = [];\n const inputToolKeys: string[] = [];\n for (const [key, entry] of toolIndex) {\n if (entry.kind === \"hosted-supervisor\") {\n hostedSupervisorKeys.push(key);\n } else {\n inputToolKeys.push(key);\n }\n }\n\n if (\n hostedSupervisorKeys.length > 0 &&\n !accepted.has(SUPERVISOR_EXTENSION_KEY)\n ) {\n logger.warn(\n `Agent '${agentName}' declares hosted-supervisor tools (${hostedSupervisorKeys.join(\", \")}) ` +\n \"but its model adapter does not accept the 'databricks.supervisor' extension. \" +\n \"Pair them with `DatabricksAdapter.fromSupervisorApi(...)`, or remove them.\",\n );\n }\n\n if (adapter.consumesInputTools === false && inputToolKeys.length > 0) {\n logger.warn(\n `Agent '${agentName}' declares function tools / sub-agents (${inputToolKeys.join(\", \")}) ` +\n \"but its model adapter does not consume input.tools. These tools will not be exposed to the model.\",\n );\n }\n}\n\nfunction providerCacheLookup(\n pluginName: string,\n cache: Map<string, ToolProvider>,\n): ToolProvider {\n const cached = cache.get(pluginName);\n if (cached) return cached;\n const available = Array.from(cache.keys()).join(\", \") || \"(none)\";\n throw new Error(\n `runAgent: tool refers to plugin '${pluginName}', but no instance was ` +\n \"initialised for that name. Add it to RunAgentInput.plugins, or — if \" +\n \"this came from a hand-rolled ToolkitEntry — go through \" +\n `plugins[name].toolkit() instead. Available: ${available}.`,\n );\n}\n\n/**\n * Lightweight `ToolProvider` shape check used by standalone `runAgent`.\n *\n * Distinct from `core/plugin-context.isToolProvider` which also requires\n * `asUser` (request-scoped, only meaningful when running inside `createApp`\n * with a live HTTP context). Standalone plugins are constructed without a\n * `WorkspaceClient` and have no request to scope to, so checking only the\n * two `ToolProvider` methods is the right narrowing here.\n */\nfunction isStandaloneToolProvider(value: unknown): value is ToolProvider {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.getAgentTools === \"function\" &&\n typeof obj.executeAgentTool === \"function\"\n );\n}\n"],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { AgentAdapter, AgentToolDefinition, ThreadStore, ToolAnnotations } from "../../shared/src/agent.js";
2
2
  import { BasePluginConfig } from "../../shared/src/plugin.js";
3
3
  import "../../shared/src/index.js";
4
+ import { HostedSupervisorTool, SupervisorTool } from "../../agents/supervisor-api.js";
4
5
  import { GenerationParams } from "../../agents/databricks.js";
5
6
  import { McpHostPolicyConfig } from "../../connectors/mcp/host-policy.js";
6
7
  import "../../connectors/mcp/index.js";
@@ -30,10 +31,11 @@ interface ToolkitEntry {
30
31
  }
31
32
  /**
32
33
  * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP
33
- * tools (`mcpServer()` / raw hosted), or toolkit references from plugins
34
- * (`analytics().toolkit()`).
34
+ * tools (`mcpServer()` / raw hosted), toolkit references from plugins
35
+ * (`analytics().toolkit()`), or adapter-hosted Supervisor-API tools
36
+ * (`supervisorTools.*`).
35
37
  */
36
- type AgentTool = FunctionTool | HostedTool | ToolkitEntry;
38
+ type AgentTool = FunctionTool | HostedTool | ToolkitEntry | HostedSupervisorTool;
37
39
  interface ToolkitOptions {
38
40
  /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */
39
41
  prefix?: string;
@@ -286,6 +288,20 @@ type ResolvedToolEntry = {
286
288
  source: "subagent";
287
289
  agentName: string;
288
290
  def: AgentToolDefinition;
291
+ } | {
292
+ /**
293
+ * Adapter-side hosted tool (executed by the model-host, not by the
294
+ * Node process). Today: Supervisor API hosted tools (Genie spaces,
295
+ * UC functions, etc.). The `spec` is opaque to the agents plugin —
296
+ * it routes the entry into `AgentInput.extensions` for the adapter
297
+ * that declared the matching `acceptsExtensions` key. `def` is a
298
+ * synthetic placeholder kept so the index has a uniform shape; it
299
+ * is intentionally NOT included in the `tools` array passed to
300
+ * `adapter.run()` (those entries are not callable functions).
301
+ */
302
+ source: "hosted-supervisor";
303
+ spec: SupervisorTool;
304
+ def: AgentToolDefinition;
289
305
  };
290
306
  interface RegisteredAgent {
291
307
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/agent/types.ts"],"mappings":";;;;;;;;;;;;;;;AAkBA;UAAiB,YAAA;EAAA,SACN,YAAA;EACT,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;EACL,WAAA,GAAc,eAAA;EADd;;;;;;EAQA,eAAA;AAAA;;;;;;KAQU,SAAA,GAAY,YAAA,GAAe,UAAA,GAAa,YAAA;AAAA,UAEnC,cAAA;EAFO;EAItB,MAAA;EAJkD;EAMlD,IAAA;EAN8D;EAQ9D,MAAA;EAN6B;EAQ7B,MAAA,GAAS,MAAA;AAAA;;;;;;;;UAUM,qBAAA;EACf,OAAA,CAAQ,IAAA,GAAO,cAAA,GAAiB,MAAA,SAAe,YAAA;AAAA;;;;;;;;;;;;;AA2BjD;;;;;AAKA;;;;;;;KALY,OAAA,GAAU,MAAA,SAAe,qBAAA;;AAWrC;;UANiB,aAAA;EACf,SAAA;EACA,WAAA;EACA,SAAA;AAAA;AAAA,KAGU,sBAAA,sBAGN,GAAA,EAAK,aAAA;;;AAiBX;;KAXY,UAAA,GAAa,MAAA,SAAe,SAAA;;;;;;;AAaxC;;;KAFY,YAAA,IAAgB,OAAA,EAAS,OAAA,KAAY,UAAA;AAAA,UAEhC,eAAA;EA2BQ;;;;;;;;;;;;;;;;;;EARvB,IAAA;EAsBS;EApBT,YAAA;EAsBA;;;;;EAhBA,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA;EAmC/B;;;AAcF;;;;;AAOA;;;EA5CE,KAAA,GAAQ,UAAA,GAAa,YAAA;EAgDZ;EA9CT,MAAA,GAAS,MAAA,SAAe,eAAA;EAkDc;EAhDtC,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;EAkD6B;;;;;;;EA1C7B,gBAAA,GAAmB,gBAAA;EAgCnB;;;;;;;;EAvBA,SAAA;AAAA;;;;;;;;;;;;UAce,sBAAA;EAgDb;EA9CF,IAAA;EA8DE;EA5DF,IAAA;AAAA;AAAA,UAGe,kBAAA,SAA2B,gBAAA;EAkFvB;EAhFnB,GAAA;EAqFU;EAnFV,MAAA,GAAS,MAAA,SAAe,eAAA;;EAExB,YAAA;EA0FkB;EAxFlB,YAAA,GAAe,YAAA,GAAe,OAAA,CAAQ,YAAA;EA8F7B;EA5FT,KAAA,GAAQ,MAAA,SAAe,SAAA;EAiGK;EA/F5B,gBAAA,aAA6B,sBAAA;EA6EzB;EA3EJ,WAAA,GAAc,WAAA;EA6EV;EA3EJ,gBAAA,GAAmB,sBAAA;EA4EV;;;;;;EArET,GAAA,GAAM,mBAAA;EA8EF;;;;;;;;;EApEJ,QAAA;IA6E8B;;;;;IAvE5B,qBAAA,YAgFiB;IA9EjB,SAAA;EAAA;EAsEF;;;;;;;;EA5DA,MAAA;IAiEA;;;;;IA3DE,2BAAA;IAgEO;AAOX;;;;IAjEI,YAAA;IAiE4C;;;;;IA3D5C,gBAAA;;;;;;;;;;;;;IAaA,iBAAA;EAAA;AAAA;;KAKQ,iBAAA;EAEN,MAAA;EACA,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,YAAA,EAAc,YAAA;EACd,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,WAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;AAAA,UAGM,eAAA;EACf,IAAA;EACA,YAAA;EACA,OAAA,EAAS,YAAA;EACT,SAAA,EAAW,GAAA,SAAY,iBAAA;EACvB,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;;EAEA,gBAAA,GAAmB,gBAAA;;EAEnB,SAAA;AAAA;;;;;iBAOc,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA"}
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/agent/types.ts"],"mappings":";;;;;;;;;;;;;;;;;UAkBiB,YAAA;EAAA,SACN,YAAA;EACT,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;EACL,WAAA,GAAc,eAAA;EAFd;;;;;;EASA,eAAA;AAAA;AASF;;;;;;AAAA,KAAY,SAAA,GACR,YAAA,GACA,UAAA,GACA,YAAA,GAAY,oBAAA;AAAA,UAGC,cAAA;EAF6C;EAI5D,MAAA;EANE;EAQF,IAAA;EAPc;EASd,MAAA;EATc;EAWd,MAAA,GAAS,MAAA;AAAA;;;;;;;;UAUM,qBAAA;EACf,OAAA,CAAQ,IAAA,GAAO,cAAA,GAAiB,MAAA,SAAe,YAAA;AAAA;;;;;;;;;;;;;;;AA2BjD;;;;;AAKA;;;;;KALY,OAAA,GAAU,MAAA,SAAe,qBAAA;;;;UAKpB,aAAA;EACf,SAAA;EACA,WAAA;EACA,SAAA;AAAA;AAAA,KAGU,sBAAA,sBAGN,GAAA,EAAK,aAAA;;;;;KAMC,UAAA,GAAa,MAAA,SAAe,SAAA;;;;;;;;;AAaxC;KAFY,YAAA,IAAgB,OAAA,EAAS,OAAA,KAAY,UAAA;AAAA,UAEhC,eAAA;EA2BP;;;;;;;;;;;;;;;;;;EARR,IAAA;EAoBqB;EAlBrB,YAAA;EAoBS;;;;;EAdT,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA;EA0B/B;;;;;AAuBF;;;;;AAOA;EA5CE,KAAA,GAAQ,UAAA,GAAa,YAAA;;EAErB,MAAA,GAAS,MAAA,SAAe,eAAA;EA8Cf;EA5CT,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;EAgDuB;;;;;;;EAxCvB,gBAAA,GAAmB,gBAAA;EA8BuC;;;;;;;;EArB1D,SAAA;AAAA;;;;;;;;;;;;UAce,sBAAA;EAwCf;EAtCA,IAAA;EA8CE;EA5CF,IAAA;AAAA;AAAA,UAGe,kBAAA,SAA2B,gBAAA;EAqExC;EAnEF,GAAA;EAgFmB;EA9EnB,MAAA,GAAS,MAAA,SAAe,eAAA;EAmFd;EAjFV,YAAA;;EAEA,YAAA,GAAe,YAAA,GAAe,OAAA,CAAQ,YAAA;EAwFpB;EAtFlB,KAAA,GAAQ,MAAA,SAAe,SAAA;EA4Fd;EA1FT,gBAAA,aAA6B,sBAAA;EA+FD;EA7F5B,WAAA,GAAc,WAAA;EA4Gc;EA1G5B,gBAAA,GAAmB,sBAAA;EAyEf;;;;;;EAlEJ,GAAA,GAAM,mBAAA;EAyEY;;;;;;;;;EA/DlB,QAAA;IA0ES;;;;;IApEP,qBAAA,YAmF0B;IAjF1B,SAAA;EAAA;EAoF4B;;;;;;;;EA1E9B,MAAA;IA2EA;;;;;IArEE,2BAAA;IAwEqB;;;;;IAlErB,YAAA;IAuEiB;;;;AASrB;IA1EI,gBAAA;IA0EqD;;;;;;;;;;;;IA7DrD,iBAAA;EAAA;AAAA;;KAKQ,iBAAA;EAEN,MAAA;EACA,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,YAAA,EAAc,YAAA;EACd,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,WAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;EAaL,MAAA;EACA,IAAA,EAdwB,cAAA;EAexB,GAAA,EAAK,mBAAA;AAAA;AAAA,UAGM,eAAA;EACf,IAAA;EACA,YAAA;EACA,OAAA,EAAS,YAAA;EACT,SAAA,EAAW,GAAA,SAAY,iBAAA;EACvB,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;;EAEA,gBAAA,GAAmB,gBAAA;;EAEnB,SAAA;AAAA;;;;;iBAOc,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\nimport type { GenerationParams } from \"../../agents/databricks\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { FunctionTool } from \"./tools/function-tool\";\nimport type { HostedTool } from \"./tools/hosted-tools\";\n\n/**\n * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin\n * recognizes the `__toolkitRef` brand and dispatches tool invocations through\n * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving\n * OBO (asUser) and telemetry spans.\n */\nexport interface ToolkitEntry {\n readonly __toolkitRef: true;\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors\n * {@link ToolEntry.autoInheritable} from the source registry so the agents\n * plugin can filter auto-inherited tools without re-walking the provider's\n * internal registry.\n */\n autoInheritable?: boolean;\n}\n\n/**\n * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP\n * tools (`mcpServer()` / raw hosted), or toolkit references from plugins\n * (`analytics().toolkit()`).\n */\nexport type AgentTool = FunctionTool | HostedTool | ToolkitEntry;\n\nexport interface ToolkitOptions {\n /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */\n prefix?: string;\n /** Only include tools whose local name matches one of these. */\n only?: string[];\n /** Exclude tools whose local name matches one of these. */\n except?: string[];\n /** Remap specific local names to different keys (applied after prefix). */\n rename?: Record<string, string>;\n}\n\n/**\n * Minimum shape every entry in the {@link Plugins} map must expose. Core\n * plugins (analytics, files, genie, lakebase) implement this directly via\n * their `.toolkit()` method. The agents plugin and standalone `runAgent`\n * synthesize this shape for any registered plugin that doesn't implement\n * `.toolkit()` directly (falling back to `getAgentTools()` walking).\n */\nexport interface PluginToolkitProvider {\n toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;\n}\n\n/**\n * Plugin map passed to the function form of {@link AgentDefinition.tools}.\n * Each entry exposes a `.toolkit(opts?)` method that returns a record of\n * {@link ToolkitEntry} markers ready to be spread into a tool record.\n *\n * AppKit does not statically know which plugins the surrounding\n * `createApp` will register, so this is a plain string-keyed record.\n * Refer to plugins by the name used in `createApp({ plugins: [...] })`;\n * unknown names resolve to `undefined` at runtime.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"...\",\n * tools(plugins) {\n * return {\n * get_weather: tool({ ... }),\n * ...plugins.analytics.toolkit(),\n * ...plugins.files.toolkit({ only: [\"uploads.read\"] }),\n * };\n * },\n * });\n * ```\n */\nexport type Plugins = Record<string, PluginToolkitProvider>;\n\n/**\n * Context passed to `baseSystemPrompt` callbacks.\n */\nexport interface PromptContext {\n agentName: string;\n pluginNames: string[];\n toolNames: string[];\n}\n\nexport type BaseSystemPromptOption =\n | false\n | string\n | ((ctx: PromptContext) => string);\n\n/**\n * Per-agent tool record. String keys map to inline tools, toolkit entries,\n * hosted tools, etc.\n */\nexport type AgentTools = Record<string, AgentTool>;\n\n/**\n * Function form of `AgentDefinition.tools`. Receives the typed\n * {@link Plugins} map and returns a tool record. Invoked exactly once at\n * setup (or once per `runAgent` call in standalone mode); the result is\n * cached as the agent's resolved tool record.\n *\n * Use the function form when an agent needs tools from registered plugins.\n * The bare object form is fine when an agent only uses inline tools.\n */\nexport type AgentToolsFn = (plugins: Plugins) => AgentTools;\n\nexport interface AgentDefinition {\n /**\n * Stable identifier for the agent. **Optional and informational** —\n * when the definition is registered via `agents: { foo: def }` (code) or\n * lives at `config/agents/<id>/agent.md` (markdown), the **registry key\n * always wins** and `name` is ignored. The agent will be reachable as\n * `foo` (or `<id>`) regardless of what this field contains.\n *\n * Set `name` when:\n * - Running standalone via `runAgent({ agent: def })`, where there is\n * no enclosing key. The runtime uses it for the agent's slot in\n * error messages and OTel spans.\n * - Building a definition that may be passed to either form and you\n * want a consistent fallback label.\n *\n * Setting `name` to a value that differs from the registry key is\n * harmless but confusing — prefer keeping them aligned or omitting `name`\n * entirely.\n */\n name?: string;\n /** System prompt body. For markdown-loaded agents this is the file body. */\n instructions: string;\n /**\n * Model adapter (or endpoint-name string sugar for\n * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —\n * falls back to the plugin's `defaultModel`.\n */\n model?: AgentAdapter | Promise<AgentAdapter> | string;\n /**\n * Per-agent tool record. Key is the LLM-visible tool-call name.\n *\n * Accepts either a plain record (for agents that only use inline tools)\n * or a function `(plugins) => Record<string, AgentTool>` that receives\n * the typed {@link Plugins} map and returns a tool record (for agents\n * that pull tools from registered plugins).\n *\n * The function is invoked once at agent setup; the result is cached.\n * Don't put per-request logic in there.\n */\n tools?: AgentTools | AgentToolsFn;\n /** Sub-agents, exposed as `agent-<key>` tools on this agent. */\n agents?: Record<string, AgentDefinition>;\n /** Override the plugin's baseSystemPrompt for this agent only. */\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /**\n * Optional generation parameters (`temperature`, `top_p`, `stop`,\n * `frequency_penalty`, `presence_penalty`) forwarded to the OpenAI-compatible\n * serving request body. Only set keys are sent. Applied only when AppKit\n * builds the adapter itself (string or omitted `model`); when you pass a\n * pre-built `AgentAdapter`, configure generation params on it directly.\n */\n generationParams?: GenerationParams;\n /**\n * When true, the thread used for a chat request against this agent is\n * deleted from `ThreadStore` after the stream completes (success or\n * failure). Use for stateless one-shot agents — e.g. autocomplete, where\n * each request is independent and retaining history would both poison\n * future calls and accumulate unbounded state in the default\n * `InMemoryThreadStore`. Defaults to `false`.\n */\n ephemeral?: boolean;\n}\n\n/**\n * Auto-inherit configuration. When enabled for a given agent origin, agents\n * with no explicit `tools:` declaration receive every registered ToolProvider\n * plugin tool whose author marked `autoInheritable: true`. Tools without that\n * flag — destructive, state-mutating, or privilege-sensitive — never spread\n * automatically and must be wired via `tools:` (object or function form in\n * code, `plugin:NAME` entries in markdown frontmatter).\n *\n * Defaults are `false` for both origins (safe-by-default): developers must\n * consciously opt an origin in to any auto-inherit behaviour.\n */\nexport interface AutoInheritToolsConfig {\n /** Default for agents loaded from markdown files. Default: `false`. */\n file?: boolean;\n /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */\n code?: boolean;\n}\n\nexport interface AgentsPluginConfig extends BasePluginConfig {\n /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */\n dir?: string | false;\n /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */\n defaultAgent?: string;\n /** Default model for agents that don't specify their own (in code or frontmatter). */\n defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;\n /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */\n tools?: Record<string, AgentTool>;\n /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */\n autoInheritTools?: boolean | AutoInheritToolsConfig;\n /** Persistent thread store. Default: in-memory. */\n threadStore?: ThreadStore;\n /** Customize or disable the AppKit base system prompt. */\n baseSystemPrompt?: BaseSystemPromptOption;\n /**\n * MCP server host policy. By default only same-origin Databricks workspace\n * URLs may be used as MCP endpoints; custom hosts must be explicitly\n * allowlisted here. Workspace credentials (SP / OBO) are never forwarded\n * to non-workspace hosts.\n */\n mcp?: McpHostPolicyConfig;\n /**\n * Human-in-the-loop approval gate for mutating tool calls. When enabled\n * (the default), the agents plugin emits an `appkit.approval_pending` SSE\n * event before executing any tool whose annotation flags it as mutating —\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean — and waits for a `POST /chat/approve`\n * decision from the same user who initiated the stream. A missing decision\n * after `timeoutMs` auto-denies the call.\n */\n approval?: {\n /**\n * Require human approval for tools that mutate state. Triggered by\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean. Default: `true`.\n */\n requireForDestructive?: boolean;\n /** Milliseconds to wait before auto-denying. Default: 60_000. */\n timeoutMs?: number;\n };\n /**\n * Runtime resource limits applied during agent execution. Defaults are\n * tuned to protect a single-instance deployment from a misbehaving user or\n * a runaway prompt injection; tighten or relax as appropriate for the\n * deployment's scale and trust model. Request-body caps (chat message\n * size, invocations input size / length) are enforced statically by the\n * Zod schemas and are not configurable here.\n */\n limits?: {\n /**\n * Max concurrent chat streams a single user may have open. Subsequent\n * `POST /chat` requests from that user while at-limit are rejected with\n * HTTP 429. Default: `5`.\n */\n maxConcurrentStreamsPerUser?: number;\n /**\n * Max tool invocations per agent run (across the full tool-call graph,\n * including sub-agent invocations). A run that exceeds the budget is\n * aborted with a terminal error event. Default: `50`.\n */\n maxToolCalls?: number;\n /**\n * Max sub-agent recursion depth. Protects against a prompt-injected\n * agent that delegates to a sub-agent which in turn delegates back to\n * itself (directly or transitively). Default: `3`.\n */\n maxSubAgentDepth?: number;\n /**\n * Per-call timeout for tools dispatched through `PluginContext`\n * (toolkit-routed tools — analytics SQL warehouse queries, Genie\n * messages, Lakebase queries). Independent of `maxToolCalls`: the\n * budget caps how many tools fire per run, this caps how long any\n * single tool call may run. The signal handed to plugin tool\n * implementations combines this timeout with the parent stream's\n * abort signal via `AbortSignal.any`. Function and MCP tools have\n * their own timeouts in their respective adapters and ignore this\n * setting. Default: `300_000` (5 minutes) — generous enough for cold\n * SQL Warehouse round-trips and long Genie conversations.\n */\n toolCallTimeoutMs?: number;\n };\n}\n\n/** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */\nexport type ResolvedToolEntry =\n | {\n source: \"toolkit\";\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"function\";\n functionTool: FunctionTool;\n def: AgentToolDefinition;\n }\n | {\n source: \"mcp\";\n mcpToolName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"subagent\";\n agentName: string;\n def: AgentToolDefinition;\n };\n\nexport interface RegisteredAgent {\n name: string;\n instructions: string;\n adapter: AgentAdapter;\n toolIndex: Map<string, ResolvedToolEntry>;\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /** Mirrors `AgentDefinition.generationParams`. */\n generationParams?: GenerationParams;\n /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */\n ephemeral?: boolean;\n}\n\n/**\n * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate\n * toolkit references from inline tools in a mixed `tools` record.\n */\nexport function isToolkitEntry(value: unknown): value is ToolkitEntry {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __toolkitRef?: unknown }).__toolkitRef === true\n );\n}\n"],"mappings":";;;;;AA0UA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\nimport type { GenerationParams } from \"../../agents/databricks\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { FunctionTool } from \"./tools/function-tool\";\nimport type { HostedTool } from \"./tools/hosted-tools\";\n\n/**\n * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin\n * recognizes the `__toolkitRef` brand and dispatches tool invocations through\n * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving\n * OBO (asUser) and telemetry spans.\n */\nexport interface ToolkitEntry {\n readonly __toolkitRef: true;\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors\n * {@link ToolEntry.autoInheritable} from the source registry so the agents\n * plugin can filter auto-inherited tools without re-walking the provider's\n * internal registry.\n */\n autoInheritable?: boolean;\n}\n\n/**\n * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP\n * tools (`mcpServer()` / raw hosted), toolkit references from plugins\n * (`analytics().toolkit()`), or adapter-hosted Supervisor-API tools\n * (`supervisorTools.*`).\n */\nexport type AgentTool =\n | FunctionTool\n | HostedTool\n | ToolkitEntry\n | import(\"../../agents/supervisor-api\").HostedSupervisorTool;\n\nexport interface ToolkitOptions {\n /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */\n prefix?: string;\n /** Only include tools whose local name matches one of these. */\n only?: string[];\n /** Exclude tools whose local name matches one of these. */\n except?: string[];\n /** Remap specific local names to different keys (applied after prefix). */\n rename?: Record<string, string>;\n}\n\n/**\n * Minimum shape every entry in the {@link Plugins} map must expose. Core\n * plugins (analytics, files, genie, lakebase) implement this directly via\n * their `.toolkit()` method. The agents plugin and standalone `runAgent`\n * synthesize this shape for any registered plugin that doesn't implement\n * `.toolkit()` directly (falling back to `getAgentTools()` walking).\n */\nexport interface PluginToolkitProvider {\n toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;\n}\n\n/**\n * Plugin map passed to the function form of {@link AgentDefinition.tools}.\n * Each entry exposes a `.toolkit(opts?)` method that returns a record of\n * {@link ToolkitEntry} markers ready to be spread into a tool record.\n *\n * AppKit does not statically know which plugins the surrounding\n * `createApp` will register, so this is a plain string-keyed record.\n * Refer to plugins by the name used in `createApp({ plugins: [...] })`;\n * unknown names resolve to `undefined` at runtime.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"...\",\n * tools(plugins) {\n * return {\n * get_weather: tool({ ... }),\n * ...plugins.analytics.toolkit(),\n * ...plugins.files.toolkit({ only: [\"uploads.read\"] }),\n * };\n * },\n * });\n * ```\n */\nexport type Plugins = Record<string, PluginToolkitProvider>;\n\n/**\n * Context passed to `baseSystemPrompt` callbacks.\n */\nexport interface PromptContext {\n agentName: string;\n pluginNames: string[];\n toolNames: string[];\n}\n\nexport type BaseSystemPromptOption =\n | false\n | string\n | ((ctx: PromptContext) => string);\n\n/**\n * Per-agent tool record. String keys map to inline tools, toolkit entries,\n * hosted tools, etc.\n */\nexport type AgentTools = Record<string, AgentTool>;\n\n/**\n * Function form of `AgentDefinition.tools`. Receives the typed\n * {@link Plugins} map and returns a tool record. Invoked exactly once at\n * setup (or once per `runAgent` call in standalone mode); the result is\n * cached as the agent's resolved tool record.\n *\n * Use the function form when an agent needs tools from registered plugins.\n * The bare object form is fine when an agent only uses inline tools.\n */\nexport type AgentToolsFn = (plugins: Plugins) => AgentTools;\n\nexport interface AgentDefinition {\n /**\n * Stable identifier for the agent. **Optional and informational** —\n * when the definition is registered via `agents: { foo: def }` (code) or\n * lives at `config/agents/<id>/agent.md` (markdown), the **registry key\n * always wins** and `name` is ignored. The agent will be reachable as\n * `foo` (or `<id>`) regardless of what this field contains.\n *\n * Set `name` when:\n * - Running standalone via `runAgent({ agent: def })`, where there is\n * no enclosing key. The runtime uses it for the agent's slot in\n * error messages and OTel spans.\n * - Building a definition that may be passed to either form and you\n * want a consistent fallback label.\n *\n * Setting `name` to a value that differs from the registry key is\n * harmless but confusing — prefer keeping them aligned or omitting `name`\n * entirely.\n */\n name?: string;\n /** System prompt body. For markdown-loaded agents this is the file body. */\n instructions: string;\n /**\n * Model adapter (or endpoint-name string sugar for\n * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —\n * falls back to the plugin's `defaultModel`.\n */\n model?: AgentAdapter | Promise<AgentAdapter> | string;\n /**\n * Per-agent tool record. Key is the LLM-visible tool-call name.\n *\n * Accepts either a plain record (for agents that only use inline tools)\n * or a function `(plugins) => Record<string, AgentTool>` that receives\n * the typed {@link Plugins} map and returns a tool record (for agents\n * that pull tools from registered plugins).\n *\n * The function is invoked once at agent setup; the result is cached.\n * Don't put per-request logic in there.\n */\n tools?: AgentTools | AgentToolsFn;\n /** Sub-agents, exposed as `agent-<key>` tools on this agent. */\n agents?: Record<string, AgentDefinition>;\n /** Override the plugin's baseSystemPrompt for this agent only. */\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /**\n * Optional generation parameters (`temperature`, `top_p`, `stop`,\n * `frequency_penalty`, `presence_penalty`) forwarded to the OpenAI-compatible\n * serving request body. Only set keys are sent. Applied only when AppKit\n * builds the adapter itself (string or omitted `model`); when you pass a\n * pre-built `AgentAdapter`, configure generation params on it directly.\n */\n generationParams?: GenerationParams;\n /**\n * When true, the thread used for a chat request against this agent is\n * deleted from `ThreadStore` after the stream completes (success or\n * failure). Use for stateless one-shot agents — e.g. autocomplete, where\n * each request is independent and retaining history would both poison\n * future calls and accumulate unbounded state in the default\n * `InMemoryThreadStore`. Defaults to `false`.\n */\n ephemeral?: boolean;\n}\n\n/**\n * Auto-inherit configuration. When enabled for a given agent origin, agents\n * with no explicit `tools:` declaration receive every registered ToolProvider\n * plugin tool whose author marked `autoInheritable: true`. Tools without that\n * flag — destructive, state-mutating, or privilege-sensitive — never spread\n * automatically and must be wired via `tools:` (object or function form in\n * code, `plugin:NAME` entries in markdown frontmatter).\n *\n * Defaults are `false` for both origins (safe-by-default): developers must\n * consciously opt an origin in to any auto-inherit behaviour.\n */\nexport interface AutoInheritToolsConfig {\n /** Default for agents loaded from markdown files. Default: `false`. */\n file?: boolean;\n /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */\n code?: boolean;\n}\n\nexport interface AgentsPluginConfig extends BasePluginConfig {\n /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */\n dir?: string | false;\n /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */\n defaultAgent?: string;\n /** Default model for agents that don't specify their own (in code or frontmatter). */\n defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;\n /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */\n tools?: Record<string, AgentTool>;\n /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */\n autoInheritTools?: boolean | AutoInheritToolsConfig;\n /** Persistent thread store. Default: in-memory. */\n threadStore?: ThreadStore;\n /** Customize or disable the AppKit base system prompt. */\n baseSystemPrompt?: BaseSystemPromptOption;\n /**\n * MCP server host policy. By default only same-origin Databricks workspace\n * URLs may be used as MCP endpoints; custom hosts must be explicitly\n * allowlisted here. Workspace credentials (SP / OBO) are never forwarded\n * to non-workspace hosts.\n */\n mcp?: McpHostPolicyConfig;\n /**\n * Human-in-the-loop approval gate for mutating tool calls. When enabled\n * (the default), the agents plugin emits an `appkit.approval_pending` SSE\n * event before executing any tool whose annotation flags it as mutating —\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean — and waits for a `POST /chat/approve`\n * decision from the same user who initiated the stream. A missing decision\n * after `timeoutMs` auto-denies the call.\n */\n approval?: {\n /**\n * Require human approval for tools that mutate state. Triggered by\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean. Default: `true`.\n */\n requireForDestructive?: boolean;\n /** Milliseconds to wait before auto-denying. Default: 60_000. */\n timeoutMs?: number;\n };\n /**\n * Runtime resource limits applied during agent execution. Defaults are\n * tuned to protect a single-instance deployment from a misbehaving user or\n * a runaway prompt injection; tighten or relax as appropriate for the\n * deployment's scale and trust model. Request-body caps (chat message\n * size, invocations input size / length) are enforced statically by the\n * Zod schemas and are not configurable here.\n */\n limits?: {\n /**\n * Max concurrent chat streams a single user may have open. Subsequent\n * `POST /chat` requests from that user while at-limit are rejected with\n * HTTP 429. Default: `5`.\n */\n maxConcurrentStreamsPerUser?: number;\n /**\n * Max tool invocations per agent run (across the full tool-call graph,\n * including sub-agent invocations). A run that exceeds the budget is\n * aborted with a terminal error event. Default: `50`.\n */\n maxToolCalls?: number;\n /**\n * Max sub-agent recursion depth. Protects against a prompt-injected\n * agent that delegates to a sub-agent which in turn delegates back to\n * itself (directly or transitively). Default: `3`.\n */\n maxSubAgentDepth?: number;\n /**\n * Per-call timeout for tools dispatched through `PluginContext`\n * (toolkit-routed tools — analytics SQL warehouse queries, Genie\n * messages, Lakebase queries). Independent of `maxToolCalls`: the\n * budget caps how many tools fire per run, this caps how long any\n * single tool call may run. The signal handed to plugin tool\n * implementations combines this timeout with the parent stream's\n * abort signal via `AbortSignal.any`. Function and MCP tools have\n * their own timeouts in their respective adapters and ignore this\n * setting. Default: `300_000` (5 minutes) — generous enough for cold\n * SQL Warehouse round-trips and long Genie conversations.\n */\n toolCallTimeoutMs?: number;\n };\n}\n\n/** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */\nexport type ResolvedToolEntry =\n | {\n source: \"toolkit\";\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"function\";\n functionTool: FunctionTool;\n def: AgentToolDefinition;\n }\n | {\n source: \"mcp\";\n mcpToolName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"subagent\";\n agentName: string;\n def: AgentToolDefinition;\n }\n | {\n /**\n * Adapter-side hosted tool (executed by the model-host, not by the\n * Node process). Today: Supervisor API hosted tools (Genie spaces,\n * UC functions, etc.). The `spec` is opaque to the agents plugin —\n * it routes the entry into `AgentInput.extensions` for the adapter\n * that declared the matching `acceptsExtensions` key. `def` is a\n * synthetic placeholder kept so the index has a uniform shape; it\n * is intentionally NOT included in the `tools` array passed to\n * `adapter.run()` (those entries are not callable functions).\n */\n source: \"hosted-supervisor\";\n spec: import(\"../../agents/supervisor-api\").SupervisorTool;\n def: AgentToolDefinition;\n };\n\nexport interface RegisteredAgent {\n name: string;\n instructions: string;\n adapter: AgentAdapter;\n toolIndex: Map<string, ResolvedToolEntry>;\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /** Mirrors `AgentDefinition.generationParams`. */\n generationParams?: GenerationParams;\n /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */\n ephemeral?: boolean;\n}\n\n/**\n * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate\n * toolkit references from inline tools in a mixed `tools` record.\n */\nexport function isToolkitEntry(value: unknown): value is ToolkitEntry {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __toolkitRef?: unknown }).__toolkitRef === true\n );\n}\n"],"mappings":";;;;;AA8VA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;cAiIa,YAAA,SAAqB,MAAA,YAAkB,YAAA;EAAA,OAC3C,QAAA,EAAuB,cAAA;EAAA,OACvB,KAAA,EAAO,WAAA;EAAA,UAEI,MAAA,EAAQ,kBAAA;EAAA,QAElB,MAAA;EAAA,QACA,gBAAA;EAAA,QACA,aAAA;EARgB;;;;;;EAAA,QAkBhB,gBAAA;EAAA,QACA,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEI,MAAA,EAAQ,kBAAA;EA4qBJ;;;;;;;;;;EAAA,QA7oBR,oBAAA;EAAA,YAKI,sBAAA,CAAA;EA3DoB;EAAA,YAqFpB,cAAA,CAAA;EApFL;EAAA,QAuGC,gBAAA;EAtGD;;;;;;EAAA,QAgHC,WAAA;EAhGA;;;;;EAAA,QAiHA,aAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAzFH;;;;;;EAuGF,MAAA,CAAA,GAAU,OAAA;EAdL;;;;;EAAA,QAwCG,kBAAA;EAAA,QAmEN,iBAAA;EAAA,QAMM,mBAAA;EAkEA;;;;;;EAAA,QAxCN,mBAAA;EAAA,QAmBM,oBAAA;EAAA,QAqBA,cAAA;EAyTY;;;;;EAAA,QA7QZ,cAAA;EAqVE;;;;;;;;;;;EAAA,QArPR,eAAA;EAmhCM;;;;;;;;;;;;EAAA,QAv/BN,eAAA;EAAA,QAkBM,gBAAA;EAAA,QA0DA,kBAAA;EAiEd,aAAA,CAAA,GAAiB,mBAAA;EAIX,gBAAA,CAAA,GAAoB,OAAA;;;;;;;UAYlB,iBAAA;EAUR,YAAA,CAAa,MAAA,EAAQ,UAAA;EAkDrB,YAAA,CAAA,GAAgB,MAAA;EAAA,QAOF,WAAA;;;;;;;;;;;;UA6EN,gCAAA;;;;;;;;;;;UAuBM,aAAA;EAAA,QAoFA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;UAqLA,qBAAA;;;;;;;;;;;;UA6IA,gBAAA;;;;;;;;;;;;;;;UA6GA,WAAA;EAAA,QA2FA,aAAA;EAAA,QA2BA,cAAA;EAAA,QAuCA,kBAAA;EAAA,QASA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAaN,YAAA;EAAA,QASA,aAAA;EAgBF,QAAA,CAAA,GAAY,OAAA;EAQlB,OAAA,CAAA;6BAE2B,GAAA,EAAO,eAAA,KAAe,OAAA;;2BAG3B,eAAA;;;oCAGS,OAAA,CAAA,MAAA;EAAA;EAAA,QAIjB,iBAAA;AAAA;;;;;;;;;;;;;;;;cA+DH,MAAA,EAAM,QAAA,QAAA,YAAA,EAAA,kBAAA"}
1
+ {"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;cAsIa,YAAA,SAAqB,MAAA,YAAkB,YAAA;EAAA,OAC3C,QAAA,EAAuB,cAAA;EAAA,OACvB,KAAA,EAAO,WAAA;EAAA,UAEI,MAAA,EAAQ,kBAAA;EAAA,QAElB,MAAA;EAAA,QACA,gBAAA;EAAA,QACA,aAAA;EARgB;;;;;;EAAA,QAkBhB,gBAAA;EAAA,QACA,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;cAEI,MAAA,EAAQ,kBAAA;EA8rBJ;;;;;;;;;;EAAA,QA/pBR,oBAAA;EAAA,YAKI,sBAAA,CAAA;EA3DoB;EAAA,YAqFpB,cAAA,CAAA;EApFL;EAAA,QAuGC,gBAAA;EAtGD;;;;;;EAAA,QAgHC,WAAA;EAhGA;;;;;EAAA,QAiHA,aAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAzFH;;;;;;EAuGF,MAAA,CAAA,GAAU,OAAA;EAdL;;;;;EAAA,QAwCG,kBAAA;EAAA,QAmEN,iBAAA;EAAA,QAMM,mBAAA;EAoEA;;;;;;EAAA,QA1CN,mBAAA;EAAA,QAmBM,oBAAA;EAAA,QAuBA,cAAA;EAyUY;;;;;EAAA,QA7RZ,cAAA;EAqWE;;;;;;;;;;;EAAA,QArPR,eAAA;EA6iCM;;;;;;;;;;;;EAAA,QAjhCN,eAAA;EAAA,QAkBM,gBAAA;EAAA,QA0DA,kBAAA;EAiEd,aAAA,CAAA,GAAiB,mBAAA;EAIX,gBAAA,CAAA,GAAoB,OAAA;;;;;;;UAYlB,iBAAA;EAUR,YAAA,CAAa,MAAA,EAAQ,UAAA;EAkDrB,YAAA,CAAA,GAAgB,MAAA;EAAA,QAOF,WAAA;;;;;;;;;;;;UA6EN,gCAAA;;;;;;;;;;;UAuBM,aAAA;EAAA,QAoFA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;UA6LA,qBAAA;;;;;;;;;;;;UA6IA,gBAAA;;;;;;;;;;;;;;;UAyHA,WAAA;EAAA,QAiGA,aAAA;EAAA,QA2BA,cAAA;EAAA,QAuCA,kBAAA;EAAA,QASA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAaN,YAAA;EAAA,QASA,aAAA;EAgBF,QAAA,CAAA,GAAY,OAAA;EAQlB,OAAA,CAAA;6BAE2B,GAAA,EAAO,eAAA,KAAe,OAAA;;2BAG3B,eAAA;;;oCAGS,OAAA,CAAA,MAAA;EAAA;EAAA,QAIjB,iBAAA;AAAA;;;;;;;;;;;;;;;;cAsJH,MAAA,EAAM,QAAA,QAAA,YAAA,EAAA,kBAAA"}
@@ -5,6 +5,7 @@ import "../../plugin/index.js";
5
5
  import { buildMcpHostPolicy } from "../../connectors/mcp/host-policy.js";
6
6
  import { AppKitMcpClient } from "../../connectors/mcp/client.js";
7
7
  import "../../connectors/mcp/index.js";
8
+ import { SUPERVISOR_EXTENSION_KEY, isSupervisorTool } from "../../agents/supervisor-api.js";
8
9
  import { consumeAdapterStream } from "../../core/agent/consume-adapter-stream.js";
9
10
  import { createPluginsProxy } from "../../core/agent/plugins-map.js";
10
11
  import { resolveToolkitFromProvider } from "../../core/agent/toolkit-resolver.js";
@@ -244,6 +245,7 @@ var AgentsPlugin = class extends Plugin {
244
245
  async buildRegisteredAgent(name, def, src) {
245
246
  const adapter = await this.resolveAdapter(def, name);
246
247
  const toolIndex = await this.buildToolIndex(name, def, src);
248
+ warnOnCapabilityMismatch(name, adapter, toolIndex);
247
249
  return {
248
250
  name,
249
251
  instructions: def.instructions,
@@ -332,6 +334,21 @@ var AgentsPlugin = class extends Plugin {
332
334
  });
333
335
  continue;
334
336
  }
337
+ if (isSupervisorTool(tool)) {
338
+ index.set(key, {
339
+ source: "hosted-supervisor",
340
+ spec: tool.spec,
341
+ def: {
342
+ name: key,
343
+ description: supervisorToolDescription(tool.spec),
344
+ parameters: {
345
+ type: "object",
346
+ properties: {}
347
+ }
348
+ }
349
+ });
350
+ continue;
351
+ }
335
352
  if (isHostedTool(tool)) {
336
353
  hostedToCollect.push(tool);
337
354
  continue;
@@ -654,7 +671,7 @@ var AgentsPlugin = class extends Plugin {
654
671
  const signal = abortController.signal;
655
672
  const requestId = randomUUID();
656
673
  this.trackStream(requestId, userId, abortController);
657
- const tools = Array.from(registered.toolIndex.values()).map((e) => e.def);
674
+ const tools = Array.from(registered.toolIndex.values()).filter((e) => e.source !== "hosted-supervisor").map((e) => e.def);
658
675
  const approvalPolicy = this.resolvedApprovalPolicy;
659
676
  const limits = this.resolvedLimits;
660
677
  const outboundEvents = new EventChannel();
@@ -693,7 +710,8 @@ var AgentsPlugin = class extends Plugin {
693
710
  messages: messagesWithSystem,
694
711
  tools,
695
712
  threadId: thread.id,
696
- signal
713
+ signal,
714
+ extensions: buildAdapterExtensions(registered.toolIndex)
697
715
  }, {
698
716
  executeTool,
699
717
  signal
@@ -906,7 +924,7 @@ var AgentsPlugin = class extends Plugin {
906
924
  const childAgent = this.agents.get(entry.agentName);
907
925
  if (!childAgent) throw new Error(`Sub-agent not found: ${entry.agentName}`);
908
926
  result = await this.runSubAgent(runState, childAgent, args, depth + 1);
909
- }
927
+ } else if (entry.source === "hosted-supervisor") throw new Error(`Tool '${name}' is a hosted-supervisor tool and cannot be invoked from the Node process. It is executed server-side by the Databricks AI Gateway and is only reachable when the agent's model is a Supervisor API adapter.`);
910
928
  return normalizeToolResult(result);
911
929
  }
912
930
  /**
@@ -926,7 +944,7 @@ var AgentsPlugin = class extends Plugin {
926
944
  async runSubAgent(runState, child, args, depth) {
927
945
  if (depth > runState.limits.maxSubAgentDepth) throw new Error(`Sub-agent depth exceeded (limit ${runState.limits.maxSubAgentDepth}). Raise agents({ limits: { maxSubAgentDepth } }) or break the delegation cycle.`);
928
946
  const input = typeof args === "object" && args !== null && typeof args.input === "string" ? args.input : JSON.stringify(args);
929
- const childTools = Array.from(child.toolIndex.values()).map((e) => e.def);
947
+ const childTools = Array.from(child.toolIndex.values()).filter((e) => e.source !== "hosted-supervisor").map((e) => e.def);
930
948
  const childExecute = (name, childArgs) => this.dispatchToolCall(runState, child.toolIndex, name, childArgs, depth);
931
949
  const runContext = {
932
950
  executeTool: childExecute,
@@ -952,7 +970,8 @@ var AgentsPlugin = class extends Plugin {
952
970
  messages,
953
971
  tools: childTools,
954
972
  threadId: randomUUID(),
955
- signal: runState.signal
973
+ signal: runState.signal,
974
+ extensions: buildAdapterExtensions(child.toolIndex)
956
975
  }, runContext), {
957
976
  signal: runState.signal,
958
977
  onEvent: (event) => {
@@ -1110,6 +1129,47 @@ function composePromptForAgent(registered, pluginLevel, ctx) {
1110
1129
  return composeSystemPrompt(base, registered.instructions);
1111
1130
  }
1112
1131
  /**
1132
+ * Pulls the LLM-readable description off any {@link SupervisorTool} kind.
1133
+ * Used to populate the synthetic placeholder `def.description` on
1134
+ * hosted-supervisor tool-index entries.
1135
+ */
1136
+ function supervisorToolDescription(spec) {
1137
+ switch (spec.type) {
1138
+ case "genie_space": return spec.genie_space.description;
1139
+ case "uc_function": return spec.uc_function.description;
1140
+ case "knowledge_assistant": return spec.knowledge_assistant.description;
1141
+ case "app": return spec.app.description;
1142
+ case "uc_connection": return spec.uc_connection.description;
1143
+ }
1144
+ }
1145
+ /**
1146
+ * Builds the `AgentInput.extensions` payload from a tool index, aggregating
1147
+ * the hosted-supervisor specs under {@link SUPERVISOR_EXTENSION_KEY}. Returns
1148
+ * `undefined` when there are no adapter-side hosted tools so the field stays
1149
+ * absent on the wire — adapters that don't read extensions never see it.
1150
+ */
1151
+ function buildAdapterExtensions(toolIndex) {
1152
+ const supervisorSpecs = [];
1153
+ for (const entry of toolIndex.values()) if (entry.source === "hosted-supervisor") supervisorSpecs.push(entry.spec);
1154
+ if (supervisorSpecs.length === 0) return void 0;
1155
+ return { [SUPERVISOR_EXTENSION_KEY]: { hostedTools: supervisorSpecs } };
1156
+ }
1157
+ /**
1158
+ * Compares the adapter's declared capabilities against the tool index and
1159
+ * logs a warning when the agent's tool declarations would be silently
1160
+ * dropped at runtime. Warn-not-throw: misconfiguration is loud enough to
1161
+ * notice without taking the whole app down.
1162
+ */
1163
+ function warnOnCapabilityMismatch(agentName, adapter, toolIndex) {
1164
+ const accepted = new Set(adapter.acceptsExtensions ?? []);
1165
+ const hostedSupervisorKeys = [];
1166
+ const inputToolKeys = [];
1167
+ for (const [key, entry] of toolIndex) if (entry.source === "hosted-supervisor") hostedSupervisorKeys.push(key);
1168
+ else inputToolKeys.push(key);
1169
+ if (hostedSupervisorKeys.length > 0 && !accepted.has(SUPERVISOR_EXTENSION_KEY)) logger.warn(`Agent '${agentName}' declares hosted-supervisor tools (${hostedSupervisorKeys.join(", ")}) but its model adapter does not accept the 'databricks.supervisor' extension. These tools will not reach the model. Pair them with \`DatabricksAdapter.fromSupervisorApi(...)\`, or remove them.`);
1170
+ if (adapter.consumesInputTools === false && inputToolKeys.length > 0) logger.warn(`Agent '${agentName}' declares function tools / sub-agents / MCP tools (${inputToolKeys.join(", ")}) but its model adapter does not consume input.tools (Supervisor API owns its own tool loop). These tools will not be exposed to the model. See docs/plugins/agents.md.`);
1171
+ }
1172
+ /**
1113
1173
  * Plugin factory for the agents plugin. Reads `config/agents/*.md` by default,
1114
1174
  * resolves toolkits/tools from registered plugins, exposes `appkit.agents.*`
1115
1175
  * runtime API and mounts `POST /invocations` and `POST /responses` (aliased