@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
package/CHANGELOG.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.25.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 5067b50: **SE20 — `agent.skills.get(name)` (read a skill's full body).**
8
+
9
+ `agent.skills.list()` already returned skill metadata (name + description only); SE20 adds `agent.skills.get(name)` returning the skill INCLUDING its `instructions` (body) — read from the inline `createSkill` body, or from the filesystem SKILL.md (frontmatter stripped) for discovered skills. Returns `undefined` when no enabled skill matches (malformed skills stay excluded). New public type `SDKAgentSkillDetail`.
10
+
11
+ `list()` stays lean (the `<skills>` block only ever carries name + description); full bodies come only through `get`. Mirrors Mastra's `agent.getSkill(name)`. Additive + backward-compatible. From the Mastra Agent-skills comparison (SDK Evolution roadmap SE20).
12
+
13
+ - 09865ee: **SE21 — `references` on `createSkill` (bundle supporting docs on an inline skill).**
14
+
15
+ `createSkill({ ..., references })` now accepts an optional `references` map (filename → content), mirroring a filesystem skill's `references/` directory. The docs travel on the inline skill object and surface to the app via `agent.skills.get(name)` (new `references` field on `SDKAgentSkillDetail`); they are NOT injected into the model prompt. Omitted when not provided (backward-compatible). Mirrors Mastra Agent-skills `references`.
16
+
17
+ Also closes a latent boundary leak surfaced by this change: `agent.skills.list()` now projects to the public shape (name + description only), so an inline skill's `instructions` / `references` / `source` never leak through `list()` — the body is reachable exclusively through `get()`, matching the documented `SystemPromptSkillRef` contract. From the Mastra Agent-skills comparison (SDK Evolution roadmap SE21).
18
+
19
+ - abfcc5d: **SE22 — dynamic skills resolver (`skills: (ctx) => SkillsSettings`).**
20
+
21
+ `AgentOptions.skills` now accepts a resolver function in addition to the static `SkillsSettings` object. The resolver receives a per-send context (`agentId`, `cwd`, `model`, `userMessage`, `memory` — mirroring the systemPrompt resolver's context, minus the not-yet-resolved `skills`) and returns the `SkillsSettings` for that run. It is evaluated per `send()` before skill assembly, so a cached `getOrCreate` agent re-resolves each run — pick skills from runtime context (e.g. the user's role).
22
+
23
+ A static object behaves exactly as today. The agent-scoped `agent.skills` handle reflects the static/base config; the resolver drives the per-send `<skills>` block. The SDK imposes no timeout (wrap your own `Promise.race`); a throwing resolver fails the run — no silent fallback (Rule 8). Cloud agents reject a function resolver (it can't run on PaaS — resolve to a static object first), mirroring the systemPrompt-resolver cloud rule. New public types `SkillsResolver` + `SkillsResolverContext`. Mirrors Mastra Agent-skills `skills: ({ requestContext }) => SkillInput[]`. From the Mastra Agent-skills comparison (SDK Evolution roadmap SE22).
24
+
25
+ - 0b9c0ac: **SE23 — `defineSkillReadTool` (opt-in model-facing lazy skill read).**
26
+
27
+ `defineSkillReadTool(skills)` returns a `skill_read` `CustomTool` the consumer explicitly adds to `AgentOptions.tools`. When the model calls it with a skill name, the handler returns that skill's `instructions` (+ SE21 `references`); an unknown-but-well-formed name returns a typed "not found" string listing the available skills — NOT a throw that kills the run (Rule 8). Malformed input (missing `name`) fails at the trust boundary via the input schema.
28
+
29
+ The SDK never auto-injects it — bring-your-own-tools stays intact (sibling of `defineSubAgent` / `workflowAsTool`). This is the LAZY read path that complements the eager `<skills>` block (name + description only): the block discloses which skills exist; `skill_read` loads a body on demand. The consumer controls exposure by choosing which skills to pass. See ADR 0007. Mirrors Mastra's `skill_read` — but opt-in, not auto-injected. From the Mastra Agent-skills comparison (SDK Evolution roadmap SE23).
30
+
31
+ ## 2.24.0
32
+
33
+ ### Minor Changes
34
+
35
+ - 7be1f18: **SE16 — `outputSchema` on `defineTool` (validate + infer the tool's return).**
36
+
37
+ `defineTool` (from `@theokit/sdk`) gains an optional `outputSchema` (a Zod schema). When set, the handler returns the STRUCTURED output inferred from it (`z.infer<outputSchema>`), the value is validated against the schema, and the tool result becomes its serialization — a string stays as-is, an object is JSON-stringified. A validation failure raises `ZodError` (converted to a `tool_result(isError)`), so a malformed tool output fails loudly instead of silently reaching the model.
38
+
39
+ Additive + fully backward-compatible: with no `outputSchema` the handler returns a plain `string` exactly as before (the handler return type is `string` when `outputSchema` is absent, `z.infer<outputSchema>` when present, via a conditional type). Mirrors Mastra `createTool`'s `outputSchema`. Pairs with SE17 (`toModelOutput`). From the Mastra Tools comparison (SDK Evolution roadmap SE16).
40
+
41
+ - f621734: **SE17 — `toModelOutput` on `defineTool` (model-facing vs app-facing output split).**
42
+
43
+ `defineTool` (from `@theokit/sdk`) gains an optional `toModelOutput`. The handler returns the FULL result (validated by SE16's `outputSchema`); `toModelOutput(output)` maps it to the compact / multimodal representation the MODEL sees in the `tool_result` — so rich app-facing detail is not forced into model context. It returns a `string` OR SE7 `ToolResultContentBlock[]` (text + image). Absent ⇒ the tool result is the serialized handler output (SE16 / pre-SE17 behavior, unchanged).
44
+
45
+ Mirrors Mastra's `toModelOutput` and the Vercel AI SDK. Additive + backward-compatible. From the Mastra Tools comparison (SDK Evolution roadmap SE17).
46
+
47
+ - 72435db: **SE18 — `SendOptions.activeTools` (per-send runtime tool subset).**
48
+
49
+ `agent.send(input, { activeTools })` restricts, per send, which of the agent's registered tools the model may actually call. A tool whose canonical name is not in the list is vetoed at dispatch (its handler never runs) — reusing the existing `withToolWhitelist` path that `Agent.fork`'s `allowedTools` uses, NOT `PermissionEngine`. Composes with `toolChoice`: `activeTools` narrows the set, `toolChoice` gates calling within it. Absent ⇒ the full toolset is available (unchanged).
50
+
51
+ The loop runs inside a `withToolWhitelist(new Set(activeTools))` scope when set. Additive + backward-compatible. Mirrors Mastra `activeTools` + the Vercel AI SDK. From the Mastra Tools comparison (SDK Evolution roadmap SE18).
52
+
53
+ - f92f720: **SE19 — `workflowAsTool` (expose a Workflow as an agent tool).**
54
+
55
+ `workflowAsTool(workflow, { name, description, inputSchema })` (from `@theokit/sdk/workflow`) turns a `Workflow` into an agent `CustomTool`, completing the Mastra "X as tools" trio (tools; agents-as-tools via `defineSubAgent`; workflows-as-tools). The handler validates the model's args against `spec.inputSchema`, runs the workflow, and returns its output (a string as-is, else JSON). A run that does not reach `status: "completed"` raises a typed `WorkflowToolError` (workflow step errors do NOT throw — they surface via `run.status === "failed"`).
56
+
57
+ Because a `Workflow` carries no top-level schema (`WorkflowOptions` is `name`/`persistence`/`workflowId`; schemas are per-step), the caller supplies the tool `inputSchema` in the spec (like `defineTool`). Accepts any `{ run }`-shaped workflow (structural), so it never imports the `Workflow` class. New exports: `workflowAsTool`, `WorkflowToolError`, `WorkflowAsToolSpec`. Additive. From the Mastra Tools comparison (SDK Evolution roadmap SE19).
58
+
3
59
  ## 2.23.0
4
60
 
5
61
  ### Minor Changes
@@ -1553,7 +1553,8 @@ function stripSecretsFromOptions(options) {
1553
1553
  local: serializeLocal(options.local),
1554
1554
  cloud: serializeCloud(options.cloud),
1555
1555
  memory: serializeMemory(options.memory),
1556
- skills: serializeEnabledList(options.skills),
1556
+ // SE22 — a SkillsResolver function isn't serializable; persist only the static form.
1557
+ skills: serializeEnabledList(typeof options.skills === "function" ? void 0 : options.skills),
1557
1558
  // Code-`Plugin` objects are closures and cannot be persisted (like custom
1558
1559
  // tools); only the named-enable settings form is serialized.
1559
1560
  plugins: serializeEnabledList(asPluginsSettings(options.plugins)),
@@ -1883,6 +1884,7 @@ function serializeCloud2(cloud) {
1883
1884
  return result;
1884
1885
  }
1885
1886
  function serializeSkills(skills) {
1887
+ if (typeof skills === "function") return void 0;
1886
1888
  if (skills?.enabled === void 0 || skills.enabled.length === 0) return void 0;
1887
1889
  return { enabled: [...skills.enabled] };
1888
1890
  }
@@ -3451,6 +3453,7 @@ var init_cloud_agent = __esm({
3451
3453
  function validateCloudToolParity(options) {
3452
3454
  if (options.cloud === void 0) return;
3453
3455
  rejectFunctionSystemPrompt(options);
3456
+ rejectFunctionSkills(options);
3454
3457
  rejectStdioMcpLocalPaths(options);
3455
3458
  }
3456
3459
  function rejectFunctionSystemPrompt(options) {
@@ -3461,6 +3464,14 @@ function rejectFunctionSystemPrompt(options) {
3461
3464
  );
3462
3465
  }
3463
3466
  }
3467
+ function rejectFunctionSkills(options) {
3468
+ if (typeof options.skills === "function") {
3469
+ throw new ConfigurationError(
3470
+ "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.",
3471
+ { code: "cloud_incompatible_function_resolver" }
3472
+ );
3473
+ }
3474
+ }
3464
3475
  function rejectStdioMcpLocalPaths(options) {
3465
3476
  if (options.mcpServers === void 0) return;
3466
3477
  for (const [name, config] of Object.entries(options.mcpServers)) {
@@ -5693,9 +5704,235 @@ var init_subagents_loader = __esm({
5693
5704
  }
5694
5705
  });
5695
5706
 
5707
+ // src/internal/runtime/skills/skill-frontmatter.ts
5708
+ function asString(v) {
5709
+ return typeof v === "string" ? v : void 0;
5710
+ }
5711
+ function toStringFields(raw) {
5712
+ const out = {};
5713
+ for (const [k, v] of Object.entries(raw)) out[k] = asString(v);
5714
+ return out;
5715
+ }
5716
+ function parseSkillFrontmatter(raw, fallbackName) {
5717
+ const fields = extractAndParseFrontmatter(raw, fallbackName);
5718
+ const name = resolveName(fields, fallbackName);
5719
+ ensureRequiredFields(fields, name);
5720
+ return buildFrontmatter(fields, name);
5721
+ }
5722
+ function stripSkillFrontmatter(raw) {
5723
+ const match = /^---\s*\n[\s\S]*?\n---\s*\n/.exec(raw);
5724
+ return (match === null ? raw : raw.slice(match[0].length)).trim();
5725
+ }
5726
+ function extractAndParseFrontmatter(raw, fallbackName) {
5727
+ const match = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
5728
+ if (match === null) {
5729
+ throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {
5730
+ code: "missing_frontmatter"
5731
+ });
5732
+ }
5733
+ const frontmatter = match[1] ?? "";
5734
+ try {
5735
+ return toStringFields(parseSimpleYaml(frontmatter));
5736
+ } catch (cause) {
5737
+ const detail = cause instanceof Error ? cause.message : String(cause);
5738
+ throw new ConfigurationError(
5739
+ `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,
5740
+ { code: "schema_invalid", cause }
5741
+ );
5742
+ }
5743
+ }
5744
+ function resolveName(fields, fallbackName) {
5745
+ if (hasContent(fields.name)) return fields.name;
5746
+ if (hasContent(fallbackName)) return fallbackName;
5747
+ throw new ConfigurationError("Skill at unknown path is missing required field: name", {
5748
+ code: "schema_invalid"
5749
+ });
5750
+ }
5751
+ function ensureRequiredFields(fields, name) {
5752
+ if (!hasContent(fields.description)) {
5753
+ throw new ConfigurationError(`Skill ${name} is missing required field: description`, {
5754
+ code: "schema_invalid"
5755
+ });
5756
+ }
5757
+ }
5758
+ function buildFrontmatter(fields, name) {
5759
+ const description = fields.description;
5760
+ if (description === void 0) {
5761
+ throw new ConfigurationError(`Skill ${name} missing description`, { code: "schema_invalid" });
5762
+ }
5763
+ const result = { name, description };
5764
+ if (hasContent(fields.category)) result.category = fields.category;
5765
+ const deps = parseDependencies(fields.dependencies);
5766
+ if (deps !== void 0) result.dependencies = deps;
5767
+ return result;
5768
+ }
5769
+ function parseDependencies(raw) {
5770
+ if (!hasContent(raw)) return void 0;
5771
+ const deps = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
5772
+ return deps.length > 0 ? deps : void 0;
5773
+ }
5774
+ function hasContent(value) {
5775
+ return value !== void 0 && value.trim().length > 0;
5776
+ }
5777
+ var init_skill_frontmatter = __esm({
5778
+ "src/internal/runtime/skills/skill-frontmatter.ts"() {
5779
+ init_errors();
5780
+ init_yaml_frontmatter();
5781
+ }
5782
+ });
5783
+ async function discoverSkills(dir, options) {
5784
+ let entries;
5785
+ try {
5786
+ entries = await readWorkspaceDir(dir, "skills_read_error", "skills directory");
5787
+ } catch {
5788
+ return [];
5789
+ }
5790
+ const skills = [];
5791
+ for (const entry of entries) {
5792
+ if (!entry.isDirectory()) continue;
5793
+ let skillDir;
5794
+ try {
5795
+ skillDir = safePathJoin(dir, entry.name);
5796
+ assertNoSymlinkEscape(skillDir, dir);
5797
+ } catch {
5798
+ continue;
5799
+ }
5800
+ const skillPath = path.join(skillDir, "SKILL.md");
5801
+ let raw;
5802
+ try {
5803
+ raw = await promises.readFile(skillPath, "utf8");
5804
+ } catch {
5805
+ continue;
5806
+ }
5807
+ const skill = tryParseSkill(raw, entry.name, skillPath, options);
5808
+ if (skill !== void 0) skills.push(skill);
5809
+ }
5810
+ return skills;
5811
+ }
5812
+ function tryParseSkill(raw, fallbackName, source, options) {
5813
+ try {
5814
+ const frontmatter = parseSkillFrontmatter(raw, fallbackName);
5815
+ const skill = {
5816
+ name: frontmatter.name,
5817
+ description: frontmatter.description,
5818
+ source
5819
+ };
5820
+ if (frontmatter.category !== void 0) skill.category = frontmatter.category;
5821
+ if (frontmatter.dependencies !== void 0) skill.dependencies = frontmatter.dependencies;
5822
+ return skill;
5823
+ } catch (cause) {
5824
+ if (cause instanceof ConfigurationError) {
5825
+ options?.onInvalidSkill?.({
5826
+ name: fallbackName,
5827
+ source,
5828
+ code: cause.code ?? "unknown",
5829
+ message: cause.message
5830
+ });
5831
+ return void 0;
5832
+ }
5833
+ throw cause;
5834
+ }
5835
+ }
5836
+ var init_discover_skills = __esm({
5837
+ "src/internal/runtime/skills/discover-skills.ts"() {
5838
+ init_errors();
5839
+ init_path_guard();
5840
+ init_workspace_dir();
5841
+ init_skill_frontmatter();
5842
+ }
5843
+ });
5844
+ var SkillsManager;
5845
+ var init_skills_manager = __esm({
5846
+ "src/internal/runtime/skills/skills-manager.ts"() {
5847
+ init_discover_skills();
5848
+ init_skill_frontmatter();
5849
+ SkillsManager = class {
5850
+ constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
5851
+ this.cwd = cwd;
5852
+ this.settingSourcesIncludeProject = settingSourcesIncludeProject;
5853
+ this.skillsDir = skillsDir;
5854
+ this.inline = inline;
5855
+ }
5856
+ cwd;
5857
+ settingSourcesIncludeProject;
5858
+ skillsDir;
5859
+ inline;
5860
+ skills = [];
5861
+ async initialize() {
5862
+ if (!this.settingSourcesIncludeProject) {
5863
+ this.skills = this.mergeInline([]);
5864
+ return;
5865
+ }
5866
+ await this.refresh();
5867
+ }
5868
+ async refresh() {
5869
+ const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
5870
+ const discovered = await discoverSkills(skillsRoot, {
5871
+ onInvalidSkill: (info) => {
5872
+ process.stderr.write(
5873
+ `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
5874
+ `
5875
+ );
5876
+ }
5877
+ });
5878
+ this.skills = this.mergeInline(discovered);
5879
+ }
5880
+ /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
5881
+ mergeInline(discovered) {
5882
+ if (this.inline === void 0 || this.inline.length === 0) return discovered;
5883
+ const inlineNames = new Set(this.inline.map((s) => s.name));
5884
+ return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
5885
+ }
5886
+ list() {
5887
+ return Promise.resolve(this.skills);
5888
+ }
5889
+ /**
5890
+ * SE20 — resolve a skill by name INCLUDING its body. Inline (`createSkill`)
5891
+ * skills carry `instructions` on the object; filesystem skills read the body
5892
+ * from their `source` SKILL.md (frontmatter stripped). `undefined` when no
5893
+ * enabled skill matches (malformed skills were already excluded at discovery).
5894
+ */
5895
+ async get(name) {
5896
+ const skill = this.skills.find((s) => s.name === name);
5897
+ if (skill === void 0) return void 0;
5898
+ const instructions = typeof skill.instructions === "string" ? skill.instructions : stripSkillFrontmatter(await promises.readFile(skill.source, "utf8"));
5899
+ const references = skill.references;
5900
+ return {
5901
+ name: skill.name,
5902
+ description: skill.description,
5903
+ instructions,
5904
+ ...references !== void 0 ? { references } : {}
5905
+ };
5906
+ }
5907
+ };
5908
+ }
5909
+ });
5910
+
5696
5911
  // src/internal/runtime/system-prompt/local-assembly.ts
5697
- async function buildSystemPromptContext(inputs, userText, memoryFacts) {
5698
- const skills = inputs.skillsManager !== void 0 ? await inputs.skillsManager.list() : [];
5912
+ async function resolveSendSkills(inputs, userText, memoryFacts) {
5913
+ const skills = inputs.options.skills;
5914
+ if (typeof skills !== "function") {
5915
+ return { manager: inputs.skillsManager, autoInject: skills?.autoInject ?? true };
5916
+ }
5917
+ const settings = await skills({
5918
+ agentId: inputs.agentId,
5919
+ cwd: inputs.workspaceCwd,
5920
+ model: inputs.model,
5921
+ userMessage: userText,
5922
+ memory: memoryFacts.map((fact) => ({ text: fact.text }))
5923
+ });
5924
+ const manager = new SkillsManager(
5925
+ inputs.workspaceCwd,
5926
+ settings.enabled,
5927
+ inputs.settingSourcesIncludeProject,
5928
+ settings.skillsDir,
5929
+ settings.inline
5930
+ );
5931
+ await manager.initialize();
5932
+ return { manager, autoInject: settings.autoInject ?? true };
5933
+ }
5934
+ async function buildSystemPromptContext(inputs, userText, memoryFacts, manager = inputs.skillsManager) {
5935
+ const skills = manager !== void 0 ? await manager.list() : [];
5699
5936
  return {
5700
5937
  agentId: inputs.agentId,
5701
5938
  cwd: inputs.workspaceCwd,
@@ -5706,10 +5943,11 @@ async function buildSystemPromptContext(inputs, userText, memoryFacts) {
5706
5943
  };
5707
5944
  }
5708
5945
  async function buildAssemblyContext(inputs, userText, baseSystemPrompt, memoryFacts, activeMemorySummary) {
5709
- const baseCtx = await buildSystemPromptContext(inputs, userText, memoryFacts);
5946
+ const resolved = await resolveSendSkills(inputs, userText, memoryFacts);
5947
+ const baseCtx = await buildSystemPromptContext(inputs, userText, memoryFacts, resolved.manager);
5710
5948
  const assemblyCtx = {
5711
5949
  ...baseCtx,
5712
- skillsAutoInject: inputs.options.skills?.autoInject ?? true,
5950
+ skillsAutoInject: resolved.autoInject,
5713
5951
  memoryAutoInject: inputs.options.memory?.autoInject ?? true
5714
5952
  };
5715
5953
  if (baseSystemPrompt !== void 0) assemblyCtx.baseSystemPrompt = baseSystemPrompt;
@@ -5735,6 +5973,7 @@ async function assembleSystemPromptForSend(inputs, userText, baseSystemPrompt, m
5735
5973
  }
5736
5974
  var init_local_assembly = __esm({
5737
5975
  "src/internal/runtime/system-prompt/local-assembly.ts"() {
5976
+ init_skills_manager();
5738
5977
  }
5739
5978
  });
5740
5979
 
@@ -7080,187 +7319,6 @@ var init_plugins_manager = __esm({
7080
7319
  }
7081
7320
  });
7082
7321
 
7083
- // src/internal/runtime/skills/skill-frontmatter.ts
7084
- function asString(v) {
7085
- return typeof v === "string" ? v : void 0;
7086
- }
7087
- function toStringFields(raw) {
7088
- const out = {};
7089
- for (const [k, v] of Object.entries(raw)) out[k] = asString(v);
7090
- return out;
7091
- }
7092
- function parseSkillFrontmatter(raw, fallbackName) {
7093
- const fields = extractAndParseFrontmatter(raw, fallbackName);
7094
- const name = resolveName(fields, fallbackName);
7095
- ensureRequiredFields(fields, name);
7096
- return buildFrontmatter(fields, name);
7097
- }
7098
- function extractAndParseFrontmatter(raw, fallbackName) {
7099
- const match = /^---\s*\n([\s\S]*?)\n---\s*\n/.exec(raw);
7100
- if (match === null) {
7101
- throw new ConfigurationError(`Skill ${fallbackName} is missing frontmatter`, {
7102
- code: "missing_frontmatter"
7103
- });
7104
- }
7105
- const frontmatter = match[1] ?? "";
7106
- try {
7107
- return toStringFields(parseSimpleYaml(frontmatter));
7108
- } catch (cause) {
7109
- const detail = cause instanceof Error ? cause.message : String(cause);
7110
- throw new ConfigurationError(
7111
- `Skill ${fallbackName} has malformed YAML frontmatter: ${detail}`,
7112
- { code: "schema_invalid", cause }
7113
- );
7114
- }
7115
- }
7116
- function resolveName(fields, fallbackName) {
7117
- if (hasContent(fields.name)) return fields.name;
7118
- if (hasContent(fallbackName)) return fallbackName;
7119
- throw new ConfigurationError("Skill at unknown path is missing required field: name", {
7120
- code: "schema_invalid"
7121
- });
7122
- }
7123
- function ensureRequiredFields(fields, name) {
7124
- if (!hasContent(fields.description)) {
7125
- throw new ConfigurationError(`Skill ${name} is missing required field: description`, {
7126
- code: "schema_invalid"
7127
- });
7128
- }
7129
- }
7130
- function buildFrontmatter(fields, name) {
7131
- const description = fields.description;
7132
- if (description === void 0) {
7133
- throw new ConfigurationError(`Skill ${name} missing description`, { code: "schema_invalid" });
7134
- }
7135
- const result = { name, description };
7136
- if (hasContent(fields.category)) result.category = fields.category;
7137
- const deps = parseDependencies(fields.dependencies);
7138
- if (deps !== void 0) result.dependencies = deps;
7139
- return result;
7140
- }
7141
- function parseDependencies(raw) {
7142
- if (!hasContent(raw)) return void 0;
7143
- const deps = raw.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
7144
- return deps.length > 0 ? deps : void 0;
7145
- }
7146
- function hasContent(value) {
7147
- return value !== void 0 && value.trim().length > 0;
7148
- }
7149
- var init_skill_frontmatter = __esm({
7150
- "src/internal/runtime/skills/skill-frontmatter.ts"() {
7151
- init_errors();
7152
- init_yaml_frontmatter();
7153
- }
7154
- });
7155
- async function discoverSkills(dir, options) {
7156
- let entries;
7157
- try {
7158
- entries = await readWorkspaceDir(dir, "skills_read_error", "skills directory");
7159
- } catch {
7160
- return [];
7161
- }
7162
- const skills = [];
7163
- for (const entry of entries) {
7164
- if (!entry.isDirectory()) continue;
7165
- let skillDir;
7166
- try {
7167
- skillDir = safePathJoin(dir, entry.name);
7168
- assertNoSymlinkEscape(skillDir, dir);
7169
- } catch {
7170
- continue;
7171
- }
7172
- const skillPath = path.join(skillDir, "SKILL.md");
7173
- let raw;
7174
- try {
7175
- raw = await promises.readFile(skillPath, "utf8");
7176
- } catch {
7177
- continue;
7178
- }
7179
- const skill = tryParseSkill(raw, entry.name, skillPath, options);
7180
- if (skill !== void 0) skills.push(skill);
7181
- }
7182
- return skills;
7183
- }
7184
- function tryParseSkill(raw, fallbackName, source, options) {
7185
- try {
7186
- const frontmatter = parseSkillFrontmatter(raw, fallbackName);
7187
- const skill = {
7188
- name: frontmatter.name,
7189
- description: frontmatter.description,
7190
- source
7191
- };
7192
- if (frontmatter.category !== void 0) skill.category = frontmatter.category;
7193
- if (frontmatter.dependencies !== void 0) skill.dependencies = frontmatter.dependencies;
7194
- return skill;
7195
- } catch (cause) {
7196
- if (cause instanceof ConfigurationError) {
7197
- options?.onInvalidSkill?.({
7198
- name: fallbackName,
7199
- source,
7200
- code: cause.code ?? "unknown",
7201
- message: cause.message
7202
- });
7203
- return void 0;
7204
- }
7205
- throw cause;
7206
- }
7207
- }
7208
- var init_discover_skills = __esm({
7209
- "src/internal/runtime/skills/discover-skills.ts"() {
7210
- init_errors();
7211
- init_path_guard();
7212
- init_workspace_dir();
7213
- init_skill_frontmatter();
7214
- }
7215
- });
7216
- var SkillsManager;
7217
- var init_skills_manager = __esm({
7218
- "src/internal/runtime/skills/skills-manager.ts"() {
7219
- init_discover_skills();
7220
- SkillsManager = class {
7221
- constructor(cwd, _enabled, settingSourcesIncludeProject, skillsDir, inline) {
7222
- this.cwd = cwd;
7223
- this.settingSourcesIncludeProject = settingSourcesIncludeProject;
7224
- this.skillsDir = skillsDir;
7225
- this.inline = inline;
7226
- }
7227
- cwd;
7228
- settingSourcesIncludeProject;
7229
- skillsDir;
7230
- inline;
7231
- skills = [];
7232
- async initialize() {
7233
- if (!this.settingSourcesIncludeProject) {
7234
- this.skills = this.mergeInline([]);
7235
- return;
7236
- }
7237
- await this.refresh();
7238
- }
7239
- async refresh() {
7240
- const skillsRoot = this.skillsDir ?? path.join(this.cwd, ".theokit", "skills");
7241
- const discovered = await discoverSkills(skillsRoot, {
7242
- onInvalidSkill: (info) => {
7243
- process.stderr.write(
7244
- `[theokit-sdk] skill ${info.name} skipped (${info.code}): ${info.message}
7245
- `
7246
- );
7247
- }
7248
- });
7249
- this.skills = this.mergeInline(discovered);
7250
- }
7251
- /** M22 — merge inline skills over discovered ones; inline wins on a name conflict. */
7252
- mergeInline(discovered) {
7253
- if (this.inline === void 0 || this.inline.length === 0) return discovered;
7254
- const inlineNames = new Set(this.inline.map((s) => s.name));
7255
- return [...discovered.filter((s) => !inlineNames.has(s.name)), ...this.inline];
7256
- }
7257
- list() {
7258
- return Promise.resolve(this.skills);
7259
- }
7260
- };
7261
- }
7262
- });
7263
-
7264
7322
  // src/internal/runtime/local-agent/local-agent-bootstrap.ts
7265
7323
  function registerLocalAgent(args) {
7266
7324
  registerAgent({
@@ -7296,16 +7354,23 @@ function bootstrapSubmanagers(args) {
7296
7354
  );
7297
7355
  }
7298
7356
  if (args.options.skills !== void 0 || args.settingSourcesIncludeProject) {
7357
+ const staticSkills = typeof args.options.skills === "function" ? void 0 : args.options.skills;
7299
7358
  out.skillsManager = new SkillsManager(
7300
7359
  args.workspaceCwd,
7301
- args.options.skills?.enabled,
7360
+ staticSkills?.enabled,
7302
7361
  args.settingSourcesIncludeProject,
7303
7362
  // M22 — custom skills directory + inline (code-defined) skills.
7304
- args.options.skills?.skillsDir,
7305
- args.options.skills?.inline
7363
+ staticSkills?.skillsDir,
7364
+ staticSkills?.inline
7306
7365
  );
7307
7366
  const localSkills = out.skillsManager;
7308
- out.skills = { list: () => localSkills.list() };
7367
+ out.skills = {
7368
+ // Project to the public shape (name + description only). Inline skills carry
7369
+ // their body + references on the object; `list()` must never leak them —
7370
+ // the body is reachable exclusively through `get()`.
7371
+ list: async () => (await localSkills.list()).map((s) => ({ name: s.name, description: s.description })),
7372
+ get: (name) => localSkills.get(name)
7373
+ };
7309
7374
  }
7310
7375
  if (args.options.plugins !== void 0 || args.settingSourcesIncludePlugins) {
7311
7376
  out.pluginsManager = new PluginsManager(
@@ -12922,6 +12987,7 @@ function buildLoopInputs(options, runId, userText) {
12922
12987
  ...options.onStep !== void 0 ? { onStep: options.onStep } : {},
12923
12988
  ...options.onDelta !== void 0 ? { onDelta: options.onDelta } : {},
12924
12989
  ...options.sendOptions.toolChoice !== void 0 ? { toolChoice: options.sendOptions.toolChoice } : {},
12990
+ ...options.sendOptions.activeTools !== void 0 ? { activeTools: options.sendOptions.activeTools } : {},
12925
12991
  ...options.priorMessages !== void 0 ? { priorMessages: options.priorMessages } : {},
12926
12992
  ...options.memoryTools !== void 0 && options.memoryTools.length > 0 ? { memoryTools: options.memoryTools } : {},
12927
12993
  ...buildCustomToolsInput(
@@ -13021,6 +13087,7 @@ var init_real_local_run = __esm({
13021
13087
  init_register_plugin_providers();
13022
13088
  init_tracer();
13023
13089
  init_personality_filter();
13090
+ init_async_local_storage();
13024
13091
  init_fixture_run_base();
13025
13092
  init_run_registry();
13026
13093
  pluginProvidersAnnounced = false;
@@ -13070,7 +13137,7 @@ var init_real_local_run = __esm({
13070
13137
  }
13071
13138
  async executeAgentLoop(inputs) {
13072
13139
  try {
13073
- const output = await runAgentLoop(inputs);
13140
+ const output = inputs.activeTools !== void 0 ? await withToolWhitelist(new Set(inputs.activeTools), () => runAgentLoop(inputs)) : await runAgentLoop(inputs);
13074
13141
  this.applyAgentLoopOutput(output);
13075
13142
  this.transitionTo(output.finalStatus);
13076
13143
  } catch (cause) {
@@ -17233,7 +17300,7 @@ var init_local_agent = __esm({
17233
17300
  }
17234
17301
  // biome-ignore format: G8 budget — thin accessor for the assembly inputs.
17235
17302
  assemblyInputs() {
17236
- return { agentId: this.agentId, workspaceCwd: this.workspaceCwd, model: this.model, options: this.options, context: this.context, skillsManager: this.skillsManager, systemPromptPipeline: this.systemPromptPipeline };
17303
+ 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 };
17237
17304
  }
17238
17305
  async resolveSystemPrompt(userText, options, memoryFacts) {
17239
17306
  const base = await resolveSystemPromptForSend(