@databricks/appkit 0.31.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 (218) hide show
  1. package/CLAUDE.md +54 -1
  2. package/NOTICE.md +2 -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 +16 -1
  8. package/dist/beta.js +14 -1
  9. package/dist/connectors/index.js +3 -0
  10. package/dist/connectors/mcp/client.d.ts +85 -0
  11. package/dist/connectors/mcp/client.d.ts.map +1 -0
  12. package/dist/connectors/mcp/client.js +296 -0
  13. package/dist/connectors/mcp/client.js.map +1 -0
  14. package/dist/connectors/mcp/host-policy.d.ts +51 -0
  15. package/dist/connectors/mcp/host-policy.d.ts.map +1 -0
  16. package/dist/connectors/mcp/host-policy.js +168 -0
  17. package/dist/connectors/mcp/host-policy.js.map +1 -0
  18. package/dist/connectors/mcp/index.d.ts +3 -0
  19. package/dist/connectors/mcp/index.js +4 -0
  20. package/dist/connectors/mcp/types.d.ts +16 -0
  21. package/dist/connectors/mcp/types.d.ts.map +1 -0
  22. package/dist/context/index.js +1 -1
  23. package/dist/core/agent/build-toolkit.d.ts +2 -0
  24. package/dist/core/agent/build-toolkit.js +45 -0
  25. package/dist/core/agent/build-toolkit.js.map +1 -0
  26. package/dist/core/agent/consume-adapter-stream.js +33 -0
  27. package/dist/core/agent/consume-adapter-stream.js.map +1 -0
  28. package/dist/core/agent/create-agent.d.ts +27 -0
  29. package/dist/core/agent/create-agent.d.ts.map +1 -0
  30. package/dist/core/agent/create-agent.js +50 -0
  31. package/dist/core/agent/create-agent.js.map +1 -0
  32. package/dist/core/agent/load-agents.d.ts +72 -0
  33. package/dist/core/agent/load-agents.d.ts.map +1 -0
  34. package/dist/core/agent/load-agents.js +268 -0
  35. package/dist/core/agent/load-agents.js.map +1 -0
  36. package/dist/core/agent/normalize-result.js +39 -0
  37. package/dist/core/agent/normalize-result.js.map +1 -0
  38. package/dist/core/agent/plugins-map.js +44 -0
  39. package/dist/core/agent/plugins-map.js.map +1 -0
  40. package/dist/core/agent/run-agent.d.ts +58 -0
  41. package/dist/core/agent/run-agent.d.ts.map +1 -0
  42. package/dist/core/agent/run-agent.js +257 -0
  43. package/dist/core/agent/run-agent.js.map +1 -0
  44. package/dist/core/agent/system-prompt.js +38 -0
  45. package/dist/core/agent/system-prompt.js.map +1 -0
  46. package/dist/core/agent/toolkit-options.js +28 -0
  47. package/dist/core/agent/toolkit-options.js.map +1 -0
  48. package/dist/core/agent/toolkit-resolver.js +44 -0
  49. package/dist/core/agent/toolkit-resolver.js.map +1 -0
  50. package/dist/core/agent/tools/define-tool.d.ts +66 -0
  51. package/dist/core/agent/tools/define-tool.d.ts.map +1 -0
  52. package/dist/core/agent/tools/define-tool.js +50 -0
  53. package/dist/core/agent/tools/define-tool.js.map +1 -0
  54. package/dist/core/agent/tools/function-tool.d.ts +38 -0
  55. package/dist/core/agent/tools/function-tool.d.ts.map +1 -0
  56. package/dist/core/agent/tools/function-tool.js +22 -0
  57. package/dist/core/agent/tools/function-tool.js.map +1 -0
  58. package/dist/core/agent/tools/hosted-tools.d.ts +47 -0
  59. package/dist/core/agent/tools/hosted-tools.d.ts.map +1 -0
  60. package/dist/core/agent/tools/hosted-tools.js +67 -0
  61. package/dist/core/agent/tools/hosted-tools.js.map +1 -0
  62. package/dist/core/agent/tools/index.d.ts +5 -0
  63. package/dist/core/agent/tools/index.js +7 -0
  64. package/dist/core/agent/tools/json-schema.js +24 -0
  65. package/dist/core/agent/tools/json-schema.js.map +1 -0
  66. package/dist/core/agent/tools/sql-policy.js +256 -0
  67. package/dist/core/agent/tools/sql-policy.js.map +1 -0
  68. package/dist/core/agent/tools/tool.d.ts +63 -0
  69. package/dist/core/agent/tools/tool.d.ts.map +1 -0
  70. package/dist/core/agent/tools/tool.js +42 -0
  71. package/dist/core/agent/tools/tool.js.map +1 -0
  72. package/dist/core/agent/types.d.ts +299 -0
  73. package/dist/core/agent/types.d.ts.map +1 -0
  74. package/dist/core/agent/types.js +12 -0
  75. package/dist/core/agent/types.js.map +1 -0
  76. package/dist/core/appkit.d.ts +1 -0
  77. package/dist/core/appkit.d.ts.map +1 -1
  78. package/dist/core/appkit.js +31 -4
  79. package/dist/core/appkit.js.map +1 -1
  80. package/dist/core/plugin-context.d.ts +133 -0
  81. package/dist/core/plugin-context.d.ts.map +1 -0
  82. package/dist/core/plugin-context.js +220 -0
  83. package/dist/core/plugin-context.js.map +1 -0
  84. package/dist/index.d.ts +11 -11
  85. package/dist/internal-telemetry/appkit-log.js +19 -0
  86. package/dist/internal-telemetry/appkit-log.js.map +1 -0
  87. package/dist/internal-telemetry/config.js +15 -0
  88. package/dist/internal-telemetry/config.js.map +1 -0
  89. package/dist/internal-telemetry/index.js +4 -0
  90. package/dist/internal-telemetry/reporter.js +132 -0
  91. package/dist/internal-telemetry/reporter.js.map +1 -0
  92. package/dist/plugin/plugin.d.ts +18 -3
  93. package/dist/plugin/plugin.d.ts.map +1 -1
  94. package/dist/plugin/plugin.js +26 -2
  95. package/dist/plugin/plugin.js.map +1 -1
  96. package/dist/plugin/to-plugin.d.ts +3 -2
  97. package/dist/plugin/to-plugin.d.ts.map +1 -1
  98. package/dist/plugin/to-plugin.js +7 -4
  99. package/dist/plugin/to-plugin.js.map +1 -1
  100. package/dist/plugins/agents/agents.d.ts +186 -0
  101. package/dist/plugins/agents/agents.d.ts.map +1 -0
  102. package/dist/plugins/agents/agents.js +979 -0
  103. package/dist/plugins/agents/agents.js.map +1 -0
  104. package/dist/plugins/agents/defaults.js +13 -0
  105. package/dist/plugins/agents/defaults.js.map +1 -0
  106. package/dist/plugins/agents/event-channel.js +64 -0
  107. package/dist/plugins/agents/event-channel.js.map +1 -0
  108. package/dist/plugins/agents/event-translator.js +224 -0
  109. package/dist/plugins/agents/event-translator.js.map +1 -0
  110. package/dist/plugins/agents/index.d.ts +4 -0
  111. package/dist/plugins/agents/index.js +6 -0
  112. package/dist/plugins/agents/manifest.js +26 -0
  113. package/dist/plugins/agents/manifest.js.map +1 -0
  114. package/dist/plugins/agents/schemas.js +51 -0
  115. package/dist/plugins/agents/schemas.js.map +1 -0
  116. package/dist/plugins/agents/thread-store.js +58 -0
  117. package/dist/plugins/agents/thread-store.js.map +1 -0
  118. package/dist/plugins/agents/tool-approval-gate.js +75 -0
  119. package/dist/plugins/agents/tool-approval-gate.js.map +1 -0
  120. package/dist/plugins/analytics/analytics.d.ts +15 -1
  121. package/dist/plugins/analytics/analytics.d.ts.map +1 -1
  122. package/dist/plugins/analytics/analytics.js +37 -2
  123. package/dist/plugins/analytics/analytics.js.map +1 -1
  124. package/dist/plugins/analytics/index.js +1 -0
  125. package/dist/plugins/analytics/types.js +15 -0
  126. package/dist/plugins/analytics/types.js.map +1 -0
  127. package/dist/plugins/beta-exports.generated.d.ts +2 -0
  128. package/dist/plugins/beta-exports.generated.js +4 -0
  129. package/dist/plugins/files/plugin.d.ts +20 -2
  130. package/dist/plugins/files/plugin.d.ts.map +1 -1
  131. package/dist/plugins/files/plugin.js +120 -2
  132. package/dist/plugins/files/plugin.js.map +1 -1
  133. package/dist/plugins/genie/genie.d.ts +17 -3
  134. package/dist/plugins/genie/genie.d.ts.map +1 -1
  135. package/dist/plugins/genie/genie.js +61 -2
  136. package/dist/plugins/genie/genie.js.map +1 -1
  137. package/dist/plugins/genie/types.d.ts +10 -2
  138. package/dist/plugins/genie/types.d.ts.map +1 -1
  139. package/dist/plugins/jobs/plugin.js +1 -1
  140. package/dist/plugins/lakebase/index.d.ts +2 -2
  141. package/dist/plugins/lakebase/index.js +1 -1
  142. package/dist/plugins/lakebase/lakebase.d.ts +31 -3
  143. package/dist/plugins/lakebase/lakebase.d.ts.map +1 -1
  144. package/dist/plugins/lakebase/lakebase.js +77 -5
  145. package/dist/plugins/lakebase/lakebase.js.map +1 -1
  146. package/dist/plugins/lakebase/types.d.ts +39 -1
  147. package/dist/plugins/lakebase/types.d.ts.map +1 -1
  148. package/dist/plugins/server/index.d.ts +12 -0
  149. package/dist/plugins/server/index.d.ts.map +1 -1
  150. package/dist/plugins/server/index.js +47 -10
  151. package/dist/plugins/server/index.js.map +1 -1
  152. package/dist/plugins/server/types.d.ts +11 -3
  153. package/dist/plugins/server/types.d.ts.map +1 -1
  154. package/dist/shared/src/agent.d.ts +75 -1
  155. package/dist/shared/src/agent.d.ts.map +1 -1
  156. package/dist/shared/src/index.d.ts +1 -1
  157. package/dist/shared/src/plugin.d.ts +8 -0
  158. package/dist/shared/src/plugin.d.ts.map +1 -1
  159. package/docs/api/appkit/Class.AppKitMcpClient.md +157 -0
  160. package/docs/api/appkit/Class.DatabricksAdapter.md +151 -0
  161. package/docs/api/appkit/Class.Plugin.md +65 -23
  162. package/docs/api/appkit/Function.agentIdFromMarkdownPath.md +18 -0
  163. package/docs/api/appkit/Function.createAgent.md +33 -0
  164. package/docs/api/appkit/Function.createApp.md +10 -8
  165. package/docs/api/appkit/Function.defineTool.md +26 -0
  166. package/docs/api/appkit/Function.executeFromRegistry.md +25 -0
  167. package/docs/api/appkit/Function.functionToolToDefinition.md +16 -0
  168. package/docs/api/appkit/Function.isFunctionTool.md +16 -0
  169. package/docs/api/appkit/Function.isHostedTool.md +16 -0
  170. package/docs/api/appkit/Function.isToolkitEntry.md +18 -0
  171. package/docs/api/appkit/Function.loadAgentFromFile.md +21 -0
  172. package/docs/api/appkit/Function.loadAgentsFromDir.md +26 -0
  173. package/docs/api/appkit/Function.mcpServer.md +28 -0
  174. package/docs/api/appkit/Function.parseTextToolCalls.md +26 -0
  175. package/docs/api/appkit/Function.resolveHostedTools.md +16 -0
  176. package/docs/api/appkit/Function.runAgent.md +26 -0
  177. package/docs/api/appkit/Function.tool.md +28 -0
  178. package/docs/api/appkit/Function.toolsFromRegistry.md +20 -0
  179. package/docs/api/appkit/Interface.AgentAdapter.md +21 -0
  180. package/docs/api/appkit/Interface.AgentDefinition.md +112 -0
  181. package/docs/api/appkit/Interface.AgentInput.md +37 -0
  182. package/docs/api/appkit/Interface.AgentRunContext.md +32 -0
  183. package/docs/api/appkit/Interface.AgentToolDefinition.md +37 -0
  184. package/docs/api/appkit/Interface.AgentsPluginConfig.md +241 -0
  185. package/docs/api/appkit/Interface.AutoInheritToolsConfig.md +27 -0
  186. package/docs/api/appkit/Interface.BasePluginConfig.md +1 -0
  187. package/docs/api/appkit/Interface.FunctionTool.md +80 -0
  188. package/docs/api/appkit/Interface.McpConnectAllResult.md +38 -0
  189. package/docs/api/appkit/Interface.Message.md +55 -0
  190. package/docs/api/appkit/Interface.PluginToolkitProvider.md +22 -0
  191. package/docs/api/appkit/Interface.PromptContext.md +30 -0
  192. package/docs/api/appkit/Interface.RegisteredAgent.md +75 -0
  193. package/docs/api/appkit/Interface.RunAgentInput.md +34 -0
  194. package/docs/api/appkit/Interface.RunAgentResult.md +23 -0
  195. package/docs/api/appkit/Interface.Thread.md +46 -0
  196. package/docs/api/appkit/Interface.ThreadStore.md +103 -0
  197. package/docs/api/appkit/Interface.ToolAnnotations.md +56 -0
  198. package/docs/api/appkit/Interface.ToolConfig.md +72 -0
  199. package/docs/api/appkit/Interface.ToolEntry.md +73 -0
  200. package/docs/api/appkit/Interface.ToolProvider.md +38 -0
  201. package/docs/api/appkit/Interface.ToolkitEntry.md +59 -0
  202. package/docs/api/appkit/Interface.ToolkitOptions.md +45 -0
  203. package/docs/api/appkit/TypeAlias.AgentEvent.md +299 -0
  204. package/docs/api/appkit/TypeAlias.AgentTool.md +11 -0
  205. package/docs/api/appkit/TypeAlias.AgentTools.md +8 -0
  206. package/docs/api/appkit/TypeAlias.AgentToolsFn.md +20 -0
  207. package/docs/api/appkit/TypeAlias.BaseSystemPromptOption.md +9 -0
  208. package/docs/api/appkit/TypeAlias.HostedTool.md +10 -0
  209. package/docs/api/appkit/TypeAlias.Plugins.md +26 -0
  210. package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +29 -0
  211. package/docs/api/appkit/TypeAlias.ToolRegistry.md +6 -0
  212. package/docs/api/appkit/Variable.agents.md +19 -0
  213. package/docs/api/appkit.md +113 -62
  214. package/docs/plugins/agents.md +441 -0
  215. package/docs/privacy.md +41 -0
  216. package/llms.txt +54 -1
  217. package/package.json +4 -2
  218. package/sbom.cdx.json +1 -1
