@databricks/appkit 0.32.0 → 0.33.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 (153) hide show
  1. package/CLAUDE.md +53 -1
  2. package/NOTICE.md +1 -0
  3. package/dist/agents/databricks.d.ts.map +1 -1
  4. package/dist/agents/databricks.js +8 -3
  5. package/dist/agents/databricks.js.map +1 -1
  6. package/dist/appkit/package.js +1 -1
  7. package/dist/beta.d.ts +5 -3
  8. package/dist/beta.js +3 -1
  9. package/dist/connectors/mcp/client.d.ts +27 -2
  10. package/dist/connectors/mcp/client.d.ts.map +1 -1
  11. package/dist/connectors/mcp/client.js +117 -18
  12. package/dist/connectors/mcp/client.js.map +1 -1
  13. package/dist/connectors/mcp/index.d.ts +1 -1
  14. package/dist/connectors/mcp/types.d.ts +1 -1
  15. package/dist/core/agent/build-toolkit.js +3 -8
  16. package/dist/core/agent/build-toolkit.js.map +1 -1
  17. package/dist/core/agent/load-agents.d.ts +6 -1
  18. package/dist/core/agent/load-agents.d.ts.map +1 -1
  19. package/dist/core/agent/load-agents.js +67 -27
  20. package/dist/core/agent/load-agents.js.map +1 -1
  21. package/dist/core/agent/plugins-map.js +44 -0
  22. package/dist/core/agent/plugins-map.js.map +1 -0
  23. package/dist/core/agent/run-agent.d.ts +31 -7
  24. package/dist/core/agent/run-agent.d.ts.map +1 -1
  25. package/dist/core/agent/run-agent.js +138 -27
  26. package/dist/core/agent/run-agent.js.map +1 -1
  27. package/dist/core/agent/toolkit-options.js +28 -0
  28. package/dist/core/agent/toolkit-options.js.map +1 -0
  29. package/dist/core/agent/toolkit-resolver.js +44 -0
  30. package/dist/core/agent/toolkit-resolver.js.map +1 -0
  31. package/dist/core/agent/tools/define-tool.d.ts +14 -2
  32. package/dist/core/agent/tools/define-tool.d.ts.map +1 -1
  33. package/dist/core/agent/tools/define-tool.js +1 -1
  34. package/dist/core/agent/tools/define-tool.js.map +1 -1
  35. package/dist/core/agent/tools/function-tool.d.ts +13 -2
  36. package/dist/core/agent/tools/function-tool.d.ts.map +1 -1
  37. package/dist/core/agent/tools/function-tool.js +4 -3
  38. package/dist/core/agent/tools/function-tool.js.map +1 -1
  39. package/dist/core/agent/tools/index.d.ts +1 -1
  40. package/dist/core/agent/tools/tool.d.ts +32 -3
  41. package/dist/core/agent/tools/tool.d.ts.map +1 -1
  42. package/dist/core/agent/tools/tool.js +4 -3
  43. package/dist/core/agent/tools/tool.js.map +1 -1
  44. package/dist/core/agent/types.d.ts +95 -10
  45. package/dist/core/agent/types.d.ts.map +1 -1
  46. package/dist/core/agent/types.js.map +1 -1
  47. package/dist/plugin/index.d.ts +1 -1
  48. package/dist/plugin/to-plugin.d.ts +3 -13
  49. package/dist/plugin/to-plugin.d.ts.map +1 -1
  50. package/dist/plugin/to-plugin.js +1 -8
  51. package/dist/plugin/to-plugin.js.map +1 -1
  52. package/dist/plugins/agents/agents.d.ts +184 -2
  53. package/dist/plugins/agents/agents.d.ts.map +1 -0
  54. package/dist/plugins/agents/agents.js +169 -72
  55. package/dist/plugins/agents/agents.js.map +1 -1
  56. package/dist/plugins/agents/index.d.ts +2 -2
  57. package/dist/plugins/agents/index.js +1 -1
  58. package/dist/plugins/agents/manifest.js +4 -5
  59. package/dist/plugins/agents/tool-approval-gate.js.map +1 -1
  60. package/dist/plugins/analytics/analytics.d.ts +3 -4
  61. package/dist/plugins/analytics/analytics.d.ts.map +1 -1
  62. package/dist/plugins/analytics/analytics.js +8 -6
  63. package/dist/plugins/analytics/analytics.js.map +1 -1
  64. package/dist/plugins/analytics/index.js +1 -0
  65. package/dist/plugins/analytics/types.js +15 -0
  66. package/dist/plugins/analytics/types.js.map +1 -0
  67. package/dist/plugins/beta-exports.generated.d.ts +2 -0
  68. package/dist/plugins/beta-exports.generated.js +4 -0
  69. package/dist/plugins/files/plugin.d.ts +1 -2
  70. package/dist/plugins/files/plugin.d.ts.map +1 -1
  71. package/dist/plugins/files/plugin.js +30 -12
  72. package/dist/plugins/files/plugin.js.map +1 -1
  73. package/dist/plugins/genie/genie.d.ts +5 -4
  74. package/dist/plugins/genie/genie.d.ts.map +1 -1
  75. package/dist/plugins/genie/genie.js +22 -8
  76. package/dist/plugins/genie/genie.js.map +1 -1
  77. package/dist/plugins/genie/types.d.ts +10 -2
  78. package/dist/plugins/genie/types.d.ts.map +1 -1
  79. package/dist/plugins/jobs/plugin.d.ts +1 -2
  80. package/dist/plugins/jobs/plugin.d.ts.map +1 -1
  81. package/dist/plugins/lakebase/lakebase.d.ts +1 -2
  82. package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
  83. package/dist/plugins/lakebase/lakebase.js +3 -3
  84. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  85. package/dist/plugins/lakebase/types.d.ts +5 -4
  86. package/dist/plugins/lakebase/types.d.ts.map +1 -1
  87. package/dist/plugins/server/index.d.ts +3 -2
  88. package/dist/plugins/server/index.d.ts.map +1 -1
  89. package/dist/plugins/server/index.js +8 -5
  90. package/dist/plugins/server/index.js.map +1 -1
  91. package/dist/plugins/server/types.d.ts +11 -0
  92. package/dist/plugins/server/types.d.ts.map +1 -1
  93. package/dist/plugins/serving/serving.d.ts +1 -2
  94. package/dist/plugins/serving/serving.d.ts.map +1 -1
  95. package/dist/shared/src/agent.d.ts +16 -4
  96. package/dist/shared/src/agent.d.ts.map +1 -1
  97. package/docs/api/appkit/Class.AppKitMcpClient.md +157 -0
  98. package/docs/api/appkit/Class.DatabricksAdapter.md +151 -0
  99. package/docs/api/appkit/Function.agentIdFromMarkdownPath.md +18 -0
  100. package/docs/api/appkit/Function.createAgent.md +33 -0
  101. package/docs/api/appkit/Function.defineTool.md +26 -0
  102. package/docs/api/appkit/Function.executeFromRegistry.md +25 -0
  103. package/docs/api/appkit/Function.functionToolToDefinition.md +16 -0
  104. package/docs/api/appkit/Function.isFunctionTool.md +16 -0
  105. package/docs/api/appkit/Function.isHostedTool.md +16 -0
  106. package/docs/api/appkit/Function.isToolkitEntry.md +18 -0
  107. package/docs/api/appkit/Function.loadAgentFromFile.md +21 -0
  108. package/docs/api/appkit/Function.loadAgentsFromDir.md +26 -0
  109. package/docs/api/appkit/Function.mcpServer.md +28 -0
  110. package/docs/api/appkit/Function.parseTextToolCalls.md +26 -0
  111. package/docs/api/appkit/Function.resolveHostedTools.md +16 -0
  112. package/docs/api/appkit/Function.runAgent.md +26 -0
  113. package/docs/api/appkit/Function.tool.md +28 -0
  114. package/docs/api/appkit/Function.toolsFromRegistry.md +20 -0
  115. package/docs/api/appkit/Interface.AgentAdapter.md +21 -0
  116. package/docs/api/appkit/Interface.AgentDefinition.md +112 -0
  117. package/docs/api/appkit/Interface.AgentInput.md +37 -0
  118. package/docs/api/appkit/Interface.AgentRunContext.md +32 -0
  119. package/docs/api/appkit/Interface.AgentToolDefinition.md +37 -0
  120. package/docs/api/appkit/Interface.AgentsPluginConfig.md +241 -0
  121. package/docs/api/appkit/Interface.AutoInheritToolsConfig.md +27 -0
  122. package/docs/api/appkit/Interface.BasePluginConfig.md +1 -0
  123. package/docs/api/appkit/Interface.FunctionTool.md +80 -0
  124. package/docs/api/appkit/Interface.McpConnectAllResult.md +38 -0
  125. package/docs/api/appkit/Interface.Message.md +55 -0
  126. package/docs/api/appkit/Interface.PluginToolkitProvider.md +22 -0
  127. package/docs/api/appkit/Interface.PromptContext.md +30 -0
  128. package/docs/api/appkit/Interface.RegisteredAgent.md +75 -0
  129. package/docs/api/appkit/Interface.RunAgentInput.md +34 -0
  130. package/docs/api/appkit/Interface.RunAgentResult.md +23 -0
  131. package/docs/api/appkit/Interface.Thread.md +46 -0
  132. package/docs/api/appkit/Interface.ThreadStore.md +103 -0
  133. package/docs/api/appkit/Interface.ToolAnnotations.md +56 -0
  134. package/docs/api/appkit/Interface.ToolConfig.md +72 -0
  135. package/docs/api/appkit/Interface.ToolEntry.md +73 -0
  136. package/docs/api/appkit/Interface.ToolProvider.md +38 -0
  137. package/docs/api/appkit/Interface.ToolkitEntry.md +59 -0
  138. package/docs/api/appkit/Interface.ToolkitOptions.md +45 -0
  139. package/docs/api/appkit/TypeAlias.AgentEvent.md +299 -0
  140. package/docs/api/appkit/TypeAlias.AgentTool.md +11 -0
  141. package/docs/api/appkit/TypeAlias.AgentTools.md +8 -0
  142. package/docs/api/appkit/TypeAlias.AgentToolsFn.md +20 -0
  143. package/docs/api/appkit/TypeAlias.BaseSystemPromptOption.md +9 -0
  144. package/docs/api/appkit/TypeAlias.HostedTool.md +10 -0
  145. package/docs/api/appkit/TypeAlias.Plugins.md +26 -0
  146. package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +29 -0
  147. package/docs/api/appkit/TypeAlias.ToolRegistry.md +6 -0
  148. package/docs/api/appkit/Variable.agents.md +19 -0
  149. package/docs/api/appkit.md +113 -62
  150. package/docs/plugins/agents.md +441 -0
  151. package/llms.txt +53 -1
  152. package/package.json +1 -1
  153. package/sbom.cdx.json +1 -1
