@databricks/appkit 0.66.0 → 0.67.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/NOTICE.md +3 -2
- package/dist/appkit/package.js +1 -1
- package/dist/core/agent/frontmatter.js +23 -0
- package/dist/core/agent/frontmatter.js.map +1 -0
- package/dist/core/agent/load-agents.d.ts.map +1 -1
- package/dist/core/agent/load-agents.js +36 -6
- package/dist/core/agent/load-agents.js.map +1 -1
- package/dist/core/agent/skills/index.js +7 -0
- package/dist/core/agent/skills/load-skills.js +78 -0
- package/dist/core/agent/skills/load-skills.js.map +1 -0
- package/dist/core/agent/skills/parse-skill.js +69 -0
- package/dist/core/agent/skills/parse-skill.js.map +1 -0
- package/dist/core/agent/skills/read-resource.js +31 -0
- package/dist/core/agent/skills/read-resource.js.map +1 -0
- package/dist/core/agent/skills/render.js +33 -0
- package/dist/core/agent/skills/render.js.map +1 -0
- package/dist/core/agent/skills/resolve-catalog.js +78 -0
- package/dist/core/agent/skills/resolve-catalog.js.map +1 -0
- package/dist/core/agent/skills/types.d.ts +50 -0
- package/dist/core/agent/skills/types.d.ts.map +1 -0
- package/dist/core/agent/types.d.ts +47 -0
- package/dist/core/agent/types.d.ts.map +1 -1
- package/dist/core/agent/types.js.map +1 -1
- package/dist/plugins/agents/agents.d.ts +50 -0
- package/dist/plugins/agents/agents.d.ts.map +1 -1
- package/dist/plugins/agents/agents.js +225 -13
- package/dist/plugins/agents/agents.js.map +1 -1
- package/dist/plugins/agents/manifest.js +40 -21
- package/dist/plugins/agents/schemas.js +2 -1
- package/dist/plugins/agents/schemas.js.map +1 -1
- package/dist/plugins/lakebase/manifest.js +1 -0
- package/dist/plugins/server/index.js +2 -2
- package/dist/plugins/server/index.js.map +1 -1
- package/dist/plugins/server/remote-tunnel/remote-tunnel-manager.js +3 -3
- package/dist/plugins/server/remote-tunnel/remote-tunnel-manager.js.map +1 -1
- package/dist/plugins/server/static-server.js +3 -3
- package/dist/plugins/server/static-server.js.map +1 -1
- package/dist/plugins/server/utils.js +3 -3
- package/dist/plugins/server/utils.js.map +1 -1
- package/dist/plugins/server/vite-dev-server.js +4 -4
- package/dist/plugins/server/vite-dev-server.js.map +1 -1
- package/dist/shared/src/schemas/manifest.d.ts +6 -6
- package/dist/type-generator/database/generate.js +3 -3
- package/dist/type-generator/database/generate.js.map +1 -1
- package/dist/type-generator/migration.js +2 -2
- package/dist/type-generator/migration.js.map +1 -1
- package/dist/type-generator/serving/server-file-extractor.js +3 -3
- package/dist/type-generator/serving/server-file-extractor.js.map +1 -1
- package/docs/api/appkit/Interface.AgentDefinition.md +11 -0
- package/docs/api/appkit/Interface.AgentsPluginConfig.md +35 -0
- package/docs/api/appkit/Interface.RegisteredAgent.md +11 -0
- package/docs/api/appkit/TypeAlias.ResolvedToolEntry.md +46 -0
- package/docs/plugins/agents.md +68 -1
- package/package.json +1 -1
- package/sbom.cdx.json +1 -1
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { createLogger } from "../../../logging/logger.js";
|
|
2
|
+
|
|
3
|
+
//#region src/core/agent/skills/resolve-catalog.ts
|
|
4
|
+
const logger = createLogger("agents:skills");
|
|
5
|
+
/** Qualified-name scope prefix per source, used only on cross-source collision. */
|
|
6
|
+
const SCOPE_BY_SOURCE = {
|
|
7
|
+
"bundle-agent": "agent",
|
|
8
|
+
"bundle-global": "bundle",
|
|
9
|
+
volume: "volume"
|
|
10
|
+
};
|
|
11
|
+
/**
|
|
12
|
+
* Applies visibility (per-agent auto; global opt-in or auto-inherit) then
|
|
13
|
+
* collision handling: a unique name is addressable bare; a name provided by
|
|
14
|
+
* multiple sources becomes `<scope>:name` per source and the bare name is
|
|
15
|
+
* marked ambiguous (addressing it errors with the alternatives). Two skills
|
|
16
|
+
* with the same name from the *same* source is a fatal config error.
|
|
17
|
+
*/
|
|
18
|
+
function resolveSkillCatalog(input) {
|
|
19
|
+
const { agentName, agentSkillNames, perAgentSkills, globalSkills, autoInherit } = input;
|
|
20
|
+
const visible = [...perAgentSkills];
|
|
21
|
+
if (autoInherit) visible.push(...globalSkills);
|
|
22
|
+
else if (agentSkillNames && agentSkillNames.length > 0) {
|
|
23
|
+
const wanted = new Set(agentSkillNames);
|
|
24
|
+
for (const skill of globalSkills) if (wanted.has(skill.name)) visible.push(skill);
|
|
25
|
+
const localNames = new Set(perAgentSkills.map((s) => s.name));
|
|
26
|
+
const globalNames = new Set(globalSkills.map((s) => s.name));
|
|
27
|
+
for (const want of agentSkillNames) if (!globalNames.has(want) && !localNames.has(want)) logger.warn("Agent '%s' lists skill '%s' in 'skills:', but no global or per-agent skill with that name exists.", agentName, want);
|
|
28
|
+
}
|
|
29
|
+
const byName = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const skill of visible) {
|
|
31
|
+
const group = byName.get(skill.name) ?? [];
|
|
32
|
+
group.push(skill);
|
|
33
|
+
byName.set(skill.name, group);
|
|
34
|
+
}
|
|
35
|
+
const byAddress = /* @__PURE__ */ new Map();
|
|
36
|
+
const ambiguous = /* @__PURE__ */ new Map();
|
|
37
|
+
for (const [name, group] of byName) {
|
|
38
|
+
if (group.length === 1) {
|
|
39
|
+
byAddress.set(name, group[0]);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const alternatives = [];
|
|
43
|
+
for (const skill of group) {
|
|
44
|
+
const qualified = `${SCOPE_BY_SOURCE[skill.source]}:${name}`;
|
|
45
|
+
const existing = byAddress.get(qualified);
|
|
46
|
+
if (existing) throw new Error(`Agent '${agentName}': two '${skill.source}' skills are both named '${name}' (${existing.dir} and ${skill.dir}). Skill names must be unique within a source.`);
|
|
47
|
+
byAddress.set(qualified, skill);
|
|
48
|
+
alternatives.push(qualified);
|
|
49
|
+
}
|
|
50
|
+
alternatives.sort();
|
|
51
|
+
ambiguous.set(name, alternatives);
|
|
52
|
+
logger.warn("Agent '%s': skill name '%s' is provided by multiple sources; address it as %s.", agentName, name, alternatives.join(" or "));
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
byAddress,
|
|
56
|
+
ambiguous,
|
|
57
|
+
catalog: [...byAddress.entries()].map(([address, skill]) => ({
|
|
58
|
+
name: address,
|
|
59
|
+
description: skill.description
|
|
60
|
+
})).sort((a, b) => a.name.localeCompare(b.name))
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Resolves a requested skill name (bare or qualified) against a catalog.
|
|
65
|
+
* Throws a helpful error on ambiguous or unknown names.
|
|
66
|
+
*/
|
|
67
|
+
function resolveSkill(catalog, requested) {
|
|
68
|
+
const direct = catalog.byAddress.get(requested);
|
|
69
|
+
if (direct) return direct;
|
|
70
|
+
const alternatives = catalog.ambiguous.get(requested);
|
|
71
|
+
if (alternatives) throw new Error(`Skill '${requested}' is ambiguous; specify one of: ${alternatives.join(", ")}.`);
|
|
72
|
+
const available = [...catalog.byAddress.keys()].sort().join(", ") || "<none>";
|
|
73
|
+
throw new Error(`Unknown skill '${requested}'. Available: ${available}.`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//#endregion
|
|
77
|
+
export { resolveSkill, resolveSkillCatalog };
|
|
78
|
+
//# sourceMappingURL=resolve-catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-catalog.js","names":[],"sources":["../../../../src/core/agent/skills/resolve-catalog.ts"],"sourcesContent":["import { createLogger } from \"../../../logging/logger\";\nimport type {\n ResolvedSkillCatalog,\n SkillCatalogEntry,\n SkillDefinition,\n SkillSource,\n} from \"./types\";\n\nconst logger = createLogger(\"agents:skills\");\n\n/** Qualified-name scope prefix per source, used only on cross-source collision. */\nconst SCOPE_BY_SOURCE: Record<SkillSource, string> = {\n \"bundle-agent\": \"agent\",\n \"bundle-global\": \"bundle\",\n volume: \"volume\",\n};\n\ninterface ResolveCatalogInput {\n agentName: string;\n /** The agent's `skills:` frontmatter — opt-in selection from the global pool. */\n agentSkillNames?: string[];\n /** Skills private to this agent (`<id>/skills/`), always visible. */\n perAgentSkills: SkillDefinition[];\n /** Shared pool (bundle-global + volume), visible only when opted in or inherited. */\n globalSkills: SkillDefinition[];\n /** When true, every global skill is visible without an explicit `skills:` list. */\n autoInherit: boolean;\n}\n\n/**\n * Applies visibility (per-agent auto; global opt-in or auto-inherit) then\n * collision handling: a unique name is addressable bare; a name provided by\n * multiple sources becomes `<scope>:name` per source and the bare name is\n * marked ambiguous (addressing it errors with the alternatives). Two skills\n * with the same name from the *same* source is a fatal config error.\n */\nexport function resolveSkillCatalog(\n input: ResolveCatalogInput,\n): ResolvedSkillCatalog {\n const {\n agentName,\n agentSkillNames,\n perAgentSkills,\n globalSkills,\n autoInherit,\n } = input;\n\n const visible: SkillDefinition[] = [...perAgentSkills];\n if (autoInherit) {\n visible.push(...globalSkills);\n } else if (agentSkillNames && agentSkillNames.length > 0) {\n const wanted = new Set(agentSkillNames);\n for (const skill of globalSkills) {\n if (wanted.has(skill.name)) visible.push(skill);\n }\n const localNames = new Set(perAgentSkills.map((s) => s.name));\n const globalNames = new Set(globalSkills.map((s) => s.name));\n for (const want of agentSkillNames) {\n if (!globalNames.has(want) && !localNames.has(want)) {\n logger.warn(\n \"Agent '%s' lists skill '%s' in 'skills:', but no global or per-agent skill with that name exists.\",\n agentName,\n want,\n );\n }\n }\n }\n\n const byName = new Map<string, SkillDefinition[]>();\n for (const skill of visible) {\n const group = byName.get(skill.name) ?? [];\n group.push(skill);\n byName.set(skill.name, group);\n }\n\n const byAddress = new Map<string, SkillDefinition>();\n const ambiguous = new Map<string, string[]>();\n\n for (const [name, group] of byName) {\n if (group.length === 1) {\n byAddress.set(name, group[0]);\n continue;\n }\n\n const alternatives: string[] = [];\n for (const skill of group) {\n const qualified = `${SCOPE_BY_SOURCE[skill.source]}:${name}`;\n const existing = byAddress.get(qualified);\n if (existing) {\n throw new Error(\n `Agent '${agentName}': two '${skill.source}' skills are both named '${name}' ` +\n `(${existing.dir} and ${skill.dir}). Skill names must be unique within a source.`,\n );\n }\n byAddress.set(qualified, skill);\n alternatives.push(qualified);\n }\n alternatives.sort();\n ambiguous.set(name, alternatives);\n logger.warn(\n \"Agent '%s': skill name '%s' is provided by multiple sources; address it as %s.\",\n agentName,\n name,\n alternatives.join(\" or \"),\n );\n }\n\n const catalog: SkillCatalogEntry[] = [...byAddress.entries()]\n .map(([address, skill]) => ({\n name: address,\n description: skill.description,\n }))\n .sort((a, b) => a.name.localeCompare(b.name));\n\n return { byAddress, ambiguous, catalog };\n}\n\n/**\n * Resolves a requested skill name (bare or qualified) against a catalog.\n * Throws a helpful error on ambiguous or unknown names.\n */\nexport function resolveSkill(\n catalog: ResolvedSkillCatalog,\n requested: string,\n): SkillDefinition {\n const direct = catalog.byAddress.get(requested);\n if (direct) return direct;\n\n const alternatives = catalog.ambiguous.get(requested);\n if (alternatives) {\n throw new Error(\n `Skill '${requested}' is ambiguous; specify one of: ${alternatives.join(\", \")}.`,\n );\n }\n\n const available = [...catalog.byAddress.keys()].sort().join(\", \") || \"<none>\";\n throw new Error(`Unknown skill '${requested}'. Available: ${available}.`);\n}\n"],"mappings":";;;AAQA,MAAM,SAAS,aAAa,gBAAgB;;AAG5C,MAAM,kBAA+C;CACnD,gBAAgB;CAChB,iBAAiB;CACjB,QAAQ;CACT;;;;;;;;AAqBD,SAAgB,oBACd,OACsB;CACtB,MAAM,EACJ,WACA,iBACA,gBACA,cACA,gBACE;CAEJ,MAAM,UAA6B,CAAC,GAAG,eAAe;AACtD,KAAI,YACF,SAAQ,KAAK,GAAG,aAAa;UACpB,mBAAmB,gBAAgB,SAAS,GAAG;EACxD,MAAM,SAAS,IAAI,IAAI,gBAAgB;AACvC,OAAK,MAAM,SAAS,aAClB,KAAI,OAAO,IAAI,MAAM,KAAK,CAAE,SAAQ,KAAK,MAAM;EAEjD,MAAM,aAAa,IAAI,IAAI,eAAe,KAAK,MAAM,EAAE,KAAK,CAAC;EAC7D,MAAM,cAAc,IAAI,IAAI,aAAa,KAAK,MAAM,EAAE,KAAK,CAAC;AAC5D,OAAK,MAAM,QAAQ,gBACjB,KAAI,CAAC,YAAY,IAAI,KAAK,IAAI,CAAC,WAAW,IAAI,KAAK,CACjD,QAAO,KACL,qGACA,WACA,KACD;;CAKP,MAAM,yBAAS,IAAI,KAAgC;AACnD,MAAK,MAAM,SAAS,SAAS;EAC3B,MAAM,QAAQ,OAAO,IAAI,MAAM,KAAK,IAAI,EAAE;AAC1C,QAAM,KAAK,MAAM;AACjB,SAAO,IAAI,MAAM,MAAM,MAAM;;CAG/B,MAAM,4BAAY,IAAI,KAA8B;CACpD,MAAM,4BAAY,IAAI,KAAuB;AAE7C,MAAK,MAAM,CAAC,MAAM,UAAU,QAAQ;AAClC,MAAI,MAAM,WAAW,GAAG;AACtB,aAAU,IAAI,MAAM,MAAM,GAAG;AAC7B;;EAGF,MAAM,eAAyB,EAAE;AACjC,OAAK,MAAM,SAAS,OAAO;GACzB,MAAM,YAAY,GAAG,gBAAgB,MAAM,QAAQ,GAAG;GACtD,MAAM,WAAW,UAAU,IAAI,UAAU;AACzC,OAAI,SACF,OAAM,IAAI,MACR,UAAU,UAAU,UAAU,MAAM,OAAO,2BAA2B,KAAK,KACrE,SAAS,IAAI,OAAO,MAAM,IAAI,gDACrC;AAEH,aAAU,IAAI,WAAW,MAAM;AAC/B,gBAAa,KAAK,UAAU;;AAE9B,eAAa,MAAM;AACnB,YAAU,IAAI,MAAM,aAAa;AACjC,SAAO,KACL,kFACA,WACA,MACA,aAAa,KAAK,OAAO,CAC1B;;AAUH,QAAO;EAAE;EAAW;EAAW,SAPM,CAAC,GAAG,UAAU,SAAS,CAAC,CAC1D,KAAK,CAAC,SAAS,YAAY;GAC1B,MAAM;GACN,aAAa,MAAM;GACpB,EAAE,CACF,MAAM,GAAG,MAAM,EAAE,KAAK,cAAc,EAAE,KAAK,CAAC;EAEP;;;;;;AAO1C,SAAgB,aACd,SACA,WACiB;CACjB,MAAM,SAAS,QAAQ,UAAU,IAAI,UAAU;AAC/C,KAAI,OAAQ,QAAO;CAEnB,MAAM,eAAe,QAAQ,UAAU,IAAI,UAAU;AACrD,KAAI,aACF,OAAM,IAAI,MACR,UAAU,UAAU,kCAAkC,aAAa,KAAK,KAAK,CAAC,GAC/E;CAGH,MAAM,YAAY,CAAC,GAAG,QAAQ,UAAU,MAAM,CAAC,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;AACrE,OAAM,IAAI,MAAM,kBAAkB,UAAU,gBAAgB,UAAU,GAAG"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
//#region src/core/agent/skills/types.d.ts
|
|
2
|
+
/** Where a skill was discovered. Drives the qualified name used on collision. */
|
|
3
|
+
type SkillSource = "bundle-agent" | "bundle-global" | "volume";
|
|
4
|
+
/**
|
|
5
|
+
* A single skill: a `SKILL.md` (frontmatter `name`+`description` + Markdown
|
|
6
|
+
* body) plus any bundled resource files in the same directory. The body is
|
|
7
|
+
* loaded into model context on demand (via the `load_skill` tool or a forced
|
|
8
|
+
* `/skill-name` invocation); only `name`+`description` are always-on in the
|
|
9
|
+
* prompt catalog.
|
|
10
|
+
*/
|
|
11
|
+
interface SkillDefinition {
|
|
12
|
+
/** Frontmatter `name`. The addressable skill id. */
|
|
13
|
+
name: string;
|
|
14
|
+
/** Frontmatter `description`. Injected into the always-on prompt catalog. */
|
|
15
|
+
description: string;
|
|
16
|
+
/** Markdown body — the instructions loaded on demand. */
|
|
17
|
+
body: string;
|
|
18
|
+
/** Where the skill came from. */
|
|
19
|
+
source: SkillSource;
|
|
20
|
+
/** Absolute directory containing `SKILL.md` and any bundled resources. */
|
|
21
|
+
dir: string;
|
|
22
|
+
/** Relative posix paths of bundled resource files (excludes `SKILL.md`). */
|
|
23
|
+
files: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Optional advisory tool allowlist from frontmatter `allowed-tools`. Surfaced
|
|
26
|
+
* as a hint in v1 — NOT enforced (loading a skill does not restrict the
|
|
27
|
+
* agent's callable tools).
|
|
28
|
+
*/
|
|
29
|
+
allowedTools?: string[];
|
|
30
|
+
}
|
|
31
|
+
/** The always-on prompt entry for a skill (what the model sees before loading). */
|
|
32
|
+
interface SkillCatalogEntry {
|
|
33
|
+
/** Addressable name — bare when unique, `<scope>:name` when collided. */
|
|
34
|
+
name: string;
|
|
35
|
+
description: string;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Per-agent resolved skill catalog: visibility + collision rules applied.
|
|
39
|
+
* `byAddress` maps every addressable name (bare or qualified) to its skill;
|
|
40
|
+
* `ambiguous` maps a bare name shadowed by multiple sources to the qualified
|
|
41
|
+
* alternatives; `catalog` is the always-on prompt list (one entry per address).
|
|
42
|
+
*/
|
|
43
|
+
interface ResolvedSkillCatalog {
|
|
44
|
+
byAddress: Map<string, SkillDefinition>;
|
|
45
|
+
ambiguous: Map<string, string[]>;
|
|
46
|
+
catalog: SkillCatalogEntry[];
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { ResolvedSkillCatalog };
|
|
50
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","names":[],"sources":["../../../../src/core/agent/skills/types.ts"],"mappings":";;KACY,WAAA;;;;;AASZ;;;UAAiB,eAAA;EAEf;EAAA,IAAA;EAIA;EAFA,WAAA;EAIQ;EAFR,IAAA;EAMA;EAJA,MAAA,EAAQ,WAAA;EAUI;EARZ,GAAA;EAYe;EAVf,KAAA;;;;AAsBF;;EAhBE,YAAA;AAAA;;UAIe,iBAAA;EAeN;EAbT,IAAA;EACA,WAAA;AAAA;;;;;;;UASe,oBAAA;EACf,SAAA,EAAW,GAAA,SAAY,eAAA;EACvB,SAAA,EAAW,GAAA;EACX,OAAA,EAAS,iBAAA;AAAA"}
|
|
@@ -5,6 +5,7 @@ import { HostedSupervisorTool, SupervisorTool } from "../../agents/supervisor-ap
|
|
|
5
5
|
import { GenerationParams } from "../../agents/databricks.js";
|
|
6
6
|
import { McpHostPolicyConfig } from "../../connectors/mcp/host-policy.js";
|
|
7
7
|
import "../../connectors/mcp/index.js";
|
|
8
|
+
import { ResolvedSkillCatalog } from "./skills/types.js";
|
|
8
9
|
import { FunctionTool } from "./tools/function-tool.js";
|
|
9
10
|
import { HostedTool } from "./tools/hosted-tools.js";
|
|
10
11
|
|
|
@@ -155,6 +156,13 @@ interface AgentDefinition {
|
|
|
155
156
|
tools?: AgentTools | AgentToolsFn;
|
|
156
157
|
/** Sub-agents, exposed as `agent-<key>` tools on this agent. */
|
|
157
158
|
agents?: Record<string, AgentDefinition>;
|
|
159
|
+
/**
|
|
160
|
+
* Names of global skills (shared `skills/` pool or catalog volume) to make
|
|
161
|
+
* visible to this agent. Per-agent skills under `<id>/skills/` are always
|
|
162
|
+
* visible and need not be listed. Ignored when the plugin's
|
|
163
|
+
* `autoInheritSkills` makes every global skill visible.
|
|
164
|
+
*/
|
|
165
|
+
skills?: string[];
|
|
158
166
|
/** Override the plugin's baseSystemPrompt for this agent only. */
|
|
159
167
|
baseSystemPrompt?: BaseSystemPromptOption;
|
|
160
168
|
maxSteps?: number;
|
|
@@ -213,6 +221,28 @@ interface AgentsPluginConfig extends BasePluginConfig {
|
|
|
213
221
|
tools?: Record<string, AgentTool>;
|
|
214
222
|
/** Whether to auto-inherit every ToolProvider plugin's toolkit. Accepts a boolean shorthand. */
|
|
215
223
|
autoInheritTools?: boolean | AutoInheritToolsConfig;
|
|
224
|
+
/**
|
|
225
|
+
* Whether every global skill (shared `skills/` pool or catalog volume) is
|
|
226
|
+
* visible to an agent without listing it in `skills:` frontmatter. Off by
|
|
227
|
+
* default so each agent's always-on skill catalog stays lean; accepts a
|
|
228
|
+
* boolean shorthand or a per-origin `{ file, code }` config, mirroring
|
|
229
|
+
* {@link autoInheritTools}.
|
|
230
|
+
*/
|
|
231
|
+
autoInheritSkills?: boolean | AutoInheritToolsConfig;
|
|
232
|
+
/**
|
|
233
|
+
* Unity Catalog Volume path for catalog-sourced skills (e.g.
|
|
234
|
+
* `/Volumes/<catalog>/<schema>/<volume>`). Falls back to the
|
|
235
|
+
* `DATABRICKS_VOLUME_AGENT_SKILLS` env var. Skills at `<volume>/<name>/SKILL.md`
|
|
236
|
+
* are discovered at boot and on `reload()` and read as the service principal.
|
|
237
|
+
*/
|
|
238
|
+
skillsVolume?: string;
|
|
239
|
+
/**
|
|
240
|
+
* Identity used to read catalog (volume) skills. v1 supports `"sp"` (default —
|
|
241
|
+
* a shared, service-principal-readable curated pool). `"obo"` is the reserved
|
|
242
|
+
* switch point for per-user skill volumes and is not wired yet (falls back to
|
|
243
|
+
* `"sp"` with a warning).
|
|
244
|
+
*/
|
|
245
|
+
skillCredentialMode?: "sp" | "obo";
|
|
216
246
|
/** Persistent thread store. Default: in-memory. */
|
|
217
247
|
threadStore?: ThreadStore;
|
|
218
248
|
/** Customize or disable the AppKit base system prompt. */
|
|
@@ -316,6 +346,17 @@ type ResolvedToolEntry = {
|
|
|
316
346
|
source: "hosted-supervisor";
|
|
317
347
|
spec: SupervisorTool;
|
|
318
348
|
def: AgentToolDefinition;
|
|
349
|
+
} | {
|
|
350
|
+
/**
|
|
351
|
+
* Built-in skill tools (`load_skill`, `read_skill_file`) injected into
|
|
352
|
+
* any agent that has a visible skill catalog. Executed in-process by the
|
|
353
|
+
* agents plugin against the agent's resolved catalog; read-only, so they
|
|
354
|
+
* bypass the approval gate.
|
|
355
|
+
*/
|
|
356
|
+
source: "skill";
|
|
357
|
+
builtin: "load_skill" | "read_skill_file";
|
|
358
|
+
catalog: ResolvedSkillCatalog;
|
|
359
|
+
def: AgentToolDefinition;
|
|
319
360
|
};
|
|
320
361
|
interface RegisteredAgent {
|
|
321
362
|
name: string;
|
|
@@ -329,6 +370,12 @@ interface RegisteredAgent {
|
|
|
329
370
|
generationParams?: GenerationParams;
|
|
330
371
|
/** Mirrors `AgentDefinition.ephemeral` — skip thread persistence. */
|
|
331
372
|
ephemeral?: boolean;
|
|
373
|
+
/**
|
|
374
|
+
* Resolved per-agent skill catalog (visibility + collision rules applied).
|
|
375
|
+
* Present when any skill is visible to this agent; drives the always-on
|
|
376
|
+
* prompt catalog and `load_skill` dispatch.
|
|
377
|
+
*/
|
|
378
|
+
skills?: ResolvedSkillCatalog;
|
|
332
379
|
}
|
|
333
380
|
/**
|
|
334
381
|
* Type guard for `ToolkitEntry` — used by the agents plugin to differentiate
|
|
@@ -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":";;;;;;;;;;;;;;;;;;UAoBiB,YAAA;EAAA,SACN,YAAA;EACT,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;EACL,WAAA,GAAc,eAAA;EAFd;;;;;;EASA,eAAA;AAAA;AASF;;;;;;AAAA,KAAY,SAAA,GACR,YAAA,GACA,UAAA,GACA,YAAA,GAAY,oBAAA;AAAA,UAGC,cAAA;EAF6C;EAI5D,MAAA;EANE;EAQF,IAAA;EAPc;EASd,MAAA;EATc;EAWd,MAAA,GAAS,MAAA;AAAA;;;;;;;;UAUM,qBAAA;EACf,OAAA,CAAQ,IAAA,GAAO,cAAA,GAAiB,MAAA,SAAe,YAAA;AAAA;;;;;;;;;;;;;;;AA2BjD;;;;;AAKA;;;;;KALY,OAAA,GAAU,MAAA,SAAe,qBAAA;;;;UAKpB,aAAA;EACf,SAAA;EACA,WAAA;EACA,SAAA;AAAA;AAAA,KAGU,sBAAA,sBAGN,GAAA,EAAK,aAAA;;;;;KAMC,UAAA,GAAa,MAAA,SAAe,SAAA;;;;;;;;;AAaxC;KAFY,YAAA,IAAgB,OAAA,EAAS,OAAA,KAAY,UAAA;AAAA,UAEhC,eAAA;EAmCP;;;;;;;;;;;;;;;;;;EAhBR,IAAA;EA4BQ;;;;;;;EApBR,OAAA;EAgCA;EA9BA,YAAA;EAuCA;;;;;EAjCA,KAAA,GAAQ,YAAA,GAAe,OAAA,CAAQ,YAAA;EAwDM;;;;AAOvC;;;;;;;EAnDE,KAAA,GAAQ,UAAA,GAAa,YAAA;EAmEE;EAjEvB,MAAA,GAAS,MAAA,SAAe,eAAA;EAmEK;;;;;;EA5D7B,MAAA;EA0C0D;EAxC1D,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;EAgDwB;;;;;;;EAxCxB,gBAAA,GAAmB,gBAAA;EA8CI;;;;;;;;EArCvB,SAAA;AAAA;;;;;;;;;;;;UAce,sBAAA;EAqHI;EAnHnB,IAAA;EAwH2B;EAtH3B,IAAA;AAAA;AAAA,UAGe,kBAAA,SAA2B,gBAAA;EA6HjC;;;;;;;;;EAnHT,MAAA,GAAS,MAAA,SAAe,eAAA;EA4GpB;EA1GJ,YAAA;EA4GI;EA1GJ,YAAA,GAAe,YAAA,GAAe,OAAA,CAAQ,YAAA;EA6GlC;EA3GJ,KAAA,GAAQ,MAAA,SAAe,SAAA;EA4GL;EA1GlB,gBAAA,aAA6B,sBAAA;EA2GpB;;;;;;;EAnGT,iBAAA,aAA8B,sBAAA;EA6GrB;;;;;;EAtGT,YAAA;EA+HI;;;;;;EAxHJ,mBAAA;EA6He;EA3Hf,WAAA,GAAc,WAAA;;EAEd,gBAAA,GAAmB,sBAAA;EA6HI;;;;;;EAtHvB,GAAA,GAAM,mBAAA;EAmHN;;;;;;;;;EAzGA,QAAA;IA+GA;;;;;IAzGE,qBAAA,YAmH2B;IAjH3B,SAAA;EAAA;EAwH0B;;;;;;;;EA9G5B,MAAA;;;;;;IAME,2BAAA;;;;;;IAMA,YAAA;;;;;;IAMA,gBAAA;;;;;;;;;;;;;IAaA,iBAAA;EAAA;AAAA;;KAKQ,iBAAA;EAEN,MAAA;EACA,UAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,YAAA,EAAc,YAAA;EACd,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,WAAA;EACA,GAAA,EAAK,mBAAA;AAAA;EAGL,MAAA;EACA,SAAA;EACA,GAAA,EAAK,mBAAA;AAAA;;;;;;;;;;;EAaL,MAAA;EACA,IAAA,EAdwB,cAAA;EAexB,GAAA,EAAK,mBAAA;AAAA;;;;;;;EASL,MAAA;EACA,OAAA;EACA,OAAA,EAAS,oBAAA;EACT,GAAA,EAAK,mBAAA;AAAA;AAAA,UAGM,eAAA;EACf,IAAA;EACA,YAAA;EACA,OAAA,EAAS,YAAA;EACT,SAAA,EAAW,GAAA,SAAY,iBAAA;EACvB,gBAAA,GAAmB,sBAAA;EACnB,QAAA;EACA,SAAA;;EAEA,gBAAA,GAAmB,gBAAA;;EAEnB,SAAA;;;;;;EAMA,MAAA,GAAS,oBAAA;AAAA;;;;;iBAOK,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/core/agent/types.ts"],"sourcesContent":["import type {\n AgentAdapter,\n AgentToolDefinition,\n BasePluginConfig,\n ThreadStore,\n ToolAnnotations,\n} from \"shared\";\n\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 `server/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 /**\n * Marks this agent as the default one chosen when a client doesn't name an\n * agent. Mirrors markdown frontmatter `default: true`. When several agents\n * set it, a code (discovered) agent wins over a markdown one, then the\n * lowest id; an explicit `agents({ defaultAgent })` always overrides it.\n * Defaults to `false`.\n */\n default?: boolean;\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 /**\n * @deprecated Put each code agent in its own folder under\n * `server/agents/<id>/agent.ts` (`export default createAgent({ ... })`); it is\n * discovered automatically at startup and the call collapses to\n * `agents({ ... })` with no map. Still honored for backward compatibility\n * (emits a one-time deprecation warning) but will be removed in a future\n * minor. If both discovery and this map define the same id, discovery wins\n * and the map entry is ignored.\n */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Precedence: this value, else a code agent with `default: true`, else a markdown agent with `default: true`, else the first-registered agent. */\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 /api/agents/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":";;;;;AA6WA,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\";\n\nimport type { GenerationParams } from \"../../agents/databricks\";\nimport type { McpHostPolicyConfig } from \"../../connectors/mcp\";\nimport type { ResolvedSkillCatalog } from \"./skills/types\";\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 `server/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 /**\n * Marks this agent as the default one chosen when a client doesn't name an\n * agent. Mirrors markdown frontmatter `default: true`. When several agents\n * set it, a code (discovered) agent wins over a markdown one, then the\n * lowest id; an explicit `agents({ defaultAgent })` always overrides it.\n * Defaults to `false`.\n */\n default?: boolean;\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 /**\n * Names of global skills (shared `skills/` pool or catalog volume) to make\n * visible to this agent. Per-agent skills under `<id>/skills/` are always\n * visible and need not be listed. Ignored when the plugin's\n * `autoInheritSkills` makes every global skill visible.\n */\n skills?: string[];\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 /**\n * @deprecated Put each code agent in its own folder under\n * `server/agents/<id>/agent.ts` (`export default createAgent({ ... })`); it is\n * discovered automatically at startup and the call collapses to\n * `agents({ ... })` with no map. Still honored for backward compatibility\n * (emits a one-time deprecation warning) but will be removed in a future\n * minor. If both discovery and this map define the same id, discovery wins\n * and the map entry is ignored.\n */\n agents?: Record<string, AgentDefinition>;\n /** Agent used when clients don't specify one. Precedence: this value, else a code agent with `default: true`, else a markdown agent with `default: true`, else the first-registered agent. */\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 /**\n * Whether every global skill (shared `skills/` pool or catalog volume) is\n * visible to an agent without listing it in `skills:` frontmatter. Off by\n * default so each agent's always-on skill catalog stays lean; accepts a\n * boolean shorthand or a per-origin `{ file, code }` config, mirroring\n * {@link autoInheritTools}.\n */\n autoInheritSkills?: boolean | AutoInheritToolsConfig;\n /**\n * Unity Catalog Volume path for catalog-sourced skills (e.g.\n * `/Volumes/<catalog>/<schema>/<volume>`). Falls back to the\n * `DATABRICKS_VOLUME_AGENT_SKILLS` env var. Skills at `<volume>/<name>/SKILL.md`\n * are discovered at boot and on `reload()` and read as the service principal.\n */\n skillsVolume?: string;\n /**\n * Identity used to read catalog (volume) skills. v1 supports `\"sp\"` (default —\n * a shared, service-principal-readable curated pool). `\"obo\"` is the reserved\n * switch point for per-user skill volumes and is not wired yet (falls back to\n * `\"sp\"` with a warning).\n */\n skillCredentialMode?: \"sp\" | \"obo\";\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 /api/agents/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 | {\n /**\n * Built-in skill tools (`load_skill`, `read_skill_file`) injected into\n * any agent that has a visible skill catalog. Executed in-process by the\n * agents plugin against the agent's resolved catalog; read-only, so they\n * bypass the approval gate.\n */\n source: \"skill\";\n builtin: \"load_skill\" | \"read_skill_file\";\n catalog: ResolvedSkillCatalog;\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 * Resolved per-agent skill catalog (visibility + collision rules applied).\n * Present when any skill is visible to this agent; drives the always-on\n * prompt catalog and `load_skill` dispatch.\n */\n skills?: ResolvedSkillCatalog;\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":";;;;;AA6ZA,SAAgB,eAAe,OAAuC;AACpE,QACE,OAAO,UAAU,YACjB,UAAU,QACT,MAAqC,iBAAiB"}
|
|
@@ -40,6 +40,12 @@ declare class AgentsPlugin extends Plugin implements ToolProvider {
|
|
|
40
40
|
* negative, or `NaN`) can't degrade into immediate auto-denial of every
|
|
41
41
|
* mutating tool call.
|
|
42
42
|
*/
|
|
43
|
+
/**
|
|
44
|
+
* Shared global skill pool (bundle `skills/` + catalog volume), loaded once
|
|
45
|
+
* per registry build. Read by {@link buildRegisteredAgent} to resolve each
|
|
46
|
+
* agent's visible catalog and by the live `register` path.
|
|
47
|
+
*/
|
|
48
|
+
private globalSkills;
|
|
43
49
|
private cachedApprovalPolicy;
|
|
44
50
|
private get resolvedApprovalPolicy();
|
|
45
51
|
/** Effective DoS limits with defaults applied. */
|
|
@@ -108,6 +114,35 @@ declare class AgentsPlugin extends Plugin implements ToolProvider {
|
|
|
108
114
|
*/
|
|
109
115
|
private pluginProviderIndex;
|
|
110
116
|
private buildRegisteredAgent;
|
|
117
|
+
/** Loads the shared global skill pool from `<agentsDir>/skills/`. */
|
|
118
|
+
private loadGlobalSkills;
|
|
119
|
+
/** Configured catalog-skills volume path, or null when none is set. */
|
|
120
|
+
private resolveSkillsVolume;
|
|
121
|
+
/**
|
|
122
|
+
* Workspace client used to read catalog skills. v1 reads as the app service
|
|
123
|
+
* principal; `getWorkspaceClient()` resolves to SP outside a user scope
|
|
124
|
+
* (boot and skill-tool dispatch are both unscoped). This is the single
|
|
125
|
+
* switch point for a future OBO mode.
|
|
126
|
+
*/
|
|
127
|
+
private skillWorkspaceClient;
|
|
128
|
+
/**
|
|
129
|
+
* Discovers catalog skills from the configured UC Volume, read as the
|
|
130
|
+
* service principal at boot (and on `reload()`). Each `<volume>/<name>/`
|
|
131
|
+
* folder with a `SKILL.md` becomes a `source: "volume"` skill. Best-effort:
|
|
132
|
+
* a missing volume, unavailable workspace client, or a malformed individual
|
|
133
|
+
* skill is logged and skipped rather than failing the whole registry build.
|
|
134
|
+
*/
|
|
135
|
+
private loadVolumeSkills;
|
|
136
|
+
/** Lists a volume skill's resource files (one level, excluding SKILL.md). */
|
|
137
|
+
private listVolumeSkillFiles;
|
|
138
|
+
/**
|
|
139
|
+
* Resolves the per-agent skill catalog: loads this agent's private skills
|
|
140
|
+
* (`<agentsDir>/<id>/skills/`, file-origin only), then applies visibility
|
|
141
|
+
* (opt-in via `def.skills` or `autoInheritSkills`) and collision rules
|
|
142
|
+
* against the shared global pool. Returns `undefined` when nothing is
|
|
143
|
+
* visible so the prompt catalog and dispatch can cheaply skip skills.
|
|
144
|
+
*/
|
|
145
|
+
private resolveAgentSkills;
|
|
111
146
|
private resolveAdapter;
|
|
112
147
|
/**
|
|
113
148
|
* Resolves an agent's tool record into a per-agent dispatch index. Connects
|
|
@@ -214,6 +249,21 @@ declare class AgentsPlugin extends Plugin implements ToolProvider {
|
|
|
214
249
|
* sub-agent, so depth limits remain enforced.
|
|
215
250
|
*/
|
|
216
251
|
private dispatchToolCall;
|
|
252
|
+
/**
|
|
253
|
+
* Executes the built-in `load_skill` / `read_skill_file` tools against the
|
|
254
|
+
* agent's resolved skill catalog. `load_skill` returns a skill's body plus a
|
|
255
|
+
* manifest of bundled files; `read_skill_file` returns the contents of one
|
|
256
|
+
* of those files (bundle skills only in v1 — catalog-volume resource reads
|
|
257
|
+
* arrive with the volume source).
|
|
258
|
+
*/
|
|
259
|
+
private dispatchSkillTool;
|
|
260
|
+
/**
|
|
261
|
+
* Renders the prompt addendum for a force-loaded skill (`/skill-name`).
|
|
262
|
+
* Returns null when the agent has no catalog or the name doesn't resolve —
|
|
263
|
+
* an unusable request shouldn't fail the whole turn, so it's logged and the
|
|
264
|
+
* model proceeds with the catalog + `load_skill` still available.
|
|
265
|
+
*/
|
|
266
|
+
private renderForcedSkill;
|
|
217
267
|
/**
|
|
218
268
|
* Runs a sub-agent in response to an `agent-<key>` tool call. Returns the
|
|
219
269
|
* concatenated text output to hand back to the parent adapter as the tool
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"agents.d.ts","names":[],"sources":["../../../src/plugins/agents/agents.ts"],"mappings":";;;;;;;;;;cAoKa,YAAA,SAAqB,MAAA,YAAkB,YAAA;EAAA,OAC3C,QAAA,EADiB,cAAA;EAAA,OAEjB,KAAA,EAAO,WAAA;EAAA,UAEI,MAAA,EAAQ,kBAAA;EAAA,QAElB,MAAA;EAAA,QACA,gBAAA;EAAA,QACA,aAAA;EARG;;;;;;EAAA,QAkBH,gBAAA;EAAA,QACA,SAAA;EAAA,QACA,WAAA;EAAA,QACA,YAAA;EA89BkB;EAAA,QA59BlB,0BAAA;EAoiCQ;EAAA,QAliCR,6BAAA;cAEI,MAAA,EAAQ,kBAAA;EAikE6B;;;;;;;;;;EA5lEC;;;;;EAAA,QA+D1C,YAAA;EAAA,QAEA,oBAAA;EAAA,YAKI,sBAAA,CAAA;EA/DJ;EAAA,YAyFI,cAAA,CAAA;EA9EJ;EAAA,QAiGA,gBAAA;EA/FA;;;;;;EAAA,QAyGA,WAAA;EA9DA;;;;;EAAA,QA+EA,aAAA;EAYF,KAAA,CAAA,GAAK,OAAA;EAAL;;;;;;EAeA,MAAA,CAAA,GAAU,OAAA;EAoLR;;;;;EAAA,QA1JM,kBAAA;EAgSA;;;;;EAAA,QAnLN,mBAAA;EA4UM;;;;EAAA,QA9SN,uBAAA;EAsiBM;;;;EAAA,QAvhBN,0BAAA;EAAA,QAUA,iBAAA;EAwpBA;;;;;;EAAA,QA9oBM,cAAA;EAozBN;EAAA,QAvxBA,mBAAA;EAAA,QAeM,mBAAA;EA+lCA;;;;;;EAAA,QA5iCN,mBAAA;EAAA,QAmBM,oBAAA;EA+jDA;EAAA,QAriDA,gBAAA;EA4jDN;EAAA,QArjDA,mBAAA;EA8kDF;;;;;;EAAA,QAlkDE,oBAAA;EA4kDyC;;;;;;;EAAA,QAjkDnC,gBAAA;;UA0EA,oBAAA;EA6/CiB;;;;;AAyMjC;;EAzMiC,QAt+CjB,kBAAA;EAAA,QA4BA,cAAA;EAmpDG;;;;;EAAA,QAvmDH,cAAA;EAumDG;;;;;;;;;;;EAAA,QAr+CT,eAAA;;;;;;;;;;;;;UA4BA,eAAA;EAAA,QAkBM,gBAAA;EAAA,QA0DA,kBAAA;EAiEd,aAAA,CAAA,GAAiB,mBAAA;EAIX,gBAAA,CAAA,GAAoB,OAAA;;;;;;;UAYlB,iBAAA;EAUR,YAAA,CAAa,MAAA,EAAQ,UAAA;EAkDrB,YAAA,CAAA,GAAgB,MAAA;EAAA,QAeF,WAAA;;;;;;;;;;;;UA2FN,gCAAA;;;;;;;;;;;UAuBM,aAAA;EAAA,QA2FA,YAAA;;;;;;;;;;;;;;;;;;;;;;;;UAqOA,qBAAA;;;;;;;;;;;;UA0KA,gBAAA;;;;;;;;UA8HA,iBAAA;;;;;;;UAkDN,iBAAA;;;;;;;;;;;;;;;UAgCM,WAAA;EAAA,QAiGA,aAAA;EAAA,QA2BA,cAAA;EAAA,QAuCA,kBAAA;EAAA,QASA,gBAAA;EAAA,QAUA,mBAAA;EAAA,QAaN,YAAA;EAAA,QASA,aAAA;EAgBF,QAAA,CAAA,GAAY,OAAA;EAQlB,OAAA,CAAA;6BAE2B,GAAA,EAAO,eAAA,KAAe,OAAA;;2BAG3B,eAAA;;;oCAGS,OAAA,CAAA,MAAA;EAAA;EAAA,QAIjB,iBAAA;AAAA;;;;;;;;;;;;;;;;;;cAqMH,MAAA,EAAM,QAAA,QAAA,YAAA,EAAA,kBAAA"}
|