@@ -0,0 +1,63 @@
1
+ import { ToolAnnotations } from "../../../shared/src/agent.js";
2
+ import "../../../shared/src/index.js";
3
+ import { FunctionTool } from "./function-tool.js";
4
+ import { z } from "zod";
5
+
6
+ //#region src/core/agent/tools/tool.d.ts
7
+ interface ToolConfig<S extends z.ZodType> {
8
+ /**
9
+ * Optional. When the tool is placed in a keyed record (the standard
10
+ * `tools: { my_tool: tool({...}) }` form, or the function form
11
+ * `tools(plugins) => ({ my_tool: tool({...}) })`), the agents plugin
12
+ * overrides the tool's LLM-visible name with the record key. Set
13
+ * `name` explicitly only if you're constructing a `FunctionTool`
14
+ * outside any keyed-record context — otherwise the record key wins.
15
+ */
16
+ name?: string;
17
+ /**
18
+ * What the tool does, what it expects, and when the LLM should call it.
19
+ * The model reads this verbatim when deciding whether to invoke the tool,
20
+ * so write it for an LLM, not for a human reader of your code: spell out
21
+ * the inputs, the return shape, and any pre-conditions or side effects.
22
+ *
23
+ * Required. Earlier versions silently fell back to the tool's name when
24
+ * omitted, which surfaced cryptic identifiers like `"get_weather"` as the
25
+ * description — the model then had no signal about expected use and
26
+ * either skipped the tool or called it speculatively. Making this
27
+ * mandatory at the type level forces a real description at authoring
28
+ * time instead of debugging a confused agent later.
29
+ */
30
+ description: string;
31
+ schema: S;
32
+ /**
33
+ * Behavioural hints forwarded to the resolved tool definition. Prefer
34
+ * `effect` (`"read" | "write" | "update" | "destructive"`) — any mutating
35
+ * value forces the agents-plugin approval gate before `execute()` runs
36
+ * and the client's approval card will colour itself accordingly. Legacy
37
+ * `destructive: true` still gates. Dropped silently before the fix that
38
+ * added this field.
39
+ */
40
+ annotations?: ToolAnnotations;
41
+ /**
42
+ * Returning a non-string value is fine: the agent runtime serializes
43
+ * the result via `normalizeToolResult` before handing it to the LLM
44
+ * (strings pass through; `null` becomes `"null"`; everything else gets
45
+ * `JSON.stringify`'d; `undefined` becomes `""`). Return whatever shape
46
+ * is most natural for your tool — typically an object — and let the
47
+ * runtime handle the wire format.
48
+ */
49
+ execute: (args: z.infer<S>) => unknown | Promise<unknown>;
50
+ }
51
+ /**
52
+ * Factory for defining function tools with Zod schemas.
53
+ *
54
+ * - Generates JSON Schema (for the LLM) from the Zod schema via `z.toJSONSchema()`.
55
+ * - Infers the `execute` argument type from the schema.
56
+ * - Validates tool call arguments at runtime. On validation failure, returns
57
+ * a formatted error string to the LLM instead of throwing, so the model
58
+ * can self-correct on its next turn.
59
+ */
60
+ declare function tool<S extends z.ZodType>(config: ToolConfig<S>): FunctionTool;
61
+ //#endregion
62
+ export { ToolConfig, tool };
63
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","names":[],"sources":["../../../../src/core/agent/tools/tool.ts"],"mappings":";;;;;;UAKiB,UAAA,WAAqB,CAAA,CAAE,OAAA;;;AAAxC;;;;;;EASE,IAAA;EAiCkB;;;;;;;;;;;;;EAnBlB,WAAA;EACA,MAAA,EAAQ,CAAA;EAkBU;;;;;;AAYpB;;EArBE,WAAA,GAAc,eAAA;EAqBiB;;;;;;;;EAZ/B,OAAA,GAAU,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,CAAA,gBAAiB,OAAA;AAAA;;;;;;;;;;iBAY3B,IAAA,WAAe,CAAA,CAAE,OAAA,CAAA,CAAS,MAAA,EAAQ,UAAA,CAAW,CAAA,IAAK,YAAA"}
@@ -0,0 +1,42 @@
1
+ import { toToolJSONSchema } from "./json-schema.js";
2
+
3
+ //#region src/core/agent/tools/tool.ts
4
+ /**
5
+ * Factory for defining function tools with Zod schemas.
6
+ *
7
+ * - Generates JSON Schema (for the LLM) from the Zod schema via `z.toJSONSchema()`.
8
+ * - Infers the `execute` argument type from the schema.
9
+ * - Validates tool call arguments at runtime. On validation failure, returns
10
+ * a formatted error string to the LLM instead of throwing, so the model
11
+ * can self-correct on its next turn.
12
+ */
13
+ function tool(config) {
14
+ const parameters = toToolJSONSchema(config.schema);
15
+ const labelForErrors = config.name ?? "tool";
16
+ return {
17
+ type: "function",
18
+ ...config.name !== void 0 ? { name: config.name } : {},
19
+ description: config.description,
20
+ parameters,
21
+ ...config.annotations ? { annotations: config.annotations } : {},
22
+ execute: async (args) => {
23
+ const parsed = config.schema.safeParse(args);
24
+ if (!parsed.success) return formatZodError(parsed.error, labelForErrors);
25
+ return config.execute(parsed.data);
26
+ }
27
+ };
28
+ }
29
+ /**
30
+ * Formats a Zod validation error into an LLM-friendly string.
31
+ *
32
+ * Example: `Invalid arguments for get_weather: city: Invalid input: expected string, received undefined`
33
+ */
34
+ function formatZodError(error, toolName) {
35
+ return `Invalid arguments for ${toolName}: ${error.issues.map((issue) => {
36
+ return `${issue.path.length > 0 ? issue.path.join(".") : "(root)"}: ${issue.message}`;
37
+ }).join("; ")}`;
38
+ }
39
+
40
+ //#endregion
41
+ export { formatZodError, tool };
42
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","names":[],"sources":["../../../../src/core/agent/tools/tool.ts"],"sourcesContent":["import type { ToolAnnotations } from \"shared\";\nimport type { z } from \"zod\";\nimport type { FunctionTool } from \"./function-tool\";\nimport { toToolJSONSchema } from \"./json-schema\";\n\nexport interface ToolConfig<S extends z.ZodType> {\n /**\n * Optional. When the tool is placed in a keyed record (the standard\n * `tools: { my_tool: tool({...}) }` form, or the function form\n * `tools(plugins) => ({ my_tool: tool({...}) })`), the agents plugin\n * overrides the tool's LLM-visible name with the record key. Set\n * `name` explicitly only if you're constructing a `FunctionTool`\n * outside any keyed-record context — otherwise the record key wins.\n */\n name?: string;\n /**\n * What the tool does, what it expects, and when the LLM should call it.\n * The model reads this verbatim when deciding whether to invoke the tool,\n * so write it for an LLM, not for a human reader of your code: spell out\n * the inputs, the return shape, and any pre-conditions or side effects.\n *\n * Required. Earlier versions silently fell back to the tool's name when\n * omitted, which surfaced cryptic identifiers like `\"get_weather\"` as the\n * description — the model then had no signal about expected use and\n * either skipped the tool or called it speculatively. Making this\n * mandatory at the type level forces a real description at authoring\n * time instead of debugging a confused agent later.\n */\n description: string;\n schema: S;\n /**\n * Behavioural hints forwarded to the resolved tool definition. Prefer\n * `effect` (`\"read\" | \"write\" | \"update\" | \"destructive\"`) — any mutating\n * value forces the agents-plugin approval gate before `execute()` runs\n * and the client's approval card will colour itself accordingly. Legacy\n * `destructive: true` still gates. Dropped silently before the fix that\n * added this field.\n */\n annotations?: ToolAnnotations;\n /**\n * Returning a non-string value is fine: the agent runtime serializes\n * the result via `normalizeToolResult` before handing it to the LLM\n * (strings pass through; `null` becomes `\"null\"`; everything else gets\n * `JSON.stringify`'d; `undefined` becomes `\"\"`). Return whatever shape\n * is most natural for your tool — typically an object — and let the\n * runtime handle the wire format.\n */\n execute: (args: z.infer<S>) => unknown | Promise<unknown>;\n}\n\n/**\n * Factory for defining function tools with Zod schemas.\n *\n * - Generates JSON Schema (for the LLM) from the Zod schema via `z.toJSONSchema()`.\n * - Infers the `execute` argument type from the schema.\n * - Validates tool call arguments at runtime. On validation failure, returns\n * a formatted error string to the LLM instead of throwing, so the model\n * can self-correct on its next turn.\n */\nexport function tool<S extends z.ZodType>(config: ToolConfig<S>): FunctionTool {\n const parameters = toToolJSONSchema(config.schema);\n\n // `name` is only used for the zod-validation error message and the\n // FunctionTool's `name` field; the agents plugin overrides the latter\n // with the record key (`tools: { my_tool: ... }` -> \"my_tool\") at\n // index-build time. Fall back to a generic label so errors are still\n // legible when `name` is omitted.\n const labelForErrors = config.name ?? \"tool\";\n\n return {\n type: \"function\",\n ...(config.name !== undefined ? { name: config.name } : {}),\n description: config.description,\n parameters,\n ...(config.annotations ? { annotations: config.annotations } : {}),\n execute: async (args: Record<string, unknown>) => {\n const parsed = config.schema.safeParse(args);\n if (!parsed.success) {\n return formatZodError(parsed.error, labelForErrors);\n }\n return config.execute(parsed.data as z.infer<S>);\n },\n };\n}\n\n/**\n * Formats a Zod validation error into an LLM-friendly string.\n *\n * Example: `Invalid arguments for get_weather: city: Invalid input: expected string, received undefined`\n */\nexport function formatZodError(error: z.ZodError, toolName: string): string {\n const parts = error.issues.map((issue) => {\n const field = issue.path.length > 0 ? issue.path.join(\".\") : \"(root)\";\n return `${field}: ${issue.message}`;\n });\n return `Invalid arguments for ${toolName}: ${parts.join(\"; \")}`;\n}\n"],"mappings":";;;;;;;;;;;;AA2DA,SAAgB,KAA0B,QAAqC;CAC7E,MAAM,aAAa,iBAAiB,OAAO,OAAO;CAOlD,MAAM,iBAAiB,OAAO,QAAQ;AAEtC,QAAO;EACL,MAAM;EACN,GAAI,OAAO,SAAS,SAAY,EAAE,MAAM,OAAO,MAAM,GAAG,EAAE;EAC1D,aAAa,OAAO;EACpB;EACA,GAAI,OAAO,cAAc,EAAE,aAAa,OAAO,aAAa,GAAG,EAAE;EACjE,SAAS,OAAO,SAAkC;GAChD,MAAM,SAAS,OAAO,OAAO,UAAU,KAAK;AAC5C,OAAI,CAAC,OAAO,QACV,QAAO,eAAe,OAAO,OAAO,eAAe;AAErD,UAAO,OAAO,QAAQ,OAAO,KAAmB;;EAEnD;;;;;;;AAQH,SAAgB,eAAe,OAAmB,UAA0B;AAK1E,QAAO,yBAAyB,SAAS,IAJ3B,MAAM,OAAO,KAAK,UAAU;AAExC,SAAO,GADO,MAAM,KAAK,SAAS,IAAI,MAAM,KAAK,KAAK,IAAI,GAAG,SAC7C,IAAI,MAAM;GAC1B,CACiD,KAAK,KAAK"}
@@ -0,0 +1,299 @@
1
+ import { AgentAdapter, AgentToolDefinition, ThreadStore, ToolAnnotations } from "../../shared/src/agent.js";
2
+ import { BasePluginConfig } from "../../shared/src/plugin.js";
3
+ import "../../shared/src/index.js";
4
+ import { McpHostPolicyConfig } from "../../connectors/mcp/host-policy.js";
5
+ import "../../connectors/mcp/index.js";
6
+ import { FunctionTool } from "./tools/function-tool.js";
7
+ import { HostedTool } from "./tools/hosted-tools.js";
8
+
9
+ //#region src/core/agent/types.d.ts
10
+ /**
11
+ * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin
12
+ * recognizes the `__toolkitRef` brand and dispatches tool invocations through
13
+ * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving
14
+ * OBO (asUser) and telemetry spans.
15
+ */
16
+ interface ToolkitEntry {
17
+ readonly __toolkitRef: true;
18
+ pluginName: string;
19
+ localName: string;
20
+ def: AgentToolDefinition;
21
+ annotations?: ToolAnnotations;
22
+ /**
23
+ * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors
24
+ * {@link ToolEntry.autoInheritable} from the source registry so the agents
25
+ * plugin can filter auto-inherited tools without re-walking the provider's
26
+ * internal registry.
27
+ */
28
+ autoInheritable?: boolean;
29
+ }
30
+ /**
31
+ * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP
32
+ * tools (`mcpServer()` / raw hosted), or toolkit references from plugins
33
+ * (`analytics().toolkit()`).
34
+ */
35
+ type AgentTool = FunctionTool | HostedTool | ToolkitEntry;
36
+ interface ToolkitOptions {
37
+ /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */
38
+ prefix?: string;
39
+ /** Only include tools whose local name matches one of these. */
40
+ only?: string[];
41
+ /** Exclude tools whose local name matches one of these. */
42
+ except?: string[];
43
+ /** Remap specific local names to different keys (applied after prefix). */
44
+ rename?: Record<string, string>;
45
+ }
46
+ /**
47
+ * Minimum shape every entry in the {@link Plugins} map must expose. Core
48
+ * plugins (analytics, files, genie, lakebase) implement this directly via
49
+ * their `.toolkit()` method. The agents plugin and standalone `runAgent`
50
+ * synthesize this shape for any registered plugin that doesn't implement
51
+ * `.toolkit()` directly (falling back to `getAgentTools()` walking).
52
+ */
53
+ interface PluginToolkitProvider {
54
+ toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;
55
+ }
56
+ /**
57
+ * Plugin map passed to the function form of {@link AgentDefinition.tools}.
58
+ * Each entry exposes a `.toolkit(opts?)` method that returns a record of
59
+ * {@link ToolkitEntry} markers ready to be spread into a tool record.
60
+ *
61
+ * AppKit does not statically know which plugins the surrounding
62
+ * `createApp` will register, so this is a plain string-keyed record.
63
+ * Refer to plugins by the name used in `createApp({ plugins: [...] })`;
64
+ * unknown names resolve to `undefined` at runtime.
65
+ *
66
+ * @example
67
+ * ```ts
68
+ * const support = createAgent({
69
+ * instructions: "...",
70
+ * tools(plugins) {
71
+ * return {
72
+ * get_weather: tool({ ... }),
73
+ * ...plugins.analytics.toolkit(),
74
+ * ...plugins.files.toolkit({ only: ["uploads.read"] }),
75
+ * };
76
+ * },
77
+ * });
78
+ * ```
79
+ */
80
+ type Plugins = Record<string, PluginToolkitProvider>;
81
+ /**
82
+ * Context passed to `baseSystemPrompt` callbacks.
83
+ */
84
+ interface PromptContext {
85
+ agentName: string;
86
+ pluginNames: string[];
87
+ toolNames: string[];
88
+ }
89
+ type BaseSystemPromptOption = false | string | ((ctx: PromptContext) => string);
90
+ /**
91
+ * Per-agent tool record. String keys map to inline tools, toolkit entries,
92
+ * hosted tools, etc.
93
+ */
94
+ type AgentTools = Record<string, AgentTool>;
95
+ /**
96
+ * Function form of `AgentDefinition.tools`. Receives the typed
97
+ * {@link Plugins} map and returns a tool record. Invoked exactly once at
98
+ * setup (or once per `runAgent` call in standalone mode); the result is
99
+ * cached as the agent's resolved tool record.
100
+ *
101
+ * Use the function form when an agent needs tools from registered plugins.
102
+ * The bare object form is fine when an agent only uses inline tools.
103
+ */
104
+ type AgentToolsFn = (plugins: Plugins) => AgentTools;
105
+ interface AgentDefinition {
106
+ /**
107
+ * Stable identifier for the agent. **Optional and informational** —
108
+ * when the definition is registered via `agents: { foo: def }` (code) or
109
+ * lives at `config/agents/<id>/agent.md` (markdown), the **registry key
110
+ * always wins** and `name` is ignored. The agent will be reachable as
111
+ * `foo` (or `<id>`) regardless of what this field contains.
112
+ *
113
+ * Set `name` when:
114
+ * - Running standalone via `runAgent({ agent: def })`, where there is
115
+ * no enclosing key. The runtime uses it for the agent's slot in
116
+ * error messages and OTel spans.
117
+ * - Building a definition that may be passed to either form and you
118
+ * want a consistent fallback label.
119
+ *
120
+ * Setting `name` to a value that differs from the registry key is
121
+ * harmless but confusing — prefer keeping them aligned or omitting `name`
122
+ * entirely.
123
+ */
124
+ name?: string;
125
+ /** System prompt body. For markdown-loaded agents this is the file body. */
126
+ instructions: string;
127
+ /**
128
+ * Model adapter (or endpoint-name string sugar for
129
+ * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —
130
+ * falls back to the plugin's `defaultModel`.
131
+ */
132
+ model?: AgentAdapter | Promise<AgentAdapter> | string;
133
+ /**
134
+ * Per-agent tool record. Key is the LLM-visible tool-call name.
135
+ *
136
+ * Accepts either a plain record (for agents that only use inline tools)
137
+ * or a function `(plugins) => Record<string, AgentTool>` that receives
138
+ * the typed {@link Plugins} map and returns a tool record (for agents
139
+ * that pull tools from registered plugins).
140
+ *
141
+ * The function is invoked once at agent setup; the result is cached.
142
+ * Don't put per-request logic in there.
143
+ */
144
+ tools?: AgentTools | AgentToolsFn;
145
+ /** Sub-agents, exposed as `agent-<key>` tools on this agent. */
146
+ agents?: Record<string, AgentDefinition>;
147
+ /** Override the plugin's baseSystemPrompt for this agent only. */
148
+ baseSystemPrompt?: BaseSystemPromptOption;
149
+ maxSteps?: number;
150
+ maxTokens?: number;
151
+ /**
152
+ * When true, the thread used for a chat request against this agent is
153
+ * deleted from `ThreadStore` after the stream completes (success or
154
+ * failure). Use for stateless one-shot agents — e.g. autocomplete, where
155
+ * each request is independent and retaining history would both poison
156
+ * future calls and accumulate unbounded state in the default
157
+ * `InMemoryThreadStore`. Defaults to `false`.
158
+ */
159
+ ephemeral?: boolean;
160
+ }
161
+ /**
162
+ * Auto-inherit configuration. When enabled for a given agent origin, agents
163
+ * with no explicit `tools:` declaration receive every registered ToolProvider
164
+ * plugin tool whose author marked `autoInheritable: true`. Tools without that
165
+ * flag — destructive, state-mutating, or privilege-sensitive — never spread
166
+ * automatically and must be wired via `tools:` (object or function form in
167
+ * code, `plugin:NAME` entries in markdown frontmatter).
168
+ *
169
+ * Defaults are `false` for both origins (safe-by-default): developers must
170
+ * consciously opt an origin in to any auto-inherit behaviour.
171
+ */
172
+ interface AutoInheritToolsConfig {
173
+ /** Default for agents loaded from markdown files. Default: `false`. */
174
+ file?: boolean;
175
+ /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */
176
+ code?: boolean;
177
+ }
178
+ interface AgentsPluginConfig extends BasePluginConfig {
179
+ /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */
180
+ dir?: string | false;
181
+ /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */
182
+ agents?: Record<string, AgentDefinition>;
183
+ /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */
184
+ defaultAgent?: string;
185
+ /** Default model for agents that don't specify their own (in code or frontmatter). */
186
+ defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;
187
+ /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */
188
+ tools?: Record<string, AgentTool>;
189
+ /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */
190
+ autoInheritTools?: boolean | AutoInheritToolsConfig;
191
+ /** Persistent thread store. Default: in-memory. */
192
+ threadStore?: ThreadStore;
193
+ /** Customize or disable the AppKit base system prompt. */
194
+ baseSystemPrompt?: BaseSystemPromptOption;
195
+ /**
196
+ * MCP server host policy. By default only same-origin Databricks workspace
197
+ * URLs may be used as MCP endpoints; custom hosts must be explicitly
198
+ * allowlisted here. Workspace credentials (SP / OBO) are never forwarded
199
+ * to non-workspace hosts.
200
+ */
201
+ mcp?: McpHostPolicyConfig;
202
+ /**
203
+ * Human-in-the-loop approval gate for mutating tool calls. When enabled
204
+ * (the default), the agents plugin emits an `appkit.approval_pending` SSE
205
+ * event before executing any tool whose annotation flags it as mutating —
206
+ * `effect: "write" | "update" | "destructive"` (preferred) or the legacy
207
+ * `destructive: true` boolean — and waits for a `POST /chat/approve`
208
+ * decision from the same user who initiated the stream. A missing decision
209
+ * after `timeoutMs` auto-denies the call.
210
+ */
211
+ approval?: {
212
+ /**
213
+ * Require human approval for tools that mutate state. Triggered by
214
+ * `effect: "write" | "update" | "destructive"` (preferred) or the legacy
215
+ * `destructive: true` boolean. Default: `true`.
216
+ */
217
+ requireForDestructive?: boolean; /** Milliseconds to wait before auto-denying. Default: 60_000. */
218
+ timeoutMs?: number;
219
+ };
220
+ /**
221
+ * Runtime resource limits applied during agent execution. Defaults are
222
+ * tuned to protect a single-instance deployment from a misbehaving user or
223
+ * a runaway prompt injection; tighten or relax as appropriate for the
224
+ * deployment's scale and trust model. Request-body caps (chat message
225
+ * size, invocations input size / length) are enforced statically by the
226
+ * Zod schemas and are not configurable here.
227
+ */
228
+ limits?: {
229
+ /**
230
+ * Max concurrent chat streams a single user may have open. Subsequent
231
+ * `POST /chat` requests from that user while at-limit are rejected with
232
+ * HTTP 429. Default: `5`.
233
+ */
234
+ maxConcurrentStreamsPerUser?: number;
235
+ /**
236
+ * Max tool invocations per agent run (across the full tool-call graph,
237
+ * including sub-agent invocations). A run that exceeds the budget is
238
+ * aborted with a terminal error event. Default: `50`.
239
+ */
240
+ maxToolCalls?: number;
241
+ /**
242
+ * Max sub-agent recursion depth. Protects against a prompt-injected
243
+ * agent that delegates to a sub-agent which in turn delegates back to
244
+ * itself (directly or transitively). Default: `3`.
245
+ */
246
+ maxSubAgentDepth?: number;
247
+ /**
248
+ * Per-call timeout for tools dispatched through `PluginContext`
249
+ * (toolkit-routed tools — analytics SQL warehouse queries, Genie
250
+ * messages, Lakebase queries). Independent of `maxToolCalls`: the
251
+ * budget caps how many tools fire per run, this caps how long any
252
+ * single tool call may run. The signal handed to plugin tool
253
+ * implementations combines this timeout with the parent stream's
254
+ * abort signal via `AbortSignal.any`. Function and MCP tools have
255
+ * their own timeouts in their respective adapters and ignore this
256
+ * setting. Default: `300_000` (5 minutes) — generous enough for cold
257
+ * SQL Warehouse round-trips and long Genie conversations.
258
+ */
259
+ toolCallTimeoutMs?: number;
260
+ };
261
+ }
262
+ /** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */
263
+ type ResolvedToolEntry = {
264
+ source: "toolkit";
265
+ pluginName: string;
266
+ localName: string;
267
+ def: AgentToolDefinition;
268
+ } | {
269
+ source: "function";
270
+ functionTool: FunctionTool;
271
+ def: AgentToolDefinition;
272
+ } | {
273
+ source: "mcp";
274
+ mcpToolName: string;
275
+ def: AgentToolDefinition;
276
+ } | {
277
+ source: "subagent";
278
+ agentName: string;
279
+ def: AgentToolDefinition;
280
+ };
281
+ interface RegisteredAgent {
282
+ name: string;
283
+ instructions: string;
284
+ adapter: AgentAdapter;
285
+ toolIndex: Map<string, ResolvedToolEntry>;
286
+ baseSystemPrompt?: BaseSystemPromptOption;
287
+ maxSteps?: number;
288
+ maxTokens?: number;
289
+ /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */
290
+ ephemeral?: boolean;
291
+ }
292
+ /**
293
+ * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate
294
+ * toolkit references from inline tools in a mixed `tools` record.
295
+ */
296
+ declare function isToolkitEntry(value: unknown): value is ToolkitEntry;
297
+ //#endregion
298
+ export { AgentDefinition, AgentTool, AgentTools, AgentToolsFn, AgentsPluginConfig, AutoInheritToolsConfig, BaseSystemPromptOption, PluginToolkitProvider, Plugins, PromptContext, RegisteredAgent, ResolvedToolEntry, ToolkitEntry, ToolkitOptions, isToolkitEntry };
299
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/agent/types.ts"],"mappings":";;;;;;;;;;;;;;AAiBA;UAAiB,YAAA;EAAA,SACN,YAAA;EACT,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;EACL,WAAA,GAAc,eAAA;EADd;;;;;;EAQA,eAAA;AAAA;;;;;;KAQU,SAAA,GAAY,YAAA,GAAe,UAAA,GAAa,YAAA;AAAA,UAEnC,cAAA;EAFO;EAItB,MAAA;EAJkD;EAMlD,IAAA;EAN8D;EAQ9D,MAAA;EAN6B;EAQ7B,MAAA,GAAS,MAAA;AAAA;;;;;;;;UAUM,qBAAA;EACf,OAAA,CAAQ,IAAA,GAAO,cAAA,GAAiB,MAAA,SAAe,YAAA;AAAA;;;;;;;;;;;;;AA2BjD;;;;;AAKA;;;;;;;KALY,OAAA,GAAU,MAAA,SAAe,qBAAA;;AAWrC;;UANiB,aAAA;EACf,SAAA;EACA,WAAA;EACA,SAAA;AAAA;AAAA,KAGU,sBAAA,sBAGN,GAAA,EAAK,aAAA;;;AAiBX;;KAXY,UAAA,GAAa,MAAA,SAAe,SAAA;;;;;;;AAaxC;;;KAFY,YAAA,IAAgB,OAAA,EAAS,OAAA,KAAY,UAAA;AAAA,UAEhC,eAAA;EA2BQ;;;;;;;;;;;;;;;;;;EARvB,IAAA;EAsBwB;EApBxB,YAAA;EAsBmB;;;;;EAhBnB,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA;EAyChB;;;;;AAOjB;;;;;;EApCE,KAAA,GAAQ,UAAA,GAAa,YAAA;EA4CS;EA1C9B,MAAA,GAAS,MAAA,SAAe,eAAA;EA4ChB;EA1CR,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;EAqDM;;;;;;;;EA5CN,SAAA;AAAA;;;;;;;;;;;;UAce,sBAAA;EAuBI;EArBnB,IAAA;EA4BM;EA1BN,IAAA;AAAA;AAAA,UAGe,kBAAA,SAA2B,gBAAA;EAmD1C;EAjDA,GAAA;EA6DE;EA3DF,MAAA,GAAS,MAAA,SAAe,eAAA;EA8EtB;EA5EF,YAAA;EA4EmB;EA1EnB,YAAA,GAAe,YAAA,GAAe,OAAA,CAAQ,YAAA;EA+EX;EA7E3B,KAAA,GAAQ,MAAA,SAAe,SAAA;EAkFd;EAhFT,gBAAA,aAA6B,sBAAA;EAqFpB;EAnFT,WAAA,GAAc,WAAA;EA6FL;EA3FT,gBAAA,GAAmB,sBAAA;EA2FS;;;;;;EApF5B,GAAA,GAAM,mBAAA;EAyEF;;;;;;;;;EA/DJ,QAAA;IA0EI;;;;AAGN;IAvEI,qBAAA,YAuE4B;IArE5B,SAAA;EAAA;EAyES;;;;;;;;EA/DX,MAAA;IA+DW;;;;;IAzDT,2BAAA;IA8DF;;;AAOF;;IA/DI,YAAA;IA+DiE;;;;;IAzDjE,gBAAA;;;;;;;;;;;;;IAaA,iBAAA;EAAA;AAAA;;KAKQ,iBAAA;EAEN,MAAA;EACA,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,YAAA,EAAc,YAAA;EACd,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,WAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;AAAA,UAGM,eAAA;EACf,IAAA;EACA,YAAA;EACA,OAAA,EAAS,YAAA;EACT,SAAA,EAAW,GAAA,SAAY,iBAAA;EACvB,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;;EAEA,SAAA;AAAA;;;;;iBAOc,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA"}
@@ -0,0 +1,12 @@
1
+ //#region src/core/agent/types.ts
2
+ /**
3
+ * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate
4
+ * toolkit references from inline tools in a mixed `tools` record.
5
+ */
6
+ function isToolkitEntry(value) {
7
+ return typeof value === "object" && value !== null && value.__toolkitRef === true;
8
+ }
9
+
10
+ //#endregion
11
+ export { isToolkitEntry };
12
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { FunctionTool } from \"./tools/function-tool\";\nimport type { HostedTool } from \"./tools/hosted-tools\";\n\n/**\n * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin\n * recognizes the `__toolkitRef` brand and dispatches tool invocations through\n * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving\n * OBO (asUser) and telemetry spans.\n */\nexport interface ToolkitEntry {\n readonly __toolkitRef: true;\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors\n * {@link ToolEntry.autoInheritable} from the source registry so the agents\n * plugin can filter auto-inherited tools without re-walking the provider's\n * internal registry.\n */\n autoInheritable?: boolean;\n}\n\n/**\n * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP\n * tools (`mcpServer()` / raw hosted), or toolkit references from plugins\n * (`analytics().toolkit()`).\n */\nexport type AgentTool = FunctionTool | HostedTool | ToolkitEntry;\n\nexport interface ToolkitOptions {\n /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */\n prefix?: string;\n /** Only include tools whose local name matches one of these. */\n only?: string[];\n /** Exclude tools whose local name matches one of these. */\n except?: string[];\n /** Remap specific local names to different keys (applied after prefix). */\n rename?: Record<string, string>;\n}\n\n/**\n * Minimum shape every entry in the {@link Plugins} map must expose. Core\n * plugins (analytics, files, genie, lakebase) implement this directly via\n * their `.toolkit()` method. The agents plugin and standalone `runAgent`\n * synthesize this shape for any registered plugin that doesn't implement\n * `.toolkit()` directly (falling back to `getAgentTools()` walking).\n */\nexport interface PluginToolkitProvider {\n toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;\n}\n\n/**\n * Plugin map passed to the function form of {@link AgentDefinition.tools}.\n * Each entry exposes a `.toolkit(opts?)` method that returns a record of\n * {@link ToolkitEntry} markers ready to be spread into a tool record.\n *\n * AppKit does not statically know which plugins the surrounding\n * `createApp` will register, so this is a plain string-keyed record.\n * Refer to plugins by the name used in `createApp({ plugins: [...] })`;\n * unknown names resolve to `undefined` at runtime.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"...\",\n * tools(plugins) {\n * return {\n * get_weather: tool({ ... }),\n * ...plugins.analytics.toolkit(),\n * ...plugins.files.toolkit({ only: [\"uploads.read\"] }),\n * };\n * },\n * });\n * ```\n */\nexport type Plugins = Record<string, PluginToolkitProvider>;\n\n/**\n * Context passed to `baseSystemPrompt` callbacks.\n */\nexport interface PromptContext {\n agentName: string;\n pluginNames: string[];\n toolNames: string[];\n}\n\nexport type BaseSystemPromptOption =\n | false\n | string\n | ((ctx: PromptContext) => string);\n\n/**\n * Per-agent tool record. String keys map to inline tools, toolkit entries,\n * hosted tools, etc.\n */\nexport type AgentTools = Record<string, AgentTool>;\n\n/**\n * Function form of `AgentDefinition.tools`. Receives the typed\n * {@link Plugins} map and returns a tool record. Invoked exactly once at\n * setup (or once per `runAgent` call in standalone mode); the result is\n * cached as the agent's resolved tool record.\n *\n * Use the function form when an agent needs tools from registered plugins.\n * The bare object form is fine when an agent only uses inline tools.\n */\nexport type AgentToolsFn = (plugins: Plugins) => AgentTools;\n\nexport interface AgentDefinition {\n /**\n * Stable identifier for the agent. **Optional and informational** —\n * when the definition is registered via `agents: { foo: def }` (code) or\n * lives at `config/agents/<id>/agent.md` (markdown), the **registry key\n * always wins** and `name` is ignored. The agent will be reachable as\n * `foo` (or `<id>`) regardless of what this field contains.\n *\n * Set `name` when:\n * - Running standalone via `runAgent({ agent: def })`, where there is\n * no enclosing key. The runtime uses it for the agent's slot in\n * error messages and OTel spans.\n * - Building a definition that may be passed to either form and you\n * want a consistent fallback label.\n *\n * Setting `name` to a value that differs from the registry key is\n * harmless but confusing — prefer keeping them aligned or omitting `name`\n * entirely.\n */\n name?: string;\n /** System prompt body. For markdown-loaded agents this is the file body. */\n instructions: string;\n /**\n * Model adapter (or endpoint-name string sugar for\n * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —\n * falls back to the plugin's `defaultModel`.\n */\n model?: AgentAdapter | Promise<AgentAdapter> | string;\n /**\n * Per-agent tool record. Key is the LLM-visible tool-call name.\n *\n * Accepts either a plain record (for agents that only use inline tools)\n * or a function `(plugins) => Record<string, AgentTool>` that receives\n * the typed {@link Plugins} map and returns a tool record (for agents\n * that pull tools from registered plugins).\n *\n * The function is invoked once at agent setup; the result is cached.\n * Don't put per-request logic in there.\n */\n tools?: AgentTools | AgentToolsFn;\n /** Sub-agents, exposed as `agent-<key>` tools on this agent. */\n agents?: Record<string, AgentDefinition>;\n /** Override the plugin's baseSystemPrompt for this agent only. */\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /**\n * When true, the thread used for a chat request against this agent is\n * deleted from `ThreadStore` after the stream completes (success or\n * failure). Use for stateless one-shot agents — e.g. autocomplete, where\n * each request is independent and retaining history would both poison\n * future calls and accumulate unbounded state in the default\n * `InMemoryThreadStore`. Defaults to `false`.\n */\n ephemeral?: boolean;\n}\n\n/**\n * Auto-inherit configuration. When enabled for a given agent origin, agents\n * with no explicit `tools:` declaration receive every registered ToolProvider\n * plugin tool whose author marked `autoInheritable: true`. Tools without that\n * flag — destructive, state-mutating, or privilege-sensitive — never spread\n * automatically and must be wired via `tools:` (object or function form in\n * code, `plugin:NAME` entries in markdown frontmatter).\n *\n * Defaults are `false` for both origins (safe-by-default): developers must\n * consciously opt an origin in to any auto-inherit behaviour.\n */\nexport interface AutoInheritToolsConfig {\n /** Default for agents loaded from markdown files. Default: `false`. */\n file?: boolean;\n /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */\n code?: boolean;\n}\n\nexport interface AgentsPluginConfig extends BasePluginConfig {\n /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */\n dir?: string | false;\n /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */\n defaultAgent?: string;\n /** Default model for agents that don't specify their own (in code or frontmatter). */\n defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;\n /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */\n tools?: Record<string, AgentTool>;\n /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */\n autoInheritTools?: boolean | AutoInheritToolsConfig;\n /** Persistent thread store. Default: in-memory. */\n threadStore?: ThreadStore;\n /** Customize or disable the AppKit base system prompt. */\n baseSystemPrompt?: BaseSystemPromptOption;\n /**\n * MCP server host policy. By default only same-origin Databricks workspace\n * URLs may be used as MCP endpoints; custom hosts must be explicitly\n * allowlisted here. Workspace credentials (SP / OBO) are never forwarded\n * to non-workspace hosts.\n */\n mcp?: McpHostPolicyConfig;\n /**\n * Human-in-the-loop approval gate for mutating tool calls. When enabled\n * (the default), the agents plugin emits an `appkit.approval_pending` SSE\n * event before executing any tool whose annotation flags it as mutating —\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean — and waits for a `POST /chat/approve`\n * decision from the same user who initiated the stream. A missing decision\n * after `timeoutMs` auto-denies the call.\n */\n approval?: {\n /**\n * Require human approval for tools that mutate state. Triggered by\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean. Default: `true`.\n */\n requireForDestructive?: boolean;\n /** Milliseconds to wait before auto-denying. Default: 60_000. */\n timeoutMs?: number;\n };\n /**\n * Runtime resource limits applied during agent execution. Defaults are\n * tuned to protect a single-instance deployment from a misbehaving user or\n * a runaway prompt injection; tighten or relax as appropriate for the\n * deployment's scale and trust model. Request-body caps (chat message\n * size, invocations input size / length) are enforced statically by the\n * Zod schemas and are not configurable here.\n */\n limits?: {\n /**\n * Max concurrent chat streams a single user may have open. Subsequent\n * `POST /chat` requests from that user while at-limit are rejected with\n * HTTP 429. Default: `5`.\n */\n maxConcurrentStreamsPerUser?: number;\n /**\n * Max tool invocations per agent run (across the full tool-call graph,\n * including sub-agent invocations). A run that exceeds the budget is\n * aborted with a terminal error event. Default: `50`.\n */\n maxToolCalls?: number;\n /**\n * Max sub-agent recursion depth. Protects against a prompt-injected\n * agent that delegates to a sub-agent which in turn delegates back to\n * itself (directly or transitively). Default: `3`.\n */\n maxSubAgentDepth?: number;\n /**\n * Per-call timeout for tools dispatched through `PluginContext`\n * (toolkit-routed tools — analytics SQL warehouse queries, Genie\n * messages, Lakebase queries). Independent of `maxToolCalls`: the\n * budget caps how many tools fire per run, this caps how long any\n * single tool call may run. The signal handed to plugin tool\n * implementations combines this timeout with the parent stream's\n * abort signal via `AbortSignal.any`. Function and MCP tools have\n * their own timeouts in their respective adapters and ignore this\n * setting. Default: `300_000` (5 minutes) — generous enough for cold\n * SQL Warehouse round-trips and long Genie conversations.\n */\n toolCallTimeoutMs?: number;\n };\n}\n\n/** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */\nexport type ResolvedToolEntry =\n | {\n source: \"toolkit\";\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"function\";\n functionTool: FunctionTool;\n def: AgentToolDefinition;\n }\n | {\n source: \"mcp\";\n mcpToolName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"subagent\";\n agentName: string;\n def: AgentToolDefinition;\n };\n\nexport interface RegisteredAgent {\n name: string;\n instructions: string;\n adapter: AgentAdapter;\n toolIndex: Map<string, ResolvedToolEntry>;\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */\n ephemeral?: boolean;\n}\n\n/**\n * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate\n * toolkit references from inline tools in a mixed `tools` record.\n */\nexport function isToolkitEntry(value: unknown): value is ToolkitEntry {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __toolkitRef?: unknown }).__toolkitRef === true\n );\n}\n"],"mappings":";;;;;AA+TA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
@@ -48,6 +48,7 @@ declare function createApp<T extends PluginData<PluginConstructor, unknown, stri
48
48
  cache?: CacheConfig;