@@ -0,0 +1,44 @@
1
+ //#region src/core/agent/plugins-map.ts
2
+ /**
3
+ * Wrap a plain `Record<string, PluginToolkitProvider>` so that accessing an
4
+ * unknown plugin name throws with a named, actionable error instead of the
5
+ * default `TypeError: Cannot read properties of undefined (reading 'toolkit')`
6
+ * that surfaces from chained access on a missing key.
7
+ *
8
+ * The {@link Plugins} type is a `Record<string, PluginToolkitProvider>`
9
+ * without `noUncheckedIndexedAccess` workspace-wide, so unknown keys type as
10
+ * present at compile time but resolve to `undefined` at runtime. The proxy
11
+ * closes that gap with a runtime error that names the missing plugin and
12
+ * lists what's available — same shape as the agents plugin's pre-existing
13
+ * "plugin is not registered" errors.
14
+ *
15
+ * @param entries - the resolved plugin map; the proxy serves these directly
16
+ * for known keys and throws for any other string key.
17
+ * @param contextLabel - prefix included in the error message; differentiates
18
+ * the runtime context (e.g. `"runAgent: tools(plugins)"` vs
19
+ * `"AgentsPlugin: tools(plugins)"`) so users know which path to debug.
20
+ */
21
+ function createPluginsProxy(entries, contextLabel) {
22
+ return new Proxy(entries, {
23
+ get(target, prop, receiver) {
24
+ if (typeof prop !== "string") return Reflect.get(target, prop, receiver);
25
+ if (prop in target) return Reflect.get(target, prop, receiver);
26
+ if (prop === "then" || prop === "toJSON" || prop === "constructor" || prop === "toString" || prop === "valueOf") return;
27
+ const available = Object.keys(target).join(", ") || "(none)";
28
+ throw new Error(`${contextLabel} referenced plugin '${prop}', but it is not registered. Available: ${available}.`);
29
+ },
30
+ has(target, prop) {
31
+ return Reflect.has(target, prop);
32
+ },
33
+ ownKeys(target) {
34
+ return Reflect.ownKeys(target);
35
+ },
36
+ getOwnPropertyDescriptor(target, prop) {
37
+ return Reflect.getOwnPropertyDescriptor(target, prop);
38
+ }
39
+ });
40
+ }
41
+
42
+ //#endregion
43
+ export { createPluginsProxy };
44
+ //# sourceMappingURL=plugins-map.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugins-map.js","names":[],"sources":["../../../src/core/agent/plugins-map.ts"],"sourcesContent":["import type { Plugins, PluginToolkitProvider } from \"./types\";\n\n/**\n * Wrap a plain `Record<string, PluginToolkitProvider>` so that accessing an\n * unknown plugin name throws with a named, actionable error instead of the\n * default `TypeError: Cannot read properties of undefined (reading 'toolkit')`\n * that surfaces from chained access on a missing key.\n *\n * The {@link Plugins} type is a `Record<string, PluginToolkitProvider>`\n * without `noUncheckedIndexedAccess` workspace-wide, so unknown keys type as\n * present at compile time but resolve to `undefined` at runtime. The proxy\n * closes that gap with a runtime error that names the missing plugin and\n * lists what's available — same shape as the agents plugin's pre-existing\n * \"plugin is not registered\" errors.\n *\n * @param entries - the resolved plugin map; the proxy serves these directly\n * for known keys and throws for any other string key.\n * @param contextLabel - prefix included in the error message; differentiates\n * the runtime context (e.g. `\"runAgent: tools(plugins)\"` vs\n * `\"AgentsPlugin: tools(plugins)\"`) so users know which path to debug.\n */\nexport function createPluginsProxy(\n entries: Record<string, PluginToolkitProvider>,\n contextLabel: string,\n): Plugins {\n return new Proxy(entries, {\n get(target, prop, receiver) {\n // Symbols and well-known string accessors (e.g. `Symbol.toPrimitive`,\n // `then` checked by Promise.resolve, `toJSON`) must pass through so\n // host code that probes the object doesn't hit the missing-plugin\n // error. Only named string-key access that misses is treated as a\n // user error.\n if (typeof prop !== \"string\") {\n return Reflect.get(target, prop, receiver);\n }\n if (prop in target) {\n return Reflect.get(target, prop, receiver);\n }\n // Probes from runtime tooling (e.g. utility inspection, JSON\n // serialization, async-iterator detection) hit common property names\n // that are clearly not plugin lookups. Pass those through silently.\n if (\n prop === \"then\" ||\n prop === \"toJSON\" ||\n prop === \"constructor\" ||\n prop === \"toString\" ||\n prop === \"valueOf\"\n ) {\n return undefined;\n }\n const available = Object.keys(target).join(\", \") || \"(none)\";\n throw new Error(\n `${contextLabel} referenced plugin '${prop}', but it is not registered. ` +\n `Available: ${available}.`,\n );\n },\n has(target, prop) {\n return Reflect.has(target, prop);\n },\n ownKeys(target) {\n return Reflect.ownKeys(target);\n },\n getOwnPropertyDescriptor(target, prop) {\n return Reflect.getOwnPropertyDescriptor(target, prop);\n },\n }) as Plugins;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,mBACd,SACA,cACS;AACT,QAAO,IAAI,MAAM,SAAS;EACxB,IAAI,QAAQ,MAAM,UAAU;AAM1B,OAAI,OAAO,SAAS,SAClB,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAE5C,OAAI,QAAQ,OACV,QAAO,QAAQ,IAAI,QAAQ,MAAM,SAAS;AAK5C,OACE,SAAS,UACT,SAAS,YACT,SAAS,iBACT,SAAS,cACT,SAAS,UAET;GAEF,MAAM,YAAY,OAAO,KAAK,OAAO,CAAC,KAAK,KAAK,IAAI;AACpD,SAAM,IAAI,MACR,GAAG,aAAa,sBAAsB,KAAK,0CAC3B,UAAU,GAC3B;;EAEH,IAAI,QAAQ,MAAM;AAChB,UAAO,QAAQ,IAAI,QAAQ,KAAK;;EAElC,QAAQ,QAAQ;AACd,UAAO,QAAQ,QAAQ,OAAO;;EAEhC,yBAAyB,QAAQ,MAAM;AACrC,UAAO,QAAQ,yBAAyB,QAAQ,KAAK;;EAExD,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { AgentEvent, Message } from "../../shared/src/agent.js";
2
+ import { PluginConstructor, PluginData } from "../../shared/src/plugin.js";
2
3
  import "../../shared/src/index.js";
