@theokit/sdk 2.24.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 +28 -0
- package/dist/a2a/index.cjs +256 -191
- package/dist/a2a/index.cjs.map +1 -1
- package/dist/a2a/index.js +256 -191
- package/dist/a2a/index.js.map +1 -1
- package/dist/create-skill.d.ts +8 -0
- package/dist/{cron-vjod0qVQ.d.ts → cron-B44D-678.d.ts} +66 -3
- package/dist/{cron-Bd2oRD7A.d.cts → cron-qI-dbG7c.d.cts} +66 -3
- package/dist/cron.cjs +243 -180
- package/dist/cron.cjs.map +1 -1
- package/dist/cron.d.cts +1 -1
- package/dist/cron.d.ts +1 -1
- package/dist/cron.js +243 -180
- package/dist/cron.js.map +1 -1
- package/dist/eval.cjs +243 -180
- package/dist/eval.cjs.map +1 -1
- package/dist/eval.js +243 -180
- package/dist/eval.js.map +1 -1
- package/dist/index.cjs +289 -184
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +40 -3
- package/dist/index.d.ts +40 -3
- package/dist/index.js +289 -185
- 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/skills.cjs.map +1 -1
- package/dist/skills.js.map +1 -1
- package/dist/types/agent.d.ts +57 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
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
|
+
|
|
3
31
|
## 2.24.0
|
|
4
32
|
|
|
5
33
|
### 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(
|
|
@@ -17235,7 +17300,7 @@ var init_local_agent = __esm({
|
|
|
17235
17300
|
}
|
|
17236
17301
|
// biome-ignore format: G8 budget — thin accessor for the assembly inputs.
|
|
17237
17302
|
assemblyInputs() {
|
|
17238
|
-
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 };
|
|
17239
17304
|
}
|
|
17240
17305
|
async resolveSystemPrompt(userText, options, memoryFacts) {
|
|
17241
17306
|
const base = await resolveSystemPromptForSend(
|