49
49
  client?: WorkspaceClient;
50
50
  onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;
51
+ disableInternalTelemetry?: boolean;
51
52
  }): Promise<PluginMap<T>>;
52
53
  //#endregion
53
54
  export { createApp };
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgRsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;AAAA,IAEnD,OAAA,CAAQ,SAAA,CAAU,CAAA"}
1
+ {"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA2TsB,SAAA,WACV,UAAA,CAAW,iBAAA,qBAAA,CAErB,MAAA;EACE,OAAA,GAAU,CAAA;EACV,SAAA,GAAY,eAAA;EACZ,KAAA,GAAQ,WAAA;EACR,MAAA,GAAS,eAAA;EACT,cAAA,IAAkB,MAAA,EAAQ,SAAA,CAAU,CAAA,aAAc,OAAA;EAClD,wBAAA;AAAA,IAED,OAAA,CAAQ,SAAA,CAAU,CAAA"}
@@ -2,11 +2,16 @@ import { createLogger } from "../logging/logger.js";
2
2
  import { TelemetryManager } from "../telemetry/telemetry-manager.js";
3
3
  import "../telemetry/index.js";
4
4
  import { CacheManager } from "../cache/index.js";
5
+ import { version } from "../appkit/package.js";
5
6
  import { ServiceContext } from "../context/service-context.js";
