@theokit/sdk 2.23.0 → 2.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/dist/a2a/index.cjs +259 -192
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +259 -192
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/create-skill.d.ts +8 -0
  7. package/dist/{cron-7CruUd_0.d.ts → cron-B44D-678.d.ts} +67 -4
  8. package/dist/{cron-Bpt_1khA.d.cts → cron-qI-dbG7c.d.cts} +67 -4
  9. package/dist/cron.cjs +246 -181
  10. package/dist/cron.cjs.map +1 -1
  11. package/dist/cron.d.cts +2 -2
  12. package/dist/cron.d.ts +2 -2
  13. package/dist/cron.js +246 -181
  14. package/dist/cron.js.map +1 -1
  15. package/dist/define-tool.d.ts +33 -20
  16. package/dist/{errors-CkCaIqVP.d.cts → errors-DIKBXffg.d.cts} +1 -1
  17. package/dist/{errors-BuwwkrAk.d.ts → errors-DRS-kqOK.d.ts} +1 -1
  18. package/dist/errors.d.cts +2 -2
  19. package/dist/eval.cjs +246 -181
  20. package/dist/eval.cjs.map +1 -1
  21. package/dist/eval.js +246 -181
  22. package/dist/eval.js.map +1 -1
  23. package/dist/index.cjs +299 -186
  24. package/dist/index.cjs.map +1 -1
  25. package/dist/index.d.cts +75 -27
  26. package/dist/index.d.ts +75 -27
  27. package/dist/index.js +299 -187
  28. package/dist/index.js.map +1 -1
  29. package/dist/internal/runtime/local-agent/local-agent-bootstrap.d.ts +2 -4
  30. package/dist/internal/runtime/skills/skill-frontmatter.d.ts +6 -0
  31. package/dist/{run-CrIulPF7.d.cts → run-Cr0C6cOM.d.cts} +17 -0
  32. package/dist/{run-CrIulPF7.d.ts → run-Cr0C6cOM.d.ts} +17 -0
  33. package/dist/skills.cjs.map +1 -1
  34. package/dist/skills.js.map +1 -1
  35. package/dist/types/agent.d.ts +57 -2
  36. package/dist/types/run.d.ts +17 -0
  37. package/dist/workflow.cjs +37 -0
  38. package/dist/workflow.cjs.map +1 -1
  39. package/dist/workflow.d.cts +47 -1
  40. package/dist/workflow.d.ts +47 -1
  41. package/dist/workflow.js +37 -2
  42. package/dist/workflow.js.map +1 -1
  43. package/package.json +1 -1
@@ -1,13 +1,21 @@
1
1
  import type { z as ZodNamespace, ZodType } from "zod";
2
2
  import type { SanitizeOptions } from "./sanitize/types.js";
3
3
  import type { CustomTool } from "./types/agent.js";
4
+ import type { ToolResultContentBlock } from "./types/content-blocks.js";
4
5
  /**
5
6
  * Spec accepted by {@link defineTool}. `inputSchema` is a Zod schema; the
6
7
  * `handler` argument type is inferred via `z.infer<T>` — no `as` casts.
7
8
  *
8
9
  * @public
9
10
  */
