@databricks/appkit 0.47.1 → 0.49.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 +11 -1
- package/dist/agents/databricks.d.ts +24 -7
- package/dist/agents/databricks.d.ts.map +1 -1
- package/dist/agents/databricks.js +25 -0
- package/dist/agents/databricks.js.map +1 -1
- package/dist/agents/supervisor-api.d.ts +362 -0
- package/dist/agents/supervisor-api.d.ts.map +1 -0
- package/dist/agents/supervisor-api.js +498 -0
- package/dist/agents/supervisor-api.js.map +1 -0
- package/dist/appkit/package.js +1 -1
- package/dist/beta.d.ts +2 -1
- package/dist/beta.js +2 -1
- package/dist/cli/commands/lint.js +6 -0
- package/dist/cli/commands/lint.js.map +1 -1
- package/dist/connectors/serving/client.d.ts +24 -0
- package/dist/connectors/serving/client.d.ts.map +1 -0
- package/dist/connectors/serving/client.js +34 -14
- package/dist/connectors/serving/client.js.map +1 -1
- package/dist/core/agent/run-agent.d.ts.map +1 -1
- package/dist/core/agent/run-agent.js +51 -2
- package/dist/core/agent/run-agent.js.map +1 -1
- package/dist/core/agent/types.d.ts +19 -3
- package/dist/core/agent/types.d.ts.map +1 -1
- package/dist/core/agent/types.js.map +1 -1
- package/dist/core/appkit.d.ts.map +1 -1
- package/dist/core/appkit.js +39 -1
- package/dist/core/appkit.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js +65 -5
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/files/plugin.js +2 -2
- package/dist/plugins/jobs/plugin.js +2 -2
- package/dist/plugins/serving/serving.js +2 -2
- package/dist/plugins/ui-variants/choice-sink.js +70 -0
- package/dist/plugins/ui-variants/choice-sink.js.map +1 -0
- package/dist/plugins/ui-variants/index.js +94 -0
- package/dist/plugins/ui-variants/index.js.map +1 -0
- package/dist/plugins/ui-variants/manifest.js +17 -0
- package/dist/plugins/ui-variants/manifest.js.map +1 -0
- package/dist/registry/manifest-loader.d.ts +1 -1
- package/dist/schemas/manifest.d.ts +1 -0
- package/dist/schemas/manifest.d.ts.map +1 -1
- package/dist/schemas/manifest.js +1 -0
- package/dist/schemas/manifest.js.map +1 -1
- package/dist/shared/src/agent.d.ts +28 -0
- package/dist/shared/src/agent.d.ts.map +1 -1
- package/dist/shared/src/plugin.d.ts +3 -1
- package/dist/shared/src/plugin.d.ts.map +1 -1
- package/dist/shared/src/schemas/manifest.d.ts +3 -2
- package/dist/shared/src/schemas/manifest.d.ts.map +1 -1
- package/dist/stream/index.js +1 -0
- package/dist/stream/sse-reader.js +86 -0
- package/dist/stream/sse-reader.js.map +1 -0
- package/docs/api/appkit/Class.DatabricksAdapter.md +34 -0
- package/docs/api/appkit/Class.SupervisorApiAdapter.md +121 -0
- package/docs/api/appkit/Function.fromSupervisorApi.md +63 -0
- package/docs/api/appkit/Function.isSupervisorTool.md +18 -0
- package/docs/api/appkit/Interface.AgentAdapter.md +24 -0
- package/docs/api/appkit/Interface.AgentInput.md +13 -0
- package/docs/api/appkit/Interface.HostedSupervisorTool.md +21 -0
- package/docs/api/appkit/Interface.PluginManifest.md +27 -9
- package/docs/api/appkit/Interface.SupervisorApiAdapterOptions.md +38 -0
- package/docs/api/appkit/Interface.SupervisorExtension.md +12 -0
- package/docs/api/appkit/Interface.WorkspaceClientLike.md +67 -0
- package/docs/api/appkit/TypeAlias.AgentTool.md +3 -2
- package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +167 -0
- package/docs/api/appkit/TypeAlias.SupervisorTool.md +45 -0
- package/docs/api/appkit/Variable.SUPERVISOR_EXTENSION_KEY.md +8 -0
- package/docs/api/appkit/Variable.supervisorTools.md +176 -0
- package/docs/api/appkit.md +118 -108
- package/docs/plugins/agents.md +131 -1
- package/docs/plugins/manifest.md +12 -11
- package/llms.txt +11 -1
- package/package.json +2 -1
- package/sbom.cdx.json +1 -1
- package/scripts/postinstall.js +0 -1
- package/skills/appkit-ui-variants/SKILL.md +183 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n];\n\nfunction isTestFile(filePath: string, rootDir: string): boolean {\n // Relative to scan root: an ancestor `tests` dir must not mark the whole project as tests.\n const rel = path.relative(rootDir, filePath);\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(rel) || /(^|[/\\\\])tests[/\\\\]/.test(rel)\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(\n filePath: string,\n rules: Rule[],\n rootDir: string,\n): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath, rootDir);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules, rootDir);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit lint`,\n )\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACF;AAED,SAAS,WAAW,UAAkB,SAA0B;CAE9D,MAAM,MAAM,KAAK,SAAS,SAAS,SAAS;AAC5C,QACE,2BAA2B,KAAK,IAAI,IAAI,sBAAsB,KAAK,IAAI;;AAI3E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SACP,UACA,OACA,SACa;CACb,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,UAAU,QAAQ;CAG9C,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,OAAO,QAAQ;AACjD,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,YACC,SACA;;iBAGD,CACA,OAAO,QAAQ"}
|
|
1
|
+
{"version":3,"file":"lint.js","names":[],"sources":["../../../src/cli/commands/lint.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { Lang, parse } from \"@ast-grep/napi\";\nimport { Command } from \"commander\";\n\ninterface Rule {\n id: string;\n pattern: string;\n message: string;\n includeTests?: boolean;\n filter?: (code: string) => boolean;\n}\n\nconst rules: Rule[] = [\n {\n id: \"no-double-type-assertion\",\n pattern: \"$X as unknown as $Y\",\n message:\n \"Avoid double type assertion (as unknown as). Use proper type guards or fix the source type.\",\n },\n {\n id: \"no-as-any\",\n pattern: \"$X as any\",\n message:\n 'Avoid \"as any\" type assertion. Use proper typing or unknown with type guards.',\n includeTests: false, // acceptable in test mocks\n },\n {\n id: \"no-array-index-key\",\n pattern: \"key={$IDX}\",\n message:\n \"Avoid using array index as React key. Use a stable unique identifier.\",\n filter: (code) => /key=\\{(idx|index|i)\\}/.test(code),\n },\n {\n id: \"no-parse-float-without-validation\",\n pattern: \"parseFloat($X).toFixed($Y)\",\n message:\n \"parseFloat can return NaN. Validate input or use toNumber() helper from shared/types.ts.\",\n },\n {\n // <Variants> is the dev-only variant picker from @databricks/appkit-ui,\n // meant to drive the local edit loop. Finalize the chosen variant before\n // deploying so the picker chrome never reaches production.\n id: \"no-variants-in-prod\",\n pattern: \"<Variants $$$P>$$$C</Variants>\",\n message:\n \"<Variants> is a development-only variant picker and must not be shipped. Finalize the chosen <Variant> before deploying.\",\n includeTests: false,\n },\n];\n\nfunction isTestFile(filePath: string, rootDir: string): boolean {\n // Relative to scan root: an ancestor `tests` dir must not mark the whole project as tests.\n const rel = path.relative(rootDir, filePath);\n return (\n /\\.(test|spec)\\.(ts|tsx)$/.test(rel) || /(^|[/\\\\])tests[/\\\\]/.test(rel)\n );\n}\n\nfunction findTsFiles(dir: string, files: string[] = []): string[] {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n\n if (entry.isDirectory()) {\n if ([\"node_modules\", \"dist\", \"build\", \".git\"].includes(entry.name))\n continue;\n findTsFiles(fullPath, files);\n } else if (entry.isFile() && /\\.(ts|tsx)$/.test(entry.name)) {\n files.push(fullPath);\n }\n }\n\n return files;\n}\n\ninterface Violation {\n file: string;\n line: number;\n column: number;\n rule: string;\n message: string;\n code: string;\n}\n\nfunction lintFile(\n filePath: string,\n rules: Rule[],\n rootDir: string,\n): Violation[] {\n const violations: Violation[] = [];\n const content = fs.readFileSync(filePath, \"utf-8\");\n const lang = filePath.endsWith(\".tsx\") ? Lang.Tsx : Lang.TypeScript;\n const testFile = isTestFile(filePath, rootDir);\n\n const ast = parse(lang, content);\n const root = ast.root();\n\n for (const rule of rules) {\n // skip rules that don't apply to test files\n if (testFile && rule.includeTests === false) continue;\n\n const matches = root.findAll(rule.pattern);\n\n for (const match of matches) {\n const code = match.text();\n\n if (rule.filter && !rule.filter(code)) continue;\n\n const range = match.range();\n violations.push({\n file: filePath,\n line: range.start.line + 1,\n column: range.start.column + 1,\n rule: rule.id,\n message: rule.message,\n code: code.length > 80 ? `${code.slice(0, 77)}...` : code,\n });\n }\n }\n\n return violations;\n}\n\n/**\n * Lint command implementation\n */\nfunction runLint() {\n const rootDir = process.cwd();\n const files = findTsFiles(rootDir);\n\n console.log(`Scanning ${files.length} TypeScript files...\\n`);\n\n const allViolations: Violation[] = [];\n\n for (const file of files) {\n const violations = lintFile(file, rules, rootDir);\n allViolations.push(...violations);\n }\n\n if (allViolations.length === 0) {\n console.log(\"No ast-grep lint violations found.\");\n process.exit(0);\n }\n\n console.log(`Found ${allViolations.length} violation(s):\\n`);\n\n for (const v of allViolations) {\n const relPath = path.relative(rootDir, v.file);\n console.log(`${relPath}:${v.line}:${v.column}`);\n console.log(` ${v.rule}: ${v.message}`);\n console.log(` > ${v.code}\\n`);\n }\n\n process.exit(1);\n}\n\nexport const lintCommand = new Command(\"lint\")\n .description(\"Run AST-based linting on TypeScript files\")\n .addHelpText(\n \"after\",\n `\nExamples:\n $ appkit lint`,\n )\n .action(runLint);\n"],"mappings":";;;;;;AAaA,MAAM,QAAgB;CACpB;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACF,SAAS,SAAS,wBAAwB,KAAK,KAAK;EACrD;CACD;EACE,IAAI;EACJ,SAAS;EACT,SACE;EACH;CACD;EAIE,IAAI;EACJ,SAAS;EACT,SACE;EACF,cAAc;EACf;CACF;AAED,SAAS,WAAW,UAAkB,SAA0B;CAE9D,MAAM,MAAM,KAAK,SAAS,SAAS,SAAS;AAC5C,QACE,2BAA2B,KAAK,IAAI,IAAI,sBAAsB,KAAK,IAAI;;AAI3E,SAAS,YAAY,KAAa,QAAkB,EAAE,EAAY;CAChE,MAAM,UAAU,GAAG,YAAY,KAAK,EAAE,eAAe,MAAM,CAAC;AAE5D,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,WAAW,KAAK,KAAK,KAAK,MAAM,KAAK;AAE3C,MAAI,MAAM,aAAa,EAAE;AACvB,OAAI;IAAC;IAAgB;IAAQ;IAAS;IAAO,CAAC,SAAS,MAAM,KAAK,CAChE;AACF,eAAY,UAAU,MAAM;aACnB,MAAM,QAAQ,IAAI,cAAc,KAAK,MAAM,KAAK,CACzD,OAAM,KAAK,SAAS;;AAIxB,QAAO;;AAYT,SAAS,SACP,UACA,OACA,SACa;CACb,MAAM,aAA0B,EAAE;CAClC,MAAM,UAAU,GAAG,aAAa,UAAU,QAAQ;CAClD,MAAM,OAAO,SAAS,SAAS,OAAO,GAAG,KAAK,MAAM,KAAK;CACzD,MAAM,WAAW,WAAW,UAAU,QAAQ;CAG9C,MAAM,OADM,MAAM,MAAM,QAAQ,CACf,MAAM;AAEvB,MAAK,MAAM,QAAQ,OAAO;AAExB,MAAI,YAAY,KAAK,iBAAiB,MAAO;EAE7C,MAAM,UAAU,KAAK,QAAQ,KAAK,QAAQ;AAE1C,OAAK,MAAM,SAAS,SAAS;GAC3B,MAAM,OAAO,MAAM,MAAM;AAEzB,OAAI,KAAK,UAAU,CAAC,KAAK,OAAO,KAAK,CAAE;GAEvC,MAAM,QAAQ,MAAM,OAAO;AAC3B,cAAW,KAAK;IACd,MAAM;IACN,MAAM,MAAM,MAAM,OAAO;IACzB,QAAQ,MAAM,MAAM,SAAS;IAC7B,MAAM,KAAK;IACX,SAAS,KAAK;IACd,MAAM,KAAK,SAAS,KAAK,GAAG,KAAK,MAAM,GAAG,GAAG,CAAC,OAAO;IACtD,CAAC;;;AAIN,QAAO;;;;;AAMT,SAAS,UAAU;CACjB,MAAM,UAAU,QAAQ,KAAK;CAC7B,MAAM,QAAQ,YAAY,QAAQ;AAElC,SAAQ,IAAI,YAAY,MAAM,OAAO,wBAAwB;CAE7D,MAAM,gBAA6B,EAAE;AAErC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,aAAa,SAAS,MAAM,OAAO,QAAQ;AACjD,gBAAc,KAAK,GAAG,WAAW;;AAGnC,KAAI,cAAc,WAAW,GAAG;AAC9B,UAAQ,IAAI,qCAAqC;AACjD,UAAQ,KAAK,EAAE;;AAGjB,SAAQ,IAAI,SAAS,cAAc,OAAO,kBAAkB;AAE5D,MAAK,MAAM,KAAK,eAAe;EAC7B,MAAM,UAAU,KAAK,SAAS,SAAS,EAAE,KAAK;AAC9C,UAAQ,IAAI,GAAG,QAAQ,GAAG,EAAE,KAAK,GAAG,EAAE,SAAS;AAC/C,UAAQ,IAAI,KAAK,EAAE,KAAK,IAAI,EAAE,UAAU;AACxC,UAAQ,IAAI,OAAO,EAAE,KAAK,IAAI;;AAGhC,SAAQ,KAAK,EAAE;;AAGjB,MAAa,cAAc,IAAI,QAAQ,OAAO,CAC3C,YAAY,4CAA4C,CACxD,YACC,SACA;;iBAGD,CACA,OAAO,QAAQ"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { WorkspaceClient } from "@databricks/sdk-experimental";
|
|
2
|
+
|
|
3
|
+
//#region src/connectors/serving/client.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Structural shape of a Databricks SDK client we need for the low-level
|
|
6
|
+
* `apiClient.request` call. Lets `streamPath` be reused by adapters that
|
|
7
|
+
* don't want a hard dependency on the concrete `WorkspaceClient` type.
|
|
8
|
+
*/
|
|
9
|
+
interface ApiClientLike {
|
|
10
|
+
apiClient: {
|
|
11
|
+
request(options: Record<string, unknown>, context?: unknown): Promise<unknown>;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Transport shim shared by the agent adapters: given a request body, returns
|
|
16
|
+
* the raw SSE byte stream from a serving / AI-gateway endpoint. Injected at
|
|
17
|
+
* adapter construction time so callers can swap in the workspace SDK (the
|
|
18
|
+
* factory paths via {@link streamPath}), a bare `fetch` (a reverse proxy /
|
|
19
|
+
* mock), or a test fake.
|
|
20
|
+
*/
|
|
21
|
+
type StreamBody = (body: Record<string, unknown>, signal?: AbortSignal) => Promise<ReadableStream<Uint8Array>>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { ApiClientLike, StreamBody };
|
|
24
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","names":[],"sources":["../../../src/connectors/serving/client.ts"],"mappings":";;;;;AAgDA;;;UAAiB,aAAA;EACf,SAAA;IACE,OAAA,CACE,OAAA,EAAS,MAAA,mBACT,OAAA,aACC,OAAA;EAAA;AAAA;;;;;AAWP;;;KAAY,UAAA,IACV,IAAA,EAAM,MAAA,mBACN,MAAA,GAAS,WAAA,KACN,OAAA,CAAQ,cAAA,CAAe,UAAA"}
|
|
@@ -39,34 +39,54 @@ async function invoke(client, endpointName, body) {
|
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
43
|
-
* No parsing is performed — bytes are passed through as-is.
|
|
42
|
+
* POSTs `body` as JSON to an arbitrary workspace API path and returns the raw
|
|
43
|
+
* SSE byte stream. No parsing is performed — bytes are passed through as-is.
|
|
44
44
|
*
|
|
45
|
-
* Uses the SDK's low-level `apiClient.request({ raw: true })`
|
|
46
|
-
* the
|
|
47
|
-
*
|
|
45
|
+
* Uses the SDK's low-level `apiClient.request({ raw: true })` so callers
|
|
46
|
+
* inherit URL resolution, the SDK credential chain (PAT/OAuth/OIDC), and
|
|
47
|
+
* any future retries/telemetry baked into the SDK transport.
|
|
48
|
+
*
|
|
49
|
+
* When `signal` is provided it is bridged to the SDK's `Context` /
|
|
50
|
+
* `CancellationToken` so aborts cancel the outbound HTTP request.
|
|
51
|
+
*
|
|
52
|
+
* @internal
|
|
53
|
+
*
|
|
54
|
+
* Not part of the public AppKit surface. `path` is passed through to the
|
|
55
|
+
* SDK without any allowlist — exposing this to user-controlled input would
|
|
56
|
+
* turn it into workspace-credentialled SSRF (CWE-918). Internal callers
|
|
57
|
+
* must hard-code the path (or build it from a closed enum). New callers
|
|
58
|
+
* inside the package: keep this constraint, and do not re-export from
|
|
59
|
+
* `beta.ts` or any other entry point.
|
|
48
60
|
*/
|
|
49
|
-
async function
|
|
50
|
-
|
|
51
|
-
logger.debug("Streaming from endpoint %s", endpointName);
|
|
61
|
+
async function streamPath(client, path, body, signal) {
|
|
62
|
+
logger.debug("Streaming from path %s", path);
|
|
52
63
|
const context = signal ? new Context({ cancellationToken: cancellationTokenFromAbortSignal(signal) }) : void 0;
|
|
53
64
|
const response = await client.apiClient.request({
|
|
54
|
-
path
|
|
65
|
+
path,
|
|
55
66
|
method: "POST",
|
|
56
67
|
headers: new Headers({
|
|
57
68
|
"Content-Type": "application/json",
|
|
58
69
|
Accept: "text/event-stream"
|
|
59
70
|
}),
|
|
60
|
-
payload:
|
|
61
|
-
...cleanBody,
|
|
62
|
-
stream: true
|
|
63
|
-
},
|
|
71
|
+
payload: body,
|
|
64
72
|
raw: true
|
|
65
73
|
}, context);
|
|
66
74
|
if (!response.contents) throw new Error("Response body is null — streaming not supported");
|
|
67
75
|
return response.contents;
|
|
68
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Returns the raw SSE byte stream from a serving endpoint. Thin wrapper over
|
|
79
|
+
* {@link streamPath} that handles serving-specific URL encoding and forces
|
|
80
|
+
* `stream: true` in the payload.
|
|
81
|
+
*/
|
|
82
|
+
async function stream(client, endpointName, body, signal) {
|
|
83
|
+
const { stream: _stream, ...cleanBody } = body;
|
|
84
|
+
return streamPath(client, `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`, {
|
|
85
|
+
...cleanBody,
|
|
86
|
+
stream: true
|
|
87
|
+
}, signal);
|
|
88
|
+
}
|
|
69
89
|
|
|
70
90
|
//#endregion
|
|
71
|
-
export { invoke, stream };
|
|
91
|
+
export { invoke, stream, streamPath };
|
|
72
92
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {\n CancellationToken,\n serving,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { Context } from \"@databricks/sdk-experimental\";\nimport { createLogger } from \"../../logging/logger\";\n\nconst logger = createLogger(\"connectors:serving\");\n\n/**\n * Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so\n * `apiClient.request` can abort the outbound HTTP request (and stop pulling\n * the SSE body) when the agent run is cancelled.\n */\nfunction cancellationTokenFromAbortSignal(\n signal: AbortSignal,\n): CancellationToken {\n const listeners = new Set<() => void>();\n const fire = () => {\n for (const cb of listeners) {\n try {\n cb();\n } catch {\n // ignore listener failures — abort must stay best-effort\n }\n }\n };\n signal.addEventListener(\"abort\", fire, { passive: true });\n\n return {\n get isCancellationRequested() {\n return signal.aborted;\n },\n onCancellationRequested(callback: (e?: unknown) => unknown) {\n listeners.add(callback as () => void);\n if (signal.aborted) {\n void callback();\n }\n },\n };\n}\n\n/**\n * Invokes a serving endpoint using the SDK's high-level query API.\n * Returns a typed QueryEndpointResponse.\n */\nexport async function invoke(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n): Promise<serving.QueryEndpointResponse> {\n // Strip `stream` from the body — the connector controls this\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Invoking endpoint %s\", endpointName);\n\n return client.servingEndpoints.query({\n name: endpointName,\n ...cleanBody,\n } as serving.QueryEndpointInput);\n}\n\n/**\n *
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../../src/connectors/serving/client.ts"],"sourcesContent":["import type {\n CancellationToken,\n serving,\n WorkspaceClient,\n} from \"@databricks/sdk-experimental\";\nimport { Context } from \"@databricks/sdk-experimental\";\nimport { createLogger } from \"../../logging/logger\";\n\nconst logger = createLogger(\"connectors:serving\");\n\n/**\n * Bridges {@link AbortSignal} to the SDK's {@link CancellationToken} so\n * `apiClient.request` can abort the outbound HTTP request (and stop pulling\n * the SSE body) when the agent run is cancelled.\n */\nfunction cancellationTokenFromAbortSignal(\n signal: AbortSignal,\n): CancellationToken {\n const listeners = new Set<() => void>();\n const fire = () => {\n for (const cb of listeners) {\n try {\n cb();\n } catch {\n // ignore listener failures — abort must stay best-effort\n }\n }\n };\n signal.addEventListener(\"abort\", fire, { passive: true });\n\n return {\n get isCancellationRequested() {\n return signal.aborted;\n },\n onCancellationRequested(callback: (e?: unknown) => unknown) {\n listeners.add(callback as () => void);\n if (signal.aborted) {\n void callback();\n }\n },\n };\n}\n\n/**\n * Structural shape of a Databricks SDK client we need for the low-level\n * `apiClient.request` call. Lets `streamPath` be reused by adapters that\n * don't want a hard dependency on the concrete `WorkspaceClient` type.\n */\nexport interface ApiClientLike {\n apiClient: {\n request(\n options: Record<string, unknown>,\n context?: unknown,\n ): Promise<unknown>;\n };\n}\n\n/**\n * Transport shim shared by the agent adapters: given a request body, returns\n * the raw SSE byte stream from a serving / AI-gateway endpoint. Injected at\n * adapter construction time so callers can swap in the workspace SDK (the\n * factory paths via {@link streamPath}), a bare `fetch` (a reverse proxy /\n * mock), or a test fake.\n */\nexport type StreamBody = (\n body: Record<string, unknown>,\n signal?: AbortSignal,\n) => Promise<ReadableStream<Uint8Array>>;\n\n/**\n * Invokes a serving endpoint using the SDK's high-level query API.\n * Returns a typed QueryEndpointResponse.\n */\nexport async function invoke(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n): Promise<serving.QueryEndpointResponse> {\n // Strip `stream` from the body — the connector controls this\n const { stream: _stream, ...cleanBody } = body;\n\n logger.debug(\"Invoking endpoint %s\", endpointName);\n\n return client.servingEndpoints.query({\n name: endpointName,\n ...cleanBody,\n } as serving.QueryEndpointInput);\n}\n\n/**\n * POSTs `body` as JSON to an arbitrary workspace API path and returns the raw\n * SSE byte stream. No parsing is performed — bytes are passed through as-is.\n *\n * Uses the SDK's low-level `apiClient.request({ raw: true })` so callers\n * inherit URL resolution, the SDK credential chain (PAT/OAuth/OIDC), and\n * any future retries/telemetry baked into the SDK transport.\n *\n * When `signal` is provided it is bridged to the SDK's `Context` /\n * `CancellationToken` so aborts cancel the outbound HTTP request.\n *\n * @internal\n *\n * Not part of the public AppKit surface. `path` is passed through to the\n * SDK without any allowlist — exposing this to user-controlled input would\n * turn it into workspace-credentialled SSRF (CWE-918). Internal callers\n * must hard-code the path (or build it from a closed enum). New callers\n * inside the package: keep this constraint, and do not re-export from\n * `beta.ts` or any other entry point.\n */\nexport async function streamPath(\n client: ApiClientLike,\n path: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n logger.debug(\"Streaming from path %s\", path);\n\n const context = signal\n ? new Context({\n cancellationToken: cancellationTokenFromAbortSignal(signal),\n })\n : undefined;\n\n const response = (await client.apiClient.request(\n {\n path,\n method: \"POST\",\n headers: new Headers({\n \"Content-Type\": \"application/json\",\n Accept: \"text/event-stream\",\n }),\n payload: body,\n raw: true,\n },\n context,\n )) as { contents: ReadableStream<Uint8Array> | null };\n\n if (!response.contents) {\n throw new Error(\"Response body is null — streaming not supported\");\n }\n\n return response.contents;\n}\n\n/**\n * Returns the raw SSE byte stream from a serving endpoint. Thin wrapper over\n * {@link streamPath} that handles serving-specific URL encoding and forces\n * `stream: true` in the payload.\n */\nexport async function stream(\n client: WorkspaceClient,\n endpointName: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n): Promise<ReadableStream<Uint8Array>> {\n const { stream: _stream, ...cleanBody } = body;\n return streamPath(\n client as unknown as ApiClientLike,\n `/serving-endpoints/${encodeURIComponent(endpointName)}/invocations`,\n { ...cleanBody, stream: true },\n signal,\n );\n}\n"],"mappings":";;;;AAQA,MAAM,SAAS,aAAa,qBAAqB;;;;;;AAOjD,SAAS,iCACP,QACmB;CACnB,MAAM,4BAAY,IAAI,KAAiB;CACvC,MAAM,aAAa;AACjB,OAAK,MAAM,MAAM,UACf,KAAI;AACF,OAAI;UACE;;AAKZ,QAAO,iBAAiB,SAAS,MAAM,EAAE,SAAS,MAAM,CAAC;AAEzD,QAAO;EACL,IAAI,0BAA0B;AAC5B,UAAO,OAAO;;EAEhB,wBAAwB,UAAoC;AAC1D,aAAU,IAAI,SAAuB;AACrC,OAAI,OAAO,QACT,CAAK,UAAU;;EAGpB;;;;;;AAiCH,eAAsB,OACpB,QACA,cACA,MACwC;CAExC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAE1C,QAAO,MAAM,wBAAwB,aAAa;AAElD,QAAO,OAAO,iBAAiB,MAAM;EACnC,MAAM;EACN,GAAG;EACJ,CAA+B;;;;;;;;;;;;;;;;;;;;;;AAuBlC,eAAsB,WACpB,QACA,MACA,MACA,QACqC;AACrC,QAAO,MAAM,0BAA0B,KAAK;CAE5C,MAAM,UAAU,SACZ,IAAI,QAAQ,EACV,mBAAmB,iCAAiC,OAAO,EAC5D,CAAC,GACF;CAEJ,MAAM,WAAY,MAAM,OAAO,UAAU,QACvC;EACE;EACA,QAAQ;EACR,SAAS,IAAI,QAAQ;GACnB,gBAAgB;GAChB,QAAQ;GACT,CAAC;EACF,SAAS;EACT,KAAK;EACN,EACD,QACD;AAED,KAAI,CAAC,SAAS,SACZ,OAAM,IAAI,MAAM,kDAAkD;AAGpE,QAAO,SAAS;;;;;;;AAQlB,eAAsB,OACpB,QACA,cACA,MACA,QACqC;CACrC,MAAM,EAAE,QAAQ,SAAS,GAAG,cAAc;AAC1C,QAAO,WACL,QACA,sBAAsB,mBAAmB,aAAa,CAAC,eACvD;EAAE,GAAG;EAAW,QAAQ;EAAM,EAC9B,OACD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"mappings":";;;;;;
|
|
1
|
+
{"version":3,"file":"run-agent.d.ts","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"mappings":";;;;;;UAoCiB,aAAA;;EAEf,QAAA,WAAmB,OAAA;;EAEnB,MAAA,GAAS,WAAA;EAJmB;;;;;;;EAY5B,OAAA,GAAU,UAAA,CAAW,iBAAA;AAAA;AAAA,UAGN,cAAA;EAXf;EAaA,IAAA;EALA;EAOA,MAAA,EAAQ,UAAA;AAAA;;;AAJV;;;;;;;;;AAmCA;;;;;;;;;;;;;;;;;iBAAsB,QAAA,CACpB,GAAA,EAAK,eAAA,EACL,KAAA,EAAO,aAAA,GACN,OAAA,CAAQ,cAAA"}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createLogger } from "../../logging/logger.js";
|
|
2
|
+
import { SUPERVISOR_EXTENSION_KEY, isSupervisorTool } from "../../agents/supervisor-api.js";
|
|
1
3
|
import { consumeAdapterStream } from "./consume-adapter-stream.js";
|
|
2
4
|
import { createPluginsProxy } from "./plugins-map.js";
|
|
3
5
|
import { resolveToolkitFromProvider } from "./toolkit-resolver.js";
|
|
@@ -7,6 +9,7 @@ import { isToolkitEntry } from "./types.js";
|
|
|
7
9
|
import { randomUUID } from "node:crypto";
|
|
8
10
|
|
|
9
11
|
//#region src/core/agent/run-agent.ts
|
|
12
|
+
const logger = createLogger("agent:run-agent");
|
|
10
13
|
/**
|
|
11
14
|
* Standalone agent execution without `createApp`. Resolves the adapter, binds
|
|
12
15
|
* inline tools, and drives the adapter's `run()` loop to completion.
|
|
@@ -44,7 +47,8 @@ async function runAgentInternal(def, input, providerCache) {
|
|
|
44
47
|
const adapter = await resolveAdapter(def);
|
|
45
48
|
const messages = normalizeMessages(input.messages, def.instructions);
|
|
46
49
|
const toolIndex = buildStandaloneToolIndex(def, input.plugins ?? [], providerCache);
|
|
47
|
-
const tools = Array.from(toolIndex.values()).map((e) => e.def);
|
|
50
|
+
const tools = Array.from(toolIndex.values()).filter((e) => e.kind !== "hosted-supervisor").map((e) => e.def);
|
|
51
|
+
warnOnCapabilityMismatch(def.name ?? "<anonymous>", adapter, toolIndex);
|
|
48
52
|
const signal = input.signal;
|
|
49
53
|
const executeTool = async (name, args) => {
|
|
50
54
|
const entry = toolIndex.get(name);
|
|
@@ -59,6 +63,7 @@ async function runAgentInternal(def, input, providerCache) {
|
|
|
59
63
|
};
|
|
60
64
|
return (await runAgentInternal(entry.agentDef, subInput, providerCache)).text;
|
|
61
65
|
}
|
|
66
|
+
if (entry.kind === "hosted-supervisor") throw new Error(`runAgent: tool "${name}" is a hosted-supervisor tool, executed server-side by the Databricks AI Gateway. It must not be invoked from the Node process.`);
|
|
62
67
|
throw new Error(`runAgent: tool "${name}" is a ${entry.kind} tool. Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).`);
|
|
63
68
|
};
|
|
64
69
|
const events = [];
|
|
@@ -67,7 +72,8 @@ async function runAgentInternal(def, input, providerCache) {
|
|
|
67
72
|
messages,
|
|
68
73
|
tools,
|
|
69
74
|
threadId: randomUUID(),
|
|
70
|
-
signal
|
|
75
|
+
signal,
|
|
76
|
+
extensions: buildStandaloneExtensions(toolIndex)
|
|
71
77
|
}, {
|
|
72
78
|
executeTool,
|
|
73
79
|
signal
|
|
@@ -228,9 +234,52 @@ function classifyTool(key, tool, providerCache) {
|
|
|
228
234
|
name: key
|
|
229
235
|
}
|
|
230
236
|
};
|
|
237
|
+
if (isSupervisorTool(tool)) return {
|
|
238
|
+
kind: "hosted-supervisor",
|
|
239
|
+
spec: tool.spec,
|
|
240
|
+
def: {
|
|
241
|
+
name: key,
|
|
242
|
+
description: supervisorToolDescription(tool.spec),
|
|
243
|
+
parameters: {
|
|
244
|
+
type: "object",
|
|
245
|
+
properties: {}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
};
|
|
231
249
|
if (isHostedTool(tool)) throw new Error(`runAgent: tool "${key}" is a hosted tool (type="${tool.type}") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`);
|
|
232
250
|
throw new Error(`runAgent: unrecognized tool shape at key "${key}"`);
|
|
233
251
|
}
|
|
252
|
+
/** Mirrors `agents.ts`'s `supervisorToolDescription`. */
|
|
253
|
+
function supervisorToolDescription(spec) {
|
|
254
|
+
switch (spec.type) {
|
|
255
|
+
case "genie_space": return spec.genie_space.description;
|
|
256
|
+
case "uc_function": return spec.uc_function.description;
|
|
257
|
+
case "knowledge_assistant": return spec.knowledge_assistant.description;
|
|
258
|
+
case "app": return spec.app.description;
|
|
259
|
+
case "uc_connection": return spec.uc_connection.description;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
/** Mirrors `agents.ts`'s `buildAdapterExtensions`. */
|
|
263
|
+
function buildStandaloneExtensions(toolIndex) {
|
|
264
|
+
const supervisorSpecs = [];
|
|
265
|
+
for (const entry of toolIndex.values()) if (entry.kind === "hosted-supervisor") supervisorSpecs.push(entry.spec);
|
|
266
|
+
if (supervisorSpecs.length === 0) return void 0;
|
|
267
|
+
return { [SUPERVISOR_EXTENSION_KEY]: { hostedTools: supervisorSpecs } };
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Mirrors the agents-plugin capability warning so standalone `runAgent`
|
|
271
|
+
* produces the same diagnostic when adapter capabilities don't match the
|
|
272
|
+
* tool index. Warn-not-throw: doesn't abort batch evals.
|
|
273
|
+
*/
|
|
274
|
+
function warnOnCapabilityMismatch(agentName, adapter, toolIndex) {
|
|
275
|
+
const accepted = new Set(adapter.acceptsExtensions ?? []);
|
|
276
|
+
const hostedSupervisorKeys = [];
|
|
277
|
+
const inputToolKeys = [];
|
|
278
|
+
for (const [key, entry] of toolIndex) if (entry.kind === "hosted-supervisor") hostedSupervisorKeys.push(key);
|
|
279
|
+
else inputToolKeys.push(key);
|
|
280
|
+
if (hostedSupervisorKeys.length > 0 && !accepted.has(SUPERVISOR_EXTENSION_KEY)) logger.warn(`Agent '${agentName}' declares hosted-supervisor tools (${hostedSupervisorKeys.join(", ")}) but its model adapter does not accept the 'databricks.supervisor' extension. Pair them with \`DatabricksAdapter.fromSupervisorApi(...)\`, or remove them.`);
|
|
281
|
+
if (adapter.consumesInputTools === false && inputToolKeys.length > 0) logger.warn(`Agent '${agentName}' declares function tools / sub-agents (${inputToolKeys.join(", ")}) but its model adapter does not consume input.tools. These tools will not be exposed to the model.`);
|
|
282
|
+
}
|
|
234
283
|
function providerCacheLookup(pluginName, cache) {
|
|
235
284
|
const cached = cache.get(pluginName);
|
|
236
285
|
if (cached) return cached;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-agent.js","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n AgentAdapter,\n AgentEvent,\n AgentToolDefinition,\n Message,\n PluginConstructor,\n PluginData,\n ToolProvider,\n} from \"shared\";\nimport { consumeAdapterStream } from \"./consume-adapter-stream\";\nimport { createPluginsProxy } from \"./plugins-map\";\nimport { resolveToolkitFromProvider } from \"./toolkit-resolver\";\nimport {\n type FunctionTool,\n functionToolToDefinition,\n isFunctionTool,\n} from \"./tools/function-tool\";\nimport { isHostedTool } from \"./tools/hosted-tools\";\nimport type {\n AgentDefinition,\n AgentTool,\n AgentTools,\n Plugins,\n PluginToolkitProvider,\n} from \"./types\";\nimport { isToolkitEntry } from \"./types\";\n\nexport interface RunAgentInput {\n /** Seed messages for the run. Either a single user string or a full message list. */\n messages: string | Message[];\n /** Abort signal for cancellation. */\n signal?: AbortSignal;\n /**\n * Optional plugin list. Required when `def.tools` is the function form\n * `(plugins) => Record<string, AgentTool>` and the function dereferences\n * any plugins. `runAgent` constructs a fresh instance per plugin and\n * dispatches tool calls against it as the service principal (no OBO —\n * there is no HTTP request in standalone mode).\n */\n plugins?: PluginData<PluginConstructor, unknown, string>[];\n}\n\nexport interface RunAgentResult {\n /** Aggregated text output from all `message_delta` events. */\n text: string;\n /** Every event the adapter yielded, in order. Useful for inspection/tests. */\n events: AgentEvent[];\n}\n\n/**\n * Standalone agent execution without `createApp`. Resolves the adapter, binds\n * inline tools, and drives the adapter's `run()` loop to completion.\n *\n * Limitations vs. running through the agents() plugin:\n * - **No OBO and no approval gate** — there is no HTTP request, so plugin\n * tools run as the service principal. The agents-plugin approval gate\n * that prompts for human confirmation on `effect: \"write\" | \"update\" |\n * \"destructive\"` tools is also absent. LLM-controlled tool arguments\n * flow straight through to the SP. Treat standalone runAgent as a\n * trusted-prompt environment (CI, batch eval, internal scripts) — not\n * as an exposed user-facing surface.\n * - **Hosted tools (MCP) are not supported** — they require a live MCP\n * client that only exists inside the agents plugin's lifecycle.\n * `runAgent` rejects them at index-build time with a clear error.\n * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested\n * `runAgent` calls with no shared thread state. Plugin instances ARE\n * shared across the recursion (same cache as the parent).\n * - **Plugin tools** (used inside the function form via\n * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via\n * `RunAgentInput`. Each plugin in that array is constructed once,\n * `attachContext({})` and `await setup()` are called eagerly, and the\n * resulting instance is shared across the top-level run and all\n * sub-agent recursions. Plugins whose `setup()` requires runtime that\n * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,\n * `PluginContext`) throw at standalone-init time with a clear \"use\n * createApp instead\" message — not mid-stream.\n */\nexport async function runAgent(\n def: AgentDefinition,\n input: RunAgentInput,\n): Promise<RunAgentResult> {\n // Single shared cache for the whole call graph: parent + every nested\n // sub-agent dispatch share constructed plugin instances. Without this,\n // each nested `runAgent` would build its own cache, re-instantiate every\n // plugin, and silently diverge in-instance state between parent and child\n // (e.g. query result caches, connection pools).\n const providerCache = new Map<string, ToolProvider>();\n await initStandalonePlugins(input.plugins ?? [], providerCache);\n return runAgentInternal(def, input, providerCache);\n}\n\nasync function runAgentInternal(\n def: AgentDefinition,\n input: RunAgentInput,\n providerCache: Map<string, ToolProvider>,\n): Promise<RunAgentResult> {\n const adapter = await resolveAdapter(def);\n const messages = normalizeMessages(input.messages, def.instructions);\n const toolIndex = buildStandaloneToolIndex(\n def,\n input.plugins ?? [],\n providerCache,\n );\n const tools = Array.from(toolIndex.values()).map((e) => e.def);\n\n const signal = input.signal;\n\n const executeTool = async (name: string, args: unknown): Promise<unknown> => {\n const entry = toolIndex.get(name);\n if (!entry) throw new Error(`Unknown tool: ${name}`);\n if (entry.kind === \"function\") {\n return entry.tool.execute(args as Record<string, unknown>);\n }\n if (entry.kind === \"toolkit\") {\n return entry.provider.executeAgentTool(\n entry.localName,\n args as Record<string, unknown>,\n signal,\n );\n }\n if (entry.kind === \"subagent\") {\n const subInput: RunAgentInput = {\n messages:\n typeof args === \"object\" &&\n args !== null &&\n typeof (args as { input?: unknown }).input === \"string\"\n ? (args as { input: string }).input\n : JSON.stringify(args),\n signal,\n plugins: input.plugins,\n };\n // Reuse the same `providerCache` so sub-agent plugin tools dispatch\n // through the same instances the parent constructed.\n const res = await runAgentInternal(\n entry.agentDef,\n subInput,\n providerCache,\n );\n return res.text;\n }\n throw new Error(\n `runAgent: tool \"${name}\" is a ${entry.kind} tool. ` +\n \"Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).\",\n );\n };\n\n const events: AgentEvent[] = [];\n\n const stream = adapter.run(\n {\n messages,\n tools,\n threadId: randomUUID(),\n signal,\n },\n { executeTool, signal },\n );\n\n // Shared accumulation rule (deltas append, `message` replaces). The\n // `events` array is filled via the `onEvent` side effect so callers that\n // inspect the raw stream still get the full record.\n const text = await consumeAdapterStream(stream, {\n signal,\n onEvent: (event) => {\n events.push(event);\n },\n });\n\n return { text, events };\n}\n\n/**\n * Eagerly construct every plugin in `input.plugins`, run the standard\n * AppKit lifecycle (`attachContext({})` + `await setup()`), and populate\n * `cache`. Failures here surface BEFORE any adapter work — mid-stream\n * `getWorkspaceClient is not initialised`-style errors become a clear\n * startup failure naming the plugin and pointing the user at `createApp`.\n *\n * Plugins that don't need runtime context (no overridden `setup`, or one\n * that doesn't dereference `createApp`-only state) initialise cleanly and\n * standalone runAgent works as documented. Plugins like analytics/files\n * that depend on `WorkspaceClient` will throw the underlying error wrapped\n * with the migration hint.\n */\nasync function initStandalonePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n cache: Map<string, ToolProvider>,\n): Promise<void> {\n for (const data of plugins) {\n if (cache.has(data.name)) continue;\n const instance = new data.plugin({\n ...(data.config ?? {}),\n name: data.name,\n });\n if (!isStandaloneToolProvider(instance)) {\n throw new Error(\n `runAgent: plugin '${data.name}' is not a ToolProvider ` +\n \"(missing getAgentTools/executeAgentTool). Only ToolProvider plugins \" +\n \"are supported in standalone runAgent.\",\n );\n }\n if (\n typeof (instance as { attachContext?: unknown }).attachContext ===\n \"function\"\n ) {\n try {\n (\n instance as { attachContext: (deps: Record<string, unknown>) => void }\n ).attachContext({});\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' attachContext() failed in ` +\n \"standalone mode. This plugin probably depends on createApp's \" +\n \"runtime (WorkspaceClient, ServiceContext, PluginContext). Run \" +\n \"via createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n if (typeof (instance as { setup?: unknown }).setup === \"function\") {\n try {\n await (instance as { setup: () => Promise<void> | void }).setup();\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' setup() failed in standalone ` +\n \"mode. This plugin probably depends on createApp's runtime \" +\n \"(WorkspaceClient, ServiceContext, PluginContext). Run via \" +\n \"createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n cache.set(data.name, instance);\n }\n}\n\nasync function resolveAdapter(def: AgentDefinition): Promise<AgentAdapter> {\n const { model } = def;\n if (!model) {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing();\n }\n if (typeof model === \"string\") {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing(model);\n }\n return await model;\n}\n\nfunction normalizeMessages(\n input: string | Message[],\n instructions: string,\n): Message[] {\n const systemMessage: Message = {\n id: \"system\",\n role: \"system\",\n content: instructions,\n createdAt: new Date(),\n };\n if (typeof input === \"string\") {\n return [\n systemMessage,\n {\n id: randomUUID(),\n role: \"user\",\n content: input,\n createdAt: new Date(),\n },\n ];\n }\n return [systemMessage, ...input];\n}\n\ntype StandaloneEntry =\n | {\n kind: \"function\";\n def: AgentToolDefinition;\n tool: FunctionTool;\n }\n | {\n kind: \"subagent\";\n def: AgentToolDefinition;\n agentDef: AgentDefinition;\n }\n | {\n kind: \"toolkit\";\n def: AgentToolDefinition;\n provider: ToolProvider;\n pluginName: string;\n localName: string;\n }\n | {\n kind: \"hosted\";\n def: AgentToolDefinition;\n };\n\n/**\n * Resolves `def.tools` (object or function form) and `def.agents`\n * (sub-agents) into a flat dispatch index. The function form is invoked\n * once per call against a {@link Plugins} map drawn from the shared\n * `providerCache` populated by {@link initStandalonePlugins}. Missing\n * references throw a named \"not registered\" error via the proxy.\n */\nfunction buildStandaloneToolIndex(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Map<string, StandaloneEntry> {\n const index = new Map<string, StandaloneEntry>();\n const tools = resolveDefTools(def, plugins, providerCache);\n\n for (const [key, tool] of Object.entries(tools)) {\n index.set(key, classifyTool(key, tool, providerCache));\n }\n\n for (const [childKey, child] of Object.entries(def.agents ?? {})) {\n const toolName = `agent-${childKey}`;\n index.set(toolName, {\n kind: \"subagent\",\n agentDef: { ...child, name: child.name ?? childKey },\n def: {\n name: toolName,\n description:\n child.instructions.slice(0, 120) ||\n `Delegate to the ${childKey} sub-agent`,\n parameters: {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"Message to send to the sub-agent.\",\n },\n },\n required: [\"input\"],\n },\n },\n });\n }\n\n return index;\n}\n\n/**\n * Resolves `def.tools` to a plain record. The function form is invoked\n * with a typed {@link Plugins} map drawn from the pre-populated\n * `providerCache`; each `plugins.foo.toolkit(opts)` lookup hits the cache\n * directly (no construction at toolkit-call time).\n */\nfunction resolveDefTools(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): AgentTools {\n if (typeof def.tools !== \"function\") {\n return def.tools ?? {};\n }\n const pluginsMap = buildStandalonePluginsMap(plugins, providerCache);\n try {\n return def.tools(pluginsMap);\n } catch (err) {\n const name = def.name ?? \"<anonymous>\";\n throw new Error(\n `runAgent: agent '${name}' tools(plugins) callback threw: ${\n err instanceof Error ? err.message : String(err)\n }`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n}\n\n/**\n * Builds the typed {@link Plugins} map passed to the function form of\n * `def.tools` in standalone mode. Reads pre-constructed instances from\n * `providerCache` (populated eagerly by {@link initStandalonePlugins})\n * and wraps the result in a Proxy so unknown plugin names produce a\n * named \"not registered, Available: ...\" error instead of bubbling up a\n * generic `TypeError: Cannot read properties of undefined`.\n */\nfunction buildStandalonePluginsMap(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Plugins {\n const out: Record<string, PluginToolkitProvider> = {};\n for (const data of plugins) {\n const provider = providerCache.get(data.name);\n if (!provider) continue; // initStandalonePlugins should have set this\n out[data.name] = {\n toolkit: (opts) => resolveToolkitFromProvider(data.name, provider, opts),\n };\n }\n return createPluginsProxy(out, \"runAgent: tools(plugins)\");\n}\n\nfunction classifyTool(\n key: string,\n tool: AgentTool,\n providerCache: Map<string, ToolProvider>,\n): StandaloneEntry {\n if (isToolkitEntry(tool)) {\n // Toolkit entries inside the function form's returned record carry the\n // provider name they came from, so we can resolve the provider on\n // demand and dispatch through it. The cache is shared with the\n // pluginsMap path so the same instance is reused.\n const provider = providerCacheLookup(tool.pluginName, providerCache);\n return {\n kind: \"toolkit\",\n provider,\n pluginName: tool.pluginName,\n localName: tool.localName,\n def: { ...tool.def, name: key },\n };\n }\n if (isFunctionTool(tool)) {\n return {\n kind: \"function\",\n tool,\n def: { ...functionToolToDefinition(tool), name: key },\n };\n }\n if (isHostedTool(tool)) {\n // Hosted tools (e.g. MCP `mcpServer(...)`) need a live MCP client that\n // only exists inside the agents plugin's lifecycle. In standalone\n // `runAgent` they would have errored at dispatch time with a confusing\n // mid-conversation failure; reject them up front so misconfiguration\n // surfaces before the adapter sees the tool list.\n throw new Error(\n `runAgent: tool \"${key}\" is a hosted tool (type=\"${tool.type}\") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`,\n );\n }\n throw new Error(`runAgent: unrecognized tool shape at key \"${key}\"`);\n}\n\nfunction providerCacheLookup(\n pluginName: string,\n cache: Map<string, ToolProvider>,\n): ToolProvider {\n const cached = cache.get(pluginName);\n if (cached) return cached;\n const available = Array.from(cache.keys()).join(\", \") || \"(none)\";\n throw new Error(\n `runAgent: tool refers to plugin '${pluginName}', but no instance was ` +\n \"initialised for that name. Add it to RunAgentInput.plugins, or — if \" +\n \"this came from a hand-rolled ToolkitEntry — go through \" +\n `plugins[name].toolkit() instead. Available: ${available}.`,\n );\n}\n\n/**\n * Lightweight `ToolProvider` shape check used by standalone `runAgent`.\n *\n * Distinct from `core/plugin-context.isToolProvider` which also requires\n * `asUser` (request-scoped, only meaningful when running inside `createApp`\n * with a live HTTP context). Standalone plugins are constructed without a\n * `WorkspaceClient` and have no request to scope to, so checking only the\n * two `ToolProvider` methods is the right narrowing here.\n */\nfunction isStandaloneToolProvider(value: unknown): value is ToolProvider {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.getAgentTools === \"function\" &&\n typeof obj.executeAgentTool === \"function\"\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"run-agent.js","names":[],"sources":["../../../src/core/agent/run-agent.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport type {\n AgentAdapter,\n AgentEvent,\n AgentToolDefinition,\n Message,\n PluginConstructor,\n PluginData,\n ToolProvider,\n} from \"shared\";\nimport {\n isSupervisorTool,\n SUPERVISOR_EXTENSION_KEY,\n type SupervisorTool,\n} from \"../../agents/supervisor-api\";\nimport { createLogger } from \"../../logging/logger\";\nimport { consumeAdapterStream } from \"./consume-adapter-stream\";\nimport { createPluginsProxy } from \"./plugins-map\";\nimport { resolveToolkitFromProvider } from \"./toolkit-resolver\";\nimport {\n type FunctionTool,\n functionToolToDefinition,\n isFunctionTool,\n} from \"./tools/function-tool\";\nimport { isHostedTool } from \"./tools/hosted-tools\";\nimport type {\n AgentDefinition,\n AgentTool,\n AgentTools,\n Plugins,\n PluginToolkitProvider,\n} from \"./types\";\nimport { isToolkitEntry } from \"./types\";\n\nconst logger = createLogger(\"agent:run-agent\");\n\nexport interface RunAgentInput {\n /** Seed messages for the run. Either a single user string or a full message list. */\n messages: string | Message[];\n /** Abort signal for cancellation. */\n signal?: AbortSignal;\n /**\n * Optional plugin list. Required when `def.tools` is the function form\n * `(plugins) => Record<string, AgentTool>` and the function dereferences\n * any plugins. `runAgent` constructs a fresh instance per plugin and\n * dispatches tool calls against it as the service principal (no OBO —\n * there is no HTTP request in standalone mode).\n */\n plugins?: PluginData<PluginConstructor, unknown, string>[];\n}\n\nexport interface RunAgentResult {\n /** Aggregated text output from all `message_delta` events. */\n text: string;\n /** Every event the adapter yielded, in order. Useful for inspection/tests. */\n events: AgentEvent[];\n}\n\n/**\n * Standalone agent execution without `createApp`. Resolves the adapter, binds\n * inline tools, and drives the adapter's `run()` loop to completion.\n *\n * Limitations vs. running through the agents() plugin:\n * - **No OBO and no approval gate** — there is no HTTP request, so plugin\n * tools run as the service principal. The agents-plugin approval gate\n * that prompts for human confirmation on `effect: \"write\" | \"update\" |\n * \"destructive\"` tools is also absent. LLM-controlled tool arguments\n * flow straight through to the SP. Treat standalone runAgent as a\n * trusted-prompt environment (CI, batch eval, internal scripts) — not\n * as an exposed user-facing surface.\n * - **Hosted tools (MCP) are not supported** — they require a live MCP\n * client that only exists inside the agents plugin's lifecycle.\n * `runAgent` rejects them at index-build time with a clear error.\n * - **Sub-agents** (`agents: { ... }` on the def) are executed as nested\n * `runAgent` calls with no shared thread state. Plugin instances ARE\n * shared across the recursion (same cache as the parent).\n * - **Plugin tools** (used inside the function form via\n * `plugins.<name>.toolkit(...)`) require passing `plugins: [...]` via\n * `RunAgentInput`. Each plugin in that array is constructed once,\n * `attachContext({})` and `await setup()` are called eagerly, and the\n * resulting instance is shared across the top-level run and all\n * sub-agent recursions. Plugins whose `setup()` requires runtime that\n * only `createApp` provides (e.g. `WorkspaceClient`, `ServiceContext`,\n * `PluginContext`) throw at standalone-init time with a clear \"use\n * createApp instead\" message — not mid-stream.\n */\nexport async function runAgent(\n def: AgentDefinition,\n input: RunAgentInput,\n): Promise<RunAgentResult> {\n // Single shared cache for the whole call graph: parent + every nested\n // sub-agent dispatch share constructed plugin instances. Without this,\n // each nested `runAgent` would build its own cache, re-instantiate every\n // plugin, and silently diverge in-instance state between parent and child\n // (e.g. query result caches, connection pools).\n const providerCache = new Map<string, ToolProvider>();\n await initStandalonePlugins(input.plugins ?? [], providerCache);\n return runAgentInternal(def, input, providerCache);\n}\n\nasync function runAgentInternal(\n def: AgentDefinition,\n input: RunAgentInput,\n providerCache: Map<string, ToolProvider>,\n): Promise<RunAgentResult> {\n const adapter = await resolveAdapter(def);\n const messages = normalizeMessages(input.messages, def.instructions);\n const toolIndex = buildStandaloneToolIndex(\n def,\n input.plugins ?? [],\n providerCache,\n );\n // Hosted-supervisor entries are routed via `extensions`, not as callable\n // tools — exclude their placeholder `def` from the wire `tools` array.\n const tools = Array.from(toolIndex.values())\n .filter((e) => e.kind !== \"hosted-supervisor\")\n .map((e) => e.def);\n\n warnOnCapabilityMismatch(def.name ?? \"<anonymous>\", adapter, toolIndex);\n\n const signal = input.signal;\n\n const executeTool = async (name: string, args: unknown): Promise<unknown> => {\n const entry = toolIndex.get(name);\n if (!entry) throw new Error(`Unknown tool: ${name}`);\n if (entry.kind === \"function\") {\n return entry.tool.execute(args as Record<string, unknown>);\n }\n if (entry.kind === \"toolkit\") {\n return entry.provider.executeAgentTool(\n entry.localName,\n args as Record<string, unknown>,\n signal,\n );\n }\n if (entry.kind === \"subagent\") {\n const subInput: RunAgentInput = {\n messages:\n typeof args === \"object\" &&\n args !== null &&\n typeof (args as { input?: unknown }).input === \"string\"\n ? (args as { input: string }).input\n : JSON.stringify(args),\n signal,\n plugins: input.plugins,\n };\n // Reuse the same `providerCache` so sub-agent plugin tools dispatch\n // through the same instances the parent constructed.\n const res = await runAgentInternal(\n entry.agentDef,\n subInput,\n providerCache,\n );\n return res.text;\n }\n if (entry.kind === \"hosted-supervisor\") {\n // Defense-in-depth: should never fire. The placeholder def is\n // filtered out of `tools` above, so the model never sees a callable\n // schema for hosted-supervisor entries. If we ever reach here, the\n // model was somehow handed the def and tried to invoke it directly.\n throw new Error(\n `runAgent: tool \"${name}\" is a hosted-supervisor tool, executed server-side by the Databricks AI Gateway. It must not be invoked from the Node process.`,\n );\n }\n throw new Error(\n `runAgent: tool \"${name}\" is a ${entry.kind} tool. ` +\n \"Hosted/MCP tools are only usable via createApp({ plugins: [..., agents(...)] }).\",\n );\n };\n\n const events: AgentEvent[] = [];\n\n const stream = adapter.run(\n {\n messages,\n tools,\n threadId: randomUUID(),\n signal,\n extensions: buildStandaloneExtensions(toolIndex),\n },\n { executeTool, signal },\n );\n\n // Shared accumulation rule (deltas append, `message` replaces). The\n // `events` array is filled via the `onEvent` side effect so callers that\n // inspect the raw stream still get the full record.\n const text = await consumeAdapterStream(stream, {\n signal,\n onEvent: (event) => {\n events.push(event);\n },\n });\n\n return { text, events };\n}\n\n/**\n * Eagerly construct every plugin in `input.plugins`, run the standard\n * AppKit lifecycle (`attachContext({})` + `await setup()`), and populate\n * `cache`. Failures here surface BEFORE any adapter work — mid-stream\n * `getWorkspaceClient is not initialised`-style errors become a clear\n * startup failure naming the plugin and pointing the user at `createApp`.\n *\n * Plugins that don't need runtime context (no overridden `setup`, or one\n * that doesn't dereference `createApp`-only state) initialise cleanly and\n * standalone runAgent works as documented. Plugins like analytics/files\n * that depend on `WorkspaceClient` will throw the underlying error wrapped\n * with the migration hint.\n */\nasync function initStandalonePlugins(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n cache: Map<string, ToolProvider>,\n): Promise<void> {\n for (const data of plugins) {\n if (cache.has(data.name)) continue;\n const instance = new data.plugin({\n ...(data.config ?? {}),\n name: data.name,\n });\n if (!isStandaloneToolProvider(instance)) {\n throw new Error(\n `runAgent: plugin '${data.name}' is not a ToolProvider ` +\n \"(missing getAgentTools/executeAgentTool). Only ToolProvider plugins \" +\n \"are supported in standalone runAgent.\",\n );\n }\n if (\n typeof (instance as { attachContext?: unknown }).attachContext ===\n \"function\"\n ) {\n try {\n (\n instance as { attachContext: (deps: Record<string, unknown>) => void }\n ).attachContext({});\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' attachContext() failed in ` +\n \"standalone mode. This plugin probably depends on createApp's \" +\n \"runtime (WorkspaceClient, ServiceContext, PluginContext). Run \" +\n \"via createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n if (typeof (instance as { setup?: unknown }).setup === \"function\") {\n try {\n await (instance as { setup: () => Promise<void> | void }).setup();\n } catch (err) {\n throw new Error(\n `runAgent: plugin '${data.name}' setup() failed in standalone ` +\n \"mode. This plugin probably depends on createApp's runtime \" +\n \"(WorkspaceClient, ServiceContext, PluginContext). Run via \" +\n \"createApp({ plugins: [..., agents(...)] }) instead. \" +\n `Cause: ${err instanceof Error ? err.message : String(err)}`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n }\n cache.set(data.name, instance);\n }\n}\n\nasync function resolveAdapter(def: AgentDefinition): Promise<AgentAdapter> {\n const { model } = def;\n if (!model) {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing();\n }\n if (typeof model === \"string\") {\n const { DatabricksAdapter } = await import(\"../../agents/databricks\");\n return DatabricksAdapter.fromModelServing(model);\n }\n return await model;\n}\n\nfunction normalizeMessages(\n input: string | Message[],\n instructions: string,\n): Message[] {\n const systemMessage: Message = {\n id: \"system\",\n role: \"system\",\n content: instructions,\n createdAt: new Date(),\n };\n if (typeof input === \"string\") {\n return [\n systemMessage,\n {\n id: randomUUID(),\n role: \"user\",\n content: input,\n createdAt: new Date(),\n },\n ];\n }\n return [systemMessage, ...input];\n}\n\ntype StandaloneEntry =\n | {\n kind: \"function\";\n def: AgentToolDefinition;\n tool: FunctionTool;\n }\n | {\n kind: \"subagent\";\n def: AgentToolDefinition;\n agentDef: AgentDefinition;\n }\n | {\n kind: \"toolkit\";\n def: AgentToolDefinition;\n provider: ToolProvider;\n pluginName: string;\n localName: string;\n }\n | {\n kind: \"hosted\";\n def: AgentToolDefinition;\n }\n | {\n /**\n * Adapter-side hosted tool. Standalone `runAgent` accepts these\n * (unlike MCP hosted tools, which need a live MCP client) because\n * the adapter has everything it needs to execute them server-side:\n * the spec travels via `AgentInput.extensions` and the SA endpoint\n * runs the tool loop. Enables batch-eval / CI use of supervisor\n * agents without `createApp`.\n */\n kind: \"hosted-supervisor\";\n def: AgentToolDefinition;\n spec: SupervisorTool;\n };\n\n/**\n * Resolves `def.tools` (object or function form) and `def.agents`\n * (sub-agents) into a flat dispatch index. The function form is invoked\n * once per call against a {@link Plugins} map drawn from the shared\n * `providerCache` populated by {@link initStandalonePlugins}. Missing\n * references throw a named \"not registered\" error via the proxy.\n */\nfunction buildStandaloneToolIndex(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Map<string, StandaloneEntry> {\n const index = new Map<string, StandaloneEntry>();\n const tools = resolveDefTools(def, plugins, providerCache);\n\n for (const [key, tool] of Object.entries(tools)) {\n index.set(key, classifyTool(key, tool, providerCache));\n }\n\n for (const [childKey, child] of Object.entries(def.agents ?? {})) {\n const toolName = `agent-${childKey}`;\n index.set(toolName, {\n kind: \"subagent\",\n agentDef: { ...child, name: child.name ?? childKey },\n def: {\n name: toolName,\n description:\n child.instructions.slice(0, 120) ||\n `Delegate to the ${childKey} sub-agent`,\n parameters: {\n type: \"object\",\n properties: {\n input: {\n type: \"string\",\n description: \"Message to send to the sub-agent.\",\n },\n },\n required: [\"input\"],\n },\n },\n });\n }\n\n return index;\n}\n\n/**\n * Resolves `def.tools` to a plain record. The function form is invoked\n * with a typed {@link Plugins} map drawn from the pre-populated\n * `providerCache`; each `plugins.foo.toolkit(opts)` lookup hits the cache\n * directly (no construction at toolkit-call time).\n */\nfunction resolveDefTools(\n def: AgentDefinition,\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): AgentTools {\n if (typeof def.tools !== \"function\") {\n return def.tools ?? {};\n }\n const pluginsMap = buildStandalonePluginsMap(plugins, providerCache);\n try {\n return def.tools(pluginsMap);\n } catch (err) {\n const name = def.name ?? \"<anonymous>\";\n throw new Error(\n `runAgent: agent '${name}' tools(plugins) callback threw: ${\n err instanceof Error ? err.message : String(err)\n }`,\n { cause: err instanceof Error ? err : undefined },\n );\n }\n}\n\n/**\n * Builds the typed {@link Plugins} map passed to the function form of\n * `def.tools` in standalone mode. Reads pre-constructed instances from\n * `providerCache` (populated eagerly by {@link initStandalonePlugins})\n * and wraps the result in a Proxy so unknown plugin names produce a\n * named \"not registered, Available: ...\" error instead of bubbling up a\n * generic `TypeError: Cannot read properties of undefined`.\n */\nfunction buildStandalonePluginsMap(\n plugins: PluginData<PluginConstructor, unknown, string>[],\n providerCache: Map<string, ToolProvider>,\n): Plugins {\n const out: Record<string, PluginToolkitProvider> = {};\n for (const data of plugins) {\n const provider = providerCache.get(data.name);\n if (!provider) continue; // initStandalonePlugins should have set this\n out[data.name] = {\n toolkit: (opts) => resolveToolkitFromProvider(data.name, provider, opts),\n };\n }\n return createPluginsProxy(out, \"runAgent: tools(plugins)\");\n}\n\nfunction classifyTool(\n key: string,\n tool: AgentTool,\n providerCache: Map<string, ToolProvider>,\n): StandaloneEntry {\n if (isToolkitEntry(tool)) {\n // Toolkit entries inside the function form's returned record carry the\n // provider name they came from, so we can resolve the provider on\n // demand and dispatch through it. The cache is shared with the\n // pluginsMap path so the same instance is reused.\n const provider = providerCacheLookup(tool.pluginName, providerCache);\n return {\n kind: \"toolkit\",\n provider,\n pluginName: tool.pluginName,\n localName: tool.localName,\n def: { ...tool.def, name: key },\n };\n }\n if (isFunctionTool(tool)) {\n return {\n kind: \"function\",\n tool,\n def: { ...functionToolToDefinition(tool), name: key },\n };\n }\n // Supervisor-API hosted tools work in standalone mode: the adapter\n // executes them server-side via `AgentInput.extensions`, no MCP client\n // required. Must come BEFORE the `isHostedTool` MCP rejection — the two\n // predicates classify disjoint values (`isSupervisorTool` matches the\n // `__kind` tag; `isHostedTool` matches the wire-format `type` field),\n // but the placement makes the intent explicit.\n if (isSupervisorTool(tool)) {\n return {\n kind: \"hosted-supervisor\",\n spec: tool.spec,\n def: {\n name: key,\n description: supervisorToolDescription(tool.spec),\n parameters: { type: \"object\", properties: {} },\n },\n };\n }\n if (isHostedTool(tool)) {\n // Hosted tools (e.g. MCP `mcpServer(...)`) need a live MCP client that\n // only exists inside the agents plugin's lifecycle. In standalone\n // `runAgent` they would have errored at dispatch time with a confusing\n // mid-conversation failure; reject them up front so misconfiguration\n // surfaces before the adapter sees the tool list.\n throw new Error(\n `runAgent: tool \"${key}\" is a hosted tool (type=\"${tool.type}\") which is only supported via createApp({ plugins: [..., agents(...)] }). Standalone runAgent has no MCP client.`,\n );\n }\n throw new Error(`runAgent: unrecognized tool shape at key \"${key}\"`);\n}\n\n/** Mirrors `agents.ts`'s `supervisorToolDescription`. */\nfunction supervisorToolDescription(spec: SupervisorTool): string {\n switch (spec.type) {\n case \"genie_space\":\n return spec.genie_space.description;\n case \"uc_function\":\n return spec.uc_function.description;\n case \"knowledge_assistant\":\n return spec.knowledge_assistant.description;\n case \"app\":\n return spec.app.description;\n case \"uc_connection\":\n return spec.uc_connection.description;\n }\n}\n\n/** Mirrors `agents.ts`'s `buildAdapterExtensions`. */\nfunction buildStandaloneExtensions(\n toolIndex: Map<string, StandaloneEntry>,\n): Readonly<Record<string, unknown>> | undefined {\n const supervisorSpecs: SupervisorTool[] = [];\n for (const entry of toolIndex.values()) {\n if (entry.kind === \"hosted-supervisor\") {\n supervisorSpecs.push(entry.spec);\n }\n }\n if (supervisorSpecs.length === 0) return undefined;\n return {\n [SUPERVISOR_EXTENSION_KEY]: { hostedTools: supervisorSpecs },\n };\n}\n\n/**\n * Mirrors the agents-plugin capability warning so standalone `runAgent`\n * produces the same diagnostic when adapter capabilities don't match the\n * tool index. Warn-not-throw: doesn't abort batch evals.\n */\nfunction warnOnCapabilityMismatch(\n agentName: string,\n adapter: AgentAdapter,\n toolIndex: Map<string, StandaloneEntry>,\n): void {\n const accepted = new Set(adapter.acceptsExtensions ?? []);\n\n const hostedSupervisorKeys: string[] = [];\n const inputToolKeys: string[] = [];\n for (const [key, entry] of toolIndex) {\n if (entry.kind === \"hosted-supervisor\") {\n hostedSupervisorKeys.push(key);\n } else {\n inputToolKeys.push(key);\n }\n }\n\n if (\n hostedSupervisorKeys.length > 0 &&\n !accepted.has(SUPERVISOR_EXTENSION_KEY)\n ) {\n logger.warn(\n `Agent '${agentName}' declares hosted-supervisor tools (${hostedSupervisorKeys.join(\", \")}) ` +\n \"but its model adapter does not accept the 'databricks.supervisor' extension. \" +\n \"Pair them with `DatabricksAdapter.fromSupervisorApi(...)`, or remove them.\",\n );\n }\n\n if (adapter.consumesInputTools === false && inputToolKeys.length > 0) {\n logger.warn(\n `Agent '${agentName}' declares function tools / sub-agents (${inputToolKeys.join(\", \")}) ` +\n \"but its model adapter does not consume input.tools. These tools will not be exposed to the model.\",\n );\n }\n}\n\nfunction providerCacheLookup(\n pluginName: string,\n cache: Map<string, ToolProvider>,\n): ToolProvider {\n const cached = cache.get(pluginName);\n if (cached) return cached;\n const available = Array.from(cache.keys()).join(\", \") || \"(none)\";\n throw new Error(\n `runAgent: tool refers to plugin '${pluginName}', but no instance was ` +\n \"initialised for that name. Add it to RunAgentInput.plugins, or — if \" +\n \"this came from a hand-rolled ToolkitEntry — go through \" +\n `plugins[name].toolkit() instead. Available: ${available}.`,\n );\n}\n\n/**\n * Lightweight `ToolProvider` shape check used by standalone `runAgent`.\n *\n * Distinct from `core/plugin-context.isToolProvider` which also requires\n * `asUser` (request-scoped, only meaningful when running inside `createApp`\n * with a live HTTP context). Standalone plugins are constructed without a\n * `WorkspaceClient` and have no request to scope to, so checking only the\n * two `ToolProvider` methods is the right narrowing here.\n */\nfunction isStandaloneToolProvider(value: unknown): value is ToolProvider {\n if (typeof value !== \"object\" || value === null) return false;\n const obj = value as Record<string, unknown>;\n return (\n typeof obj.getAgentTools === \"function\" &&\n typeof obj.executeAgentTool === \"function\"\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AgentAdapter, AgentToolDefinition, ThreadStore, ToolAnnotations } from "../../shared/src/agent.js";
|
|
2
2
|
import { BasePluginConfig } from "../../shared/src/plugin.js";
|
|
3
3
|
import "../../shared/src/index.js";
|
|
4
|
+
import { HostedSupervisorTool, SupervisorTool } from "../../agents/supervisor-api.js";
|
|
4
5
|
import { GenerationParams } from "../../agents/databricks.js";
|
|
5
6
|
import { McpHostPolicyConfig } from "../../connectors/mcp/host-policy.js";
|
|
6
7
|
import "../../connectors/mcp/index.js";
|
|
@@ -30,10 +31,11 @@ interface ToolkitEntry {
|
|
|
30
31
|
}
|
|
31
32
|
/**
|
|
32
33
|
* Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP
|
|
33
|
-
* tools (`mcpServer()` / raw hosted),
|
|
34
|
-
* (`analytics().toolkit()`)
|
|
34
|
+
* tools (`mcpServer()` / raw hosted), toolkit references from plugins
|
|
35
|
+
* (`analytics().toolkit()`), or adapter-hosted Supervisor-API tools
|
|
36
|
+
* (`supervisorTools.*`).
|
|
35
37
|
*/
|
|
36
|
-
type AgentTool = FunctionTool | HostedTool | ToolkitEntry;
|
|
38
|
+
type AgentTool = FunctionTool | HostedTool | ToolkitEntry | HostedSupervisorTool;
|
|
37
39
|
interface ToolkitOptions {
|
|
38
40
|
/** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */
|
|
39
41
|
prefix?: string;
|
|
@@ -286,6 +288,20 @@ type ResolvedToolEntry = {
|
|
|
286
288
|
source: "subagent";
|
|
287
289
|
agentName: string;
|
|
288
290
|
def: AgentToolDefinition;
|
|
291
|
+
} | {
|
|
292
|
+
/**
|
|
293
|
+
* Adapter-side hosted tool (executed by the model-host, not by the
|
|
294
|
+
* Node process). Today: Supervisor API hosted tools (Genie spaces,
|
|
295
|
+
* UC functions, etc.). The `spec` is opaque to the agents plugin —
|
|
296
|
+
* it routes the entry into `AgentInput.extensions` for the adapter
|
|
297
|
+
* that declared the matching `acceptsExtensions` key. `def` is a
|
|
298
|
+
* synthetic placeholder kept so the index has a uniform shape; it
|
|
299
|
+
* is intentionally NOT included in the `tools` array passed to
|
|
300
|
+
* `adapter.run()` (those entries are not callable functions).
|
|
301
|
+
*/
|
|
302
|
+
source: "hosted-supervisor";
|
|
303
|
+
spec: SupervisorTool;
|
|
304
|
+
def: AgentToolDefinition;
|
|
289
305
|
};
|
|
290
306
|
interface RegisteredAgent {
|
|
291
307
|
name: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/agent/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/core/agent/types.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\nimport type { GenerationParams } from \"../../agents/databricks\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { FunctionTool } from \"./tools/function-tool\";\nimport type { HostedTool } from \"./tools/hosted-tools\";\n\n/**\n * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin\n * recognizes the `__toolkitRef` brand and dispatches tool invocations through\n * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving\n * OBO (asUser) and telemetry spans.\n */\nexport interface ToolkitEntry {\n readonly __toolkitRef: true;\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors\n * {@link ToolEntry.autoInheritable} from the source registry so the agents\n * plugin can filter auto-inherited tools without re-walking the provider's\n * internal registry.\n */\n autoInheritable?: boolean;\n}\n\n/**\n * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP\n * tools (`mcpServer()` / raw hosted), or toolkit references from plugins\n * (`analytics().toolkit()`).\n */\nexport type AgentTool = FunctionTool | HostedTool | ToolkitEntry;\n\nexport interface ToolkitOptions {\n /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */\n prefix?: string;\n /** Only include tools whose local name matches one of these. */\n only?: string[];\n /** Exclude tools whose local name matches one of these. */\n except?: string[];\n /** Remap specific local names to different keys (applied after prefix). */\n rename?: Record<string, string>;\n}\n\n/**\n * Minimum shape every entry in the {@link Plugins} map must expose. Core\n * plugins (analytics, files, genie, lakebase) implement this directly via\n * their `.toolkit()` method. The agents plugin and standalone `runAgent`\n * synthesize this shape for any registered plugin that doesn't implement\n * `.toolkit()` directly (falling back to `getAgentTools()` walking).\n */\nexport interface PluginToolkitProvider {\n toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;\n}\n\n/**\n * Plugin map passed to the function form of {@link AgentDefinition.tools}.\n * Each entry exposes a `.toolkit(opts?)` method that returns a record of\n * {@link ToolkitEntry} markers ready to be spread into a tool record.\n *\n * AppKit does not statically know which plugins the surrounding\n * `createApp` will register, so this is a plain string-keyed record.\n * Refer to plugins by the name used in `createApp({ plugins: [...] })`;\n * unknown names resolve to `undefined` at runtime.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"...\",\n * tools(plugins) {\n * return {\n * get_weather: tool({ ... }),\n * ...plugins.analytics.toolkit(),\n * ...plugins.files.toolkit({ only: [\"uploads.read\"] }),\n * };\n * },\n * });\n * ```\n */\nexport type Plugins = Record<string, PluginToolkitProvider>;\n\n/**\n * Context passed to `baseSystemPrompt` callbacks.\n */\nexport interface PromptContext {\n agentName: string;\n pluginNames: string[];\n toolNames: string[];\n}\n\nexport type BaseSystemPromptOption =\n | false\n | string\n | ((ctx: PromptContext) => string);\n\n/**\n * Per-agent tool record. String keys map to inline tools, toolkit entries,\n * hosted tools, etc.\n */\nexport type AgentTools = Record<string, AgentTool>;\n\n/**\n * Function form of `AgentDefinition.tools`. Receives the typed\n * {@link Plugins} map and returns a tool record. Invoked exactly once at\n * setup (or once per `runAgent` call in standalone mode); the result is\n * cached as the agent's resolved tool record.\n *\n * Use the function form when an agent needs tools from registered plugins.\n * The bare object form is fine when an agent only uses inline tools.\n */\nexport type AgentToolsFn = (plugins: Plugins) => AgentTools;\n\nexport interface AgentDefinition {\n /**\n * Stable identifier for the agent. **Optional and informational** —\n * when the definition is registered via `agents: { foo: def }` (code) or\n * lives at `config/agents/<id>/agent.md` (markdown), the **registry key\n * always wins** and `name` is ignored. The agent will be reachable as\n * `foo` (or `<id>`) regardless of what this field contains.\n *\n * Set `name` when:\n * - Running standalone via `runAgent({ agent: def })`, where there is\n * no enclosing key. The runtime uses it for the agent's slot in\n * error messages and OTel spans.\n * - Building a definition that may be passed to either form and you\n * want a consistent fallback label.\n *\n * Setting `name` to a value that differs from the registry key is\n * harmless but confusing — prefer keeping them aligned or omitting `name`\n * entirely.\n */\n name?: string;\n /** System prompt body. For markdown-loaded agents this is the file body. */\n instructions: string;\n /**\n * Model adapter (or endpoint-name string sugar for\n * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —\n * falls back to the plugin's `defaultModel`.\n */\n model?: AgentAdapter | Promise<AgentAdapter> | string;\n /**\n * Per-agent tool record. Key is the LLM-visible tool-call name.\n *\n * Accepts either a plain record (for agents that only use inline tools)\n * or a function `(plugins) => Record<string, AgentTool>` that receives\n * the typed {@link Plugins} map and returns a tool record (for agents\n * that pull tools from registered plugins).\n *\n * The function is invoked once at agent setup; the result is cached.\n * Don't put per-request logic in there.\n */\n tools?: AgentTools | AgentToolsFn;\n /** Sub-agents, exposed as `agent-<key>` tools on this agent. */\n agents?: Record<string, AgentDefinition>;\n /** Override the plugin's baseSystemPrompt for this agent only. */\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /**\n * Optional generation parameters (`temperature`, `top_p`, `stop`,\n * `frequency_penalty`, `presence_penalty`) forwarded to the OpenAI-compatible\n * serving request body. Only set keys are sent. Applied only when AppKit\n * builds the adapter itself (string or omitted `model`); when you pass a\n * pre-built `AgentAdapter`, configure generation params on it directly.\n */\n generationParams?: GenerationParams;\n /**\n * When true, the thread used for a chat request against this agent is\n * deleted from `ThreadStore` after the stream completes (success or\n * failure). Use for stateless one-shot agents — e.g. autocomplete, where\n * each request is independent and retaining history would both poison\n * future calls and accumulate unbounded state in the default\n * `InMemoryThreadStore`. Defaults to `false`.\n */\n ephemeral?: boolean;\n}\n\n/**\n * Auto-inherit configuration. When enabled for a given agent origin, agents\n * with no explicit `tools:` declaration receive every registered ToolProvider\n * plugin tool whose author marked `autoInheritable: true`. Tools without that\n * flag — destructive, state-mutating, or privilege-sensitive — never spread\n * automatically and must be wired via `tools:` (object or function form in\n * code, `plugin:NAME` entries in markdown frontmatter).\n *\n * Defaults are `false` for both origins (safe-by-default): developers must\n * consciously opt an origin in to any auto-inherit behaviour.\n */\nexport interface AutoInheritToolsConfig {\n /** Default for agents loaded from markdown files. Default: `false`. */\n file?: boolean;\n /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */\n code?: boolean;\n}\n\nexport interface AgentsPluginConfig extends BasePluginConfig {\n /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */\n dir?: string | false;\n /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */\n defaultAgent?: string;\n /** Default model for agents that don't specify their own (in code or frontmatter). */\n defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;\n /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */\n tools?: Record<string, AgentTool>;\n /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */\n autoInheritTools?: boolean | AutoInheritToolsConfig;\n /** Persistent thread store. Default: in-memory. */\n threadStore?: ThreadStore;\n /** Customize or disable the AppKit base system prompt. */\n baseSystemPrompt?: BaseSystemPromptOption;\n /**\n * MCP server host policy. By default only same-origin Databricks workspace\n * URLs may be used as MCP endpoints; custom hosts must be explicitly\n * allowlisted here. Workspace credentials (SP / OBO) are never forwarded\n * to non-workspace hosts.\n */\n mcp?: McpHostPolicyConfig;\n /**\n * Human-in-the-loop approval gate for mutating tool calls. When enabled\n * (the default), the agents plugin emits an `appkit.approval_pending` SSE\n * event before executing any tool whose annotation flags it as mutating —\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean — and waits for a `POST /chat/approve`\n * decision from the same user who initiated the stream. A missing decision\n * after `timeoutMs` auto-denies the call.\n */\n approval?: {\n /**\n * Require human approval for tools that mutate state. Triggered by\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean. Default: `true`.\n */\n requireForDestructive?: boolean;\n /** Milliseconds to wait before auto-denying. Default: 60_000. */\n timeoutMs?: number;\n };\n /**\n * Runtime resource limits applied during agent execution. Defaults are\n * tuned to protect a single-instance deployment from a misbehaving user or\n * a runaway prompt injection; tighten or relax as appropriate for the\n * deployment's scale and trust model. Request-body caps (chat message\n * size, invocations input size / length) are enforced statically by the\n * Zod schemas and are not configurable here.\n */\n limits?: {\n /**\n * Max concurrent chat streams a single user may have open. Subsequent\n * `POST /chat` requests from that user while at-limit are rejected with\n * HTTP 429. Default: `5`.\n */\n maxConcurrentStreamsPerUser?: number;\n /**\n * Max tool invocations per agent run (across the full tool-call graph,\n * including sub-agent invocations). A run that exceeds the budget is\n * aborted with a terminal error event. Default: `50`.\n */\n maxToolCalls?: number;\n /**\n * Max sub-agent recursion depth. Protects against a prompt-injected\n * agent that delegates to a sub-agent which in turn delegates back to\n * itself (directly or transitively). Default: `3`.\n */\n maxSubAgentDepth?: number;\n /**\n * Per-call timeout for tools dispatched through `PluginContext`\n * (toolkit-routed tools — analytics SQL warehouse queries, Genie\n * messages, Lakebase queries). Independent of `maxToolCalls`: the\n * budget caps how many tools fire per run, this caps how long any\n * single tool call may run. The signal handed to plugin tool\n * implementations combines this timeout with the parent stream's\n * abort signal via `AbortSignal.any`. Function and MCP tools have\n * their own timeouts in their respective adapters and ignore this\n * setting. Default: `300_000` (5 minutes) — generous enough for cold\n * SQL Warehouse round-trips and long Genie conversations.\n */\n toolCallTimeoutMs?: number;\n };\n}\n\n/** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */\nexport type ResolvedToolEntry =\n | {\n source: \"toolkit\";\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"function\";\n functionTool: FunctionTool;\n def: AgentToolDefinition;\n }\n | {\n source: \"mcp\";\n mcpToolName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"subagent\";\n agentName: string;\n def: AgentToolDefinition;\n };\n\nexport interface RegisteredAgent {\n name: string;\n instructions: string;\n adapter: AgentAdapter;\n toolIndex: Map<string, ResolvedToolEntry>;\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /** Mirrors `AgentDefinition.generationParams`. */\n generationParams?: GenerationParams;\n /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */\n ephemeral?: boolean;\n}\n\n/**\n * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate\n * toolkit references from inline tools in a mixed `tools` record.\n */\nexport function isToolkitEntry(value: unknown): value is ToolkitEntry {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __toolkitRef?: unknown }).__toolkitRef === true\n );\n}\n"],"mappings":";;;;;AA0UA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\nimport type { GenerationParams } from \"../../agents/databricks\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { FunctionTool } from \"./tools/function-tool\";\nimport type { HostedTool } from \"./tools/hosted-tools\";\n\n/**\n * A tool reference produced by a plugin's `.toolkit()` call. The agents plugin\n * recognizes the `__toolkitRef` brand and dispatches tool invocations through\n * `PluginContext.executeTool(req, pluginName, localName, ...)`, preserving\n * OBO (asUser) and telemetry spans.\n */\nexport interface ToolkitEntry {\n readonly __toolkitRef: true;\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n annotations?: ToolAnnotations;\n /**\n * Whether this tool is eligible for `autoInheritTools` spreading. Mirrors\n * {@link ToolEntry.autoInheritable} from the source registry so the agents\n * plugin can filter auto-inherited tools without re-walking the provider's\n * internal registry.\n */\n autoInheritable?: boolean;\n}\n\n/**\n * Any tool an agent can invoke: inline function tools (`tool()`), hosted MCP\n * tools (`mcpServer()` / raw hosted), toolkit references from plugins\n * (`analytics().toolkit()`), or adapter-hosted Supervisor-API tools\n * (`supervisorTools.*`).\n */\nexport type AgentTool =\n | FunctionTool\n | HostedTool\n | ToolkitEntry\n | import(\"../../agents/supervisor-api\").HostedSupervisorTool;\n\nexport interface ToolkitOptions {\n /** Key prefix to prepend to each tool's local name. Defaults to `${pluginName}.`. */\n prefix?: string;\n /** Only include tools whose local name matches one of these. */\n only?: string[];\n /** Exclude tools whose local name matches one of these. */\n except?: string[];\n /** Remap specific local names to different keys (applied after prefix). */\n rename?: Record<string, string>;\n}\n\n/**\n * Minimum shape every entry in the {@link Plugins} map must expose. Core\n * plugins (analytics, files, genie, lakebase) implement this directly via\n * their `.toolkit()` method. The agents plugin and standalone `runAgent`\n * synthesize this shape for any registered plugin that doesn't implement\n * `.toolkit()` directly (falling back to `getAgentTools()` walking).\n */\nexport interface PluginToolkitProvider {\n toolkit(opts?: ToolkitOptions): Record<string, ToolkitEntry>;\n}\n\n/**\n * Plugin map passed to the function form of {@link AgentDefinition.tools}.\n * Each entry exposes a `.toolkit(opts?)` method that returns a record of\n * {@link ToolkitEntry} markers ready to be spread into a tool record.\n *\n * AppKit does not statically know which plugins the surrounding\n * `createApp` will register, so this is a plain string-keyed record.\n * Refer to plugins by the name used in `createApp({ plugins: [...] })`;\n * unknown names resolve to `undefined` at runtime.\n *\n * @example\n * ```ts\n * const support = createAgent({\n * instructions: \"...\",\n * tools(plugins) {\n * return {\n * get_weather: tool({ ... }),\n * ...plugins.analytics.toolkit(),\n * ...plugins.files.toolkit({ only: [\"uploads.read\"] }),\n * };\n * },\n * });\n * ```\n */\nexport type Plugins = Record<string, PluginToolkitProvider>;\n\n/**\n * Context passed to `baseSystemPrompt` callbacks.\n */\nexport interface PromptContext {\n agentName: string;\n pluginNames: string[];\n toolNames: string[];\n}\n\nexport type BaseSystemPromptOption =\n | false\n | string\n | ((ctx: PromptContext) => string);\n\n/**\n * Per-agent tool record. String keys map to inline tools, toolkit entries,\n * hosted tools, etc.\n */\nexport type AgentTools = Record<string, AgentTool>;\n\n/**\n * Function form of `AgentDefinition.tools`. Receives the typed\n * {@link Plugins} map and returns a tool record. Invoked exactly once at\n * setup (or once per `runAgent` call in standalone mode); the result is\n * cached as the agent's resolved tool record.\n *\n * Use the function form when an agent needs tools from registered plugins.\n * The bare object form is fine when an agent only uses inline tools.\n */\nexport type AgentToolsFn = (plugins: Plugins) => AgentTools;\n\nexport interface AgentDefinition {\n /**\n * Stable identifier for the agent. **Optional and informational** —\n * when the definition is registered via `agents: { foo: def }` (code) or\n * lives at `config/agents/<id>/agent.md` (markdown), the **registry key\n * always wins** and `name` is ignored. The agent will be reachable as\n * `foo` (or `<id>`) regardless of what this field contains.\n *\n * Set `name` when:\n * - Running standalone via `runAgent({ agent: def })`, where there is\n * no enclosing key. The runtime uses it for the agent's slot in\n * error messages and OTel spans.\n * - Building a definition that may be passed to either form and you\n * want a consistent fallback label.\n *\n * Setting `name` to a value that differs from the registry key is\n * harmless but confusing — prefer keeping them aligned or omitting `name`\n * entirely.\n */\n name?: string;\n /** System prompt body. For markdown-loaded agents this is the file body. */\n instructions: string;\n /**\n * Model adapter (or endpoint-name string sugar for\n * `DatabricksAdapter.fromServingEndpoint({ endpointName })`). Optional —\n * falls back to the plugin's `defaultModel`.\n */\n model?: AgentAdapter | Promise<AgentAdapter> | string;\n /**\n * Per-agent tool record. Key is the LLM-visible tool-call name.\n *\n * Accepts either a plain record (for agents that only use inline tools)\n * or a function `(plugins) => Record<string, AgentTool>` that receives\n * the typed {@link Plugins} map and returns a tool record (for agents\n * that pull tools from registered plugins).\n *\n * The function is invoked once at agent setup; the result is cached.\n * Don't put per-request logic in there.\n */\n tools?: AgentTools | AgentToolsFn;\n /** Sub-agents, exposed as `agent-<key>` tools on this agent. */\n agents?: Record<string, AgentDefinition>;\n /** Override the plugin's baseSystemPrompt for this agent only. */\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /**\n * Optional generation parameters (`temperature`, `top_p`, `stop`,\n * `frequency_penalty`, `presence_penalty`) forwarded to the OpenAI-compatible\n * serving request body. Only set keys are sent. Applied only when AppKit\n * builds the adapter itself (string or omitted `model`); when you pass a\n * pre-built `AgentAdapter`, configure generation params on it directly.\n */\n generationParams?: GenerationParams;\n /**\n * When true, the thread used for a chat request against this agent is\n * deleted from `ThreadStore` after the stream completes (success or\n * failure). Use for stateless one-shot agents — e.g. autocomplete, where\n * each request is independent and retaining history would both poison\n * future calls and accumulate unbounded state in the default\n * `InMemoryThreadStore`. Defaults to `false`.\n */\n ephemeral?: boolean;\n}\n\n/**\n * Auto-inherit configuration. When enabled for a given agent origin, agents\n * with no explicit `tools:` declaration receive every registered ToolProvider\n * plugin tool whose author marked `autoInheritable: true`. Tools without that\n * flag — destructive, state-mutating, or privilege-sensitive — never spread\n * automatically and must be wired via `tools:` (object or function form in\n * code, `plugin:NAME` entries in markdown frontmatter).\n *\n * Defaults are `false` for both origins (safe-by-default): developers must\n * consciously opt an origin in to any auto-inherit behaviour.\n */\nexport interface AutoInheritToolsConfig {\n /** Default for agents loaded from markdown files. Default: `false`. */\n file?: boolean;\n /** Default for code-defined agents (via `agents: { foo: createAgent(...) }`). Default: `false`. */\n code?: boolean;\n}\n\nexport interface AgentsPluginConfig extends BasePluginConfig {\n /** Directory of agent packages (`<id>/agent.md` each). Default `./config/agents`. Set to `false` to disable. */\n dir?: string | false;\n /** Code-defined agents, merged with file-loaded ones (code wins on key collision). */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Defaults to the first-registered agent or the file with `default: true` frontmatter. */\n defaultAgent?: string;\n /** Default model for agents that don't specify their own (in code or frontmatter). */\n defaultModel?: AgentAdapter | Promise<AgentAdapter> | string;\n /** Ambient tool library. Keys may be referenced by markdown frontmatter via `tools: [key1, key2]`. */\n tools?: Record<string, AgentTool>;\n /** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */\n autoInheritTools?: boolean | AutoInheritToolsConfig;\n /** Persistent thread store. Default: in-memory. */\n threadStore?: ThreadStore;\n /** Customize or disable the AppKit base system prompt. */\n baseSystemPrompt?: BaseSystemPromptOption;\n /**\n * MCP server host policy. By default only same-origin Databricks workspace\n * URLs may be used as MCP endpoints; custom hosts must be explicitly\n * allowlisted here. Workspace credentials (SP / OBO) are never forwarded\n * to non-workspace hosts.\n */\n mcp?: McpHostPolicyConfig;\n /**\n * Human-in-the-loop approval gate for mutating tool calls. When enabled\n * (the default), the agents plugin emits an `appkit.approval_pending` SSE\n * event before executing any tool whose annotation flags it as mutating —\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean — and waits for a `POST /chat/approve`\n * decision from the same user who initiated the stream. A missing decision\n * after `timeoutMs` auto-denies the call.\n */\n approval?: {\n /**\n * Require human approval for tools that mutate state. Triggered by\n * `effect: \"write\" | \"update\" | \"destructive\"` (preferred) or the legacy\n * `destructive: true` boolean. Default: `true`.\n */\n requireForDestructive?: boolean;\n /** Milliseconds to wait before auto-denying. Default: 60_000. */\n timeoutMs?: number;\n };\n /**\n * Runtime resource limits applied during agent execution. Defaults are\n * tuned to protect a single-instance deployment from a misbehaving user or\n * a runaway prompt injection; tighten or relax as appropriate for the\n * deployment's scale and trust model. Request-body caps (chat message\n * size, invocations input size / length) are enforced statically by the\n * Zod schemas and are not configurable here.\n */\n limits?: {\n /**\n * Max concurrent chat streams a single user may have open. Subsequent\n * `POST /chat` requests from that user while at-limit are rejected with\n * HTTP 429. Default: `5`.\n */\n maxConcurrentStreamsPerUser?: number;\n /**\n * Max tool invocations per agent run (across the full tool-call graph,\n * including sub-agent invocations). A run that exceeds the budget is\n * aborted with a terminal error event. Default: `50`.\n */\n maxToolCalls?: number;\n /**\n * Max sub-agent recursion depth. Protects against a prompt-injected\n * agent that delegates to a sub-agent which in turn delegates back to\n * itself (directly or transitively). Default: `3`.\n */\n maxSubAgentDepth?: number;\n /**\n * Per-call timeout for tools dispatched through `PluginContext`\n * (toolkit-routed tools — analytics SQL warehouse queries, Genie\n * messages, Lakebase queries). Independent of `maxToolCalls`: the\n * budget caps how many tools fire per run, this caps how long any\n * single tool call may run. The signal handed to plugin tool\n * implementations combines this timeout with the parent stream's\n * abort signal via `AbortSignal.any`. Function and MCP tools have\n * their own timeouts in their respective adapters and ignore this\n * setting. Default: `300_000` (5 minutes) — generous enough for cold\n * SQL Warehouse round-trips and long Genie conversations.\n */\n toolCallTimeoutMs?: number;\n };\n}\n\n/** Internal tool-index entry after a tool record has been resolved to a dispatchable form. */\nexport type ResolvedToolEntry =\n | {\n source: \"toolkit\";\n pluginName: string;\n localName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"function\";\n functionTool: FunctionTool;\n def: AgentToolDefinition;\n }\n | {\n source: \"mcp\";\n mcpToolName: string;\n def: AgentToolDefinition;\n }\n | {\n source: \"subagent\";\n agentName: string;\n def: AgentToolDefinition;\n }\n | {\n /**\n * Adapter-side hosted tool (executed by the model-host, not by the\n * Node process). Today: Supervisor API hosted tools (Genie spaces,\n * UC functions, etc.). The `spec` is opaque to the agents plugin —\n * it routes the entry into `AgentInput.extensions` for the adapter\n * that declared the matching `acceptsExtensions` key. `def` is a\n * synthetic placeholder kept so the index has a uniform shape; it\n * is intentionally NOT included in the `tools` array passed to\n * `adapter.run()` (those entries are not callable functions).\n */\n source: \"hosted-supervisor\";\n spec: import(\"../../agents/supervisor-api\").SupervisorTool;\n def: AgentToolDefinition;\n };\n\nexport interface RegisteredAgent {\n name: string;\n instructions: string;\n adapter: AgentAdapter;\n toolIndex: Map<string, ResolvedToolEntry>;\n baseSystemPrompt?: BaseSystemPromptOption;\n maxSteps?: number;\n maxTokens?: number;\n /** Mirrors `AgentDefinition.generationParams`. */\n generationParams?: GenerationParams;\n /** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */\n ephemeral?: boolean;\n}\n\n/**\n * Type guard for `ToolkitEntry` — used by the agents plugin to differentiate\n * toolkit references from inline tools in a mixed `tools` record.\n */\nexport function isToolkitEntry(value: unknown): value is ToolkitEntry {\n return (\n typeof value === \"object\" &&\n value !== null &&\n (value as { __toolkitRef?: unknown }).__toolkitRef === true\n );\n}\n"],"mappings":";;;;;AA8VA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"appkit.d.ts","names":[],"sources":["../../src/core/appkit.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAqXsB,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"}
|
package/dist/core/appkit.js
CHANGED
|
@@ -9,6 +9,7 @@ import { isInternalTelemetryEnabled } from "../internal-telemetry/config.js";
|
|
|
9
9
|
import { TelemetryReporter } from "../internal-telemetry/reporter.js";
|
|
10
10
|
import "../internal-telemetry/index.js";
|
|
11
11
|
import { isPlainObject } from "../plugin/plugin.js";
|
|
12
|
+
import { uiVariants } from "../plugins/ui-variants/index.js";
|
|
12
13
|
import { ResourceType } from "../registry/types.generated.js";
|
|
13
14
|
import { ResourceRegistry } from "../registry/resource-registry.js";
|
|
14
15
|
import "../registry/index.js";
|
|
@@ -100,7 +101,8 @@ var AppKit = class AppKit {
|
|
|
100
101
|
static async _createApp(config = {}) {
|
|
101
102
|
TelemetryManager.initialize(config?.telemetry);
|
|
102
103
|
await CacheManager.getInstance(config?.cache);
|
|
103
|
-
const
|
|
104
|
+
const withDefaults = AppKit.withDefaultPlugins(config.plugins);
|
|
105
|
+
const rawPlugins = AppKit.filterDevOnlyPlugins(withDefaults);
|
|
104
106
|
const registry = new ResourceRegistry();
|
|
105
107
|
registry.collectResources(rawPlugins);
|
|
106
108
|
const needsWarehouse = registry.getRequired().some((r) => r.type === ResourceType.SQL_WAREHOUSE);
|
|
@@ -132,6 +134,42 @@ var AppKit = class AppKit {
|
|
|
132
134
|
reporter.start();
|
|
133
135
|
reporter.sendStartup().catch(() => {});
|
|
134
136
|
}
|
|
137
|
+
/**
|
|
138
|
+
* Injects framework-owned default plugins the app author shouldn't have to
|
|
139
|
+
* register by hand. Runs before {@link filterDevOnlyPlugins}, so a default
|
|
140
|
+
* that is itself `devOnly` (like `ui-variants`) is present in dev and stripped
|
|
141
|
+
* in prod through the exact same guard as any user plugin — never alive in a
|
|
142
|
+
* deployed app.
|
|
143
|
+
*
|
|
144
|
+
* Currently injects the dev-only `ui-variants` recorder that backs the
|
|
145
|
+
* `<Variants>` UI picker, so neither the developer nor their coding agent has
|
|
146
|
+
* to remember to add it. If the app already registered it explicitly, that
|
|
147
|
+
* entry wins and no duplicate is added.
|
|
148
|
+
*/
|
|
149
|
+
static withDefaultPlugins(plugins) {
|
|
150
|
+
const list = plugins ?? [];
|
|
151
|
+
const missing = [uiVariants()].filter((def) => !list.some((p) => p?.name === def.name));
|
|
152
|
+
return [...list, ...missing];
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Drops plugins whose manifest declares `devOnly: true` unless
|
|
156
|
+
* `NODE_ENV === "development"`. Runs before resource collection so a skipped
|
|
157
|
+
* plugin is never constructed, never injects routes, and has its resource
|
|
158
|
+
* requirements ignored — the framework, not the app author, enforces that
|
|
159
|
+
* dev-only tooling can never run in a deployed app.
|
|
160
|
+
*
|
|
161
|
+
* This is the primary guard; plugins that expose a mutating dev endpoint
|
|
162
|
+
* should still keep an in-handler `NODE_ENV` check as fail-safe defense
|
|
163
|
+
* against being mounted through a path that bypasses this filter.
|
|
164
|
+
*/
|
|
165
|
+
static filterDevOnlyPlugins(plugins) {
|
|
166
|
+
if (!plugins || process.env.NODE_ENV === "development") return plugins;
|
|
167
|
+
return plugins.filter((pluginData) => {
|
|
168
|
+
const isDevOnly = pluginData?.plugin?.manifest?.devOnly === true;
|
|
169
|
+
if (isDevOnly) logger.debug("Skipping dev-only plugin %s (NODE_ENV=%s)", pluginData?.name ?? "unknown", process.env.NODE_ENV ?? "<unset>");
|
|
170
|
+
return !isDevOnly;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
135
173
|
static preparePlugins(plugins) {
|
|
136
174
|
const result = {};
|
|
137
175
|
for (const currentPlugin of plugins) result[currentPlugin.name] = {
|