6
7
  import { init_context } from "../context/index.js";
8
+ import { isInternalTelemetryEnabled } from "../internal-telemetry/config.js";
9
+ import { TelemetryReporter } from "../internal-telemetry/reporter.js";
10
+ import "../internal-telemetry/index.js";
7
11
  import { ResourceType } from "../registry/types.generated.js";
8
12
  import { ResourceRegistry } from "../registry/resource-registry.js";
9
13
  import "../registry/index.js";
14
+ import { PluginContext, isToolProvider } from "./plugin-context.js";
10
15
 
11
16
  //#region src/core/appkit.ts
12
17
  init_context();
@@ -14,28 +19,37 @@ const logger = createLogger("appkit");
14
19
  var AppKit = class AppKit {
15
20
  #pluginInstances = {};
16
21
  #setupPromises = [];
22
+ #context;
17
23
  constructor(config) {
18
24
  const { plugins, ...globalConfig } = config;
25
+ this.#context = new PluginContext();
19
26
  const pluginEntries = Object.entries(plugins);
20
27
  const corePlugins = pluginEntries.filter(([_, p]) => {
21
28
  return (p?.plugin?.phase ?? "normal") === "core";
22
29
  });
23
30
  const normalPlugins = pluginEntries.filter(([_, p]) => (p?.plugin?.phase ?? "normal") === "normal");
24
31
  const deferredPlugins = pluginEntries.filter(([_, p]) => (p?.plugin?.phase ?? "normal") === "deferred");
25
- for (const [name, pluginData] of corePlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData);
26
- for (const [name, pluginData] of normalPlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData);
27
- for (const [name, pluginData] of deferredPlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData, { plugins: this.#pluginInstances });
32
+ for (const [name, pluginData] of corePlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData, { context: this.#context });
33
+ for (const [name, pluginData] of normalPlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData, { context: this.#context });
34
+ for (const [name, pluginData] of deferredPlugins) if (pluginData) this.createAndRegisterPlugin(globalConfig, name, pluginData, { context: this.#context });
28
35
  }
29
36
  createAndRegisterPlugin(config, name, pluginData, extraData) {
30
37
  const { plugin: Plugin, config: pluginConfig } = pluginData;
31
- const pluginInstance = new Plugin({
38
+ const baseConfig = {
32
39
  ...config,
33
40
  ...Plugin.DEFAULT_CONFIG,
34
41
  ...pluginConfig,
35
42
  name,
36
43
  ...extraData
44
+ };
45
+ const pluginInstance = new Plugin(baseConfig);
46
+ if (typeof pluginInstance.attachContext === "function") pluginInstance.attachContext({
47
+ context: this.#context,
48
+ telemetryConfig: baseConfig.telemetry
37
49
  });
38
50
  this.#pluginInstances[name] = pluginInstance;
51
+ this.#context.registerPlugin(name, pluginInstance);
52
+ if (isToolProvider(pluginInstance)) this.#context.registerToolProvider(name, pluginInstance);
39
53
  this.#setupPromises.push(pluginInstance.setup());
40
54
  const self = this;
41
55
  Object.defineProperty(this, name, {
@@ -101,16 +115,29 @@ var AppKit = class AppKit {
101
115
  registry.enforceValidation();
102
116
  const instance = new AppKit({ plugins: AppKit.preparePlugins(rawPlugins) });
103
117
  await Promise.all(instance.#setupPromises);
118
+ await instance.#context.emitLifecycle("setup:complete");
104
119
  const handle = instance;
105
120
  if (config.onPluginsReady) {
106
121
  logger.debug("Running onPluginsReady hook");
107
122
  await config.onPluginsReady(handle);
108
123
  logger.debug("onPluginsReady hook completed");
109
124
  }
125
+ if (isInternalTelemetryEnabled(config)) AppKit.bootstrapInternalTelemetry();
110
126
  const serverPlugin = instance.#pluginInstances.server;
111
127
  if (serverPlugin && typeof serverPlugin.start === "function") await serverPlugin.start();
112
128
  return handle;
113
129
  }
130
+ static bootstrapInternalTelemetry() {
131
+ const serviceCtx = ServiceContext.get();
132
+ const reporter = TelemetryReporter.initialize({
133
+ workspaceId: serviceCtx.workspaceId,
134
+ client: serviceCtx.client,
135
+ appId: process.env.DATABRICKS_CLIENT_ID || "",
136
+ appkitVersion: version
137
+ });
138
+ reporter.start();
139
+ reporter.sendStartup().catch(() => {});
140
+ }
114
141
  static preparePlugins(plugins) {
115
142
  const result = {};
116
143
  for (const currentPlugin of plugins) result[currentPlugin.name] = {
@@ -1 +1 @@
1
- {"version":3,"file":"appkit.js","names":["#pluginInstances","#setupPromises"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport { createLogger } from \"../logging/logger\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData);\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n plugins: this.#pluginInstances,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (!Object.hasOwn(exports, key)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (AppKit.isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n *\n * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return objExports;\n }\n\n return {\n ...objExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) => {\n const userPlugin = (plugin as any).asUser(req);\n const userExports = (userPlugin.exports?.() ?? {}) as Record<\n string,\n unknown\n >;\n this.bindExportMethods(userExports, userPlugin);\n return userExports;\n },\n };\n }\n\n /**\n * Returns true if the value is a plain object (not an array, Date, etc.).\n */\n private static isPlainObject(\n value: unknown,\n ): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\n registry.enforceValidation();\n\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"appkit.js","names":["#context","#pluginInstances","#setupPromises","productVersion"],"sources":["../../src/core/appkit.ts"],"sourcesContent":["import type { WorkspaceClient } from \"@databricks/sdk-experimental\";\nimport type {\n BasePlugin,\n CacheConfig,\n InputPluginMap,\n OptionalConfigPluginDef,\n PluginConstructor,\n PluginData,\n PluginMap,\n} from \"shared\";\nimport { version as productVersion } from \"../../package.json\";\nimport { CacheManager } from \"../cache\";\nimport { ServiceContext } from \"../context\";\nimport {\n isInternalTelemetryEnabled,\n TelemetryReporter,\n} from \"../internal-telemetry\";\nimport { createLogger } from \"../logging/logger\";\nimport { ResourceRegistry, ResourceType } from \"../registry\";\nimport type { TelemetryConfig } from \"../telemetry\";\nimport { TelemetryManager } from \"../telemetry\";\nimport { isToolProvider, PluginContext } from \"./plugin-context\";\n\nconst logger = createLogger(\"appkit\");\n\nexport class AppKit<TPlugins extends InputPluginMap> {\n #pluginInstances: Record<string, BasePlugin> = {};\n #setupPromises: Promise<void>[] = [];\n #context: PluginContext;\n\n private constructor(config: { plugins: TPlugins }) {\n const { plugins, ...globalConfig } = config;\n\n this.#context = new PluginContext();\n\n const pluginEntries = Object.entries(plugins);\n\n const corePlugins = pluginEntries.filter(([_, p]) => {\n return (p?.plugin?.phase ?? \"normal\") === \"core\";\n });\n const normalPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"normal\",\n );\n const deferredPlugins = pluginEntries.filter(\n ([_, p]) => (p?.plugin?.phase ?? \"normal\") === \"deferred\",\n );\n\n for (const [name, pluginData] of corePlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of normalPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n\n for (const [name, pluginData] of deferredPlugins) {\n if (pluginData) {\n this.createAndRegisterPlugin(globalConfig, name, pluginData, {\n context: this.#context,\n });\n }\n }\n }\n\n private createAndRegisterPlugin<T extends PluginConstructor>(\n config: Omit<{ plugins: TPlugins }, \"plugins\">,\n name: string,\n pluginData: OptionalConfigPluginDef<T>,\n extraData?: Record<string, unknown>,\n ) {\n const { plugin: Plugin, config: pluginConfig } = pluginData;\n const baseConfig = {\n ...config,\n ...Plugin.DEFAULT_CONFIG,\n ...pluginConfig,\n name,\n ...extraData,\n };\n const pluginInstance = new Plugin(baseConfig);\n\n if (typeof pluginInstance.attachContext === \"function\") {\n pluginInstance.attachContext({\n context: this.#context,\n telemetryConfig: baseConfig.telemetry,\n });\n }\n\n this.#pluginInstances[name] = pluginInstance;\n\n this.#context.registerPlugin(name, pluginInstance);\n if (isToolProvider(pluginInstance)) {\n this.#context.registerToolProvider(name, pluginInstance);\n }\n\n this.#setupPromises.push(pluginInstance.setup());\n\n const self = this;\n\n Object.defineProperty(this, name, {\n get() {\n const plugin = self.#pluginInstances[name];\n return self.wrapWithAsUser(plugin);\n },\n enumerable: true,\n });\n }\n\n /**\n * Binds all function properties in an exports object to the given context.\n * Recurses into plain objects to handle nested APIs (e.g., volume APIs).\n */\n private bindExportMethods(\n exports: Record<string, unknown>,\n context: BasePlugin,\n ) {\n for (const key in exports) {\n if (!Object.hasOwn(exports, key)) continue;\n const val = exports[key];\n if (typeof val === \"function\") {\n exports[key] = (val as (...args: unknown[]) => unknown).bind(context);\n } else if (AppKit.isPlainObject(val)) {\n this.bindExportMethods(val as Record<string, unknown>, context);\n }\n }\n }\n\n /**\n * Wraps a plugin's exports with an `asUser` method that returns\n * a user-scoped version of the exports.\n *\n * When `exports()` returns a callable (function), it is returned as-is\n * since the plugin manages its own `asUser` per-call (e.g. files plugin).\n * When it returns a plain object, the standard `asUser` wrapper is added.\n */\n private wrapWithAsUser<T extends BasePlugin>(plugin: T) {\n // If plugin doesn't implement exports(), return empty object\n const pluginExports = plugin.exports?.() ?? {};\n\n // If exports is a function, the plugin manages its own asUser pattern\n if (typeof pluginExports === \"function\") {\n return pluginExports;\n }\n\n const objExports = pluginExports as Record<string, unknown>;\n this.bindExportMethods(objExports, plugin);\n\n // If plugin doesn't support asUser (no asUser method), return exports as-is\n if (typeof (plugin as any).asUser !== \"function\") {\n return objExports;\n }\n\n return {\n ...objExports,\n /**\n * Execute operations using the user's identity from the request.\n * Returns user-scoped exports where all methods execute with the\n * user's Databricks credentials instead of the service principal.\n */\n asUser: (req: import(\"express\").Request) => {\n const userPlugin = (plugin as any).asUser(req);\n const userExports = (userPlugin.exports?.() ?? {}) as Record<\n string,\n unknown\n >;\n this.bindExportMethods(userExports, userPlugin);\n return userExports;\n },\n };\n }\n\n /**\n * Returns true if the value is a plain object (not an array, Date, etc.).\n */\n private static isPlainObject(\n value: unknown,\n ): value is Record<string, unknown> {\n if (typeof value !== \"object\" || value === null) return false;\n const proto = Object.getPrototypeOf(value);\n return proto === Object.prototype || proto === null;\n }\n\n static async _createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n >(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n ): Promise<PluginMap<T>> {\n // Initialize core services\n TelemetryManager.initialize(config?.telemetry);\n await CacheManager.getInstance(config?.cache);\n\n const rawPlugins = config.plugins as T;\n\n // Collect manifest resources via registry\n const registry = new ResourceRegistry();\n registry.collectResources(rawPlugins);\n\n // Derive ServiceContext needs from what manifests declared\n const needsWarehouse = registry\n .getRequired()\n .some((r) => r.type === ResourceType.SQL_WAREHOUSE);\n await ServiceContext.initialize(\n { warehouseId: needsWarehouse },\n config?.client,\n );\n\n // Validate env vars\n registry.enforceValidation();\n\n const preparedPlugins = AppKit.preparePlugins(rawPlugins);\n const mergedConfig = {\n plugins: preparedPlugins,\n };\n\n const instance = new AppKit(mergedConfig);\n\n await Promise.all(instance.#setupPromises);\n await instance.#context.emitLifecycle(\"setup:complete\");\n\n const handle = instance as unknown as PluginMap<T>;\n\n if (config.onPluginsReady) {\n logger.debug(\"Running onPluginsReady hook\");\n await config.onPluginsReady(handle);\n logger.debug(\"onPluginsReady hook completed\");\n }\n\n if (isInternalTelemetryEnabled(config)) {\n AppKit.bootstrapInternalTelemetry();\n }\n\n const serverPlugin = instance.#pluginInstances.server;\n if (serverPlugin && typeof (serverPlugin as any).start === \"function\") {\n await (serverPlugin as any).start();\n }\n\n return handle;\n }\n\n private static bootstrapInternalTelemetry(): void {\n const serviceCtx = ServiceContext.get();\n const reporter = TelemetryReporter.initialize({\n workspaceId: serviceCtx.workspaceId,\n client: serviceCtx.client,\n appId: process.env.DATABRICKS_CLIENT_ID || \"\",\n appkitVersion: productVersion,\n });\n reporter.start();\n reporter.sendStartup().catch(() => {});\n }\n\n private static preparePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n ) {\n const result: InputPluginMap = {};\n for (const currentPlugin of plugins) {\n result[currentPlugin.name] = {\n plugin: currentPlugin.plugin,\n config: currentPlugin.config as Record<string, unknown>,\n };\n }\n return result;\n }\n}\n\n/**\n * Bootstraps AppKit with the provided configuration.\n *\n * Initializes telemetry, cache, and service context, then registers plugins\n * in phase order (core, normal, deferred) and awaits their setup.\n * If a `onPluginsReady` callback is provided it runs after plugin setup but\n * before the server starts, giving you access to the full appkit handle\n * for registering custom routes or performing async setup.\n * The returned object maps each plugin name to its `exports()` API,\n * with an `asUser(req)` method for user-scoped execution.\n *\n * @returns A `PluginMap` keyed by plugin name with typed exports\n *\n * @example Minimal server\n * ```ts\n * import { createApp, server } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server()],\n * });\n * ```\n *\n * @example Server with custom routes via onPluginsReady\n * ```ts\n * import { createApp, server, analytics } from \"@databricks/appkit\";\n *\n * await createApp({\n * plugins: [server(), analytics({})],\n * onPluginsReady(appkit) {\n * appkit.server.extend((app) => {\n * app.get(\"/custom\", (_req, res) => res.json({ ok: true }));\n * });\n * },\n * });\n * ```\n */\nexport async function createApp<\n T extends PluginData<PluginConstructor, unknown, string>[],\n>(\n config: {\n plugins?: T;\n telemetry?: TelemetryConfig;\n cache?: CacheConfig;\n client?: WorkspaceClient;\n onPluginsReady?: (appkit: PluginMap<T>) => void | Promise<void>;\n disableInternalTelemetry?: boolean;\n } = {},\n): Promise<PluginMap<T>> {\n return AppKit._createApp(config);\n}\n"],"mappings":"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"}