@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.
- package/CHANGELOG.md +56 -0
- package/dist/a2a/index.cjs +259 -192
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +259 -192
- package/dist/a2a/index.js.map +1 -1
- package/dist/create-skill.d.ts +8 -0
- package/dist/{cron-7CruUd_0.d.ts → cron-B44D-678.d.ts} +67 -4
- package/dist/{cron-Bpt_1khA.d.cts → cron-qI-dbG7c.d.cts} +67 -4
- package/dist/cron.cjs +246 -181
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +2 -2
- package/dist/cron.d.ts +2 -2
- package/dist/cron.js +246 -181
- package/dist/cron.js.map +1 -1
- package/dist/define-tool.d.ts +33 -20
- package/dist/{errors-CkCaIqVP.d.cts → errors-DIKBXffg.d.cts} +1 -1
- package/dist/{errors-BuwwkrAk.d.ts → errors-DRS-kqOK.d.ts} +1 -1
- package/dist/errors.d.cts +2 -2
- package/dist/eval.cjs +246 -181
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +246 -181
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +299 -186
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -27
- package/dist/index.d.ts +75 -27
- package/dist/index.js +299 -187
- package/dist/index.js.map +1 -1
- package/dist/internal/runtime/local-agent/local-agent-bootstrap.d.ts +2 -4
- package/dist/internal/runtime/skills/skill-frontmatter.d.ts +6 -0
- package/dist/{run-CrIulPF7.d.cts → run-Cr0C6cOM.d.cts} +17 -0
- package/dist/{run-CrIulPF7.d.ts → run-Cr0C6cOM.d.ts} +17 -0
- package/dist/skills.cjs.map +1 -1
- package/dist/skills.js.map +1 -1
- package/dist/types/agent.d.ts +57 -2
- package/dist/types/run.d.ts +17 -0
- package/dist/workflow.cjs +37 -0
- package/dist/workflow.cjs.map +1 -1
- package/dist/workflow.d.cts +47 -1
- package/dist/workflow.d.ts +47 -1
- package/dist/workflow.js +37 -2
- package/dist/workflow.js.map +1 -1
- 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
|
package/dist/a2a/index.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
|
5698
|
-
const skills = inputs.
|
|
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
|
|
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:
|
|
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
|
-
|
|
7360
|
+
staticSkills?.enabled,
|
|
7302
7361
|
args.settingSourcesIncludeProject,
|
|
7303
7362
|
// M22 — custom skills directory + inline (code-defined) skills.
|
|
7304
|
-
|
|
7305
|
-
|
|
7363
|
+
staticSkills?.skillsDir,
|
|
7364
|
+
staticSkills?.inline
|
|
7306
7365
|
);
|
|
7307
7366
|
const localSkills = out.skillsManager;
|
|
7308
|
-
out.skills = {
|
|
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(
|