@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.
- package/CLAUDE.md +53 -1
- package/NOTICE.md +1 -0
- package/dist/agents/databricks.d.ts.map +1 -1
- package/dist/agents/databricks.js +8 -3
- package/dist/agents/databricks.js.map +1 -1
- package/dist/appkit/package.js +1 -1
- package/dist/beta.d.ts +5 -3
- package/dist/beta.js +3 -1
- package/dist/connectors/mcp/client.d.ts +27 -2
- package/dist/connectors/mcp/client.d.ts.map +1 -1
- package/dist/connectors/mcp/client.js +117 -18
- package/dist/connectors/mcp/client.js.map +1 -1
- package/dist/connectors/mcp/index.d.ts +1 -1
- package/dist/connectors/mcp/types.d.ts +1 -1
- package/dist/core/agent/build-toolkit.js +3 -8
- package/dist/core/agent/build-toolkit.js.map +1 -1
- package/dist/core/agent/load-agents.d.ts +6 -1
- package/dist/core/agent/load-agents.d.ts.map +1 -1
- package/dist/core/agent/load-agents.js +67 -27
- package/dist/core/agent/load-agents.js.map +1 -1
- package/dist/core/agent/plugins-map.js +44 -0
- package/dist/core/agent/plugins-map.js.map +1 -0
- package/dist/core/agent/run-agent.d.ts +31 -7
- package/dist/core/agent/run-agent.d.ts.map +1 -1
- package/dist/core/agent/run-agent.js +138 -27
- package/dist/core/agent/run-agent.js.map +1 -1
- package/dist/core/agent/toolkit-options.js +28 -0
- package/dist/core/agent/toolkit-options.js.map +1 -0
- package/dist/core/agent/toolkit-resolver.js +44 -0
- package/dist/core/agent/toolkit-resolver.js.map +1 -0
- package/dist/core/agent/tools/define-tool.d.ts +14 -2
- package/dist/core/agent/tools/define-tool.d.ts.map +1 -1
- package/dist/core/agent/tools/define-tool.js +1 -1
- package/dist/core/agent/tools/define-tool.js.map +1 -1
- package/dist/core/agent/tools/function-tool.d.ts +13 -2
- package/dist/core/agent/tools/function-tool.d.ts.map +1 -1
- package/dist/core/agent/tools/function-tool.js +4 -3
- package/dist/core/agent/tools/function-tool.js.map +1 -1
- package/dist/core/agent/tools/index.d.ts +1 -1
- package/dist/core/agent/tools/tool.d.ts +32 -3
- package/dist/core/agent/tools/tool.d.ts.map +1 -1
- package/dist/core/agent/tools/tool.js +4 -3
- package/dist/core/agent/tools/tool.js.map +1 -1
- package/dist/core/agent/types.d.ts +95 -10
- package/dist/core/agent/types.d.ts.map +1 -1
- package/dist/core/agent/types.js.map +1 -1
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/to-plugin.d.ts +3 -13
- package/dist/plugin/to-plugin.d.ts.map +1 -1
- package/dist/plugin/to-plugin.js +1 -8
- package/dist/plugin/to-plugin.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts +184 -2
- package/dist/plugins/agents/agents.d.ts.map +1 -0
- package/dist/plugins/agents/agents.js +169 -72
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/index.d.ts +2 -2
- package/dist/plugins/agents/index.js +1 -1
- package/dist/plugins/agents/manifest.js +4 -5
- package/dist/plugins/agents/tool-approval-gate.js.map +1 -1
- package/dist/plugins/analytics/analytics.d.ts +3 -4
- package/dist/plugins/analytics/analytics.d.ts.map +1 -1
- package/dist/plugins/analytics/analytics.js +8 -6
- package/dist/plugins/analytics/analytics.js.map +1 -1
- package/dist/plugins/analytics/index.js +1 -0
- package/dist/plugins/analytics/types.js +15 -0
- package/dist/plugins/analytics/types.js.map +1 -0
- package/dist/plugins/beta-exports.generated.d.ts +2 -0
- package/dist/plugins/beta-exports.generated.js +4 -0
- package/dist/plugins/files/plugin.d.ts +1 -2
- package/dist/plugins/files/plugin.d.ts.map +1 -1
- package/dist/plugins/files/plugin.js +30 -12
- package/dist/plugins/files/plugin.js.map +1 -1
- package/dist/plugins/genie/genie.d.ts +5 -4
- package/dist/plugins/genie/genie.d.ts.map +1 -1
- package/dist/plugins/genie/genie.js +22 -8
- package/dist/plugins/genie/genie.js.map +1 -1
- package/dist/plugins/genie/types.d.ts +10 -2
- package/dist/plugins/genie/types.d.ts.map +1 -1
- package/dist/plugins/jobs/plugin.d.ts +1 -2
- package/dist/plugins/jobs/plugin.d.ts.map +1 -1
- package/dist/plugins/lakebase/lakebase.d.ts +1 -2
- package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
- package/dist/plugins/lakebase/lakebase.js +3 -3
- package/dist/plugins/lakebase/lakebase.js.map +1 -1
- package/dist/plugins/lakebase/types.d.ts +5 -4
- package/dist/plugins/lakebase/types.d.ts.map +1 -1
- package/dist/plugins/server/index.d.ts +3 -2
- package/dist/plugins/server/index.d.ts.map +1 -1
- package/dist/plugins/server/index.js +8 -5
- package/dist/plugins/server/index.js.map +1 -1
- package/dist/plugins/server/types.d.ts +11 -0
- package/dist/plugins/server/types.d.ts.map +1 -1
- package/dist/plugins/serving/serving.d.ts +1 -2
- package/dist/plugins/serving/serving.d.ts.map +1 -1
- package/dist/shared/src/agent.d.ts +16 -4
- package/dist/shared/src/agent.d.ts.map +1 -1
- package/docs/api/appkit/Class.AppKitMcpClient.md +157 -0
- package/docs/api/appkit/Class.DatabricksAdapter.md +151 -0
- package/docs/api/appkit/Function.agentIdFromMarkdownPath.md +18 -0
- package/docs/api/appkit/Function.createAgent.md +33 -0
- package/docs/api/appkit/Function.defineTool.md +26 -0
- package/docs/api/appkit/Function.executeFromRegistry.md +25 -0
- package/docs/api/appkit/Function.functionToolToDefinition.md +16 -0
- package/docs/api/appkit/Function.isFunctionTool.md +16 -0
- package/docs/api/appkit/Function.isHostedTool.md +16 -0
- package/docs/api/appkit/Function.isToolkitEntry.md +18 -0
- package/docs/api/appkit/Function.loadAgentFromFile.md +21 -0
- package/docs/api/appkit/Function.loadAgentsFromDir.md +26 -0
- package/docs/api/appkit/Function.mcpServer.md +28 -0
- package/docs/api/appkit/Function.parseTextToolCalls.md +26 -0
- package/docs/api/appkit/Function.resolveHostedTools.md +16 -0
- package/docs/api/appkit/Function.runAgent.md +26 -0
- package/docs/api/appkit/Function.tool.md +28 -0
- package/docs/api/appkit/Function.toolsFromRegistry.md +20 -0
- package/docs/api/appkit/Interface.AgentAdapter.md +21 -0
- package/docs/api/appkit/Interface.AgentDefinition.md +112 -0
- package/docs/api/appkit/Interface.AgentInput.md +37 -0
- package/docs/api/appkit/Interface.AgentRunContext.md +32 -0
- package/docs/api/appkit/Interface.AgentToolDefinition.md +37 -0
- package/docs/api/appkit/Interface.AgentsPluginConfig.md +241 -0
- package/docs/api/appkit/Interface.AutoInheritToolsConfig.md +27 -0
- package/docs/api/appkit/Interface.BasePluginConfig.md +1 -0
- package/docs/api/appkit/Interface.FunctionTool.md +80 -0
- package/docs/api/appkit/Interface.McpConnectAllResult.md +38 -0
- package/docs/api/appkit/Interface.Message.md +55 -0
- package/docs/api/appkit/Interface.PluginToolkitProvider.md +22 -0
- package/docs/api/appkit/Interface.PromptContext.md +30 -0
- package/docs/api/appkit/Interface.RegisteredAgent.md +75 -0
- package/docs/api/appkit/Interface.RunAgentInput.md +34 -0
- package/docs/api/appkit/Interface.RunAgentResult.md +23 -0
- package/docs/api/appkit/Interface.Thread.md +46 -0
- package/docs/api/appkit/Interface.ThreadStore.md +103 -0
- package/docs/api/appkit/Interface.ToolAnnotations.md +56 -0
- package/docs/api/appkit/Interface.ToolConfig.md +72 -0
- package/docs/api/appkit/Interface.ToolEntry.md +73 -0
- package/docs/api/appkit/Interface.ToolProvider.md +38 -0
- package/docs/api/appkit/Interface.ToolkitEntry.md +59 -0
- package/docs/api/appkit/Interface.ToolkitOptions.md +45 -0
- package/docs/api/appkit/TypeAlias.AgentEvent.md +299 -0
- package/docs/api/appkit/TypeAlias.AgentTool.md +11 -0
- package/docs/api/appkit/TypeAlias.AgentTools.md +8 -0
- package/docs/api/appkit/TypeAlias.AgentToolsFn.md +20 -0
- package/docs/api/appkit/TypeAlias.BaseSystemPromptOption.md +9 -0
- package/docs/api/appkit/TypeAlias.HostedTool.md +10 -0
- package/docs/api/appkit/TypeAlias.Plugins.md +26 -0
- package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +29 -0
- package/docs/api/appkit/TypeAlias.ToolRegistry.md +6 -0
- package/docs/api/appkit/Variable.agents.md +19 -0
- package/docs/api/appkit.md +113 -62
- package/docs/plugins/agents.md +441 -0
- package/llms.txt +53 -1
- package/package.json +1 -1
- 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
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* `
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
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":"
|
|
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
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* `
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
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
|
|
60
|
+
return (await runAgentInternal(entry.agentDef, subInput, providerCache)).text;
|
|
37
61
|
}
|
|
38
|
-
throw new Error(`runAgent: tool "${name}" is a ${entry.kind} tool.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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))
|
|
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":"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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 { 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
|
|
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
|
-
|
|
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;
|
|
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.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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
|
|
10
|
-
description: tool.description ??
|
|
10
|
+
name,
|
|
11
|
+
description: tool.description ?? name,
|
|
11
12
|
parameters: tool.parameters ?? {
|
|
12
13
|
type: "object",
|
|
13
14
|
properties: {}
|