10
- export interface DefineToolSpec<T extends ZodType> {
11
+ /**
12
+ * SE16 — the handler's return type. With no `outputSchema` the tool returns a
13
+ * plain `string` (pre-SE16 shape). With an `outputSchema` the handler returns the
14
+ * STRUCTURED output inferred from it (validated + serialized to the tool result).
15
+ * The `[O]` tuple wrap prevents distribution so `never` maps cleanly to `string`.
16
+ */
17
+ type ToolHandlerReturn<O extends ZodType> = [O] extends [never] ? string : ZodNamespace.infer<O>;
18
+ export interface DefineToolSpec<T extends ZodType, O extends ZodType = never> {
11
19
  /** Tool name surfaced to the LLM. Same constraints as {@link CustomTool.name}. */
12
20
  name: string;
13
21
  /** Description surfaced to the LLM. */
@@ -15,7 +23,16 @@ export interface DefineToolSpec<T extends ZodType> {
15
23
  /** Zod schema describing the input. Must be `z.object(...)` at the root for the LLM tool contract. */
16
24
  inputSchema: T;
17
25
  /**
18
- * Handler invoked with the parsed input. Type is inferred via `z.infer<T>`.
26
+ * SE16 optional Zod schema describing the OUTPUT. When set, the handler
27
+ * returns the structured value inferred from it; the value is validated against
28
+ * this schema and serialized to the tool result (a string stays as-is, an object
29
+ * is JSON-stringified). A validation failure raises `ZodError`, converted to a
30
+ * `tool_result(isError)`. Absent ⇒ the handler returns a plain string (unchanged).
31
+ */
32
+ outputSchema?: O;
33
+ /**
34
+ * Handler invoked with the parsed input. Type is inferred via `z.infer<T>`; the
35
+ * return type is `z.infer<O>` when `outputSchema` is set, else `string`.
19
36
  * #65 — an optional 2nd `ToolContext` argument carries the run's `AbortSignal`,
20
37
  * so a cooperative handler can stop early when the run is cancelled. Existing
21
38
  * single-argument handlers are unaffected.
@@ -23,7 +40,18 @@ export interface DefineToolSpec<T extends ZodType> {
23
40
  handler: (input: ZodNamespace.infer<T>, ctx?: {
24
41
  signal?: AbortSignal;
25
42
  context?: unknown;
26
- }) => string | Promise<string>;
43
+ }) => ToolHandlerReturn<O> | Promise<ToolHandlerReturn<O>>;
44
+ /**
45
+ * SE17 — map the handler's (validated) output to the compact / multimodal
46
+ * representation the MODEL sees in the tool_result. The handler keeps returning
47
+ * the FULL result (validated by `outputSchema`); `toModelOutput` shapes only what
48
+ * reaches the model, so app-facing detail is not forced into model context.
49
+ * Returns a string OR SE7 `ToolResultContentBlock[]` (text + image). Absent ⇒
50
+ * the tool_result is the serialized handler output (SE16 / pre-SE17 behavior).
51
+ * Note: observability (`onToolEnd`) sees the model-facing result this returns,
52
+ * not the raw handler output — the full result lives in the handler's own scope.
53
+ */
54
+ toModelOutput?: (output: ToolHandlerReturn<O>) => string | ToolResultContentBlock[];
27
55
  /**
28
56
  * Sanitize the raw model-emitted args BEFORE schema validation (`@theokit/sdk/sanitize`).
29
57
  * `true` trims whitespace; an object opts into coercion / JSON-repair. Coercion is schema-aware
@@ -32,20 +60,5 @@ export interface DefineToolSpec<T extends ZodType> {
32
60
  */
33
61
  sanitize?: boolean | SanitizeOptions;
34
62
  }
35
- /**
36
- * Type-safe builder for {@link CustomTool}. Converts a Zod schema to JSON
37
- * Schema (for the LLM-facing `inputSchema` field), wraps the handler with a
38
- * runtime `schema.parse` step, and preserves type inference.
39
- *
40
- * Behaviour (ADR D24):
41
- * - JSON Schema conversion uses Zod 4's native `z.toJSONSchema` with
42
- * `unrepresentable: "any"` so transforms/refinements round-trip.
43
- * - Runtime parse failures throw `ZodError`; the SDK's tool-dispatch converts
44
- * them to `tool_result(isError)` with the Zod message.
45
- * - Handler signature is `(input: z.infer<T>)`, not `Record<string, unknown>`.
46
- * - `zod` loads lazily via `createRequire` — consumers who don't call
47
- * `defineTool` don't need `zod` installed.
48
- *
49
- * @public
50
- */
51
- export declare function defineTool<T extends ZodType>(spec: DefineToolSpec<T>): CustomTool;
63
+ export declare function defineTool<T extends ZodType, O extends ZodType = never>(spec: DefineToolSpec<T, O>): CustomTool;
64
+ export {};
@@ -1,4 +1,4 @@
1
- import { v as RunOperation } from './run-CrIulPF7.cjs';
1
+ import { v as RunOperation } from './run-Cr0C6cOM.cjs';
2
2
 
3
3
  /**
4
4
  * Public type contract for the Budget enforcement primitive
@@ -1,4 +1,4 @@
1
- import { v as RunOperation } from './run-CrIulPF7.js';
1
+ import { v as RunOperation } from './run-Cr0C6cOM.js';
2
2
 
3
3
  /**
4
4
  * Public type contract for the Budget enforcement primitive
package/dist/errors.d.cts CHANGED
@@ -1,3 +1,3 @@
1
- export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, g as BudgetExceededError, C as ConfigurationError, u as CredentialPoolExhaustedError, m as ErrorCode, E as ErrorMetadata, I as IntegrationNotConnectedError, n as InvalidTaskIdError, K as KnownAgentRunErrorCode, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, T as TheokitAgentError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-CkCaIqVP.cjs';
2
- import './run-CrIulPF7.cjs';
1
+ export { A as AgentDisposedError, c as AgentRunError, d as AgentRunErrorCode, e as AuthenticationError, g as BudgetExceededError, C as ConfigurationError, u as CredentialPoolExhaustedError, m as ErrorCode, E as ErrorMetadata, I as IntegrationNotConnectedError, n as InvalidTaskIdError, K as KnownAgentRunErrorCode, M as MemoryAdapterError, o as MemoryAdapterErrorCode, N as NetworkError, R as RateLimitError, p as TaskNotFoundError, T as TheokitAgentError, U as UnknownAgentError, q as UnsupportedBudgetOperationError, r as UnsupportedRunOperationError, s as UnsupportedTaskOperationError, t as isTransientError } from './errors-DIKBXffg.cjs';
2
+ import './run-Cr0C6cOM.cjs';
3
3
  import 'zod';
package/dist/eval.cjs CHANGED
@@ -3457,7 +3457,8 @@ function stripSecretsFromOptions(options) {
3457
3457
  local: serializeLocal(options.local),
3458
3458
  cloud: serializeCloud(options.cloud),
3459
3459
  memory: serializeMemory(options.memory),
3460
- skills: serializeEnabledList(options.skills),
3460
+ // SE22 — a SkillsResolver function isn't serializable; persist only the static form.
3461
+ skills: serializeEnabledList(typeof options.skills === "function" ? void 0 : options.skills),
3461
3462
  // Code-`Plugin` objects are closures and cannot be persisted (like custom
3462
3463
  // tools); only the named-enable settings form is serialized.
3463
3464
  plugins: serializeEnabledList(asPluginsSettings(options.plugins)),
@@ -3765,6 +3766,7 @@ function serializeCloud2(cloud) {
3765
3766
  return result;
3766
3767
  }
3767
3768
  function serializeSkills(skills) {
3769
+ if (typeof skills === "function") return void 0;
3768
3770
  if (skills?.enabled === void 0 || skills.enabled.length === 0) return void 0;
3769
3771
  return { enabled: [...skills.enabled] };
3770
3772
  }
@@ -5236,6 +5238,7 @@ init_errors();
5236
5238
  function validateCloudToolParity(options) {
5237
5239
  if (options.cloud === void 0) return;
5238
5240
  rejectFunctionSystemPrompt(options);
5241
+ rejectFunctionSkills(options);
5239
5242
  rejectStdioMcpLocalPaths(options);
5240
5243
  }
5241
5244
  function rejectFunctionSystemPrompt(options) {
@@ -5246,6 +5249,14 @@ function rejectFunctionSystemPrompt(options) {
5246
5249
  );
5247
5250
  }
5248
5251
  }
5252
+ function rejectFunctionSkills(options) {
5253
+ if (typeof options.skills === "function") {
5254
+ throw new ConfigurationError(
5255
+ "Cloud agents require skills as a static settings object. SkillsResolver functions can't run on PaaS \u2014 resolve to a SkillsSettings object before Agent.create() or move the dynamic logic into a hook rule.",
5256
+ { code: "cloud_incompatible_function_resolver" }
5257
+ );
5258
+ }
5259
+ }
5249
5260
  function rejectStdioMcpLocalPaths(options) {
5250
5261
  if (options.mcpServers === void 0) return;
5251
5262
  for (const [name, config] of Object.entries(options.mcpServers)) {
@@ -7102,9 +7113,223 @@ function parseFrontmatterFields(frontmatter) {
7102
7113
  return out;
7103
7114
  }
7104
7115
 
7116
+ // src/internal/runtime/skills/discover-skills.ts
7117
+ init_errors();
7118
+
7119
+ // src/internal/runtime/skills/skill-frontmatter.ts
7120
+ init_errors();
7121
+ init_yaml_frontmatter();
7122
+ function asString(v) {
7123
+ return typeof v === "string" ? v : void 0;
7124
+ }
7125
+ function toStringFields(raw) {
7126
+ const out = {};
7127
+ for (const [k, v] of Object.entries(raw)) out[k] = asString(v);
7128
+ return out;
7129
+ }
7130
+ function parseSkillFrontmatter(raw, fallbackName) {
7131
+ const fields = extractAndParseFrontmatter(raw, fallbackName);
7132
+ const name = resolveName(fields, fallbackName);
7133
+ ensureRequiredFields(fields, name);
7134
+ return buildFrontmatter(fields, name);
7135
+ }
7136
+ function stripSkillFrontmatter(raw) {
7137
+ const match = /^---\s*\n[\s\S]*?\n---\s*\n/.exec(raw);
7138
+ return (match === null ? raw : raw.slice(match[0].length)).trim();
7139
+ }
7140
+ function extractAndParseFrontmatter(raw, fallbackName) {
7141
+ const match = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
7142
+ if (match === null) {
7143
+ throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {
7144
+ code: "missing_frontmatter"
7145
+ });
7146
+ }
7147
+ const frontmatter = match[1] ?? "";
7148
+ try {
7149
+ return toStringFields(parseSimpleYaml(frontmatter));
7150
+ } catch (cause) {
7151
+ const detail = cause instanceof Error ? cause.message : String(cause);
7152
+ throw new ConfigurationError(
7153
+ `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,
7154
+ { code: "schema_invalid", cause }
7155
+ );
7156
+ }
7157
+ }
7158
+ function resolveName(fields, fallbackName) {
7159
+ if (hasContent(fields.name)) return fields.name;
7160
+ if (hasContent(fallbackName)) return fallbackName;
7161
+ throw new ConfigurationError("Skill at unknown path is missing required field: name", {
7162
+ code: "schema_invalid"
7163
+ });
7164
+ }
7165
+ function ensureRequiredFields(fields, name) {
7166
+ if (!hasContent(fields.description)) {
7167
+ throw new ConfigurationError(`Skill ${name} is missing required field: description`, {
7168
+ code: "schema_invalid"
7169
+ });
7170
+ }
7171
+ }
7172
+ function buildFrontmatter(fields, name) {
7173
+ const description = fields.description;
7174
+ if (description === void 0) {
7175
+ throw new ConfigurationError(`Skill ${name} missing description`, { code: "schema_invalid" });
7176
+ }
7177
+ const result = { name, description };
7178
+ if (hasContent(fields.category)) result.category = fields.category;
7179
+ const deps = parseDependencies(fields.dependencies);
7180
+ if (deps !== void 0) result.dependencies = deps;
7181
+ return result;
7182
+ }
7183
+ function parseDependencies(raw) {
7184
+ if (!hasContent(raw)) return void 0;
7185
+ const deps = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
7186
+ return deps.length > 0 ? deps : void 0;
7187
+ }
7188
+ function hasContent(value) {
7189
+ return value !== void 0 && value.trim().length > 0;
7190
+ }
7191
+
7192
+ // src/internal/runtime/skills/discover-skills.ts
7193
+ async function discoverSkills(dir, options) {
7194
+ let entries;
7195
+ try {
7196
+ entries = await readWorkspaceDir(dir, "skills_read_error", "skills directory");
7197
+ } catch {
7198
+ return [];
7199
+ }
7200
+ const skills = [];
7201
+ for (const entry of entries) {
7202
+ if (!entry.isDirectory()) continue;
7203
+ let skillDir;
7204
+ try {
7205
+ skillDir = safePathJoin(dir, entry.name);
7206
+ assertNoSymlinkEscape(skillDir, dir);
7207
+ } catch {
7208
+ continue;
7209
+ }
7210
+ const skillPath = path.join(skillDir, "SKILL.md");
7211
+ let raw;
7212
+ try {
7213
+ raw = await promises.readFile(skillPath, "utf8");
7214
+ } catch {
7215
+ continue;
7216
+ }
7217
+ const skill = tryParseSkill(raw, entry.name, skillPath, options);
7218
+ if (skill !== void 0) skills.push(skill);
7219
+ }
7220
+ return skills;
7221
+ }
7222
+ function tryParseSkill(raw, fallbackName, source, options) {
7223
+ try {
7224
+ const frontmatter = parseSkillFrontmatter(raw, fallbackName);
7225
+ const skill = {
7226
+ name: frontmatter.name,
7227
+ description: frontmatter.description,
7228
+ source
7229
+ };
7230
+ if (frontmatter.category !== void 0) skill.category = frontmatter.category;
7231
+ if (frontmatter.dependencies !== void 0) skill.dependencies = frontmatter.dependencies;
7232
+ return skill;
7233
+ } catch (cause) {
7234
+ if (cause instanceof ConfigurationError) {
7235
+ options?.onInvalidSkill?.({
7236
+ name: fallbackName,
7237
+ source,
7238
+ code: cause.code ?? "unknown",
7239
+ message: cause.message
7240
+ });
7241
+ return void 0;
7242
+ }
7243
+ throw cause;
7244
+ }
7245
+ }
7246
+
7247
+ // src/internal/runtime/skills/skills-manager.ts
7248
+ var SkillsManager = class {
7249
+ constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
7250
+ this.cwd = cwd;
7251
+ this.settingSourcesIncludeProject = settingSourcesIncludeProject;
7252
+ this.skillsDir = skillsDir;
7253
+ this.inline = inline;
7254
+ }
7255
+ cwd;
7256
+ settingSourcesIncludeProject;
7257
+ skillsDir;
7258
+ inline;
7259
+ skills = [];
7260
+ async initialize() {
7261
+ if (!this.settingSourcesIncludeProject) {
7262
+ this.skills = this.mergeInline([]);
7263
+ return;
7264
+ }
7265
+ await this.refresh();
7266
+ }
7267
+ async refresh() {
7268
+ const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
7269
+ const discovered = await discoverSkills(skillsRoot, {
7270
+ onInvalidSkill: (info) => {
7271
+ process.stderr.write(
7272
+ `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
7273
+ `
7274
+ );
7275
+ }
7276
+ });
7277
+ this.skills = this.mergeInline(discovered);
7278
+ }
7279
+ /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
7280
+ mergeInline(discovered) {
7281
+ if (this.inline === void 0 || this.inline.length === 0) return discovered;
7282
+ const inlineNames = new Set(this.inline.map((s) => s.name));
7283
+ return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
7284
+ }
7285
+ list() {
7286
+ return Promise.resolve(this.skills);
7287
+ }
7288
+ /**
7289
+ * SE20 — resolve a skill by name INCLUDING its body. Inline (`createSkill`)
7290
+ * skills carry `instructions` on the object; filesystem skills read the body
7291
+ * from their `source` SKILL.md (frontmatter stripped). `undefined` when no
7292
+ * enabled skill matches (malformed skills were already excluded at discovery).
7293
+ */
7294
+ async get(name) {
7295
+ const skill = this.skills.find((s) => s.name === name);
7296
+ if (skill === void 0) return void 0;
7297
+ const instructions = typeof skill.instructions === "string" ? skill.instructions : stripSkillFrontmatter(await promises.readFile(skill.source, "utf8"));
7298
+ const references = skill.references;
7299
+ return {
7300
+ name: skill.name,
7301
+ description: skill.description,
7302
+ instructions,
7303
+ ...references !== void 0 ? { references } : {}
7304
+ };
7305
+ }
7306
+ };
7307
+
7105
7308
  // src/internal/runtime/system-prompt/local-assembly.ts
7106
- async function buildSystemPromptContext(inputs, userText, memoryFacts) {
7107
- const skills = inputs.skillsManager !== void 0 ? await inputs.skillsManager.list() : [];
7309
+ async function resolveSendSkills(inputs, userText, memoryFacts) {
7310
+ const skills = inputs.options.skills;
7311
+ if (typeof skills !== "function") {
7312
+ return { manager: inputs.skillsManager, autoInject: skills?.autoInject ?? true };
7313
+ }
7314
+ const settings = await skills({
7315
+ agentId: inputs.agentId,
7316
+ cwd: inputs.workspaceCwd,
7317
+ model: inputs.model,
7318
+ userMessage: userText,
7319
+ memory: memoryFacts.map((fact) => ({ text: fact.text }))
7320
+ });
7321
+ const manager = new SkillsManager(
7322
+ inputs.workspaceCwd,
7323
+ settings.enabled,
7324
+ inputs.settingSourcesIncludeProject,
7325
+ settings.skillsDir,
7326
+ settings.inline
7327
+ );
7328
+ await manager.initialize();
7329
+ return { manager, autoInject: settings.autoInject ?? true };
7330
+ }
7331
+ async function buildSystemPromptContext(inputs, userText, memoryFacts, manager = inputs.skillsManager) {
7332
+ const skills = manager !== void 0 ? await manager.list() : [];
7108
7333
  return {
7109
7334
  agentId: inputs.agentId,
7110
7335
  cwd: inputs.workspaceCwd,
@@ -7115,10 +7340,11 @@ async function buildSystemPromptContext(inputs, userText, memoryFacts) {
7115
7340
  };
7116
7341
  }
7117
7342
  async function buildAssemblyContext(inputs, userText, baseSystemPrompt, memoryFacts, activeMemorySummary) {
7118
- const baseCtx = await buildSystemPromptContext(inputs, userText, memoryFacts);
7343
+ const resolved = await resolveSendSkills(inputs, userText, memoryFacts);
7344
+ const baseCtx = await buildSystemPromptContext(inputs, userText, memoryFacts, resolved.manager);
7119
7345
  const assemblyCtx = {
7120
7346
  ...baseCtx,
7121
- skillsAutoInject: inputs.options.skills?.autoInject ?? true,
7347
+ skillsAutoInject: resolved.autoInject,
7122
7348
  memoryAutoInject: inputs.options.memory?.autoInject ?? true
7123
7349
  };
7124
7350
  if (baseSystemPrompt !== void 0) assemblyCtx.baseSystemPrompt = baseSystemPrompt;
@@ -8370,176 +8596,6 @@ async function loadPluginManifestFromMarkdown(pluginsRoot, folderName) {
8370
8596
  return metadata;
8371
8597
  }
8372
8598
 
8373
- // src/internal/runtime/skills/discover-skills.ts
8374
- init_errors();
8375
-
8376
- // src/internal/runtime/skills/skill-frontmatter.ts
8377
- init_errors();
8378
- init_yaml_frontmatter();
8379
- function asString(v) {
8380
- return typeof v === "string" ? v : void 0;
8381
- }
8382
- function toStringFields(raw) {
8383
- const out = {};
8384
- for (const [k, v] of Object.entries(raw)) out[k] = asString(v);
8385
- return out;
8386
- }
8387
- function parseSkillFrontmatter(raw, fallbackName) {
8388
- const fields = extractAndParseFrontmatter(raw, fallbackName);
8389
- const name = resolveName(fields, fallbackName);
8390
- ensureRequiredFields(fields, name);
8391
- return buildFrontmatter(fields, name);
8392
- }
8393
- function extractAndParseFrontmatter(raw, fallbackName) {
8394
- const match = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
8395
- if (match === null) {
8396
- throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {
8397
- code: "missing_frontmatter"
8398
- });
8399
- }
8400
- const frontmatter = match[1] ?? "";
8401
- try {
8402
- return toStringFields(parseSimpleYaml(frontmatter));
8403
- } catch (cause) {
8404
- const detail = cause instanceof Error ? cause.message : String(cause);
8405
- throw new ConfigurationError(
8406
- `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,
8407
- { code: "schema_invalid", cause }
8408
- );
8409
- }
8410
- }
8411
- function resolveName(fields, fallbackName) {
8412
- if (hasContent(fields.name)) return fields.name;
8413
- if (hasContent(fallbackName)) return fallbackName;
8414
- throw new ConfigurationError("Skill at unknown path is missing required field: name", {
8415
- code: "schema_invalid"
8416
- });
8417
- }
8418
- function ensureRequiredFields(fields, name) {
8419
- if (!hasContent(fields.description)) {
8420
- throw new ConfigurationError(`Skill ${name} is missing required field: description`, {
8421
- code: "schema_invalid"
8422
- });
8423
- }
8424
- }
8425
- function buildFrontmatter(fields, name) {
8426
- const description = fields.description;
8427
- if (description === void 0) {
8428
- throw new ConfigurationError(`Skill ${name} missing description`, { code: "schema_invalid" });
8429
- }
8430
- const result = { name, description };
8431
- if (hasContent(fields.category)) result.category = fields.category;
8432
- const deps = parseDependencies(fields.dependencies);
8433
- if (deps !== void 0) result.dependencies = deps;
8434
- return result;
8435
- }
8436
- function parseDependencies(raw) {
8437
- if (!hasContent(raw)) return void 0;
8438
- const deps = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
8439
- return deps.length > 0 ? deps : void 0;
8440
- }
8441
- function hasContent(value) {
8442
- return value !== void 0 && value.trim().length > 0;
8443
- }
8444
-
8445
- // src/internal/runtime/skills/discover-skills.ts
8446
- async function discoverSkills(dir, options) {
8447
- let entries;
8448
- try {
8449
- entries = await readWorkspaceDir(dir, "skills_read_error", "skills directory");
8450
- } catch {
8451
- return [];
8452
- }
8453
- const skills = [];
8454
- for (const entry of entries) {
8455
- if (!entry.isDirectory()) continue;
8456
- let skillDir;
8457
- try {
8458
- skillDir = safePathJoin(dir, entry.name);
8459
- assertNoSymlinkEscape(skillDir, dir);
8460
- } catch {
8461
- continue;
8462
- }
8463
- const skillPath = path.join(skillDir, "SKILL.md");
8464
- let raw;
8465
- try {
8466
- raw = await promises.readFile(skillPath, "utf8");
8467
- } catch {
8468
- continue;
8469
- }
8470
- const skill = tryParseSkill(raw, entry.name, skillPath, options);
8471
- if (skill !== void 0) skills.push(skill);
8472
- }
8473
- return skills;
8474
- }
8475
- function tryParseSkill(raw, fallbackName, source, options) {
8476
- try {
8477
- const frontmatter = parseSkillFrontmatter(raw, fallbackName);
8478
- const skill = {
8479
- name: frontmatter.name,
8480
- description: frontmatter.description,
8481
- source
8482
- };
8483
- if (frontmatter.category !== void 0) skill.category = frontmatter.category;
8484
- if (frontmatter.dependencies !== void 0) skill.dependencies = frontmatter.dependencies;
8485
- return skill;
8486
- } catch (cause) {
8487
- if (cause instanceof ConfigurationError) {
8488
- options?.onInvalidSkill?.({
8489
- name: fallbackName,
8490
- source,
8491
- code: cause.code ?? "unknown",
8492
- message: cause.message
8493
- });
8494
- return void 0;
8495
- }
8496
- throw cause;
8497
- }
8498
- }
8499
-
8500
- // src/internal/runtime/skills/skills-manager.ts
8501
- var SkillsManager = class {
8502
- constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
8503
- this.cwd = cwd;
8504
- this.settingSourcesIncludeProject = settingSourcesIncludeProject;
8505
- this.skillsDir = skillsDir;
8506
- this.inline = inline;
8507
- }
8508
- cwd;
8509
- settingSourcesIncludeProject;
8510
- skillsDir;
8511
- inline;
8512
- skills = [];
8513
- async initialize() {
8514
- if (!this.settingSourcesIncludeProject) {
8515
- this.skills = this.mergeInline([]);
8516
- return;
8517
- }
8518
- await this.refresh();
8519
- }
8520
- async refresh() {
8521
- const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
8522
- const discovered = await discoverSkills(skillsRoot, {
8523
- onInvalidSkill: (info) => {
8524
- process.stderr.write(
8525
- `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
8526
- `
8527
- );
8528
- }
8529
- });
8530
- this.skills = this.mergeInline(discovered);
8531
- }
8532
- /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
8533
- mergeInline(discovered) {
8534
- if (this.inline === void 0 || this.inline.length === 0) return discovered;
8535
- const inlineNames = new Set(this.inline.map((s) => s.name));
8536
- return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
8537
- }
8538
- list() {
8539
- return Promise.resolve(this.skills);
8540
- }
8541
- };
8542
-
8543
8599
  // src/internal/runtime/local-agent/local-agent-bootstrap.ts
8544
8600
  function registerLocalAgent(args) {
8545
8601
  registerAgent({
@@ -8575,16 +8631,23 @@ function bootstrapSubmanagers(args) {
8575
8631
  );
8576
8632
  }
8577
8633
  if (args.options.skills !== void 0 || args.settingSourcesIncludeProject) {
8634
+ const staticSkills = typeof args.options.skills === "function" ? void 0 : args.options.skills;
8578
8635
  out.skillsManager = new SkillsManager(
8579
8636
  args.workspaceCwd,
8580
- args.options.skills?.enabled,
8637
+ staticSkills?.enabled,
8581
8638
  args.settingSourcesIncludeProject,
8582
8639
  // M22 — custom skills directory + inline (code-defined) skills.
8583
- args.options.skills?.skillsDir,
8584
- args.options.skills?.inline
8640
+ staticSkills?.skillsDir,
8641
+ staticSkills?.inline
8585
8642
  );
8586
8643
  const localSkills = out.skillsManager;
8587
- out.skills = { list: () => localSkills.list() };
8644
+ out.skills = {
8645
+ // Project to the public shape (name + description only). Inline skills carry
8646
+ // their body + references on the object; `list()` must never leak them —
8647
+ // the body is reachable exclusively through `get()`.
8648
+ list: async () => (await localSkills.list()).map((s) => ({ name: s.name, description: s.description })),
8649
+ get: (name) => localSkills.get(name)
8650
+ };
8588
8651
  }
8589
8652
  if (args.options.plugins !== void 0 || args.settingSourcesIncludePlugins) {
8590
8653
  out.pluginsManager = new PluginsManager(
@@ -13302,6 +13365,7 @@ function levenshtein(a, b) {
13302
13365
  }
13303
13366
 
13304
13367
  // src/internal/runtime/local-agent/real-local-run.ts
13368
+ init_async_local_storage();
13305
13369
  function createRealLocalRun(options) {
13306
13370
  const { userText, id, startTime } = prepareRunContext(options.message);
13307
13371
  const supported = /* @__PURE__ */ new Set(["stream", "wait", "cancel", "conversation"]);
@@ -13413,6 +13477,7 @@ function buildLoopInputs(options, runId, userText) {
13413
13477
  ...options.onStep !== void 0 ? { onStep: options.onStep } : {},
13414
13478
  ...options.onDelta !== void 0 ? { onDelta: options.onDelta } : {},
13415
13479
  ...options.sendOptions.toolChoice !== void 0 ? { toolChoice: options.sendOptions.toolChoice } : {},
13480
+ ...options.sendOptions.activeTools !== void 0 ? { activeTools: options.sendOptions.activeTools } : {},
13416
13481
  ...options.priorMessages !== void 0 ? { priorMessages: options.priorMessages } : {},
13417
13482
  ...options.memoryTools !== void 0 && options.memoryTools.length > 0 ? { memoryTools: options.memoryTools } : {},
13418
13483
  ...buildCustomToolsInput(
@@ -13543,7 +13608,7 @@ var RealLocalRun = class extends FixtureRunBase {
13543
13608
  }
13544
13609
  async executeAgentLoop(inputs) {
13545
13610
  try {
13546
- const output = await runAgentLoop(inputs);
13611
+ const output = inputs.activeTools !== void 0 ? await withToolWhitelist(new Set(inputs.activeTools), () => runAgentLoop(inputs)) : await runAgentLoop(inputs);
13547
13612
  this.applyAgentLoopOutput(output);
13548
13613
  this.transitionTo(output.finalStatus);
13549
13614
  } catch (cause) {
@@ -16428,7 +16493,7 @@ var LocalAgent = class {
16428
16493
  }
16429
16494
  // biome-ignore format: G8 budget — thin accessor for the assembly inputs.
16430
16495
  assemblyInputs() {
16431
- return { agentId: this.agentId, workspaceCwd: this.workspaceCwd, model: this.model, options: this.options, context: this.context, skillsManager: this.skillsManager, systemPromptPipeline: this.systemPromptPipeline };
16496
+ return { agentId: this.agentId, workspaceCwd: this.workspaceCwd, model: this.model, options: this.options, context: this.context, skillsManager: this.skillsManager, settingSourcesIncludeProject: this.settingSourcesIncludeProject, systemPromptPipeline: this.systemPromptPipeline };
16432
16497
  }
16433
16498
  async resolveSystemPrompt(userText, options, memoryFacts) {
16434
16499
  const base = await resolveSystemPromptForSend(