@geminixiang/mikan 1.0.0-beta.37 → 1.0.0-beta.38
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 +6 -0
- package/dist/agent.d.ts +0 -1
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +29 -52
- package/dist/agent.js.map +1 -1
- package/dist/harness/skills.d.ts +8 -0
- package/dist/harness/skills.d.ts.map +1 -1
- package/dist/harness/skills.js +46 -4
- package/dist/harness/skills.js.map +1 -1
- package/dist/harness/types.d.ts +2 -0
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js.map +1 -1
- package/package.json +1 -1
package/dist/harness/skills.d.ts
CHANGED
|
@@ -18,6 +18,14 @@ export declare function parseFrontmatter(content: string): Frontmatter;
|
|
|
18
18
|
export declare function loadSkillsFromDir(options: {
|
|
19
19
|
dir: string;
|
|
20
20
|
source: string;
|
|
21
|
+
/**
|
|
22
|
+
* Refuse to follow symlinks on any path this load would read, skipping the
|
|
23
|
+
* offending entry with a `code: "symlink"` diagnostic instead of loading
|
|
24
|
+
* it. For untrusted trees (conversation offices) the host must never
|
|
25
|
+
* follow an agent-created link; entries the loader never reads — dot
|
|
26
|
+
* directories, vendored node_modules — cannot disqualify anything.
|
|
27
|
+
*/
|
|
28
|
+
rejectSymlinks?: boolean;
|
|
21
29
|
}): LoadSkillsResult;
|
|
22
30
|
/**
|
|
23
31
|
* Format skills for a system prompt using the Agent Skills XML block.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAEhF,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKhF,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAoB7D;AAkED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAmB,MAAM,YAAY,CAAC;AAEhF,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKhF,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,WAAW,CAoB7D;AAkED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE;IACzC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,GAAG,gBAAgB,CAgBnB;AA8GD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,CAyBlE"}
|
package/dist/harness/skills.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* system prompt documents: a directory with a `SKILL.md` is a skill root
|
|
8
8
|
* (no further recursion), other directories are traversed.
|
|
9
9
|
*/
|
|
10
|
-
import { existsSync, readdirSync, readFileSync, statSync } from "fs";
|
|
10
|
+
import { existsSync, lstatSync, readdirSync, readFileSync, statSync } from "fs";
|
|
11
11
|
import { basename, dirname, join } from "path";
|
|
12
12
|
const MAX_NAME_LENGTH = 64;
|
|
13
13
|
const MAX_DESCRIPTION_LENGTH = 1024;
|
|
@@ -96,9 +96,39 @@ function loadSkillFromFile(filePath, source) {
|
|
|
96
96
|
* - Dot-directories and `node_modules` are skipped.
|
|
97
97
|
*/
|
|
98
98
|
export function loadSkillsFromDir(options) {
|
|
99
|
-
|
|
99
|
+
const rejectSymlinks = options.rejectSymlinks === true;
|
|
100
|
+
if (rejectSymlinks && isSymlink(options.dir)) {
|
|
101
|
+
return {
|
|
102
|
+
skills: [],
|
|
103
|
+
diagnostics: [
|
|
104
|
+
{
|
|
105
|
+
type: "warning",
|
|
106
|
+
code: "symlink",
|
|
107
|
+
message: "Skills directory is a symlink; skipped",
|
|
108
|
+
path: options.dir,
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return loadSkillsFromDirInternal(options.dir, options.source, true, rejectSymlinks);
|
|
100
114
|
}
|
|
101
|
-
function
|
|
115
|
+
function isSymlink(path) {
|
|
116
|
+
try {
|
|
117
|
+
return lstatSync(path).isSymbolicLink();
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function symlinkDiagnostic(path) {
|
|
124
|
+
return {
|
|
125
|
+
type: "warning",
|
|
126
|
+
code: "symlink",
|
|
127
|
+
message: "Skill entry is a symlink; skipped",
|
|
128
|
+
path,
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
function loadSkillsFromDirInternal(dir, source, includeRootFiles, rejectSymlinks) {
|
|
102
132
|
const skills = [];
|
|
103
133
|
const diagnostics = [];
|
|
104
134
|
if (!existsSync(dir))
|
|
@@ -112,6 +142,10 @@ function loadSkillsFromDirInternal(dir, source, includeRootFiles) {
|
|
|
112
142
|
}
|
|
113
143
|
const skillFile = entries.find((entry) => entry.name === "SKILL.md" && isFileLike(dir, entry));
|
|
114
144
|
if (skillFile) {
|
|
145
|
+
if (rejectSymlinks && skillFile.isSymbolicLink()) {
|
|
146
|
+
diagnostics.push(symlinkDiagnostic(join(dir, skillFile.name)));
|
|
147
|
+
return { skills, diagnostics };
|
|
148
|
+
}
|
|
115
149
|
const result = loadSkillFromFile(join(dir, skillFile.name), source);
|
|
116
150
|
if (result.skill)
|
|
117
151
|
skills.push(result.skill);
|
|
@@ -123,13 +157,21 @@ function loadSkillsFromDirInternal(dir, source, includeRootFiles) {
|
|
|
123
157
|
continue;
|
|
124
158
|
const fullPath = join(dir, entry.name);
|
|
125
159
|
if (isDirectoryLike(dir, entry)) {
|
|
126
|
-
|
|
160
|
+
if (rejectSymlinks && entry.isSymbolicLink()) {
|
|
161
|
+
diagnostics.push(symlinkDiagnostic(fullPath));
|
|
162
|
+
continue;
|
|
163
|
+
}
|
|
164
|
+
const subResult = loadSkillsFromDirInternal(fullPath, source, false, rejectSymlinks);
|
|
127
165
|
skills.push(...subResult.skills);
|
|
128
166
|
diagnostics.push(...subResult.diagnostics);
|
|
129
167
|
continue;
|
|
130
168
|
}
|
|
131
169
|
if (!includeRootFiles || !entry.name.endsWith(".md") || !isFileLike(dir, entry))
|
|
132
170
|
continue;
|
|
171
|
+
if (rejectSymlinks && entry.isSymbolicLink()) {
|
|
172
|
+
diagnostics.push(symlinkDiagnostic(fullPath));
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
133
175
|
const result = loadSkillFromFile(fullPath, source);
|
|
134
176
|
if (result.skill)
|
|
135
177
|
skills.push(result.skill);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill loading for the mikan harness.\n *\n * Skills follow the Agent Skills layout: a directory containing a `SKILL.md`\n * with YAML frontmatter (`name`, `description`), or standalone `.md` files in\n * the root of a skills directory. Discovery mirrors the behavior mikan's\n * system prompt documents: a directory with a `SKILL.md` is a skill root\n * (no further recursion), other directories are traversed.\n */\nimport { existsSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join } from \"path\";\nimport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\n\nexport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\ninterface Frontmatter {\n values: Record<string, string>;\n body: string;\n}\n\n/**\n * Parse simple `key: value` YAML frontmatter delimited by `---` lines.\n * Quoted values are unquoted; nested structures are not supported.\n */\nexport function parseFrontmatter(content: string): Frontmatter {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/);\n if (!match) return { values: {}, body: content };\n\n const values: Record<string, string> = {};\n for (const line of match[1].split(/\\r?\\n/)) {\n const separator = line.indexOf(\":\");\n if (separator === -1) continue;\n const key = line.slice(0, separator).trim();\n if (!key) continue;\n let value = line.slice(separator + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n values[key] = value;\n }\n return { values, body: content.slice(match[0].length) };\n}\n\nfunction validateSkill(name: string, description: string): string[] {\n const errors: string[] = [];\n if (name.length > MAX_NAME_LENGTH) {\n errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n }\n if (\n !/^[a-z0-9-]+$/.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\")\n ) {\n errors.push(\"name must be lowercase a-z, 0-9 and single hyphens, not at the edges\");\n }\n if (description.length > MAX_DESCRIPTION_LENGTH) {\n errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n }\n return errors;\n}\n\nfunction loadSkillFromFile(\n filePath: string,\n source: string,\n): {\n skill: MikanSkill | null;\n diagnostics: SkillDiagnostic[];\n} {\n const diagnostics: SkillDiagnostic[] = [];\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const { values, body } = parseFrontmatter(raw);\n const skillDir = dirname(filePath);\n const name = values.name || basename(skillDir);\n const description = values.description ?? \"\";\n\n if (!description.trim()) {\n diagnostics.push({ type: \"warning\", message: \"description is required\", path: filePath });\n return { skill: null, diagnostics };\n }\n for (const error of validateSkill(name, description)) {\n diagnostics.push({ type: \"warning\", message: error, path: filePath });\n }\n\n return {\n skill: {\n name,\n description,\n content: body.trim(),\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: values[\"disable-model-invocation\"] === \"true\",\n },\n diagnostics,\n };\n } catch (error) {\n diagnostics.push({\n type: \"warning\",\n message: error instanceof Error ? error.message : \"failed to parse skill file\",\n path: filePath,\n });\n return { skill: null, diagnostics };\n }\n}\n\n/**\n * Load skills from a directory tree.\n * - A directory containing `SKILL.md` is a skill root; no further recursion.\n * - Direct `.md` children of the top-level directory load as skills.\n * - Dot-directories and `node_modules` are skipped.\n */\nexport function loadSkillsFromDir(options: { dir: string; source: string }): LoadSkillsResult {\n return loadSkillsFromDirInternal(options.dir, options.source, true);\n}\n\nfunction loadSkillsFromDirInternal(\n dir: string,\n source: string,\n includeRootFiles: boolean,\n): LoadSkillsResult {\n const skills: MikanSkill[] = [];\n const diagnostics: SkillDiagnostic[] = [];\n if (!existsSync(dir)) return { skills, diagnostics };\n\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { skills, diagnostics };\n }\n\n const skillFile = entries.find((entry) => entry.name === \"SKILL.md\" && isFileLike(dir, entry));\n if (skillFile) {\n const result = loadSkillFromFile(join(dir, skillFile.name), source);\n if (result.skill) skills.push(result.skill);\n diagnostics.push(...result.diagnostics);\n return { skills, diagnostics };\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n\n if (isDirectoryLike(dir, entry)) {\n const subResult = loadSkillsFromDirInternal(fullPath, source, false);\n skills.push(...subResult.skills);\n diagnostics.push(...subResult.diagnostics);\n continue;\n }\n if (!includeRootFiles || !entry.name.endsWith(\".md\") || !isFileLike(dir, entry)) continue;\n\n const result = loadSkillFromFile(fullPath, source);\n if (result.skill) skills.push(result.skill);\n diagnostics.push(...result.diagnostics);\n }\n return { skills, diagnostics };\n}\n\nfunction isFileLike(\n dir: string,\n entry: { name: string; isFile(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isFile()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isDirectoryLike(\n dir: string,\n entry: { name: string; isDirectory(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Format skills for a system prompt using the Agent Skills XML block.\n * Skills with `disableModelInvocation` are excluded.\n */\nexport function formatSkillsForPrompt(skills: MikanSkill[]): string {\n const visible = skills.filter((skill) => !skill.disableModelInvocation);\n if (visible.length === 0) return \"\";\n\n const lines = [\n \"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n \"Use the read tool to load a skill's file when the task matches its description.\",\n \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n \"\",\n \"<available_skills>\",\n ];\n for (const skill of visible) {\n lines.push(\" <skill>\");\n lines.push(` <name>${escapeXml(skill.name)}</name>`);\n lines.push(` <description>${escapeXml(skill.description)}</description>`);\n if (skill.inline) {\n // Inline skills carry their body: the agent cannot read their file.\n lines.push(` <instructions>${escapeXml(skill.content)}</instructions>`);\n } else {\n lines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n }\n lines.push(\" </skill>\");\n }\n lines.push(\"</available_skills>\");\n return lines.join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/harness/skills.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Skill loading for the mikan harness.\n *\n * Skills follow the Agent Skills layout: a directory containing a `SKILL.md`\n * with YAML frontmatter (`name`, `description`), or standalone `.md` files in\n * the root of a skills directory. Discovery mirrors the behavior mikan's\n * system prompt documents: a directory with a `SKILL.md` is a skill root\n * (no further recursion), other directories are traversed.\n */\nimport { existsSync, lstatSync, readdirSync, readFileSync, statSync } from \"fs\";\nimport { basename, dirname, join } from \"path\";\nimport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\n\nexport type { LoadSkillsResult, MikanSkill, SkillDiagnostic } from \"./types.js\";\n\nconst MAX_NAME_LENGTH = 64;\nconst MAX_DESCRIPTION_LENGTH = 1024;\n\ninterface Frontmatter {\n values: Record<string, string>;\n body: string;\n}\n\n/**\n * Parse simple `key: value` YAML frontmatter delimited by `---` lines.\n * Quoted values are unquoted; nested structures are not supported.\n */\nexport function parseFrontmatter(content: string): Frontmatter {\n const match = content.match(/^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/);\n if (!match) return { values: {}, body: content };\n\n const values: Record<string, string> = {};\n for (const line of match[1].split(/\\r?\\n/)) {\n const separator = line.indexOf(\":\");\n if (separator === -1) continue;\n const key = line.slice(0, separator).trim();\n if (!key) continue;\n let value = line.slice(separator + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n values[key] = value;\n }\n return { values, body: content.slice(match[0].length) };\n}\n\nfunction validateSkill(name: string, description: string): string[] {\n const errors: string[] = [];\n if (name.length > MAX_NAME_LENGTH) {\n errors.push(`name exceeds ${MAX_NAME_LENGTH} characters (${name.length})`);\n }\n if (\n !/^[a-z0-9-]+$/.test(name) ||\n name.startsWith(\"-\") ||\n name.endsWith(\"-\") ||\n name.includes(\"--\")\n ) {\n errors.push(\"name must be lowercase a-z, 0-9 and single hyphens, not at the edges\");\n }\n if (description.length > MAX_DESCRIPTION_LENGTH) {\n errors.push(`description exceeds ${MAX_DESCRIPTION_LENGTH} characters (${description.length})`);\n }\n return errors;\n}\n\nfunction loadSkillFromFile(\n filePath: string,\n source: string,\n): {\n skill: MikanSkill | null;\n diagnostics: SkillDiagnostic[];\n} {\n const diagnostics: SkillDiagnostic[] = [];\n try {\n const raw = readFileSync(filePath, \"utf-8\");\n const { values, body } = parseFrontmatter(raw);\n const skillDir = dirname(filePath);\n const name = values.name || basename(skillDir);\n const description = values.description ?? \"\";\n\n if (!description.trim()) {\n diagnostics.push({ type: \"warning\", message: \"description is required\", path: filePath });\n return { skill: null, diagnostics };\n }\n for (const error of validateSkill(name, description)) {\n diagnostics.push({ type: \"warning\", message: error, path: filePath });\n }\n\n return {\n skill: {\n name,\n description,\n content: body.trim(),\n filePath,\n baseDir: skillDir,\n source,\n disableModelInvocation: values[\"disable-model-invocation\"] === \"true\",\n },\n diagnostics,\n };\n } catch (error) {\n diagnostics.push({\n type: \"warning\",\n message: error instanceof Error ? error.message : \"failed to parse skill file\",\n path: filePath,\n });\n return { skill: null, diagnostics };\n }\n}\n\n/**\n * Load skills from a directory tree.\n * - A directory containing `SKILL.md` is a skill root; no further recursion.\n * - Direct `.md` children of the top-level directory load as skills.\n * - Dot-directories and `node_modules` are skipped.\n */\nexport function loadSkillsFromDir(options: {\n dir: string;\n source: string;\n /**\n * Refuse to follow symlinks on any path this load would read, skipping the\n * offending entry with a `code: \"symlink\"` diagnostic instead of loading\n * it. For untrusted trees (conversation offices) the host must never\n * follow an agent-created link; entries the loader never reads — dot\n * directories, vendored node_modules — cannot disqualify anything.\n */\n rejectSymlinks?: boolean;\n}): LoadSkillsResult {\n const rejectSymlinks = options.rejectSymlinks === true;\n if (rejectSymlinks && isSymlink(options.dir)) {\n return {\n skills: [],\n diagnostics: [\n {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skills directory is a symlink; skipped\",\n path: options.dir,\n },\n ],\n };\n }\n return loadSkillsFromDirInternal(options.dir, options.source, true, rejectSymlinks);\n}\n\nfunction isSymlink(path: string): boolean {\n try {\n return lstatSync(path).isSymbolicLink();\n } catch {\n return false;\n }\n}\n\nfunction symlinkDiagnostic(path: string): SkillDiagnostic {\n return {\n type: \"warning\",\n code: \"symlink\",\n message: \"Skill entry is a symlink; skipped\",\n path,\n };\n}\n\nfunction loadSkillsFromDirInternal(\n dir: string,\n source: string,\n includeRootFiles: boolean,\n rejectSymlinks: boolean,\n): LoadSkillsResult {\n const skills: MikanSkill[] = [];\n const diagnostics: SkillDiagnostic[] = [];\n if (!existsSync(dir)) return { skills, diagnostics };\n\n let entries;\n try {\n entries = readdirSync(dir, { withFileTypes: true });\n } catch {\n return { skills, diagnostics };\n }\n\n const skillFile = entries.find((entry) => entry.name === \"SKILL.md\" && isFileLike(dir, entry));\n if (skillFile) {\n if (rejectSymlinks && skillFile.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(join(dir, skillFile.name)));\n return { skills, diagnostics };\n }\n const result = loadSkillFromFile(join(dir, skillFile.name), source);\n if (result.skill) skills.push(result.skill);\n diagnostics.push(...result.diagnostics);\n return { skills, diagnostics };\n }\n\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const fullPath = join(dir, entry.name);\n\n if (isDirectoryLike(dir, entry)) {\n if (rejectSymlinks && entry.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(fullPath));\n continue;\n }\n const subResult = loadSkillsFromDirInternal(fullPath, source, false, rejectSymlinks);\n skills.push(...subResult.skills);\n diagnostics.push(...subResult.diagnostics);\n continue;\n }\n if (!includeRootFiles || !entry.name.endsWith(\".md\") || !isFileLike(dir, entry)) continue;\n\n if (rejectSymlinks && entry.isSymbolicLink()) {\n diagnostics.push(symlinkDiagnostic(fullPath));\n continue;\n }\n const result = loadSkillFromFile(fullPath, source);\n if (result.skill) skills.push(result.skill);\n diagnostics.push(...result.diagnostics);\n }\n return { skills, diagnostics };\n}\n\nfunction isFileLike(\n dir: string,\n entry: { name: string; isFile(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isFile()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isFile();\n } catch {\n return false;\n }\n}\n\nfunction isDirectoryLike(\n dir: string,\n entry: { name: string; isDirectory(): boolean; isSymbolicLink(): boolean },\n): boolean {\n if (entry.isDirectory()) return true;\n if (!entry.isSymbolicLink()) return false;\n try {\n return statSync(join(dir, entry.name)).isDirectory();\n } catch {\n return false;\n }\n}\n\nfunction escapeXml(str: string): string {\n return str\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\n/**\n * Format skills for a system prompt using the Agent Skills XML block.\n * Skills with `disableModelInvocation` are excluded.\n */\nexport function formatSkillsForPrompt(skills: MikanSkill[]): string {\n const visible = skills.filter((skill) => !skill.disableModelInvocation);\n if (visible.length === 0) return \"\";\n\n const lines = [\n \"\\n\\nThe following skills provide specialized instructions for specific tasks.\",\n \"Use the read tool to load a skill's file when the task matches its description.\",\n \"When a skill file references a relative path, resolve it against the skill directory (parent of SKILL.md / dirname of the path) and use that absolute path in tool commands.\",\n \"\",\n \"<available_skills>\",\n ];\n for (const skill of visible) {\n lines.push(\" <skill>\");\n lines.push(` <name>${escapeXml(skill.name)}</name>`);\n lines.push(` <description>${escapeXml(skill.description)}</description>`);\n if (skill.inline) {\n // Inline skills carry their body: the agent cannot read their file.\n lines.push(` <instructions>${escapeXml(skill.content)}</instructions>`);\n } else {\n lines.push(` <location>${escapeXml(skill.filePath)}</location>`);\n }\n lines.push(\" </skill>\");\n }\n lines.push(\"</available_skills>\");\n return lines.join(\"\\n\");\n}\n"]}
|
package/dist/harness/types.d.ts
CHANGED
|
@@ -204,6 +204,8 @@ export interface SkillDiagnostic {
|
|
|
204
204
|
type: "warning";
|
|
205
205
|
message: string;
|
|
206
206
|
path: string;
|
|
207
|
+
/** Set when the entry was skipped because it is a symlink on a rejecting load. */
|
|
208
|
+
code?: "symlink";
|
|
207
209
|
}
|
|
208
210
|
export interface LoadSkillsResult {
|
|
209
211
|
skills: MikanSkill[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"AA2CA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC","sourcesContent":["/**\n * Core types for the mikan agent harness.\n *\n * The harness is built directly on pi-agent-core and pi-ai. Session entries\n * are structurally identical to pi-agent-core's `SessionTreeEntry`, and the\n * on-disk JSONL format stays compatible with the v3 session files mikan has\n * always written, so existing conversation history keeps working unchanged.\n */\nimport type {\n AgentEvent,\n AgentTool,\n BranchSummaryEntry,\n CompactionEntry,\n CustomEntry,\n CustomMessageEntry,\n MessageEntry,\n SessionContext,\n SessionInfoEntry,\n SessionTreeEntry,\n ThinkingLevel,\n CompactionSettings,\n} from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model, Usage } from \"@earendil-works/pi-ai\";\nimport type { ExtensionRegistry } from \"./extensions/registry.js\";\nimport type { MikanModels } from \"./models.js\";\nimport type { SessionStore } from \"./session-store.js\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\n\nexport type {\n BranchSummaryEntry,\n CompactionEntry,\n CustomEntry,\n CustomMessageEntry,\n SessionContext,\n SessionInfoEntry,\n};\n\n/** Message entry as stored in mikan session files. */\nexport type SessionMessageEntry = MessageEntry;\n\n/** Union of entry types mikan reads and writes. Alias of pi-agent-core's tree entry. */\nexport type SessionEntry = SessionTreeEntry;\n\nexport const CURRENT_SESSION_VERSION = 3;\n\nexport interface SubagentModelSpec {\n provider: string;\n id: string;\n}\n\n/**\n * A curated capability set a subagent can be launched with. Built-ins ship\n * with the harness; `<workspaceDir>/agents/<name>.md` patches them per\n * installation. Turn, cost, and duration fields are caps — an explicit\n * `request.budget` may tighten them but never raise them. Token budgets use the\n * larger of the profile default and the request value.\n */\nexport interface SubagentProfile {\n name: string;\n description: string;\n systemPrompt: string;\n tools: string[];\n requiredTools: string[];\n model?: SubagentModelSpec;\n thinkingLevel?: ThinkingLevel;\n maxTurns?: number;\n maxTokens?: number;\n maxCostUsd?: number;\n maxDurationMs?: number;\n}\n\nexport interface SubagentRunBudget {\n /** Maximum assistant/model calls in the subagent run. */\n maxTurns?: number;\n /** Maximum cumulative input/output/cache tokens. */\n maxTokens?: number;\n /** Maximum provider cost in USD. */\n maxCostUsd?: number;\n /** Maximum wall-clock duration. */\n maxDurationMs?: number;\n}\n\nexport type SubagentRunStatus =\n | \"completed\"\n | \"failed\"\n | \"cancelled\"\n | \"timeout\"\n | \"budget_exceeded\"\n | \"invalid_output\";\n\nexport interface SubagentParentContext {\n mode: \"normalized\";\n /** Number of recent user/assistant turns to include. Defaults to 3. */\n recentTurns?: number;\n}\n\n/** Aggregated model usage across every assistant turn in a subagent run. */\nexport type SubagentUsage = Usage;\n\n/** Receives usage from a subagent run, including after detached cleanup settles. */\nexport type SubagentUsageSink = (usage: SubagentUsage) => void | Promise<void>;\n\n/** A fresh, isolated subagent run. */\nexport interface SubagentRunRequest<TOutputSchema extends TSchema | undefined = undefined> {\n task: string;\n /** Named profile: a harness built-in, patched by `<workspaceDir>/agents/<name>.md`. */\n profile?: string;\n /** Opt in to a normalized textual snapshot of the active parent run. Defaults to fresh. */\n parentContext?: SubagentParentContext;\n systemPrompt?: string;\n /** JSON-serializable input appended to the task. */\n input?: unknown;\n /** Defaults to the parent runner's configured model. */\n model?: SubagentModelSpec;\n /** Tool names explicitly granted to the subagent. Defaults to no tools. */\n tools?: string[];\n /** Tool names that must each be invoked at least once before completion. */\n requiredTools?: string[];\n /** Per-profile thinking override. */\n thinkingLevel?: ThinkingLevel;\n /** When present, the final response must be JSON matching this schema. */\n outputSchema?: TOutputSchema;\n budget?: SubagentRunBudget;\n signal?: AbortSignal;\n}\n\nexport type SubagentRunOutput<TSchemaOrUndefined extends TSchema | undefined> =\n TSchemaOrUndefined extends TSchema ? Static<TSchemaOrUndefined> : string;\n\ninterface SubagentRunMetadata {\n runId: string;\n /** Raw final assistant text, including when structured validation failed. */\n text?: string;\n model: SubagentModelSpec;\n turns: number;\n toolCalls: number;\n toolCallCounts: Record<string, number>;\n /** Full token and cost breakdown across the run. */\n usage: SubagentUsage;\n /** Aggregate token count; equivalent to `usage.totalTokens`. */\n tokens: number;\n /** Aggregate provider cost; equivalent to `usage.cost.total`. */\n costUsd: number;\n durationMs: number;\n /**\n * The caller received a terminal result before the underlying run settled.\n * When true, `usage`, `tokens`, and `costUsd` are provisional snapshots;\n * final usage is delivered later through the run's bound usage sink. The\n * global slot remains held until cleanup settles because in-process work\n * cannot be safely reclaimed without a killable execution boundary.\n */\n cleanupPending?: boolean;\n}\n\ninterface SubagentRunCompletedResult<TOutput> extends SubagentRunMetadata {\n status: \"completed\";\n output: TOutput;\n error?: never;\n}\n\ninterface SubagentRunIncompleteResult extends SubagentRunMetadata {\n status: Exclude<SubagentRunStatus, \"completed\">;\n output?: never;\n error?: string;\n}\n\nexport type SubagentRunResult<TOutput = string> =\n | SubagentRunCompletedResult<TOutput>\n | SubagentRunIncompleteResult;\n\n/**\n * First line of every session file. `cwd` records where the session was\n * started; extra fields (for example mikan's `source` marker) are preserved\n * verbatim on read and rewrite.\n */\nexport interface SessionHeader {\n type: \"session\";\n version?: number;\n id: string;\n timestamp: string;\n cwd: string;\n parentSession?: string;\n parentSessionId?: string;\n [extra: string]: unknown;\n}\n\n/** Raw file line: the header or one session entry. */\nexport type SessionFileEntry = SessionHeader | SessionEntry;\n\nexport interface CreateMikanModelsOptions {\n authPath?: string;\n modelsJsonPath?: string;\n}\n\nexport type EventConversationKind = \"direct\" | \"shared\";\n\nexport type EventType = \"immediate\" | \"one-shot\" | \"periodic\";\n\ninterface EventPayloadBase {\n /** Target platform; may be omitted when only one platform is running. */\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n /** Self-contained task text; event runs do not inherit conversation history. */\n text: string;\n}\n\nexport interface ImmediateEventPayload extends EventPayloadBase {\n type: \"immediate\";\n}\n\nexport interface OneShotEventPayload extends EventPayloadBase {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n}\n\nexport interface PeriodicEventPayload extends EventPayloadBase {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n}\n\n/** Wire shape of one event file. */\nexport type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;\n\nexport interface EventPayloadInput {\n type: EventType;\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n/** A loaded skill. `baseDir` is the directory containing the skill file. */\nexport interface MikanSkill {\n name: string;\n description: string;\n /** Full skill instructions (file content without frontmatter). */\n content: string;\n filePath: string;\n baseDir: string;\n /** Where the skill was loaded from (e.g. \"workspace\", \"channel\"). */\n source: string;\n /** Exclude from model-visible skill lists. */\n disableModelInvocation?: boolean;\n /**\n * Embed the skill body in the prompt instead of referencing its file path.\n * Used for skills whose files the agent cannot read at runtime (e.g.\n * extension skills under the host-only state dir in sandbox modes).\n */\n inline?: boolean;\n}\n\nexport interface SkillDiagnostic {\n type: \"warning\";\n message: string;\n path: string;\n}\n\nexport interface LoadSkillsResult {\n skills: MikanSkill[];\n diagnostics: SkillDiagnostic[];\n}\n\nexport interface RetrySettings {\n enabled: boolean;\n maxRetries: number;\n baseDelayMs: number;\n}\n\nexport interface BudgetSettings {\n /** Max cumulative tokens processed this run (input + output + cache read/write). */\n maxTokens?: number;\n /** Max cumulative provider cost (USD) this run. Requires a populated model cost table. */\n maxCostUsd?: number;\n /** Max wall-clock duration for the run, in milliseconds. */\n maxDurationMs?: number;\n /** Max number of LLM calls (assistant turns) this run. */\n maxLlmCalls?: number;\n}\n\nexport interface HarnessSettings {\n compaction: CompactionSettings;\n retry: RetrySettings;\n budget: BudgetSettings;\n}\n\nexport interface SubagentProfileDiagnostic {\n type: \"warning\";\n message: string;\n path: string;\n}\n\nexport interface LoadSubagentProfilesResult {\n profiles: Map<string, SubagentProfile>;\n diagnostics: SubagentProfileDiagnostic[];\n}\n\nexport type CompactionReason = \"threshold\" | \"overflow\" | \"manual\";\n\ninterface CompactionResultSummary {\n summary: string;\n firstKeptEntryId: string;\n tokensBefore: number;\n}\n\nexport type HarnessEvent =\n | AgentEvent\n | { type: \"compaction_start\"; reason: CompactionReason }\n | {\n type: \"compaction_end\";\n reason: CompactionReason;\n result?: CompactionResultSummary;\n aborted: boolean;\n errorMessage?: string;\n }\n | {\n type: \"auto_retry_start\";\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n errorMessage: string;\n }\n | { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string }\n | {\n type: \"budget_exceeded\";\n /** Which cap was hit, e.g. \"cost 2.01 USD > 2 USD limit\". */\n reason: string;\n tokens: number;\n costUsd: number;\n llmCalls: number;\n durationMs: number;\n };\n\nexport type HarnessEventListener = (event: HarnessEvent) => void | Promise<void>;\n\n/** Outcome of a `prompt()` call that an extension blocked before the model ran. */\nexport interface PromptBlockedOutcome {\n blocked: true;\n reason?: string;\n}\n\nexport interface MikanAgentSessionOptions {\n systemPrompt: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n tools: AgentTool[];\n models: MikanModels;\n sessionStore: SessionStore;\n settings?: {\n compaction?: Partial<CompactionSettings>;\n retry?: Partial<RetrySettings>;\n budget?: Partial<BudgetSettings>;\n };\n extensions?: ExtensionRegistry;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/harness/types.ts"],"names":[],"mappings":"AA2CA,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC","sourcesContent":["/**\n * Core types for the mikan agent harness.\n *\n * The harness is built directly on pi-agent-core and pi-ai. Session entries\n * are structurally identical to pi-agent-core's `SessionTreeEntry`, and the\n * on-disk JSONL format stays compatible with the v3 session files mikan has\n * always written, so existing conversation history keeps working unchanged.\n */\nimport type {\n AgentEvent,\n AgentTool,\n BranchSummaryEntry,\n CompactionEntry,\n CustomEntry,\n CustomMessageEntry,\n MessageEntry,\n SessionContext,\n SessionInfoEntry,\n SessionTreeEntry,\n ThinkingLevel,\n CompactionSettings,\n} from \"@earendil-works/pi-agent-core\";\nimport type { Api, Model, Usage } from \"@earendil-works/pi-ai\";\nimport type { ExtensionRegistry } from \"./extensions/registry.js\";\nimport type { MikanModels } from \"./models.js\";\nimport type { SessionStore } from \"./session-store.js\";\nimport type { Static, TSchema } from \"@sinclair/typebox\";\n\nexport type {\n BranchSummaryEntry,\n CompactionEntry,\n CustomEntry,\n CustomMessageEntry,\n SessionContext,\n SessionInfoEntry,\n};\n\n/** Message entry as stored in mikan session files. */\nexport type SessionMessageEntry = MessageEntry;\n\n/** Union of entry types mikan reads and writes. Alias of pi-agent-core's tree entry. */\nexport type SessionEntry = SessionTreeEntry;\n\nexport const CURRENT_SESSION_VERSION = 3;\n\nexport interface SubagentModelSpec {\n provider: string;\n id: string;\n}\n\n/**\n * A curated capability set a subagent can be launched with. Built-ins ship\n * with the harness; `<workspaceDir>/agents/<name>.md` patches them per\n * installation. Turn, cost, and duration fields are caps — an explicit\n * `request.budget` may tighten them but never raise them. Token budgets use the\n * larger of the profile default and the request value.\n */\nexport interface SubagentProfile {\n name: string;\n description: string;\n systemPrompt: string;\n tools: string[];\n requiredTools: string[];\n model?: SubagentModelSpec;\n thinkingLevel?: ThinkingLevel;\n maxTurns?: number;\n maxTokens?: number;\n maxCostUsd?: number;\n maxDurationMs?: number;\n}\n\nexport interface SubagentRunBudget {\n /** Maximum assistant/model calls in the subagent run. */\n maxTurns?: number;\n /** Maximum cumulative input/output/cache tokens. */\n maxTokens?: number;\n /** Maximum provider cost in USD. */\n maxCostUsd?: number;\n /** Maximum wall-clock duration. */\n maxDurationMs?: number;\n}\n\nexport type SubagentRunStatus =\n | \"completed\"\n | \"failed\"\n | \"cancelled\"\n | \"timeout\"\n | \"budget_exceeded\"\n | \"invalid_output\";\n\nexport interface SubagentParentContext {\n mode: \"normalized\";\n /** Number of recent user/assistant turns to include. Defaults to 3. */\n recentTurns?: number;\n}\n\n/** Aggregated model usage across every assistant turn in a subagent run. */\nexport type SubagentUsage = Usage;\n\n/** Receives usage from a subagent run, including after detached cleanup settles. */\nexport type SubagentUsageSink = (usage: SubagentUsage) => void | Promise<void>;\n\n/** A fresh, isolated subagent run. */\nexport interface SubagentRunRequest<TOutputSchema extends TSchema | undefined = undefined> {\n task: string;\n /** Named profile: a harness built-in, patched by `<workspaceDir>/agents/<name>.md`. */\n profile?: string;\n /** Opt in to a normalized textual snapshot of the active parent run. Defaults to fresh. */\n parentContext?: SubagentParentContext;\n systemPrompt?: string;\n /** JSON-serializable input appended to the task. */\n input?: unknown;\n /** Defaults to the parent runner's configured model. */\n model?: SubagentModelSpec;\n /** Tool names explicitly granted to the subagent. Defaults to no tools. */\n tools?: string[];\n /** Tool names that must each be invoked at least once before completion. */\n requiredTools?: string[];\n /** Per-profile thinking override. */\n thinkingLevel?: ThinkingLevel;\n /** When present, the final response must be JSON matching this schema. */\n outputSchema?: TOutputSchema;\n budget?: SubagentRunBudget;\n signal?: AbortSignal;\n}\n\nexport type SubagentRunOutput<TSchemaOrUndefined extends TSchema | undefined> =\n TSchemaOrUndefined extends TSchema ? Static<TSchemaOrUndefined> : string;\n\ninterface SubagentRunMetadata {\n runId: string;\n /** Raw final assistant text, including when structured validation failed. */\n text?: string;\n model: SubagentModelSpec;\n turns: number;\n toolCalls: number;\n toolCallCounts: Record<string, number>;\n /** Full token and cost breakdown across the run. */\n usage: SubagentUsage;\n /** Aggregate token count; equivalent to `usage.totalTokens`. */\n tokens: number;\n /** Aggregate provider cost; equivalent to `usage.cost.total`. */\n costUsd: number;\n durationMs: number;\n /**\n * The caller received a terminal result before the underlying run settled.\n * When true, `usage`, `tokens`, and `costUsd` are provisional snapshots;\n * final usage is delivered later through the run's bound usage sink. The\n * global slot remains held until cleanup settles because in-process work\n * cannot be safely reclaimed without a killable execution boundary.\n */\n cleanupPending?: boolean;\n}\n\ninterface SubagentRunCompletedResult<TOutput> extends SubagentRunMetadata {\n status: \"completed\";\n output: TOutput;\n error?: never;\n}\n\ninterface SubagentRunIncompleteResult extends SubagentRunMetadata {\n status: Exclude<SubagentRunStatus, \"completed\">;\n output?: never;\n error?: string;\n}\n\nexport type SubagentRunResult<TOutput = string> =\n | SubagentRunCompletedResult<TOutput>\n | SubagentRunIncompleteResult;\n\n/**\n * First line of every session file. `cwd` records where the session was\n * started; extra fields (for example mikan's `source` marker) are preserved\n * verbatim on read and rewrite.\n */\nexport interface SessionHeader {\n type: \"session\";\n version?: number;\n id: string;\n timestamp: string;\n cwd: string;\n parentSession?: string;\n parentSessionId?: string;\n [extra: string]: unknown;\n}\n\n/** Raw file line: the header or one session entry. */\nexport type SessionFileEntry = SessionHeader | SessionEntry;\n\nexport interface CreateMikanModelsOptions {\n authPath?: string;\n modelsJsonPath?: string;\n}\n\nexport type EventConversationKind = \"direct\" | \"shared\";\n\nexport type EventType = \"immediate\" | \"one-shot\" | \"periodic\";\n\ninterface EventPayloadBase {\n /** Target platform; may be omitted when only one platform is running. */\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n /** Self-contained task text; event runs do not inherit conversation history. */\n text: string;\n}\n\nexport interface ImmediateEventPayload extends EventPayloadBase {\n type: \"immediate\";\n}\n\nexport interface OneShotEventPayload extends EventPayloadBase {\n type: \"one-shot\";\n /** ISO 8601 timestamp with offset. */\n at: string;\n}\n\nexport interface PeriodicEventPayload extends EventPayloadBase {\n type: \"periodic\";\n /** Cron expression (croner syntax). */\n schedule: string;\n /** IANA timezone, e.g. \"Asia/Taipei\". */\n timezone: string;\n}\n\n/** Wire shape of one event file. */\nexport type EventFilePayload = ImmediateEventPayload | OneShotEventPayload | PeriodicEventPayload;\n\nexport interface EventPayloadInput {\n type: EventType;\n platform?: string;\n conversationId: string;\n conversationKind?: EventConversationKind;\n userId?: string;\n text: string;\n at?: string;\n schedule?: string;\n timezone?: string;\n}\n\n/** A loaded skill. `baseDir` is the directory containing the skill file. */\nexport interface MikanSkill {\n name: string;\n description: string;\n /** Full skill instructions (file content without frontmatter). */\n content: string;\n filePath: string;\n baseDir: string;\n /** Where the skill was loaded from (e.g. \"workspace\", \"channel\"). */\n source: string;\n /** Exclude from model-visible skill lists. */\n disableModelInvocation?: boolean;\n /**\n * Embed the skill body in the prompt instead of referencing its file path.\n * Used for skills whose files the agent cannot read at runtime (e.g.\n * extension skills under the host-only state dir in sandbox modes).\n */\n inline?: boolean;\n}\n\nexport interface SkillDiagnostic {\n type: \"warning\";\n message: string;\n path: string;\n /** Set when the entry was skipped because it is a symlink on a rejecting load. */\n code?: \"symlink\";\n}\n\nexport interface LoadSkillsResult {\n skills: MikanSkill[];\n diagnostics: SkillDiagnostic[];\n}\n\nexport interface RetrySettings {\n enabled: boolean;\n maxRetries: number;\n baseDelayMs: number;\n}\n\nexport interface BudgetSettings {\n /** Max cumulative tokens processed this run (input + output + cache read/write). */\n maxTokens?: number;\n /** Max cumulative provider cost (USD) this run. Requires a populated model cost table. */\n maxCostUsd?: number;\n /** Max wall-clock duration for the run, in milliseconds. */\n maxDurationMs?: number;\n /** Max number of LLM calls (assistant turns) this run. */\n maxLlmCalls?: number;\n}\n\nexport interface HarnessSettings {\n compaction: CompactionSettings;\n retry: RetrySettings;\n budget: BudgetSettings;\n}\n\nexport interface SubagentProfileDiagnostic {\n type: \"warning\";\n message: string;\n path: string;\n}\n\nexport interface LoadSubagentProfilesResult {\n profiles: Map<string, SubagentProfile>;\n diagnostics: SubagentProfileDiagnostic[];\n}\n\nexport type CompactionReason = \"threshold\" | \"overflow\" | \"manual\";\n\ninterface CompactionResultSummary {\n summary: string;\n firstKeptEntryId: string;\n tokensBefore: number;\n}\n\nexport type HarnessEvent =\n | AgentEvent\n | { type: \"compaction_start\"; reason: CompactionReason }\n | {\n type: \"compaction_end\";\n reason: CompactionReason;\n result?: CompactionResultSummary;\n aborted: boolean;\n errorMessage?: string;\n }\n | {\n type: \"auto_retry_start\";\n attempt: number;\n maxAttempts: number;\n delayMs: number;\n errorMessage: string;\n }\n | { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string }\n | {\n type: \"budget_exceeded\";\n /** Which cap was hit, e.g. \"cost 2.01 USD > 2 USD limit\". */\n reason: string;\n tokens: number;\n costUsd: number;\n llmCalls: number;\n durationMs: number;\n };\n\nexport type HarnessEventListener = (event: HarnessEvent) => void | Promise<void>;\n\n/** Outcome of a `prompt()` call that an extension blocked before the model ran. */\nexport interface PromptBlockedOutcome {\n blocked: true;\n reason?: string;\n}\n\nexport interface MikanAgentSessionOptions {\n systemPrompt: string;\n model: Model<Api>;\n thinkingLevel: ThinkingLevel;\n tools: AgentTool[];\n models: MikanModels;\n sessionStore: SessionStore;\n settings?: {\n compaction?: Partial<CompactionSettings>;\n retry?: Partial<RetrySettings>;\n budget?: Partial<BudgetSettings>;\n };\n extensions?: ExtensionRegistry;\n}\n"]}
|