3
4
  import { AgentDefinition } from "./types.js";
4
5
 
@@ -8,6 +9,14 @@ interface RunAgentInput {
8
9
  messages: string | Message[];
9
10
  /** Abort signal for cancellation. */
10
11
  signal?: AbortSignal;
12
+ /**
13
+ * Optional plugin list. Required when `def.tools` is the function form
14
+ * `(plugins) => Record<string, AgentTool>` and the function dereferences
15
+ * any plugins. `runAgent` constructs a fresh instance per plugin and
16
+ * dispatches tool calls against it as the service principal (no OBO —
17
+ * there is no HTTP request in standalone mode).
18
+ */
19
+ plugins?: PluginData<PluginConstructor, unknown, string>[];
11
20
  }
12
21
  interface RunAgentResult {
13
22
  /** Aggregated text output from all `message_delta` events. */
@@ -20,13 +29,28 @@ interface RunAgentResult {
20
29
  * inline tools, and drives the adapter's `run()` loop to completion.
21
30
  *
22
31
  * Limitations vs. running through the agents() plugin:
23
- * - No OBO: there is no HTTP request, so plugin tools run as the service
24
- * principal (when they work at all).
25
- * - Plugin tools (`ToolkitEntry`) are not supported they require a live
26
- * `PluginContext` that only exists when registered in a `createApp`
27
- * instance. This function throws a clear error if encountered.
28
- * - Sub-agents (`agents: { ... }` on the def) are executed as nested
29
- * `runAgent` calls with no shared thread state.
32
+ * - **No OBO and no approval gate** — there is no HTTP request, so plugin
33
+ * tools run as the service principal. The agents-plugin approval gate
34
+ * that prompts for human confirmation on `effect: "write" | "update" |
35
+ * "destructive"` tools is also absent. LLM-controlled tool arguments
36
+ * flow straight through to the SP. Treat standalone runAgent as a
37
+ * trusted-prompt environment (CI, batch eval, internal scripts) not
38
+ * as an exposed user-facing surface.
39
+ * - **Hosted tools (MCP) are not supported** — they require a live MCP
40
+ * client that only exists inside the agents plugin's lifecycle.
41
+ * `runAgent` rejects them at index-build time with a clear error.
42
+ * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested
43
+ * `runAgent` calls with no shared thread state. Plugin instances ARE
44
+ * shared across the recursion (same cache as the parent).
45
+ * - **Plugin tools** (used inside the function form via
46
+ * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via
47
+ * `RunAgentInput`. Each plugin in that array is constructed once,
48
+ * `attachContext({})` and `await setup()` are called eagerly, and the
49
+ * resulting instance is shared across the top-level run and all
50
+ * sub-agent recursions. Plugins whose `setup()` requires runtime that
51
+ * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,
52
+ * `PluginContext`) throw at standalone-init time with a clear "use
53
+ * createApp instead" message — not mid-stream.
30
54
  */
31
55
  declare function runAgent(def: AgentDefinition, input: RunAgentInput): Promise<RunAgentResult>;
32
56
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"mappings":";;;;;UAiBiB,aAAA;;EAEf,QAAA,WAAmB,OAAA;EAFJ;EAIf,MAAA,GAAS,WAAA;AAAA;AAAA,UAGM,cAAA;EALf;EAOA,IAAA;EALA;EAOA,MAAA,EAAQ,UAAA;AAAA;;AAJV;;;;;;;;;AAoBA;;;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":";;;;;;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,4 +1,6 @@
1
1
  import { consumeAdapterStream } from "./consume-adapter-stream.js";
2
+ import { createPluginsProxy } from "./plugins-map.js";
3
+ import { resolveToolkitFromProvider } from "./toolkit-resolver.js";
2
4
  import { functionToolToDefinition, isFunctionTool } from "./tools/function-tool.js";
3
5
  import { isHostedTool } from "./tools/hosted-tools.js";
4
6
  import { isToolkitEntry } from "./types.js";
@@ -10,32 +12,54 @@ import { randomUUID } from "node:crypto";
10
12
  * inline tools, and drives the adapter's `run()` loop to completion.
11
13
  *
12
14
  * Limitations vs. running through the agents() plugin:
13
- * - No OBO: there is no HTTP request, so plugin tools run as the service
14
- * principal (when they work at all).
15
- * - Plugin tools (`ToolkitEntry`) are not supported they require a live
16
- * `PluginContext` that only exists when registered in a `createApp`
17
- * instance. This function throws a clear error if encountered.
18
- * - Sub-agents (`agents: { ... }` on the def) are executed as nested
19
- * `runAgent` calls with no shared thread state.
15
+ * - **No OBO and no approval gate** — there is no HTTP request, so plugin
16
+ * tools run as the service principal. The agents-plugin approval gate
17
+ * that prompts for human confirmation on `effect: "write" | "update" |
18
+ * "destructive"` tools is also absent. LLM-controlled tool arguments
19
+ * flow straight through to the SP. Treat standalone runAgent as a
20
+ * trusted-prompt environment (CI, batch eval, internal scripts) not
21
+ * as an exposed user-facing surface.
22
+ * - **Hosted tools (MCP) are not supported** — they require a live MCP
23
+ * client that only exists inside the agents plugin's lifecycle.
24
+ * `runAgent` rejects them at index-build time with a clear error.
25
+ * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested
26
+ * `runAgent` calls with no shared thread state. Plugin instances ARE
27
+ * shared across the recursion (same cache as the parent).
28
+ * - **Plugin tools** (used inside the function form via
29
+ * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via
30
+ * `RunAgentInput`. Each plugin in that array is constructed once,
31
+ * `attachContext({})` and `await setup()` are called eagerly, and the
32
+ * resulting instance is shared across the top-level run and all
33
+ * sub-agent recursions. Plugins whose `setup()` requires runtime that
34
+ * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,
35
+ * `PluginContext`) throw at standalone-init time with a clear "use
36
+ * createApp instead" message — not mid-stream.
20
37
  */
21
38
  async function runAgent(def, input) {
39
+ const providerCache = /* @__PURE__ */ new Map();
40
+ await initStandalonePlugins(input.plugins ?? [], providerCache);
41
+ return runAgentInternal(def, input, providerCache);
42
+ }
43
+ async function runAgentInternal(def, input, providerCache) {
22
44
  const adapter = await resolveAdapter(def);
23
45
  const messages = normalizeMessages(input.messages, def.instructions);
24
- const toolIndex = buildStandaloneToolIndex(def);
46
+ const toolIndex = buildStandaloneToolIndex(def, input.plugins ?? [], providerCache);
25
47
  const tools = Array.from(toolIndex.values()).map((e) => e.def);
26
48
  const signal = input.signal;
27
49
  const executeTool = async (name, args) => {
28
50
  const entry = toolIndex.get(name);
29
51
  if (!entry) throw new Error(`Unknown tool: ${name}`);
30
52
  if (entry.kind === "function") return entry.tool.execute(args);
53
+ if (entry.kind === "toolkit") return entry.provider.executeAgentTool(entry.localName, args, signal);
31
54
  if (entry.kind === "subagent") {
32
55
  const subInput = {
33
56
  messages: typeof args === "object" && args !== null && typeof args.input === "string" ? args.input : JSON.stringify(args),
34
- signal
57
+ signal,
58
+ plugins: input.plugins
35
59
  };
36
- return (await runAgent(entry.agentDef, subInput)).text;
60
+ return (await runAgentInternal(entry.agentDef, subInput, providerCache)).text;
37
61
  }
38
- throw new Error(`runAgent: tool "${name}" is a ${entry.kind} tool. Plugin toolkits and MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).`);
62
+ throw new Error(`runAgent: tool "${name}" is a ${entry.kind} tool. Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).`);
39
63
  };
40
64
  const events = [];
41
65
  return {
@@ -56,6 +80,40 @@ async function runAgent(def, input) {
56
80
  events
57
81
  };
58
82
  }
83
+ /**
84
+ * Eagerly construct every plugin in `input.plugins`, run the standard
85
+ * AppKit lifecycle (`attachContext({})` + `await setup()`), and populate
86
+ * `cache`. Failures here surface BEFORE any adapter work — mid-stream
87
+ * `getWorkspaceClient is not initialised`-style errors become a clear
88
+ * startup failure naming the plugin and pointing the user at `createApp`.
89
+ *
90
+ * Plugins that don't need runtime context (no overridden `setup`, or one
91
+ * that doesn't dereference `createApp`-only state) initialise cleanly and
92
+ * standalone runAgent works as documented. Plugins like analytics/files
93
+ * that depend on `WorkspaceClient` will throw the underlying error wrapped
94
+ * with the migration hint.
95
+ */
96
+ async function initStandalonePlugins(plugins, cache) {
97
+ for (const data of plugins) {
98
+ if (cache.has(data.name)) continue;
99
+ const instance = new data.plugin({
100
+ ...data.config ?? {},
101
+ name: data.name
102
+ });
103
+ if (!isStandaloneToolProvider(instance)) throw new Error(`runAgent: plugin '${data.name}' is not a ToolProvider (missing getAgentTools/executeAgentTool). Only ToolProvider plugins are supported in standalone runAgent.`);
104
+ if (typeof instance.attachContext === "function") try {
105
+ instance.attachContext({});
106
+ } catch (err) {
107
+ throw new Error(`runAgent: plugin '${data.name}' attachContext() failed in standalone mode. This plugin probably depends on createApp's runtime (WorkspaceClient, ServiceContext, PluginContext). Run via createApp({ plugins: [..., agents(...)] }) instead. Cause: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err : void 0 });
108
+ }
109
+ if (typeof instance.setup === "function") try {
110
+ await instance.setup();
111
+ } catch (err) {
112
+ throw new Error(`runAgent: plugin '${data.name}' setup() failed in standalone mode. This plugin probably depends on createApp's runtime (WorkspaceClient, ServiceContext, PluginContext). Run via createApp({ plugins: [..., agents(...)] }) instead. Cause: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err : void 0 });
113
+ }
114
+ cache.set(data.name, instance);
115
+ }
116
+ }
59
117
  async function resolveAdapter(def) {
60
118
  const { model } = def;
61
119
  if (!model) {
@@ -83,9 +141,17 @@ function normalizeMessages(input, instructions) {
83
141
  }];
84
142
  return [systemMessage, ...input];
85
143
  }
86
- function buildStandaloneToolIndex(def) {
144
+ /**
145
+ * Resolves `def.tools` (object or function form) and `def.agents`
146
+ * (sub-agents) into a flat dispatch index. The function form is invoked
147
+ * once per call against a {@link Plugins} map drawn from the shared
148
+ * `providerCache` populated by {@link initStandalonePlugins}. Missing
149
+ * references throw a named "not registered" error via the proxy.
150
+ */
151
+ function buildStandaloneToolIndex(def, plugins, providerCache) {
87
152
  const index = /* @__PURE__ */ new Map();
88
- for (const [key, tool] of Object.entries(def.tools ?? {})) index.set(key, classifyTool(key, tool));
153
+ const tools = resolveDefTools(def, plugins, providerCache);
154
+ for (const [key, tool] of Object.entries(tools)) index.set(key, classifyTool(key, tool, providerCache));
89
155
  for (const [childKey, child] of Object.entries(def.agents ?? {})) {
90
156
  const toolName = `agent-${childKey}`;
91
157
  index.set(toolName, {
@@ -110,14 +176,49 @@ function buildStandaloneToolIndex(def) {
110
176
  }
111
177
  return index;
112
178
  }
113
- function classifyTool(key, tool) {
179
+ /**
180
+ * Resolves `def.tools` to a plain record. The function form is invoked
181
+ * with a typed {@link Plugins} map drawn from the pre-populated
182
+ * `providerCache`; each `plugins.foo.toolkit(opts)` lookup hits the cache
183
+ * directly (no construction at toolkit-call time).
184
+ */
185
+ function resolveDefTools(def, plugins, providerCache) {
186
+ if (typeof def.tools !== "function") return def.tools ?? {};
187
+ const pluginsMap = buildStandalonePluginsMap(plugins, providerCache);
188
+ try {
189
+ return def.tools(pluginsMap);
190
+ } catch (err) {
191
+ const name = def.name ?? "<anonymous>";
192
+ throw new Error(`runAgent: agent '${name}' tools(plugins) callback threw: ${err instanceof Error ? err.message : String(err)}`, { cause: err instanceof Error ? err : void 0 });
193
+ }
194
+ }
195
+ /**
196
+ * Builds the typed {@link Plugins} map passed to the function form of
197
+ * `def.tools` in standalone mode. Reads pre-constructed instances from
198
+ * `providerCache` (populated eagerly by {@link initStandalonePlugins})
199
+ * and wraps the result in a Proxy so unknown plugin names produce a
200
+ * named "not registered, Available: ..." error instead of bubbling up a
201
+ * generic `TypeError: Cannot read properties of undefined`.
202
+ */
203
+ function buildStandalonePluginsMap(plugins, providerCache) {
204
+ const out = {};
205
+ for (const data of plugins) {
206
+ const provider = providerCache.get(data.name);
207
+ if (!provider) continue;
208
+ out[data.name] = { toolkit: (opts) => resolveToolkitFromProvider(data.name, provider, opts) };
209
+ }
210
+ return createPluginsProxy(out, "runAgent: tools(plugins)");
211
+ }
212
+ function classifyTool(key, tool, providerCache) {
114
213
  if (isToolkitEntry(tool)) return {
115
214
  kind: "toolkit",
215
+ provider: providerCacheLookup(tool.pluginName, providerCache),
216
+ pluginName: tool.pluginName,
217
+ localName: tool.localName,
116
218
  def: {
117
219
  ...tool.def,
118
220
  name: key
119
- },
120
- entry: tool
221
+ }
121
222
  };
122
223
  if (isFunctionTool(tool)) return {
123
224
  kind: "function",
@@ -127,19 +228,29 @@ function classifyTool(key, tool) {
127
228
  name: key
128
229
  }
129
230
  };
130
- if (isHostedTool(tool)) return {
131
- kind: "hosted",
132
- def: {
133
- name: key,
134
- description: `Hosted tool: ${tool.type}`,
135
- parameters: {
136
- type: "object",
137
- properties: {}
138
- }
139
- }
140
- };
231
+ 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.`);
141
232
  throw new Error(`runAgent: unrecognized tool shape at key "${key}"`);
142
233
  }
234
+ function providerCacheLookup(pluginName, cache) {
235
+ const cached = cache.get(pluginName);
236
+ if (cached) return cached;
237
+ const available = Array.from(cache.keys()).join(", ") || "(none)";
238
+ throw new Error(`runAgent: tool refers to plugin '${pluginName}', but no instance was initialised for that name. Add it to RunAgentInput.plugins, or — if this came from a hand-rolled ToolkitEntry — go through plugins[name].toolkit() instead. Available: ${available}.`);
239
+ }
240
+ /**
241
+ * Lightweight `ToolProvider` shape check used by standalone `runAgent`.
242
+ *
243
+ * Distinct from `core/plugin-context.isToolProvider` which also requires
244
+ * `asUser` (request-scoped, only meaningful when running inside `createApp`
245
+ * with a live HTTP context). Standalone plugins are constructed without a
246
+ * `WorkspaceClient` and have no request to scope to, so checking only the
247
+ * two `ToolProvider` methods is the right narrowing here.
248
+ */
249
+ function isStandaloneToolProvider(value) {
250
+ if (typeof value !== "object" || value === null) return false;
251
+ const obj = value;
252
+ return typeof obj.getAgentTools === "function" && typeof obj.executeAgentTool === "function";
253
+ }
143
254
 
144
255
  //#endregion
145
256
  export { runAgent };
@@ -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} from \"shared\";\nimport { consumeAdapterStream } from \"./consume-adapter-stream\";\nimport {\n type FunctionTool,\n functionToolToDefinition,\n isFunctionTool,\n} from \"./tools/function-tool\";\nimport { isHostedTool } from \"./tools/hosted-tools\";\nimport type { AgentDefinition, AgentTool, ToolkitEntry } 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\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: there is no HTTP request, so plugin tools run as the service\n * principal (when they work at all).\n * - Plugin tools (`ToolkitEntry`) are not supported — they require a live\n * `PluginContext` that only exists when registered in a `createApp`\n * instance. This function throws a clear error if encountered.\n * - Sub-agents (`agents: { ... }` on the def) are executed as nested\n * `runAgent` calls with no shared thread state.\n */\nexport async function runAgent(\n def: AgentDefinition,\n input: RunAgentInput,\n): Promise<RunAgentResult> {\n const adapter = await resolveAdapter(def);\n const messages = normalizeMessages(input.messages, def.instructions);\n const toolIndex = buildStandaloneToolIndex(def);\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 === \"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 };\n const res = await runAgent(entry.agentDef, subInput);\n return res.text;\n }\n throw new Error(\n `runAgent: tool \"${name}\" is a ${entry.kind} tool. ` +\n \"Plugin toolkits and 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\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 entry: ToolkitEntry;\n }\n | {\n kind: \"hosted\";\n def: AgentToolDefinition;\n };\n\nfunction buildStandaloneToolIndex(\n def: AgentDefinition,\n): Map<string, StandaloneEntry> {\n const index = new Map<string, StandaloneEntry>();\n\n for (const [key, tool] of Object.entries(def.tools ?? {})) {\n index.set(key, classifyTool(key, tool));\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\nfunction classifyTool(key: string, tool: AgentTool): StandaloneEntry {\n if (isToolkitEntry(tool)) {\n return { kind: \"toolkit\", def: { ...tool.def, name: key }, entry: tool };\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 return {\n kind: \"hosted\",\n def: {\n name: key,\n description: `Hosted tool: ${tool.type}`,\n parameters: { type: \"object\", properties: {} },\n },\n };\n }\n throw new Error(`runAgent: unrecognized tool shape at key \"${key}\"`);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4CA,eAAsB,SACpB,KACA,OACyB;CACzB,MAAM,UAAU,MAAM,eAAe,IAAI;CACzC,MAAM,WAAW,kBAAkB,MAAM,UAAU,IAAI,aAAa;CACpE,MAAM,YAAY,yBAAyB,IAAI;CAC/C,MAAM,QAAQ,MAAM,KAAK,UAAU,QAAQ,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CAE9D,MAAM,SAAS,MAAM;CAErB,MAAM,cAAc,OAAO,MAAc,SAAoC;EAC3E,MAAM,QAAQ,UAAU,IAAI,KAAK;AACjC,MAAI,CAAC,MAAO,OAAM,IAAI,MAAM,iBAAiB,OAAO;AACpD,MAAI,MAAM,SAAS,WACjB,QAAO,MAAM,KAAK,QAAQ,KAAgC;AAE5D,MAAI,MAAM,SAAS,YAAY;GAC7B,MAAM,WAA0B;IAC9B,UACE,OAAO,SAAS,YAChB,SAAS,QACT,OAAQ,KAA6B,UAAU,WAC1C,KAA2B,QAC5B,KAAK,UAAU,KAAK;IAC1B;IACD;AAED,WADY,MAAM,SAAS,MAAM,UAAU,SAAS,EACzC;;AAEb,QAAM,IAAI,MACR,mBAAmB,KAAK,SAAS,MAAM,KAAK,sGAE7C;;CAGH,MAAM,SAAuB,EAAE;AAsB/B,QAAO;EAAE,MAPI,MAAM,qBAbJ,QAAQ,IACrB;GACE;GACA;GACA,UAAU,YAAY;GACtB;GACD,EACD;GAAE;GAAa;GAAQ,CACxB,EAK+C;GAC9C;GACA,UAAU,UAAU;AAClB,WAAO,KAAK,MAAM;;GAErB,CAAC;EAEa;EAAQ;;AAGzB,eAAe,eAAe,KAA6C;CACzE,MAAM,EAAE,UAAU;AAClB,KAAI,CAAC,OAAO;EACV,MAAM,EAAE,sBAAsB,MAAM,OAAO;AAC3C,SAAO,kBAAkB,kBAAkB;;AAE7C,KAAI,OAAO,UAAU,UAAU;EAC7B,MAAM,EAAE,sBAAsB,MAAM,OAAO;AAC3C,SAAO,kBAAkB,iBAAiB,MAAM;;AAElD,QAAO,MAAM;;AAGf,SAAS,kBACP,OACA,cACW;CACX,MAAM,gBAAyB;EAC7B,IAAI;EACJ,MAAM;EACN,SAAS;EACT,2BAAW,IAAI,MAAM;EACtB;AACD,KAAI,OAAO,UAAU,SACnB,QAAO,CACL,eACA;EACE,IAAI,YAAY;EAChB,MAAM;EACN,SAAS;EACT,2BAAW,IAAI,MAAM;EACtB,CACF;AAEH,QAAO,CAAC,eAAe,GAAG,MAAM;;AAwBlC,SAAS,yBACP,KAC8B;CAC9B,MAAM,wBAAQ,IAAI,KAA8B;AAEhD,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,IAAI,SAAS,EAAE,CAAC,CACvD,OAAM,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC;AAGzC,MAAK,MAAM,CAAC,UAAU,UAAU,OAAO,QAAQ,IAAI,UAAU,EAAE,CAAC,EAAE;EAChE,MAAM,WAAW,SAAS;AAC1B,QAAM,IAAI,UAAU;GAClB,MAAM;GACN,UAAU;IAAE,GAAG;IAAO,MAAM,MAAM,QAAQ;IAAU;GACpD,KAAK;IACH,MAAM;IACN,aACE,MAAM,aAAa,MAAM,GAAG,IAAI,IAChC,mBAAmB,SAAS;IAC9B,YAAY;KACV,MAAM;KACN,YAAY,EACV,OAAO;MACL,MAAM;MACN,aAAa;MACd,EACF;KACD,UAAU,CAAC,QAAQ;KACpB;IACF;GACF,CAAC;;AAGJ,QAAO;;AAGT,SAAS,aAAa,KAAa,MAAkC;AACnE,KAAI,eAAe,KAAK,CACtB,QAAO;EAAE,MAAM;EAAW,KAAK;GAAE,GAAG,KAAK;GAAK,MAAM;GAAK;EAAE,OAAO;EAAM;AAE1E,KAAI,eAAe,KAAK,CACtB,QAAO;EACL,MAAM;EACN;EACA,KAAK;GAAE,GAAG,yBAAyB,KAAK;GAAE,MAAM;GAAK;EACtD;AAEH,KAAI,aAAa,KAAK,CACpB,QAAO;EACL,MAAM;EACN,KAAK;GACH,MAAM;GACN,aAAa,gBAAgB,KAAK;GAClC,YAAY;IAAE,MAAM;IAAU,YAAY,EAAE;IAAE;GAC/C;EACF;AAEH,OAAM,IAAI,MAAM,6CAA6C,IAAI,GAAG"}
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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"}
@@ -0,0 +1,28 @@
1
+ //#region src/core/agent/toolkit-options.ts
2
+ /**
3
+ * Filter / prefix / rename a tool's local name into its toolkit key, or
4
+ * skip it entirely. Encapsulates the four-knob `ToolkitOptions` contract:
5
+ *
6
+ * - `only` — allowlist of local names; everything else is dropped.
7
+ * - `except` — denylist of local names.
8
+ * - `prefix` — string prepended to the local name; defaults to
9
+ * `${pluginName}.`. Pass `""` to drop the prefix entirely.
10
+ * - `rename` — per-tool exact remapping; wins over `prefix`.
11
+ *
12
+ * Returns the final key, or `null` when the tool is filtered out.
13
+ *
14
+ * Single source of truth so {@link buildToolkitEntries} (registry path)
15
+ * and {@link resolveToolkitFromProvider} (`getAgentTools()` fallback) stay
16
+ * in lockstep — bug fixes here apply to both.
17
+ */
18
+ function applyToolkitOptions(localName, pluginName, opts = {}) {
19
+ if (opts.only && !opts.only.includes(localName)) return null;
20
+ if (opts.except?.includes(localName)) return null;
21
+ const renamed = opts.rename?.[localName];
22
+ if (typeof renamed === "string" && renamed.length > 0) return renamed;
23
+ return `${opts.prefix ?? `${pluginName}.`}${localName}`;
24
+ }
25
+
26
+ //#endregion
27
+ export { applyToolkitOptions };
28
+ //# sourceMappingURL=toolkit-options.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolkit-options.js","names":[],"sources":["../../../src/core/agent/toolkit-options.ts"],"sourcesContent":["import type { ToolkitOptions } from \"./types\";\n\n/**\n * Filter / prefix / rename a tool's local name into its toolkit key, or\n * skip it entirely. Encapsulates the four-knob `ToolkitOptions` contract:\n *\n * - `only` — allowlist of local names; everything else is dropped.\n * - `except` — denylist of local names.\n * - `prefix` — string prepended to the local name; defaults to\n * `${pluginName}.`. Pass `\"\"` to drop the prefix entirely.\n * - `rename` — per-tool exact remapping; wins over `prefix`.\n *\n * Returns the final key, or `null` when the tool is filtered out.\n *\n * Single source of truth so {@link buildToolkitEntries} (registry path)\n * and {@link resolveToolkitFromProvider} (`getAgentTools()` fallback) stay\n * in lockstep — bug fixes here apply to both.\n */\nexport function applyToolkitOptions(\n localName: string,\n pluginName: string,\n opts: ToolkitOptions = {},\n): string | null {\n // `only`/`except` take precedence: filter first, then derive the key.\n if (opts.only && !opts.only.includes(localName)) return null;\n if (opts.except?.includes(localName)) return null;\n\n // `rename` accepts string overrides; explicit `undefined` (e.g. from a\n // ternary that didn't fire) and empty strings fall through to the prefix\n // path so we never produce a tool keyed literally `\"undefined\"` or `\"\"`.\n const renamed = opts.rename?.[localName];\n if (typeof renamed === \"string\" && renamed.length > 0) return renamed;\n\n const prefix = opts.prefix ?? `${pluginName}.`;\n return `${prefix}${localName}`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAkBA,SAAgB,oBACd,WACA,YACA,OAAuB,EAAE,EACV;AAEf,KAAI,KAAK,QAAQ,CAAC,KAAK,KAAK,SAAS,UAAU,CAAE,QAAO;AACxD,KAAI,KAAK,QAAQ,SAAS,UAAU,CAAE,QAAO;CAK7C,MAAM,UAAU,KAAK,SAAS;AAC9B,KAAI,OAAO,YAAY,YAAY,QAAQ,SAAS,EAAG,QAAO;AAG9D,QAAO,GADQ,KAAK,UAAU,GAAG,WAAW,KACzB"}
@@ -0,0 +1,44 @@
1
+ import { applyToolkitOptions } from "./toolkit-options.js";
2
+
3
+ //#region src/core/agent/toolkit-resolver.ts
4
+ /**
5
+ * Resolve a plugin's tools into a keyed record of {@link ToolkitEntry} markers
6
+ * ready to be merged into an agent's tool index.
7
+ *
8
+ * Preferred path: call the plugin's own `.toolkit(opts)` method, which
9
+ * typically delegates to `buildToolkitEntries` with full `ToolkitOptions`
10
+ * support (prefix, only, except, rename).
11
+ *
12
+ * Fallback path: when the plugin doesn't expose `.toolkit()` (e.g. a
13
+ * third-party `ToolProvider` built with plain `toPlugin`), walk
14
+ * `getAgentTools()` and synthesize namespaced keys (`${pluginName}.${name}`)
15
+ * while still honoring `only` / `except` / `rename` / `prefix`.
16
+ *
17
+ * This helper is the single source of truth for "turn a provider into a
18
+ * toolkit entry record" and is used by `AgentsPlugin.buildToolIndex`
19
+ * (the `tools(plugins)` resolution pass and auto-inherit) and by the
20
+ * standalone `runAgent` executor.
21
+ */
22
+ function resolveToolkitFromProvider(pluginName, provider, opts) {
23
+ const withToolkit = provider;
24
+ if (typeof withToolkit.toolkit === "function") return withToolkit.toolkit(opts);
25
+ const out = {};
26
+ for (const tool of provider.getAgentTools()) {
27
+ const key = applyToolkitOptions(tool.name, pluginName, opts);
28
+ if (key === null) continue;
29
+ out[key] = {
30
+ __toolkitRef: true,
31
+ pluginName,
32
+ localName: tool.name,
33
+ def: {
34
+ ...tool,
35
+ name: key
36
+ }
37
+ };
38
+ }
39
+ return out;
40
+ }
41
+
42
+ //#endregion
43
+ export { resolveToolkitFromProvider };
44
+ //# sourceMappingURL=toolkit-resolver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolkit-resolver.js","names":[],"sources":["../../../src/core/agent/toolkit-resolver.ts"],"sourcesContent":["import type { ToolProvider } from \"shared\";\nimport { applyToolkitOptions } from \"./toolkit-options\";\nimport type { ToolkitEntry, ToolkitOptions } from \"./types\";\n\n/**\n * Internal interface: a `ToolProvider` that optionally exposes a typed\n * `.toolkit(opts)` method. Core plugins (analytics, files, genie, lakebase)\n * implement this; third-party `ToolProvider`s may not.\n */\ntype MaybeToolkitProvider = ToolProvider & {\n toolkit?: (opts?: ToolkitOptions) => Record<string, ToolkitEntry>;\n};\n\n/**\n * Resolve a plugin's tools into a keyed record of {@link ToolkitEntry} markers\n * ready to be merged into an agent's tool index.\n *\n * Preferred path: call the plugin's own `.toolkit(opts)` method, which\n * typically delegates to `buildToolkitEntries` with full `ToolkitOptions`\n * support (prefix, only, except, rename).\n *\n * Fallback path: when the plugin doesn't expose `.toolkit()` (e.g. a\n * third-party `ToolProvider` built with plain `toPlugin`), walk\n * `getAgentTools()` and synthesize namespaced keys (`${pluginName}.${name}`)\n * while still honoring `only` / `except` / `rename` / `prefix`.\n *\n * This helper is the single source of truth for \"turn a provider into a\n * toolkit entry record\" and is used by `AgentsPlugin.buildToolIndex`\n * (the `tools(plugins)` resolution pass and auto-inherit) and by the\n * standalone `runAgent` executor.\n */\nexport function resolveToolkitFromProvider(\n pluginName: string,\n provider: ToolProvider,\n opts?: ToolkitOptions,\n): Record<string, ToolkitEntry> {\n const withToolkit = provider as MaybeToolkitProvider;\n if (typeof withToolkit.toolkit === \"function\") {\n return withToolkit.toolkit(opts);\n }\n\n const out: Record<string, ToolkitEntry> = {};\n for (const tool of provider.getAgentTools()) {\n const key = applyToolkitOptions(tool.name, pluginName, opts);\n if (key === null) continue;\n\n out[key] = {\n __toolkitRef: true,\n pluginName,\n localName: tool.name,\n def: { ...tool, name: key },\n };\n }\n return out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,2BACd,YACA,UACA,MAC8B;CAC9B,MAAM,cAAc;AACpB,KAAI,OAAO,YAAY,YAAY,WACjC,QAAO,YAAY,QAAQ,KAAK;CAGlC,MAAM,MAAoC,EAAE;AAC5C,MAAK,MAAM,QAAQ,SAAS,eAAe,EAAE;EAC3C,MAAM,MAAM,oBAAoB,KAAK,MAAM,YAAY,KAAK;AAC5D,MAAI,QAAQ,KAAM;AAElB,MAAI,OAAO;GACT,cAAc;GACd;GACA,WAAW,KAAK;GAChB,KAAK;IAAE,GAAG;IAAM,MAAM;IAAK;GAC5B;;AAEH,QAAO"}
@@ -20,10 +20,22 @@ interface ToolEntry<S extends z.ZodType = z.ZodType> {
20
20
  * consider it safe enough to appear in every agent's tool record without an
21
21
  * explicit `tools:` declaration. Destructive or privilege-sensitive tools
22
22
  * should leave this unset so that they only reach agents that wire them
23
- * explicitly (via `tools:`, `toolkits:`, or `fromPlugin({ only: [...] })`).
23
+ * explicitly (via `tools:` object/function form, markdown `plugin:NAME`
24
+ * entries in the unified `tools:` list, or
25
+ * `plugins.<name>.toolkit({ only: [...] })`).
24
26
  */
25
27
  autoInheritable?: boolean;
26
- handler: (args: z.infer<S>, signal?: AbortSignal) => unknown | Promise<unknown>;
28
+ /**
29
+ * Callback the agents plugin invokes after Zod validation succeeds.
30
+ *
31
+ * Named `execute` to match the public `tool({ execute })` form — both the
32
+ * agent-author surface and the plugin-author surface now spell their
33
+ * callback the same way. `args` is the inferred Zod output (so `T extends
34
+ * z.ZodType` flows through and `args` is fully typed). `signal` is the
35
+ * per-run AbortSignal: forward it to any awaited I/O so cancellation
36
+ * actually unwinds the call (analytics and lakebase both do this).
37
+ */
38
+ execute: (args: z.infer<S>, signal?: AbortSignal) => unknown | Promise<unknown>;
27
39
  }
28
40
  type ToolRegistry = Record<string, ToolEntry>;
29
41
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"define-tool.d.ts","names":[],"sources":["../../../../src/core/agent/tools/define-tool.ts"],"mappings":";;;;;;;;AAWA;;;UAAiB,SAAA,WAAoB,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,OAAA;EACjD,WAAA;EACA,MAAA,EAAQ,CAAA;EACR,WAAA,GAAc,eAAA;EAYE;;;;;;;;;EAFhB,eAAA;EACA,OAAA,GACE,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,CAAA,GACd,MAAA,GAAS,WAAA,eACI,OAAA;AAAA;AAAA,KAGL,YAAA,GAAe,MAAA,SAAe,SAAA;;;;;;;;iBAS1B,UAAA,WAAqB,CAAA,CAAE,OAAA,CAAA,CACrC,MAAA,EAAQ,SAAA,CAAU,CAAA,IACjB,SAAA,CAAU,CAAA;;;;;;;iBAUS,mBAAA,CACpB,QAAA,EAAU,YAAA,EACV,IAAA,UACA,IAAA,WACA,MAAA,GAAS,WAAA,GACR,OAAA;;;;;AAjBH;;;iBAoCgB,iBAAA,CACd,QAAA,EAAU,YAAA,GACT,mBAAA"}
1
+ {"version":3,"file":"define-tool.d.ts","names":[],"sources":["../../../../src/core/agent/tools/define-tool.ts"],"mappings":";;;;;;;;AAWA;;;UAAiB,SAAA,WAAoB,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,OAAA;EACjD,WAAA;EACA,MAAA,EAAQ,CAAA;EACR,WAAA,GAAc,eAAA;EAwBE;;;;;;;;;;;EAZhB,eAAA;EAbA;;;;;;;;;;EAwBA,OAAA,GACE,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,CAAA,GACd,MAAA,GAAS,WAAA,eACI,OAAA;AAAA;AAAA,KAGL,YAAA,GAAe,MAAA,SAAe,SAAA;;;AAA1C;;;;;iBASgB,UAAA,WAAqB,CAAA,CAAE,OAAA,CAAA,CACrC,MAAA,EAAQ,SAAA,CAAU,CAAA,IACjB,SAAA,CAAU,CAAA;;;;;;;iBAUS,mBAAA,CACpB,QAAA,EAAU,YAAA,EACV,IAAA,UACA,IAAA,WACA,MAAA,GAAS,WAAA,GACR,OAAA;;;;;;;;iBAmBa,iBAAA,CACd,QAAA,EAAU,YAAA,GACT,mBAAA"}
@@ -23,7 +23,7 @@ async function executeFromRegistry(registry, name, args, signal) {
23
23
  if (!entry) throw new Error(`Unknown tool: ${name}`);
24
24
  const parsed = entry.schema.safeParse(args);
25
25
  if (!parsed.success) return formatZodError(parsed.error, name);
26
- return entry.handler(parsed.data, signal);
26
+ return entry.execute(parsed.data, signal);
27
27
  }
28
28
  /**
29
29
  * Produces the `AgentToolDefinition[]` a ToolProvider exposes to the LLM,
@@ -1 +1 @@
1
- {"version":3,"file":"define-tool.js","names":[],"sources":["../../../../src/core/agent/tools/define-tool.ts"],"sourcesContent":["import type { AgentToolDefinition, ToolAnnotations } from \"shared\";\nimport type { z } from \"zod\";\nimport { toToolJSONSchema } from \"./json-schema\";\nimport { formatZodError } from \"./tool\";\n\n/**\n * Single-tool entry for a plugin's internal tool registry.\n *\n * Plugins collect these into a `Record<string, ToolEntry>` keyed by the tool's\n * public name and dispatch via `executeFromRegistry`.\n */\nexport interface ToolEntry<S extends z.ZodType = z.ZodType> {\n description: string;\n schema: S;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for auto-inheritance into markdown or\n * code-defined agents that enable `autoInheritTools`. Defaults to `false`\n * (safe-by-default) — plugin authors must explicitly opt a tool in if they\n * consider it safe enough to appear in every agent's tool record without an\n * explicit `tools:` declaration. Destructive or privilege-sensitive tools\n * should leave this unset so that they only reach agents that wire them\n * explicitly (via `tools:`, `toolkits:`, or `fromPlugin({ only: [...] })`).\n */\n autoInheritable?: boolean;\n handler: (\n args: z.infer<S>,\n signal?: AbortSignal,\n ) => unknown | Promise<unknown>;\n}\n\nexport type ToolRegistry = Record<string, ToolEntry>;\n\n/**\n * Defines a single tool entry for a plugin's internal registry.\n *\n * The generic `S` flows from `schema` through to the `handler` callback so\n * `args` is fully typed from the Zod schema. Names are assigned by the\n * registry key, so they are not repeated inside the entry.\n */\nexport function defineTool<S extends z.ZodType>(\n config: ToolEntry<S>,\n): ToolEntry<S> {\n return config;\n}\n\n/**\n * Validates tool-call arguments against the entry's schema and invokes its\n * handler. On validation failure, returns an LLM-friendly error string\n * (matching the behavior of `tool()`) rather than throwing, so the model\n * can self-correct on its next turn.\n */\nexport async function executeFromRegistry(\n registry: ToolRegistry,\n name: string,\n args: unknown,\n signal?: AbortSignal,\n): Promise<unknown> {\n const entry = registry[name];\n if (!entry) {\n throw new Error(`Unknown tool: ${name}`);\n }\n const parsed = entry.schema.safeParse(args);\n if (!parsed.success) {\n return formatZodError(parsed.error, name);\n }\n return entry.handler(parsed.data, signal);\n}\n\n/**\n * Produces the `AgentToolDefinition[]` a ToolProvider exposes to the LLM,\n * deriving `parameters` JSON Schema from each entry's Zod schema.\n *\n * Tool names come from registry keys (supports dotted names like\n * `uploads.list` for dynamic plugins).\n */\nexport function toolsFromRegistry(\n registry: ToolRegistry,\n): AgentToolDefinition[] {\n return Object.entries(registry).map(([name, entry]) => {\n const parameters = toToolJSONSchema(\n entry.schema,\n ) as unknown as AgentToolDefinition[\"parameters\"];\n const def: AgentToolDefinition = {\n name,\n description: entry.description,\n parameters,\n };\n if (entry.annotations) {\n def.annotations = entry.annotations;\n }\n return def;\n });\n}\n"],"mappings":";;;;;;;;;;;AAwCA,SAAgB,WACd,QACc;AACd,QAAO;;;;;;;;AAST,eAAsB,oBACpB,UACA,MACA,MACA,QACkB;CAClB,MAAM,QAAQ,SAAS;AACvB,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,iBAAiB,OAAO;CAE1C,MAAM,SAAS,MAAM,OAAO,UAAU,KAAK;AAC3C,KAAI,CAAC,OAAO,QACV,QAAO,eAAe,OAAO,OAAO,KAAK;AAE3C,QAAO,MAAM,QAAQ,OAAO,MAAM,OAAO;;;;;;;;;AAU3C,SAAgB,kBACd,UACuB;AACvB,QAAO,OAAO,QAAQ,SAAS,CAAC,KAAK,CAAC,MAAM,WAAW;EACrD,MAAM,aAAa,iBACjB,MAAM,OACP;EACD,MAAM,MAA2B;GAC/B;GACA,aAAa,MAAM;GACnB;GACD;AACD,MAAI,MAAM,YACR,KAAI,cAAc,MAAM;AAE1B,SAAO;GACP"}
1
+ {"version":3,"file":"define-tool.js","names":[],"sources":["../../../../src/core/agent/tools/define-tool.ts"],"sourcesContent":["import type { AgentToolDefinition, ToolAnnotations } from \"shared\";\nimport type { z } from \"zod\";\nimport { toToolJSONSchema } from \"./json-schema\";\nimport { formatZodError } from \"./tool\";\n\n/**\n * Single-tool entry for a plugin's internal tool registry.\n *\n * Plugins collect these into a `Record<string, ToolEntry>` keyed by the tool's\n * public name and dispatch via `executeFromRegistry`.\n */\nexport interface ToolEntry<S extends z.ZodType = z.ZodType> {\n description: string;\n schema: S;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for auto-inheritance into markdown or\n * code-defined agents that enable `autoInheritTools`. Defaults to `false`\n * (safe-by-default) — plugin authors must explicitly opt a tool in if they\n * consider it safe enough to appear in every agent's tool record without an\n * explicit `tools:` declaration. Destructive or privilege-sensitive tools\n * should leave this unset so that they only reach agents that wire them\n * explicitly (via `tools:` object/function form, markdown `plugin:NAME`\n * entries in the unified `tools:` list, or\n * `plugins.<name>.toolkit({ only: [...] })`).\n */\n autoInheritable?: boolean;\n /**\n * Callback the agents plugin invokes after Zod validation succeeds.\n *\n * Named `execute` to match the public `tool({ execute })` form — both the\n * agent-author surface and the plugin-author surface now spell their\n * callback the same way. `args` is the inferred Zod output (so `T extends\n * z.ZodType` flows through and `args` is fully typed). `signal` is the\n * per-run AbortSignal: forward it to any awaited I/O so cancellation\n * actually unwinds the call (analytics and lakebase both do this).\n */\n execute: (\n args: z.infer<S>,\n signal?: AbortSignal,\n ) => unknown | Promise<unknown>;\n}\n\nexport type ToolRegistry = Record<string, ToolEntry>;\n\n/**\n * Defines a single tool entry for a plugin's internal registry.\n *\n * The generic `S` flows from `schema` through to the `handler` callback so\n * `args` is fully typed from the Zod schema. Names are assigned by the\n * registry key, so they are not repeated inside the entry.\n */\nexport function defineTool<S extends z.ZodType>(\n config: ToolEntry<S>,\n): ToolEntry<S> {\n return config;\n}\n\n/**\n * Validates tool-call arguments against the entry's schema and invokes its\n * handler. On validation failure, returns an LLM-friendly error string\n * (matching the behavior of `tool()`) rather than throwing, so the model\n * can self-correct on its next turn.\n */\nexport async function executeFromRegistry(\n registry: ToolRegistry,\n name: string,\n args: unknown,\n signal?: AbortSignal,\n): Promise<unknown> {\n const entry = registry[name];\n if (!entry) {\n throw new Error(`Unknown tool: ${name}`);\n }\n const parsed = entry.schema.safeParse(args);\n if (!parsed.success) {\n return formatZodError(parsed.error, name);\n }\n return entry.execute(parsed.data, signal);\n}\n\n/**\n * Produces the `AgentToolDefinition[]` a ToolProvider exposes to the LLM,\n * deriving `parameters` JSON Schema from each entry's Zod schema.\n *\n * Tool names come from registry keys (supports dotted names like\n * `uploads.list` for dynamic plugins).\n */\nexport function toolsFromRegistry(\n registry: ToolRegistry,\n): AgentToolDefinition[] {\n return Object.entries(registry).map(([name, entry]) => {\n const parameters = toToolJSONSchema(\n entry.schema,\n ) as unknown as AgentToolDefinition[\"parameters\"];\n const def: AgentToolDefinition = {\n name,\n description: entry.description,\n parameters,\n };\n if (entry.annotations) {\n def.annotations = entry.annotations;\n }\n return def;\n });\n}\n"],"mappings":";;;;;;;;;;;AAoDA,SAAgB,WACd,QACc;AACd,QAAO;;;;;;;;AAST,eAAsB,oBACpB,UACA,MACA,MACA,QACkB;CAClB,MAAM,QAAQ,SAAS;AACvB,KAAI,CAAC,MACH,OAAM,IAAI,MAAM,iBAAiB,OAAO;CAE1C,MAAM,SAAS,MAAM,OAAO,UAAU,KAAK;AAC3C,KAAI,CAAC,OAAO,QACV,QAAO,eAAe,OAAO,OAAO,KAAK;AAE3C,QAAO,MAAM,QAAQ,OAAO,MAAM,OAAO;;;;;;;;;AAU3C,SAAgB,kBACd,UACuB;AACvB,QAAO,OAAO,QAAQ,SAAS,CAAC,KAAK,CAAC,MAAM,WAAW;EACrD,MAAM,aAAa,iBACjB,MAAM,OACP;EACD,MAAM,MAA2B;GAC/B;GACA,aAAa,MAAM;GACnB;GACD;AACD,MAAI,MAAM,YACR,KAAI,cAAc,MAAM;AAE1B,SAAO;GACP"}
@@ -4,7 +4,14 @@ import "../../../shared/src/index.js";
4
4
  //#region src/core/agent/tools/function-tool.d.ts
5
5
  interface FunctionTool {
6
6
  type: "function";
7
- name: string;
7
+ /**
8
+ * Optional. When this tool is placed in a keyed record
9
+ * (`tools: { my_tool: ... }` or the function form), the agents plugin
10
+ * overrides this with the record key at index-build time. Only set it
11
+ * explicitly when constructing a `FunctionTool` outside any
12
+ * keyed-record context.
13
+ */
14
+ name?: string;
8
15
  description?: string | null;
9
16
  parameters?: Record<string, unknown> | null;
10
17
  strict?: boolean | null;
@@ -18,7 +25,11 @@ interface FunctionTool {
18
25
  * tool indexes.
19
26
  */
20
27
  annotations?: ToolAnnotations;
21
- execute: (args: Record<string, unknown>) => Promise<string> | string;
28
+ /**
29
+ * Returns any shape; downstream `normalizeToolResult` serializes to a
30
+ * string before handing the value to the LLM.
31
+ */
32
+ execute: (args: Record<string, unknown>) => unknown | Promise<unknown>;
22
33
  }
23
34
  declare function isFunctionTool(value: unknown): value is FunctionTool;
24
35
  declare function functionToolToDefinition(tool: FunctionTool): AgentToolDefinition;
@@ -1 +1 @@
1
- {"version":3,"file":"function-tool.d.ts","names":[],"sources":["../../../../src/core/agent/tools/function-tool.ts"],"mappings":";;;;UAEiB,YAAA;EACf,IAAA;EACA,IAAA;EACA,WAAA;EACA,UAAA,GAAa,MAAA;EACb,MAAA;EADa;;;;;;;;;EAWb,WAAA,GAAc,eAAA;EACd,OAAA,GAAU,IAAA,EAAM,MAAA,sBAA4B,OAAA;AAAA;AAAA,iBAG9B,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA;AAAA,iBAUzC,wBAAA,CACd,IAAA,EAAM,YAAA,GACL,mBAAA"}
1
+ {"version":3,"file":"function-tool.d.ts","names":[],"sources":["../../../../src/core/agent/tools/function-tool.ts"],"mappings":";;;;UAEiB,YAAA;EACf,IAAA;;AADF;;;;;;EASE,IAAA;EACA,WAAA;EACA,UAAA,GAAa,MAAA;EACb,MAAA;EAHA;;;;;;;;;EAaA,WAAA,GAAc,eAAA;EAKwC;;;AAGxD;EAHE,OAAA,GAAU,IAAA,EAAM,MAAA,gCAAsC,OAAA;AAAA;AAAA,iBAGxC,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA;AAAA,iBAUzC,wBAAA,CACd,IAAA,EAAM,YAAA,GACL,mBAAA"}
@@ -2,12 +2,13 @@
2
2
  function isFunctionTool(value) {
3
3
  if (typeof value !== "object" || value === null) return false;
4
4
  const obj = value;
5
- return obj.type === "function" && typeof obj.name === "string" && typeof obj.execute === "function";
5
+ return obj.type === "function" && typeof obj.execute === "function";
6
6
  }
7
7
  function functionToolToDefinition(tool) {
8
+ const name = tool.name ?? "";
8
9
  return {
9
- name: tool.name,
10
- description: tool.description ?? tool.name,
10
+ name,
11
+ description: tool.description ?? name,
11
12
  parameters: tool.parameters ?? {
12
13
  type: "object",
13
14
  properties: {}