@astralyn/pi 0.82.4 → 0.82.5
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 +24 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +2 -2
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +1 -1
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +2 -3
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/types.d.ts +9 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js +11 -0
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/extensions/question/dialog.d.ts +3 -1
- package/dist/extensions/question/dialog.d.ts.map +1 -1
- package/dist/extensions/question/dialog.js +106 -52
- package/dist/extensions/question/dialog.js.map +1 -1
- package/dist/extensions/question/index.d.ts.map +1 -1
- package/dist/extensions/question/index.js +2 -2
- package/dist/extensions/question/index.js.map +1 -1
- package/dist/extensions/question/render-cache.d.ts +9 -0
- package/dist/extensions/question/render-cache.d.ts.map +1 -1
- package/dist/extensions/question/render-cache.js +22 -0
- package/dist/extensions/question/render-cache.js.map +1 -1
- package/dist/extensions/question/results.d.ts.map +1 -1
- package/dist/extensions/question/results.js +6 -1
- package/dist/extensions/question/results.js.map +1 -1
- package/dist/extensions/question/schema.d.ts +4 -0
- package/dist/extensions/question/schema.d.ts.map +1 -1
- package/dist/extensions/question/schema.js +19 -28
- package/dist/extensions/question/schema.js.map +1 -1
- package/dist/extensions/question/types.d.ts +1 -1
- package/dist/extensions/question/types.d.ts.map +1 -1
- package/dist/extensions/question/types.js.map +1 -1
- package/dist/extensions/subagent/agents.d.ts.map +1 -1
- package/dist/extensions/subagent/agents.js +12 -6
- package/dist/extensions/subagent/agents.js.map +1 -1
- package/dist/extensions/subagent/constants.d.ts +1 -1
- package/dist/extensions/subagent/constants.d.ts.map +1 -1
- package/dist/extensions/subagent/constants.js +3 -2
- package/dist/extensions/subagent/constants.js.map +1 -1
- package/dist/extensions/subagent/runner.d.ts +1 -1
- package/dist/extensions/subagent/runner.d.ts.map +1 -1
- package/dist/extensions/subagent/runner.js +5 -1
- package/dist/extensions/subagent/runner.js.map +1 -1
- package/dist/extensions/subagent/schema.d.ts.map +1 -1
- package/dist/extensions/subagent/schema.js +2 -2
- package/dist/extensions/subagent/schema.js.map +1 -1
- package/dist/extensions/subagent/sdk-runner.d.ts.map +1 -1
- package/dist/extensions/subagent/sdk-runner.js +5 -0
- package/dist/extensions/subagent/sdk-runner.js.map +1 -1
- package/dist/extensions/subagent/types.d.ts +7 -0
- package/dist/extensions/subagent/types.d.ts.map +1 -1
- package/dist/extensions/subagent/types.js.map +1 -1
- package/dist/extensions/todo/constants.d.ts +1 -1
- package/dist/extensions/todo/constants.d.ts.map +1 -1
- package/dist/extensions/todo/constants.js +29 -4
- package/dist/extensions/todo/constants.js.map +1 -1
- package/dist/extensions/todo/index.d.ts +1 -1
- package/dist/extensions/todo/index.d.ts.map +1 -1
- package/dist/extensions/todo/index.js +22 -3
- package/dist/extensions/todo/index.js.map +1 -1
- package/dist/extensions/todo/schema.d.ts +6 -5
- package/dist/extensions/todo/schema.d.ts.map +1 -1
- package/dist/extensions/todo/schema.js +20 -9
- package/dist/extensions/todo/schema.js.map +1 -1
- package/dist/extensions/todo/state.d.ts +5 -1
- package/dist/extensions/todo/state.d.ts.map +1 -1
- package/dist/extensions/todo/state.js +184 -38
- package/dist/extensions/todo/state.js.map +1 -1
- package/dist/extensions/todo/view.d.ts.map +1 -1
- package/dist/extensions/todo/view.js +10 -6
- package/dist/extensions/todo/view.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +34 -1
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/coalescing-terminal.d.ts +71 -17
- package/dist/utils/coalescing-terminal.d.ts.map +1 -1
- package/dist/utils/coalescing-terminal.js +136 -31
- package/dist/utils/coalescing-terminal.js.map +1 -1
- package/docs/bundled/extensions/question.md +9 -7
- package/docs/bundled/extensions/subagent.md +2 -2
- package/docs/bundled/extensions/todo.md +5 -3
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memoize rendered preview lines by (previewText, width, maxLines) so editor
|
|
3
|
+
* keystrokes don't re-parse the preview markdown on every frame. Questions are
|
|
4
|
+
* immutable for a dialog's lifetime and carry few previews, so no eviction.
|
|
5
|
+
*/
|
|
6
|
+
export class PreviewLinesCache {
|
|
7
|
+
cache = new Map();
|
|
8
|
+
get(previewText, width, maxLines, compute) {
|
|
9
|
+
let byDimensions = this.cache.get(previewText);
|
|
10
|
+
if (!byDimensions) {
|
|
11
|
+
byDimensions = new Map();
|
|
12
|
+
this.cache.set(previewText, byDimensions);
|
|
13
|
+
}
|
|
14
|
+
const key = `${width}x${maxLines}`;
|
|
15
|
+
let lines = byDimensions.get(key);
|
|
16
|
+
if (!lines) {
|
|
17
|
+
lines = compute();
|
|
18
|
+
byDimensions.set(key, lines);
|
|
19
|
+
}
|
|
20
|
+
return lines;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
1
23
|
/** Cache custom dialog output by terminal dimensions. */
|
|
2
24
|
export class WidthCachedRender {
|
|
3
25
|
cachedLines;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-cache.js","sourceRoot":"","sources":["../../../src/extensions/question/render-cache.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,MAAM,OAAO,iBAAiB;IACrB,WAAW,CAAuB;IAClC,WAAW,CAAqB;IAChC,YAAY,CAAqB;IAEzC,UAAU,GAAS;QAClB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;IAAA,CAC7B;IAED,GAAG,CAAC,KAAa,EAAE,MAAc,EAAE,OAAoD,EAAY;QAClG,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM;YAC/F,OAAO,IAAI,CAAC,WAAW,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC3B,OAAO,IAAI,CAAC,WAAW,CAAC;IAAA,CACxB;CACD","sourcesContent":["/** Cache custom dialog output by terminal dimensions. */\nexport class WidthCachedRender {\n\tprivate cachedLines: string[] | undefined;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedHeight: number | undefined;\n\n\tinvalidate(): void {\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tget(width: number, height: number, compute: (width: number, height: number) => string[]): string[] {\n\t\tif (this.cachedLines !== undefined && this.cachedWidth === width && this.cachedHeight === height)\n\t\t\treturn this.cachedLines;\n\t\tthis.cachedLines = compute(width, height);\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedHeight = height;\n\t\treturn this.cachedLines;\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"file":"render-cache.js","sourceRoot":"","sources":["../../../src/extensions/question/render-cache.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,iBAAiB;IACrB,KAAK,GAAG,IAAI,GAAG,EAAiC,CAAC;IAEzD,GAAG,CAAC,WAAmB,EAAE,KAAa,EAAE,QAAgB,EAAE,OAAuB,EAAY;QAC5F,IAAI,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QAC/C,IAAI,CAAC,YAAY,EAAE,CAAC;YACnB,YAAY,GAAG,IAAI,GAAG,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,EAAE,YAAY,CAAC,CAAC;QAC3C,CAAC;QACD,MAAM,GAAG,GAAG,GAAG,KAAK,IAAI,QAAQ,EAAE,CAAC;QACnC,IAAI,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClC,IAAI,CAAC,KAAK,EAAE,CAAC;YACZ,KAAK,GAAG,OAAO,EAAE,CAAC;YAClB,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,KAAK,CAAC;IAAA,CACb;CACD;AAED,yDAAyD;AACzD,MAAM,OAAO,iBAAiB;IACrB,WAAW,CAAuB;IAClC,WAAW,CAAqB;IAChC,YAAY,CAAqB;IAEzC,UAAU,GAAS;QAClB,IAAI,CAAC,WAAW,GAAG,SAAS,CAAC;IAAA,CAC7B;IAED,GAAG,CAAC,KAAa,EAAE,MAAc,EAAE,OAAoD,EAAY;QAClG,IAAI,IAAI,CAAC,WAAW,KAAK,SAAS,IAAI,IAAI,CAAC,WAAW,KAAK,KAAK,IAAI,IAAI,CAAC,YAAY,KAAK,MAAM;YAC/F,OAAO,IAAI,CAAC,WAAW,CAAC;QACzB,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC1C,IAAI,CAAC,WAAW,GAAG,KAAK,CAAC;QACzB,IAAI,CAAC,YAAY,GAAG,MAAM,CAAC;QAC3B,OAAO,IAAI,CAAC,WAAW,CAAC;IAAA,CACxB;CACD","sourcesContent":["/**\n * Memoize rendered preview lines by (previewText, width, maxLines) so editor\n * keystrokes don't re-parse the preview markdown on every frame. Questions are\n * immutable for a dialog's lifetime and carry few previews, so no eviction.\n */\nexport class PreviewLinesCache {\n\tprivate cache = new Map<string, Map<string, string[]>>();\n\n\tget(previewText: string, width: number, maxLines: number, compute: () => string[]): string[] {\n\t\tlet byDimensions = this.cache.get(previewText);\n\t\tif (!byDimensions) {\n\t\t\tbyDimensions = new Map();\n\t\t\tthis.cache.set(previewText, byDimensions);\n\t\t}\n\t\tconst key = `${width}x${maxLines}`;\n\t\tlet lines = byDimensions.get(key);\n\t\tif (!lines) {\n\t\t\tlines = compute();\n\t\t\tbyDimensions.set(key, lines);\n\t\t}\n\t\treturn lines;\n\t}\n}\n\n/** Cache custom dialog output by terminal dimensions. */\nexport class WidthCachedRender {\n\tprivate cachedLines: string[] | undefined;\n\tprivate cachedWidth: number | undefined;\n\tprivate cachedHeight: number | undefined;\n\n\tinvalidate(): void {\n\t\tthis.cachedLines = undefined;\n\t}\n\n\tget(width: number, height: number, compute: (width: number, height: number) => string[]): string[] {\n\t\tif (this.cachedLines !== undefined && this.cachedWidth === width && this.cachedHeight === height)\n\t\t\treturn this.cachedLines;\n\t\tthis.cachedLines = compute(width, height);\n\t\tthis.cachedWidth = width;\n\t\tthis.cachedHeight = height;\n\t\treturn this.cachedLines;\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAoBzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAO3G;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAG3D;AAiBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAS7F;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAc,EAAO,GAAG,eAAe,CAAC,mBAAmB,CAAC,
|
|
1
|
+
{"version":3,"file":"results.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAoBzF,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAO3G;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAG3D;AAiBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAS7F;AAED,wBAAgB,YAAY,CAAC,OAAO,GAAE,cAAc,EAAO,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAOjG;AAED,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,cAAc,EAAO,GAAG,eAAe,CAAC,mBAAmB,CAAC,CAYxG","sourcesContent":["import type { AgentToolResult } from \"../../core/extensions/types.ts\";\nimport { QUESTION_LIMITS, TRUNCATION_FOLLOW_UP } from \"./limits.ts\";\nimport type { QuestionAnswer, QuestionToolDetails, QuestionToolError } from \"./types.ts\";\n\nconst DECLINE_MESSAGE = \"User declined to answer the questions.\";\nconst CLARIFICATION_MESSAGE = \"The user wants to discuss these questions before choosing an answer.\";\nconst ENVELOPE_PREFIX = \"User decisions:\";\nconst ENVELOPE_SUFFIX = \"Continue with these decisions in mind.\";\n\nfunction buildToolResult(text: string, details: QuestionToolDetails): AgentToolResult<QuestionToolDetails> {\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tdetails,\n\t};\n}\n\nfunction boundedText(text: string): string {\n\tif (text.length <= QUESTION_LIMITS.modelResultChars) return text;\n\tconst suffix = `\\n\\n[Question result truncated. ${TRUNCATION_FOLLOW_UP}]`;\n\treturn `${text.slice(0, Math.max(0, QUESTION_LIMITS.modelResultChars - suffix.length))}${suffix}`;\n}\n\nexport function errorResult(error: QuestionToolError, message: string): AgentToolResult<QuestionToolDetails> {\n\treturn buildToolResult(`Question tool error (${error}): ${message}`, {\n\t\tanswers: [],\n\t\toutcome: \"error\",\n\t\tcancelled: false,\n\t\terror,\n\t});\n}\n\nexport function answerScalar(answer: QuestionAnswer): string {\n\tif (answer.kind === \"multi\") return answer.selected?.length ? answer.selected.join(\", \") : \"(no input)\";\n\treturn answer.answer && answer.answer.length > 0 ? answer.answer : \"(no input)\";\n}\n\nfunction answerKindLabel(answer: QuestionAnswer): string {\n\tif (answer.kind === \"multi\") return \"Selections\";\n\treturn answer.kind === \"custom\" ? \"Custom answer\" : \"Selected option\";\n}\n\nfunction answerSegment(answer: QuestionAnswer): string {\n\tconst lines = [\n\t\t`${answer.questionIndex + 1}. [${answer.header}] ${answer.question}`,\n\t\t` ${answerKindLabel(answer)}: ${answerScalar(answer)}`,\n\t];\n\tif (answer.preview) lines.push(\" Preview: selected (kept in tool details)\");\n\tfor (const note of answer.notes ?? []) lines.push(` Note for ${note.option}: ${note.text}`);\n\treturn lines.join(\"\\n\");\n}\n\nexport function successResult(answers: QuestionAnswer[]): AgentToolResult<QuestionToolDetails> {\n\tconst text = answers.length\n\t\t? boundedText(`${ENVELOPE_PREFIX}\\n${answers.map(answerSegment).join(\"\\n\\n\")}\\n\\n${ENVELOPE_SUFFIX}`)\n\t\t: DECLINE_MESSAGE;\n\treturn buildToolResult(text, {\n\t\tanswers,\n\t\toutcome: answers.length ? \"answered\" : \"cancelled\",\n\t\tcancelled: answers.length === 0,\n\t});\n}\n\nexport function cancelResult(answers: QuestionAnswer[] = []): AgentToolResult<QuestionToolDetails> {\n\tconst answered = answers.length ? `\\n\\nPartial answers so far:\\n${answers.map(answerSegment).join(\"\\n\\n\")}` : \"\";\n\treturn buildToolResult(boundedText(`${DECLINE_MESSAGE}${answered}`), {\n\t\tanswers,\n\t\toutcome: \"cancelled\",\n\t\tcancelled: true,\n\t});\n}\n\nexport function clarificationResult(answers: QuestionAnswer[] = []): AgentToolResult<QuestionToolDetails> {\n\tconst answered = answers.length ? ` Partial answers so far:\\n${answers.map(answerSegment).join(\"\\n\\n\")}` : \"\";\n\treturn buildToolResult(\n\t\tboundedText(\n\t\t\t`${CLARIFICATION_MESSAGE}${answered}\\n\\nExplain the trade-offs or ask what the user would like clarified.`,\n\t\t),\n\t\t{\n\t\t\tanswers,\n\t\t\toutcome: \"needs_clarification\",\n\t\t\tcancelled: false,\n\t\t},\n\t);\n}\n"]}
|
|
@@ -55,7 +55,12 @@ export function successResult(answers) {
|
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
export function cancelResult(answers = []) {
|
|
58
|
-
|
|
58
|
+
const answered = answers.length ? `\n\nPartial answers so far:\n${answers.map(answerSegment).join("\n\n")}` : "";
|
|
59
|
+
return buildToolResult(boundedText(`${DECLINE_MESSAGE}${answered}`), {
|
|
60
|
+
answers,
|
|
61
|
+
outcome: "cancelled",
|
|
62
|
+
cancelled: true,
|
|
63
|
+
});
|
|
59
64
|
}
|
|
60
65
|
export function clarificationResult(answers = []) {
|
|
61
66
|
const answered = answers.length ? ` Partial answers so far:\n${answers.map(answerSegment).join("\n\n")}` : "";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/extensions/question/results.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"results.js","sourceRoot":"","sources":["../../../src/extensions/question/results.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentToolResult } from \"../../core/extensions/types.ts\";\nimport { QUESTION_LIMITS, TRUNCATION_FOLLOW_UP } from \"./limits.ts\";\nimport type { QuestionAnswer, QuestionToolDetails, QuestionToolError } from \"./types.ts\";\n\nconst DECLINE_MESSAGE = \"User declined to answer the questions.\";\nconst CLARIFICATION_MESSAGE = \"The user wants to discuss these questions before choosing an answer.\";\nconst ENVELOPE_PREFIX = \"User decisions:\";\nconst ENVELOPE_SUFFIX = \"Continue with these decisions in mind.\";\n\nfunction buildToolResult(text: string, details: QuestionToolDetails): AgentToolResult<QuestionToolDetails> {\n\treturn {\n\t\tcontent: [{ type: \"text\", text }],\n\t\tdetails,\n\t};\n}\n\nfunction boundedText(text: string): string {\n\tif (text.length <= QUESTION_LIMITS.modelResultChars) return text;\n\tconst suffix = `\\n\\n[Question result truncated. ${TRUNCATION_FOLLOW_UP}]`;\n\treturn `${text.slice(0, Math.max(0, QUESTION_LIMITS.modelResultChars - suffix.length))}${suffix}`;\n}\n\nexport function errorResult(error: QuestionToolError, message: string): AgentToolResult<QuestionToolDetails> {\n\treturn buildToolResult(`Question tool error (${error}): ${message}`, {\n\t\tanswers: [],\n\t\toutcome: \"error\",\n\t\tcancelled: false,\n\t\terror,\n\t});\n}\n\nexport function answerScalar(answer: QuestionAnswer): string {\n\tif (answer.kind === \"multi\") return answer.selected?.length ? answer.selected.join(\", \") : \"(no input)\";\n\treturn answer.answer && answer.answer.length > 0 ? answer.answer : \"(no input)\";\n}\n\nfunction answerKindLabel(answer: QuestionAnswer): string {\n\tif (answer.kind === \"multi\") return \"Selections\";\n\treturn answer.kind === \"custom\" ? \"Custom answer\" : \"Selected option\";\n}\n\nfunction answerSegment(answer: QuestionAnswer): string {\n\tconst lines = [\n\t\t`${answer.questionIndex + 1}. [${answer.header}] ${answer.question}`,\n\t\t` ${answerKindLabel(answer)}: ${answerScalar(answer)}`,\n\t];\n\tif (answer.preview) lines.push(\" Preview: selected (kept in tool details)\");\n\tfor (const note of answer.notes ?? []) lines.push(` Note for ${note.option}: ${note.text}`);\n\treturn lines.join(\"\\n\");\n}\n\nexport function successResult(answers: QuestionAnswer[]): AgentToolResult<QuestionToolDetails> {\n\tconst text = answers.length\n\t\t? boundedText(`${ENVELOPE_PREFIX}\\n${answers.map(answerSegment).join(\"\\n\\n\")}\\n\\n${ENVELOPE_SUFFIX}`)\n\t\t: DECLINE_MESSAGE;\n\treturn buildToolResult(text, {\n\t\tanswers,\n\t\toutcome: answers.length ? \"answered\" : \"cancelled\",\n\t\tcancelled: answers.length === 0,\n\t});\n}\n\nexport function cancelResult(answers: QuestionAnswer[] = []): AgentToolResult<QuestionToolDetails> {\n\tconst answered = answers.length ? `\\n\\nPartial answers so far:\\n${answers.map(answerSegment).join(\"\\n\\n\")}` : \"\";\n\treturn buildToolResult(boundedText(`${DECLINE_MESSAGE}${answered}`), {\n\t\tanswers,\n\t\toutcome: \"cancelled\",\n\t\tcancelled: true,\n\t});\n}\n\nexport function clarificationResult(answers: QuestionAnswer[] = []): AgentToolResult<QuestionToolDetails> {\n\tconst answered = answers.length ? ` Partial answers so far:\\n${answers.map(answerSegment).join(\"\\n\\n\")}` : \"\";\n\treturn buildToolResult(\n\t\tboundedText(\n\t\t\t`${CLARIFICATION_MESSAGE}${answered}\\n\\nExplain the trade-offs or ask what the user would like clarified.`,\n\t\t),\n\t\t{\n\t\t\tanswers,\n\t\t\toutcome: \"needs_clarification\",\n\t\t\tcancelled: false,\n\t\t},\n\t);\n}\n"]}
|
|
@@ -12,6 +12,10 @@ export declare const QuestionParams: Type.TObject<{
|
|
|
12
12
|
multiSelect: Type.TOptional<Type.TBoolean>;
|
|
13
13
|
}>>;
|
|
14
14
|
}>;
|
|
15
|
+
/**
|
|
16
|
+
* Checks the schema cannot express. Length and count limits are omitted:
|
|
17
|
+
* the agent core validates params against `QuestionParams` before execute runs.
|
|
18
|
+
*/
|
|
15
19
|
export declare function validateQuestions(questions: Question[]): {
|
|
16
20
|
ok: true;
|
|
17
21
|
} | {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,KAAK,EAAE,QAAQ,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAoD9E,eAAO,MAAM,cAAc;;;;;;;;;;;EAMzB,CAAC;AAEH;;;GAGG;AACH,wBAAgB,iBAAiB,CAChC,SAAS,EAAE,QAAQ,EAAE,GACnB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,iBAAiB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAwCzE","sourcesContent":["import { Type } from \"typebox\";\nimport { QUESTION_LIMITS } from \"./limits.ts\";\nimport type { Question, QuestionOption, QuestionToolError } from \"./types.ts\";\n\nconst MIN_OPTIONS = 2;\nconst MAX_OPTIONS = 4;\nconst MAX_QUESTIONS = 4;\nconst RESERVED_LABELS = [\"Other\", \"Type something.\", \"Chat about this\"] as const;\n\nconst normalizeLabel = (text: string) => text.trim().toLowerCase();\nconst RESERVED_NORMALIZED = new Set(RESERVED_LABELS.map(normalizeLabel));\n\nconst OptionSchema = Type.Object({\n\tlabel: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.optionLabelChars,\n\t\tdescription:\n\t\t\t\"Short user-facing option label (1-5 words), distinct within the question. Reserved labels ('Other', 'Type something.', 'Chat about this') are rejected — the UI adds the custom-answer path itself.\",\n\t}),\n\tdescription: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.optionDescriptionChars,\n\t\tdescription: \"One concise sentence explaining the option's meaning, consequence, or tradeoff.\",\n\t}),\n\tpreview: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: QUESTION_LIMITS.previewChars,\n\t\t\tdescription:\n\t\t\t\t\"Optional markdown preview shown only for focused single-select options; use for concrete snippets, layouts, copy, or config comparisons.\",\n\t\t}),\n\t),\n});\n\nconst QuestionSchema = Type.Object({\n\tquestion: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.questionChars,\n\t\tdescription:\n\t\t\t\"One clear, specific decision or preference question ending in a question mark. Ask only what is needed to proceed.\",\n\t}),\n\theader: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.headerChars,\n\t\tdescription: \"Very short decision label shown as a chip; aim for ~12 chars, max 32. E.g. 'Auth method'.\",\n\t}),\n\toptions: Type.Array(OptionSchema, {\n\t\tminItems: MIN_OPTIONS,\n\t\tmaxItems: MAX_OPTIONS,\n\t\tdescription: \"Mutually distinct options for this decision; do not include reserved custom-answer labels.\",\n\t}),\n\tmultiSelect: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Allow selecting multiple options only when choices can be combined. Defaults to false for mutually exclusive decisions.\",\n\t\t}),\n\t),\n});\n\nexport const QuestionParams = Type.Object({\n\tquestions: Type.Array(QuestionSchema, {\n\t\tminItems: 1,\n\t\tmaxItems: MAX_QUESTIONS,\n\t\tdescription: \"Related decisions to ask now (1-4); ask only what is needed to unblock progress.\",\n\t}),\n});\n\n/**\n * Checks the schema cannot express. Length and count limits are omitted:\n * the agent core validates params against `QuestionParams` before execute runs.\n */\nexport function validateQuestions(\n\tquestions: Question[],\n): { ok: true } | { ok: false; error: QuestionToolError; message: string } {\n\tconst seenQuestions = new Set<string>();\n\tfor (const q of questions) {\n\t\tconst questionKey = normalizeLabel(q.question);\n\t\tif (seenQuestions.has(questionKey)) {\n\t\t\treturn { ok: false, error: \"duplicate_question\", message: \"Question text must be unique\" };\n\t\t}\n\t\tseenQuestions.add(questionKey);\n\n\t\tif (q.multiSelect && q.options.some((option) => option.preview)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: \"preview_multiselect\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"Option previews are not supported on multiSelect questions; drop the previews or make the question single-select\",\n\t\t\t};\n\t\t}\n\n\t\tconst seenLabels = new Set<string>();\n\t\tfor (const option of q.options as QuestionOption[]) {\n\t\t\tconst labelKey = normalizeLabel(option.label);\n\t\t\tif (RESERVED_NORMALIZED.has(labelKey)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: \"reserved_label\",\n\t\t\t\t\tmessage: `Option label is reserved (${RESERVED_LABELS.join(\", \")})`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (seenLabels.has(labelKey)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: \"duplicate_option_label\",\n\t\t\t\t\tmessage: \"Option labels must be unique within a question\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tseenLabels.add(labelKey);\n\t\t}\n\t}\n\n\treturn { ok: true };\n}\n"]}
|
|
@@ -3,11 +3,13 @@ import { QUESTION_LIMITS } from "./limits.js";
|
|
|
3
3
|
const MIN_OPTIONS = 2;
|
|
4
4
|
const MAX_OPTIONS = 4;
|
|
5
5
|
const MAX_QUESTIONS = 4;
|
|
6
|
-
const RESERVED_LABELS = ["Other", "Type something.", "Chat about this"
|
|
6
|
+
const RESERVED_LABELS = ["Other", "Type something.", "Chat about this"];
|
|
7
|
+
const normalizeLabel = (text) => text.trim().toLowerCase();
|
|
8
|
+
const RESERVED_NORMALIZED = new Set(RESERVED_LABELS.map(normalizeLabel));
|
|
7
9
|
const OptionSchema = Type.Object({
|
|
8
10
|
label: Type.String({
|
|
9
11
|
maxLength: QUESTION_LIMITS.optionLabelChars,
|
|
10
|
-
description: "Short user-facing option label (1-5 words), distinct within the question. Reserved labels ('Other', 'Type something.', 'Chat about this'
|
|
12
|
+
description: "Short user-facing option label (1-5 words), distinct within the question. Reserved labels ('Other', 'Type something.', 'Chat about this') are rejected — the UI adds the custom-answer path itself.",
|
|
11
13
|
}),
|
|
12
14
|
description: Type.String({
|
|
13
15
|
maxLength: QUESTION_LIMITS.optionDescriptionChars,
|
|
@@ -25,7 +27,7 @@ const QuestionSchema = Type.Object({
|
|
|
25
27
|
}),
|
|
26
28
|
header: Type.String({
|
|
27
29
|
maxLength: QUESTION_LIMITS.headerChars,
|
|
28
|
-
description: "Very short decision label shown as a chip
|
|
30
|
+
description: "Very short decision label shown as a chip; aim for ~12 chars, max 32. E.g. 'Auth method'.",
|
|
29
31
|
}),
|
|
30
32
|
options: Type.Array(OptionSchema, {
|
|
31
33
|
minItems: MIN_OPTIONS,
|
|
@@ -43,54 +45,43 @@ export const QuestionParams = Type.Object({
|
|
|
43
45
|
description: "Related decisions to ask now (1-4); ask only what is needed to unblock progress.",
|
|
44
46
|
}),
|
|
45
47
|
});
|
|
48
|
+
/**
|
|
49
|
+
* Checks the schema cannot express. Length and count limits are omitted:
|
|
50
|
+
* the agent core validates params against `QuestionParams` before execute runs.
|
|
51
|
+
*/
|
|
46
52
|
export function validateQuestions(questions) {
|
|
47
|
-
if (questions.length === 0)
|
|
48
|
-
return { ok: false, error: "no_questions", message: "At least one question is required" };
|
|
49
|
-
if (questions.length > MAX_QUESTIONS) {
|
|
50
|
-
return { ok: false, error: "too_many_questions", message: `At most ${MAX_QUESTIONS} questions are allowed` };
|
|
51
|
-
}
|
|
52
53
|
const seenQuestions = new Set();
|
|
53
54
|
for (const q of questions) {
|
|
54
|
-
|
|
55
|
+
const questionKey = normalizeLabel(q.question);
|
|
56
|
+
if (seenQuestions.has(questionKey)) {
|
|
55
57
|
return { ok: false, error: "duplicate_question", message: "Question text must be unique" };
|
|
56
58
|
}
|
|
57
|
-
seenQuestions.add(
|
|
58
|
-
if (q.
|
|
59
|
-
return {
|
|
60
|
-
ok: false,
|
|
61
|
-
error: "invalid_text_length",
|
|
62
|
-
message: "Question text or header exceeds its length limit",
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
if (q.options.length < MIN_OPTIONS || q.options.length > MAX_OPTIONS) {
|
|
59
|
+
seenQuestions.add(questionKey);
|
|
60
|
+
if (q.multiSelect && q.options.some((option) => option.preview)) {
|
|
66
61
|
return {
|
|
67
62
|
ok: false,
|
|
68
|
-
error: "
|
|
69
|
-
message:
|
|
63
|
+
error: "preview_multiselect",
|
|
64
|
+
message: "Option previews are not supported on multiSelect questions; drop the previews or make the question single-select",
|
|
70
65
|
};
|
|
71
66
|
}
|
|
72
67
|
const seenLabels = new Set();
|
|
73
68
|
for (const option of q.options) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
(option.preview?.length ?? 0) > QUESTION_LIMITS.previewChars) {
|
|
77
|
-
return { ok: false, error: "invalid_text_length", message: "Option text exceeds its length limit" };
|
|
78
|
-
}
|
|
79
|
-
if (RESERVED_LABELS.includes(option.label)) {
|
|
69
|
+
const labelKey = normalizeLabel(option.label);
|
|
70
|
+
if (RESERVED_NORMALIZED.has(labelKey)) {
|
|
80
71
|
return {
|
|
81
72
|
ok: false,
|
|
82
73
|
error: "reserved_label",
|
|
83
74
|
message: `Option label is reserved (${RESERVED_LABELS.join(", ")})`,
|
|
84
75
|
};
|
|
85
76
|
}
|
|
86
|
-
if (seenLabels.has(
|
|
77
|
+
if (seenLabels.has(labelKey)) {
|
|
87
78
|
return {
|
|
88
79
|
ok: false,
|
|
89
80
|
error: "duplicate_option_label",
|
|
90
81
|
message: "Option labels must be unique within a question",
|
|
91
82
|
};
|
|
92
83
|
}
|
|
93
|
-
seenLabels.add(
|
|
84
|
+
seenLabels.add(labelKey);
|
|
94
85
|
}
|
|
95
86
|
}
|
|
96
87
|
return { ok: true };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/extensions/question/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAG9C,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,WAAW,GAAG,CAAC,CAAC;AACtB,MAAM,aAAa,GAAG,CAAC,CAAC;AACxB,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../src/extensions/question/schema.ts"],"names":[],"mappings":"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","sourcesContent":["import { Type } from \"typebox\";\nimport { QUESTION_LIMITS } from \"./limits.ts\";\nimport type { Question, QuestionOption, QuestionToolError } from \"./types.ts\";\n\nconst MIN_OPTIONS = 2;\nconst MAX_OPTIONS = 4;\nconst MAX_QUESTIONS = 4;\nconst RESERVED_LABELS = [\"Other\", \"Type something.\", \"Chat about this\"] as const;\n\nconst normalizeLabel = (text: string) => text.trim().toLowerCase();\nconst RESERVED_NORMALIZED = new Set(RESERVED_LABELS.map(normalizeLabel));\n\nconst OptionSchema = Type.Object({\n\tlabel: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.optionLabelChars,\n\t\tdescription:\n\t\t\t\"Short user-facing option label (1-5 words), distinct within the question. Reserved labels ('Other', 'Type something.', 'Chat about this') are rejected — the UI adds the custom-answer path itself.\",\n\t}),\n\tdescription: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.optionDescriptionChars,\n\t\tdescription: \"One concise sentence explaining the option's meaning, consequence, or tradeoff.\",\n\t}),\n\tpreview: Type.Optional(\n\t\tType.String({\n\t\t\tmaxLength: QUESTION_LIMITS.previewChars,\n\t\t\tdescription:\n\t\t\t\t\"Optional markdown preview shown only for focused single-select options; use for concrete snippets, layouts, copy, or config comparisons.\",\n\t\t}),\n\t),\n});\n\nconst QuestionSchema = Type.Object({\n\tquestion: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.questionChars,\n\t\tdescription:\n\t\t\t\"One clear, specific decision or preference question ending in a question mark. Ask only what is needed to proceed.\",\n\t}),\n\theader: Type.String({\n\t\tmaxLength: QUESTION_LIMITS.headerChars,\n\t\tdescription: \"Very short decision label shown as a chip; aim for ~12 chars, max 32. E.g. 'Auth method'.\",\n\t}),\n\toptions: Type.Array(OptionSchema, {\n\t\tminItems: MIN_OPTIONS,\n\t\tmaxItems: MAX_OPTIONS,\n\t\tdescription: \"Mutually distinct options for this decision; do not include reserved custom-answer labels.\",\n\t}),\n\tmultiSelect: Type.Optional(\n\t\tType.Boolean({\n\t\t\tdescription:\n\t\t\t\t\"Allow selecting multiple options only when choices can be combined. Defaults to false for mutually exclusive decisions.\",\n\t\t}),\n\t),\n});\n\nexport const QuestionParams = Type.Object({\n\tquestions: Type.Array(QuestionSchema, {\n\t\tminItems: 1,\n\t\tmaxItems: MAX_QUESTIONS,\n\t\tdescription: \"Related decisions to ask now (1-4); ask only what is needed to unblock progress.\",\n\t}),\n});\n\n/**\n * Checks the schema cannot express. Length and count limits are omitted:\n * the agent core validates params against `QuestionParams` before execute runs.\n */\nexport function validateQuestions(\n\tquestions: Question[],\n): { ok: true } | { ok: false; error: QuestionToolError; message: string } {\n\tconst seenQuestions = new Set<string>();\n\tfor (const q of questions) {\n\t\tconst questionKey = normalizeLabel(q.question);\n\t\tif (seenQuestions.has(questionKey)) {\n\t\t\treturn { ok: false, error: \"duplicate_question\", message: \"Question text must be unique\" };\n\t\t}\n\t\tseenQuestions.add(questionKey);\n\n\t\tif (q.multiSelect && q.options.some((option) => option.preview)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\terror: \"preview_multiselect\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"Option previews are not supported on multiSelect questions; drop the previews or make the question single-select\",\n\t\t\t};\n\t\t}\n\n\t\tconst seenLabels = new Set<string>();\n\t\tfor (const option of q.options as QuestionOption[]) {\n\t\t\tconst labelKey = normalizeLabel(option.label);\n\t\t\tif (RESERVED_NORMALIZED.has(labelKey)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: \"reserved_label\",\n\t\t\t\t\tmessage: `Option label is reserved (${RESERVED_LABELS.join(\", \")})`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (seenLabels.has(labelKey)) {\n\t\t\t\treturn {\n\t\t\t\t\tok: false,\n\t\t\t\t\terror: \"duplicate_option_label\",\n\t\t\t\t\tmessage: \"Option labels must be unique within a question\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tseenLabels.add(labelKey);\n\t\t}\n\t}\n\n\treturn { ok: true };\n}\n"]}
|
|
@@ -10,7 +10,7 @@ export interface Question {
|
|
|
10
10
|
multiSelect?: boolean;
|
|
11
11
|
}
|
|
12
12
|
export type InputMode = "custom" | "notes" | undefined;
|
|
13
|
-
export type QuestionToolError = "no_ui" | "
|
|
13
|
+
export type QuestionToolError = "no_ui" | "duplicate_question" | "duplicate_option_label" | "reserved_label" | "preview_multiselect";
|
|
14
14
|
export interface AnswerNote {
|
|
15
15
|
option: string;
|
|
16
16
|
text: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAC1B,OAAO,GACP,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extensions/question/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,WAAW,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAEvD,MAAM,MAAM,iBAAiB,GAC1B,OAAO,GACP,oBAAoB,GACpB,wBAAwB,GACxB,gBAAgB,GAChB,qBAAqB,CAAC;AAEzB,MAAM,WAAW,UAAU;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,cAAc;IAC9B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,OAAO,CAAC;IACpC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,UAAU,GAAG,WAAW,GAAG,qBAAqB,GAAG,OAAO,CAAC;AAEzF,MAAM,WAAW,mBAAmB;IACnC,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,eAAe,CAAC;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,CAAC,EAAE,iBAAiB,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,aAAa;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B,aAAa,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC5B,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,OAAO,EAAE,eAAe,CAAC;CACzB;AAED,MAAM,MAAM,aAAa,GACtB,CAAC,cAAc,GAAG;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,GAC1D;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AAEnD,eAAO,MAAM,YAAY,EAAE,aAA0E,CAAC","sourcesContent":["export interface QuestionOption {\n\tlabel: string;\n\tdescription: string;\n\tpreview?: string;\n}\n\nexport interface Question {\n\tquestion: string;\n\theader: string;\n\toptions: QuestionOption[];\n\tmultiSelect?: boolean;\n}\n\nexport type InputMode = \"custom\" | \"notes\" | undefined;\n\nexport type QuestionToolError =\n\t| \"no_ui\"\n\t| \"duplicate_question\"\n\t| \"duplicate_option_label\"\n\t| \"reserved_label\"\n\t| \"preview_multiselect\";\n\nexport interface AnswerNote {\n\toption: string;\n\ttext: string;\n}\n\nexport interface QuestionAnswer {\n\tquestionIndex: number;\n\tquestion: string;\n\theader: string;\n\tkind: \"option\" | \"custom\" | \"multi\";\n\tanswer: string | null;\n\tselected?: string[];\n\tnotes?: AnswerNote[];\n\tpreview?: string;\n}\n\nexport type QuestionOutcome = \"answered\" | \"cancelled\" | \"needs_clarification\" | \"error\";\n\nexport interface QuestionToolDetails {\n\tanswers: QuestionAnswer[];\n\toutcome: QuestionOutcome;\n\tcancelled: boolean;\n\terror?: QuestionToolError;\n}\n\nexport interface CustomAnswer {\n\ttext: string;\n\tselected: boolean;\n}\n\nexport interface QuestionState {\n\toptionIndex: number;\n\tsingleAnswer?: QuestionAnswer;\n\tmultiSelected: Set<number>;\n\tcustomAnswer?: CustomAnswer;\n\tnotesByOption: Map<string, string>;\n\twarning?: string;\n}\n\nexport interface DialogResult {\n\tanswers: QuestionAnswer[];\n\toutcome: QuestionOutcome;\n}\n\nexport type DisplayOption =\n\t| (QuestionOption & { kind: \"option\"; optionIndex: number })\n\t| { kind: \"other\"; label: string; isOther: true };\n\nexport const OTHER_OPTION: DisplayOption = { kind: \"other\", label: \"Type something.\", isOther: true };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extensions/question/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extensions/question/types.ts"],"names":[],"mappings":"AAsEA,MAAM,CAAC,MAAM,YAAY,GAAkB,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC","sourcesContent":["export interface QuestionOption {\n\tlabel: string;\n\tdescription: string;\n\tpreview?: string;\n}\n\nexport interface Question {\n\tquestion: string;\n\theader: string;\n\toptions: QuestionOption[];\n\tmultiSelect?: boolean;\n}\n\nexport type InputMode = \"custom\" | \"notes\" | undefined;\n\nexport type QuestionToolError =\n\t| \"no_ui\"\n\t| \"duplicate_question\"\n\t| \"duplicate_option_label\"\n\t| \"reserved_label\"\n\t| \"preview_multiselect\";\n\nexport interface AnswerNote {\n\toption: string;\n\ttext: string;\n}\n\nexport interface QuestionAnswer {\n\tquestionIndex: number;\n\tquestion: string;\n\theader: string;\n\tkind: \"option\" | \"custom\" | \"multi\";\n\tanswer: string | null;\n\tselected?: string[];\n\tnotes?: AnswerNote[];\n\tpreview?: string;\n}\n\nexport type QuestionOutcome = \"answered\" | \"cancelled\" | \"needs_clarification\" | \"error\";\n\nexport interface QuestionToolDetails {\n\tanswers: QuestionAnswer[];\n\toutcome: QuestionOutcome;\n\tcancelled: boolean;\n\terror?: QuestionToolError;\n}\n\nexport interface CustomAnswer {\n\ttext: string;\n\tselected: boolean;\n}\n\nexport interface QuestionState {\n\toptionIndex: number;\n\tsingleAnswer?: QuestionAnswer;\n\tmultiSelected: Set<number>;\n\tcustomAnswer?: CustomAnswer;\n\tnotesByOption: Map<string, string>;\n\twarning?: string;\n}\n\nexport interface DialogResult {\n\tanswers: QuestionAnswer[];\n\toutcome: QuestionOutcome;\n}\n\nexport type DisplayOption =\n\t| (QuestionOption & { kind: \"option\"; optionIndex: number })\n\t| { kind: \"other\"; label: string; isOther: true };\n\nexport const OTHER_OPTION: DisplayOption = { kind: \"other\", label: \"Type something.\", isOther: true };\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/agents.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAoC,oBAAoB,EAAe,MAAM,YAAY,CAAC;AAwItG,wBAAgB,cAAc,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,oBAAoB,CAiBtB;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,oBAAoB,GAAG,MAAM,CAkD/E","sourcesContent":["import { type Dirent, existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../config.ts\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport { utf8Prefix } from \"./activity.ts\";\nimport { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS } from \"./constants.ts\";\nimport type { AgentDefinition, AgentDiagnostic, AgentDiscoveryResult, AgentSource } from \"./types.ts\";\n\nconst AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/u;\nconst BUILTIN_TOOL_SET = new Set<string>(BUILTIN_TOOL_NAMES);\nconst TOOL_DESCRIPTION_AGENT_LIST_LIMIT = 8_000;\nconst TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT = 480;\n\nconst BUILTIN_AGENTS: AgentDefinition[] = [\n\t{\n\t\tname: \"general\",\n\t\tdescription: \"General-purpose implementation agent with coding tools\",\n\t\ttools: [...DEFAULT_AGENT_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"Work independently on the delegated task from start to finish.\",\n\t\t\t\"Inspect relevant repository instructions before changing files.\",\n\t\t\t\"Prefer editing existing files; never create documentation files unless the task explicitly asks for them.\",\n\t\t\t\"Keep changes focused, run appropriate verification, and report exact paths, checks, blockers, and remaining risks.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:general>\",\n\t\tbackend: \"sdk\",\n\t},\n\t{\n\t\tname: \"explorer\",\n\t\tdescription:\n\t\t\t'Fast read-only agent for finding files, searching code, and answering codebase questions. State thoroughness in the prompt: \"quick\" for a targeted lookup, \"medium\" for checking likely related locations, or \"very thorough\" for exhaustive sweeps across locations and naming conventions',\n\t\ttools: [...EXPLORER_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"You are a fast read-only exploration agent; return findings as quickly as possible.\",\n\t\t\t\"Explore the delegated question without modifying files.\",\n\t\t\t\"Use read and search tools to gather exact evidence, batching independent searches and reads instead of running them one at a time.\",\n\t\t\t\"Match the depth the caller requested: quick targets the direct question, medium checks likely related locations, and very thorough sweeps multiple locations and naming conventions.\",\n\t\t\t\"Return concise findings with precise paths, symbols, relationships, and unresolved uncertainties.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:explorer>\",\n\t\tbackend: \"sdk\",\n\t},\n];\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction findNearestProjectAgentsDir(cwd: string): string | undefined {\n\tlet current = cwd;\n\twhile (true) {\n\t\tconst candidate = join(current, CONFIG_DIR_NAME, \"agents\");\n\t\tif (isDirectory(candidate)) return candidate;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\nfunction parseTools(raw: string | undefined, filePath: string): string[] {\n\tif (!raw?.trim()) return [...DEFAULT_AGENT_TOOLS];\n\tconst tools = [\n\t\t...new Set(\n\t\t\traw\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((tool) => tool.trim())\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n\tconst unsupported = tools.filter((tool) => !BUILTIN_TOOL_SET.has(tool));\n\tif (unsupported.length > 0) {\n\t\tthrow new Error(`Unsupported tool(s) ${unsupported.join(\", \")} in ${filePath}.`);\n\t}\n\treturn tools;\n}\n\n// Frontmatter model/thinking keys are intentionally ignored: agent files\n// travel across machines (project repos), so a pinned model rarely exists\n// in the reader's environment. Model and thinking come from /agents\n// overrides or default to the parent session.\nfunction parseAgentFile(filePath: string, source: Exclude<AgentSource, \"builtin\">): AgentDefinition {\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);\n\tconst name = frontmatter.name?.trim() ?? \"\";\n\tconst description = frontmatter.description?.trim() ?? \"\";\n\tif (!name) throw new Error(\"Missing required frontmatter field: name.\");\n\tif (!AGENT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(`Agent name \"${name}\" must use lowercase letters, digits, hyphens, or underscores.`);\n\t}\n\tif (!description) throw new Error(\"Missing required frontmatter field: description.\");\n\tif (!body.trim()) throw new Error(\"Agent prompt body must not be empty.\");\n\tconst backend = frontmatter.backend?.trim();\n\tif (backend && backend !== \"sdk\") throw new Error(`Backend \"${backend}\" is not implemented; use \"sdk\".`);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\ttools: parseTools(frontmatter.tools, filePath),\n\t\tsystemPrompt: body.trim(),\n\t\tsource,\n\t\tfilePath,\n\t\tbackend: \"sdk\",\n\t};\n}\n\nfunction loadAgentDirectory(\n\tdir: string,\n\tsource: Exclude<AgentSource, \"builtin\">,\n): { agents: AgentDefinition[]; diagnostics: AgentDiagnostic[] } {\n\tif (!existsSync(dir)) return { agents: [], diagnostics: [] };\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));\n\t} catch (error) {\n\t\treturn {\n\t\t\tagents: [],\n\t\t\tdiagnostics: [{ path: dir, source, message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\tconst agents: AgentDefinition[] = [];\n\tconst diagnostics: AgentDiagnostic[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.name.endsWith(\".md\") || (!entry.isFile() && !entry.isSymbolicLink())) continue;\n\t\tconst filePath = join(dir, entry.name);\n\t\ttry {\n\t\t\tagents.push(parseAgentFile(filePath, source));\n\t\t} catch (error) {\n\t\t\tdiagnostics.push({\n\t\t\t\tpath: filePath,\n\t\t\t\tsource,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t}\n\treturn { agents, diagnostics };\n}\n\nexport function discoverAgents(\n\tcwd: string,\n\toptions: { projectTrusted: boolean; agentDir?: string },\n): AgentDiscoveryResult {\n\tconst userDir = join(options.agentDir ?? getAgentDir(), \"agents\");\n\tconst projectAgentsDir = findNearestProjectAgentsDir(cwd);\n\tconst user = loadAgentDirectory(userDir, \"user\");\n\tconst project =\n\t\toptions.projectTrusted && projectAgentsDir\n\t\t\t? loadAgentDirectory(projectAgentsDir, \"project\")\n\t\t\t: { agents: [], diagnostics: [] };\n\tconst agents = new Map(BUILTIN_AGENTS.map((agent) => [agent.name, { ...agent, tools: [...agent.tools] }]));\n\tfor (const agent of user.agents) agents.set(agent.name, agent);\n\tfor (const agent of project.agents) agents.set(agent.name, agent);\n\treturn {\n\t\tagents: [...agents.values()],\n\t\tdiagnostics: [...user.diagnostics, ...project.diagnostics],\n\t\tprojectAgentsDir,\n\t\tprojectAgentsTrusted: options.projectTrusted,\n\t};\n}\n\nexport function subagentToolDescription(discovery: AgentDiscoveryResult): string {\n\tconst agentLines: string[] = [];\n\tlet agentListLength = 0;\n\tfor (const [index, agent] of discovery.agents.entries()) {\n\t\tconst normalizedDescription = agent.description.replace(/\\s+/gu, \" \").trim();\n\t\tconst description =\n\t\t\tBuffer.byteLength(normalizedDescription, \"utf8\") <= TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT\n\t\t\t\t? normalizedDescription\n\t\t\t\t: `${utf8Prefix(normalizedDescription, TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT - Buffer.byteLength(\"…\", \"utf8\"))}…`;\n\t\tconst defaultLabel = agent.name === \"general\" ? \" (default)\" : \"\";\n\t\tconst tools = agent.tools.length > 0 ? agent.tools.join(\", \") : \"none\";\n\t\tconst line = `- ${agent.name}${defaultLabel}: ${description} (Tools: ${tools})`;\n\t\tconst lineLength = Buffer.byteLength(line, \"utf8\") + 1;\n\t\tif (agentListLength + lineLength > TOOL_DESCRIPTION_AGENT_LIST_LIMIT) {\n\t\t\tlet omitted = discovery.agents.length - index;\n\t\t\tlet notice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\twhile (\n\t\t\t\tagentLines.length > 0 &&\n\t\t\t\tagentListLength + Buffer.byteLength(notice, \"utf8\") + 1 > TOOL_DESCRIPTION_AGENT_LIST_LIMIT\n\t\t\t) {\n\t\t\t\tconst removed = agentLines.pop();\n\t\t\t\tif (!removed) break;\n\t\t\t\tagentListLength -= Buffer.byteLength(removed, \"utf8\") + 1;\n\t\t\t\tomitted++;\n\t\t\t\tnotice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\t}\n\t\t\tagentLines.push(notice);\n\t\t\tbreak;\n\t\t}\n\t\tagentLines.push(line);\n\t\tagentListLength += lineLength;\n\t}\n\n\treturn [\n\t\t\"Delegate bounded work to isolated one-shot subagents. Choose exactly one mode: prompt for one task, or tasks for independent parallel work. For sequential work, call this tool again with the previous result folded into the next briefing.\",\n\t\t\"\",\n\t\t\"Available agent profiles:\",\n\t\t...agentLines,\n\t\t\"\",\n\t\t\"When not to delegate:\",\n\t\t\"- Read a known file directly with read, or search for a known symbol directly with grep.\",\n\t\t\"- Do not delegate a trivial task when the coordination overhead exceeds the work.\",\n\t\t\"\",\n\t\t\"Writing the briefing:\",\n\t\t\"- Brief the worker like a capable colleague entering the project now: include the objective, relevant context, exact paths or symbols already known, constraints, and expected output.\",\n\t\t\"- Never delegate understanding with vague instructions such as 'fix this based on your findings'; state what must be investigated or changed and whether the worker should research, implement, or review.\",\n\t\t\"- Ask for a concise report when only findings are needed. Workers cannot see the parent conversation or ask the end user questions.\",\n\t\t\"\",\n\t\t\"Subagent results are reports for you to interpret and relay. Surface the important findings, changes, verification, and unresolved risks to the user.\",\n\t].join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/agents.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAoC,oBAAoB,EAAe,MAAM,YAAY,CAAC;AA4ItG,wBAAgB,cAAc,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,EAAE;IAAE,cAAc,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,oBAAoB,CAiBtB;AAED,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,oBAAoB,GAAG,MAAM,CAqD/E","sourcesContent":["import { type Dirent, existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../config.ts\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport { utf8Prefix } from \"./activity.ts\";\nimport { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS, MAX_CONCURRENCY, MAX_TASKS } from \"./constants.ts\";\nimport type { AgentDefinition, AgentDiagnostic, AgentDiscoveryResult, AgentSource } from \"./types.ts\";\n\nconst AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/u;\nconst BUILTIN_TOOL_SET = new Set<string>(BUILTIN_TOOL_NAMES);\nconst TOOL_DESCRIPTION_AGENT_LIST_LIMIT = 8_000;\nconst TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT = 480;\n\nconst BUILTIN_AGENTS: AgentDefinition[] = [\n\t{\n\t\tname: \"general\",\n\t\tdescription:\n\t\t\t\"Implementation agent for bounded coding tasks: edits, fixes, refactors, and verification in a scoped area. Use when the task changes files; use explorer for read-only questions\",\n\t\ttools: [...DEFAULT_AGENT_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"Work independently on the delegated task from start to finish.\",\n\t\t\t\"Inspect relevant repository instructions before changing files.\",\n\t\t\t\"Prefer editing existing files; never create documentation files unless the task explicitly asks for them.\",\n\t\t\t\"Keep changes focused, run appropriate verification, and report exact paths, checks, blockers, and remaining risks.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:general>\",\n\t\tbackend: \"sdk\",\n\t},\n\t{\n\t\tname: \"explorer\",\n\t\tdescription:\n\t\t\t'Fast read-only agent for finding files, searching code, and answering codebase questions. Can inspect git history (log, blame, diff) via read-only bash. State thoroughness in the prompt: \"quick\" for a targeted lookup, \"medium\" for checking likely related locations, or \"very thorough\" for exhaustive sweeps across locations and naming conventions',\n\t\ttools: [...EXPLORER_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"You are a fast read-only exploration agent; return findings as quickly as possible.\",\n\t\t\t\"Explore the delegated question without modifying files.\",\n\t\t\t\"Use read and search tools to gather exact evidence, batching independent searches and reads instead of running them one at a time.\",\n\t\t\t\"bash is for read-only inspection only: git log/diff/blame/show/status, ls, wc, head, tail, cat, and similar.\",\n\t\t\t\"Never run anything that modifies state: no file creation or deletion, no redirect (>, >>) or heredoc writes, no temp files, no git commands that write (add, commit, checkout, restore, stash, clean), no installs, no network access.\",\n\t\t\t\"Match the depth the caller requested: quick targets the direct question, medium checks likely related locations, and very thorough sweeps multiple locations and naming conventions.\",\n\t\t\t\"Return concise findings with precise paths, symbols, relationships, and unresolved uncertainties.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:explorer>\",\n\t\tbackend: \"sdk\",\n\t\tomitContextFiles: true,\n\t},\n];\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction findNearestProjectAgentsDir(cwd: string): string | undefined {\n\tlet current = cwd;\n\twhile (true) {\n\t\tconst candidate = join(current, CONFIG_DIR_NAME, \"agents\");\n\t\tif (isDirectory(candidate)) return candidate;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\nfunction parseTools(raw: string | undefined, filePath: string): string[] {\n\tif (!raw?.trim()) return [...DEFAULT_AGENT_TOOLS];\n\tconst tools = [\n\t\t...new Set(\n\t\t\traw\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((tool) => tool.trim())\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n\tconst unsupported = tools.filter((tool) => !BUILTIN_TOOL_SET.has(tool));\n\tif (unsupported.length > 0) {\n\t\tthrow new Error(`Unsupported tool(s) ${unsupported.join(\", \")} in ${filePath}.`);\n\t}\n\treturn tools;\n}\n\n// Frontmatter model/thinking keys are intentionally ignored: agent files\n// travel across machines (project repos), so a pinned model rarely exists\n// in the reader's environment. Model and thinking come from /agents\n// overrides or default to the parent session.\nfunction parseAgentFile(filePath: string, source: Exclude<AgentSource, \"builtin\">): AgentDefinition {\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);\n\tconst name = frontmatter.name?.trim() ?? \"\";\n\tconst description = frontmatter.description?.trim() ?? \"\";\n\tif (!name) throw new Error(\"Missing required frontmatter field: name.\");\n\tif (!AGENT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(`Agent name \"${name}\" must use lowercase letters, digits, hyphens, or underscores.`);\n\t}\n\tif (!description) throw new Error(\"Missing required frontmatter field: description.\");\n\tif (!body.trim()) throw new Error(\"Agent prompt body must not be empty.\");\n\tconst backend = frontmatter.backend?.trim();\n\tif (backend && backend !== \"sdk\") throw new Error(`Backend \"${backend}\" is not implemented; use \"sdk\".`);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\ttools: parseTools(frontmatter.tools, filePath),\n\t\tsystemPrompt: body.trim(),\n\t\tsource,\n\t\tfilePath,\n\t\tbackend: \"sdk\",\n\t};\n}\n\nfunction loadAgentDirectory(\n\tdir: string,\n\tsource: Exclude<AgentSource, \"builtin\">,\n): { agents: AgentDefinition[]; diagnostics: AgentDiagnostic[] } {\n\tif (!existsSync(dir)) return { agents: [], diagnostics: [] };\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));\n\t} catch (error) {\n\t\treturn {\n\t\t\tagents: [],\n\t\t\tdiagnostics: [{ path: dir, source, message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\tconst agents: AgentDefinition[] = [];\n\tconst diagnostics: AgentDiagnostic[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.name.endsWith(\".md\") || (!entry.isFile() && !entry.isSymbolicLink())) continue;\n\t\tconst filePath = join(dir, entry.name);\n\t\ttry {\n\t\t\tagents.push(parseAgentFile(filePath, source));\n\t\t} catch (error) {\n\t\t\tdiagnostics.push({\n\t\t\t\tpath: filePath,\n\t\t\t\tsource,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t}\n\treturn { agents, diagnostics };\n}\n\nexport function discoverAgents(\n\tcwd: string,\n\toptions: { projectTrusted: boolean; agentDir?: string },\n): AgentDiscoveryResult {\n\tconst userDir = join(options.agentDir ?? getAgentDir(), \"agents\");\n\tconst projectAgentsDir = findNearestProjectAgentsDir(cwd);\n\tconst user = loadAgentDirectory(userDir, \"user\");\n\tconst project =\n\t\toptions.projectTrusted && projectAgentsDir\n\t\t\t? loadAgentDirectory(projectAgentsDir, \"project\")\n\t\t\t: { agents: [], diagnostics: [] };\n\tconst agents = new Map(BUILTIN_AGENTS.map((agent) => [agent.name, { ...agent, tools: [...agent.tools] }]));\n\tfor (const agent of user.agents) agents.set(agent.name, agent);\n\tfor (const agent of project.agents) agents.set(agent.name, agent);\n\treturn {\n\t\tagents: [...agents.values()],\n\t\tdiagnostics: [...user.diagnostics, ...project.diagnostics],\n\t\tprojectAgentsDir,\n\t\tprojectAgentsTrusted: options.projectTrusted,\n\t};\n}\n\nexport function subagentToolDescription(discovery: AgentDiscoveryResult): string {\n\tconst agentLines: string[] = [];\n\tlet agentListLength = 0;\n\tfor (const [index, agent] of discovery.agents.entries()) {\n\t\tconst normalizedDescription = agent.description.replace(/\\s+/gu, \" \").trim();\n\t\tconst description =\n\t\t\tBuffer.byteLength(normalizedDescription, \"utf8\") <= TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT\n\t\t\t\t? normalizedDescription\n\t\t\t\t: `${utf8Prefix(normalizedDescription, TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT - Buffer.byteLength(\"…\", \"utf8\"))}…`;\n\t\tconst defaultLabel = agent.name === \"general\" ? \" (default)\" : \"\";\n\t\tconst tools = agent.tools.length > 0 ? agent.tools.join(\", \") : \"none\";\n\t\tconst line = `- ${agent.name}${defaultLabel}: ${description} (Tools: ${tools})`;\n\t\tconst lineLength = Buffer.byteLength(line, \"utf8\") + 1;\n\t\tif (agentListLength + lineLength > TOOL_DESCRIPTION_AGENT_LIST_LIMIT) {\n\t\t\tlet omitted = discovery.agents.length - index;\n\t\t\tlet notice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\twhile (\n\t\t\t\tagentLines.length > 0 &&\n\t\t\t\tagentListLength + Buffer.byteLength(notice, \"utf8\") + 1 > TOOL_DESCRIPTION_AGENT_LIST_LIMIT\n\t\t\t) {\n\t\t\t\tconst removed = agentLines.pop();\n\t\t\t\tif (!removed) break;\n\t\t\t\tagentListLength -= Buffer.byteLength(removed, \"utf8\") + 1;\n\t\t\t\tomitted++;\n\t\t\t\tnotice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\t}\n\t\t\tagentLines.push(notice);\n\t\t\tbreak;\n\t\t}\n\t\tagentLines.push(line);\n\t\tagentListLength += lineLength;\n\t}\n\n\treturn [\n\t\t`Delegate bounded work to isolated one-shot subagents. Delegation keeps intermediate tool output (file dumps, search results) out of your context: you receive only the final report. Choose exactly one mode: prompt for one task, or tasks for independent parallel work (up to ${MAX_TASKS} per call; ${MAX_CONCURRENCY} run concurrently, the rest queue). For sequential work, call this tool again with the previous result folded into the next briefing.`,\n\t\t\"\",\n\t\t\"Available agent profiles:\",\n\t\t...agentLines,\n\t\t\"\",\n\t\t\"When not to delegate:\",\n\t\t\"- Read a known file directly with read, or search for a known symbol directly with grep.\",\n\t\t\"- Prefer direct tools when a directed lookup answers the question; delegate when the investigation will clearly take more than ~3 searches or would flood your context with intermediate output.\",\n\t\t\"- Do not delegate a trivial task when the coordination overhead exceeds the work.\",\n\t\t\"\",\n\t\t\"Writing the briefing:\",\n\t\t\"- Brief the worker like a capable colleague entering the project now: include the objective, relevant context, exact paths or symbols already known, constraints, and expected output.\",\n\t\t\"- Never delegate understanding with vague instructions such as 'fix this based on your findings'; state what must be investigated or changed and whether the worker should research, implement, or review.\",\n\t\t\"- Lookups: hand over the exact command or file. Investigations: hand over the question — prescribed steps become dead weight when the premise is wrong.\",\n\t\t'- If you need a short answer, say so (e.g. \"report in under 200 words\"). Workers cannot see the parent conversation or ask the end user questions.',\n\t\t'- Example briefing (explorer): \"Quick: which commit introduced the retry loop in src/net/client.ts? Use git log/blame; report the hash and a one-line summary.\"',\n\t\t\"\",\n\t\t\"The subagent's report is not shown to the user. Interpret it and relay the important findings, changes, verification, and unresolved risks in your own reply.\",\n\t].join(\"\\n\");\n}\n"]}
|
|
@@ -3,7 +3,7 @@ import { dirname, join } from "node:path";
|
|
|
3
3
|
import { CONFIG_DIR_NAME, getAgentDir } from "../../config.js";
|
|
4
4
|
import { parseFrontmatter } from "../../utils/frontmatter.js";
|
|
5
5
|
import { utf8Prefix } from "./activity.js";
|
|
6
|
-
import { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS } from "./constants.js";
|
|
6
|
+
import { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS, MAX_CONCURRENCY, MAX_TASKS } from "./constants.js";
|
|
7
7
|
const AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/u;
|
|
8
8
|
const BUILTIN_TOOL_SET = new Set(BUILTIN_TOOL_NAMES);
|
|
9
9
|
const TOOL_DESCRIPTION_AGENT_LIST_LIMIT = 8_000;
|
|
@@ -11,7 +11,7 @@ const TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT = 480;
|
|
|
11
11
|
const BUILTIN_AGENTS = [
|
|
12
12
|
{
|
|
13
13
|
name: "general",
|
|
14
|
-
description: "
|
|
14
|
+
description: "Implementation agent for bounded coding tasks: edits, fixes, refactors, and verification in a scoped area. Use when the task changes files; use explorer for read-only questions",
|
|
15
15
|
tools: [...DEFAULT_AGENT_TOOLS],
|
|
16
16
|
systemPrompt: [
|
|
17
17
|
"Work independently on the delegated task from start to finish.",
|
|
@@ -25,18 +25,21 @@ const BUILTIN_AGENTS = [
|
|
|
25
25
|
},
|
|
26
26
|
{
|
|
27
27
|
name: "explorer",
|
|
28
|
-
description: 'Fast read-only agent for finding files, searching code, and answering codebase questions. State thoroughness in the prompt: "quick" for a targeted lookup, "medium" for checking likely related locations, or "very thorough" for exhaustive sweeps across locations and naming conventions',
|
|
28
|
+
description: 'Fast read-only agent for finding files, searching code, and answering codebase questions. Can inspect git history (log, blame, diff) via read-only bash. State thoroughness in the prompt: "quick" for a targeted lookup, "medium" for checking likely related locations, or "very thorough" for exhaustive sweeps across locations and naming conventions',
|
|
29
29
|
tools: [...EXPLORER_TOOLS],
|
|
30
30
|
systemPrompt: [
|
|
31
31
|
"You are a fast read-only exploration agent; return findings as quickly as possible.",
|
|
32
32
|
"Explore the delegated question without modifying files.",
|
|
33
33
|
"Use read and search tools to gather exact evidence, batching independent searches and reads instead of running them one at a time.",
|
|
34
|
+
"bash is for read-only inspection only: git log/diff/blame/show/status, ls, wc, head, tail, cat, and similar.",
|
|
35
|
+
"Never run anything that modifies state: no file creation or deletion, no redirect (>, >>) or heredoc writes, no temp files, no git commands that write (add, commit, checkout, restore, stash, clean), no installs, no network access.",
|
|
34
36
|
"Match the depth the caller requested: quick targets the direct question, medium checks likely related locations, and very thorough sweeps multiple locations and naming conventions.",
|
|
35
37
|
"Return concise findings with precise paths, symbols, relationships, and unresolved uncertainties.",
|
|
36
38
|
].join("\n"),
|
|
37
39
|
source: "builtin",
|
|
38
40
|
filePath: "<builtin:explorer>",
|
|
39
41
|
backend: "sdk",
|
|
42
|
+
omitContextFiles: true,
|
|
40
43
|
},
|
|
41
44
|
];
|
|
42
45
|
function isDirectory(path) {
|
|
@@ -187,21 +190,24 @@ export function subagentToolDescription(discovery) {
|
|
|
187
190
|
agentListLength += lineLength;
|
|
188
191
|
}
|
|
189
192
|
return [
|
|
190
|
-
|
|
193
|
+
`Delegate bounded work to isolated one-shot subagents. Delegation keeps intermediate tool output (file dumps, search results) out of your context: you receive only the final report. Choose exactly one mode: prompt for one task, or tasks for independent parallel work (up to ${MAX_TASKS} per call; ${MAX_CONCURRENCY} run concurrently, the rest queue). For sequential work, call this tool again with the previous result folded into the next briefing.`,
|
|
191
194
|
"",
|
|
192
195
|
"Available agent profiles:",
|
|
193
196
|
...agentLines,
|
|
194
197
|
"",
|
|
195
198
|
"When not to delegate:",
|
|
196
199
|
"- Read a known file directly with read, or search for a known symbol directly with grep.",
|
|
200
|
+
"- Prefer direct tools when a directed lookup answers the question; delegate when the investigation will clearly take more than ~3 searches or would flood your context with intermediate output.",
|
|
197
201
|
"- Do not delegate a trivial task when the coordination overhead exceeds the work.",
|
|
198
202
|
"",
|
|
199
203
|
"Writing the briefing:",
|
|
200
204
|
"- Brief the worker like a capable colleague entering the project now: include the objective, relevant context, exact paths or symbols already known, constraints, and expected output.",
|
|
201
205
|
"- Never delegate understanding with vague instructions such as 'fix this based on your findings'; state what must be investigated or changed and whether the worker should research, implement, or review.",
|
|
202
|
-
"-
|
|
206
|
+
"- Lookups: hand over the exact command or file. Investigations: hand over the question — prescribed steps become dead weight when the premise is wrong.",
|
|
207
|
+
'- If you need a short answer, say so (e.g. "report in under 200 words"). Workers cannot see the parent conversation or ask the end user questions.',
|
|
208
|
+
'- Example briefing (explorer): "Quick: which commit introduced the retry loop in src/net/client.ts? Use git log/blame; report the hash and a one-line summary."',
|
|
203
209
|
"",
|
|
204
|
-
"
|
|
210
|
+
"The subagent's report is not shown to the user. Interpret it and relay the important findings, changes, verification, and unresolved risks in your own reply.",
|
|
205
211
|
].join("\n");
|
|
206
212
|
}
|
|
207
213
|
//# sourceMappingURL=agents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/extensions/subagent/agents.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Dirent, existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../config.ts\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport { utf8Prefix } from \"./activity.ts\";\nimport { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS } from \"./constants.ts\";\nimport type { AgentDefinition, AgentDiagnostic, AgentDiscoveryResult, AgentSource } from \"./types.ts\";\n\nconst AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/u;\nconst BUILTIN_TOOL_SET = new Set<string>(BUILTIN_TOOL_NAMES);\nconst TOOL_DESCRIPTION_AGENT_LIST_LIMIT = 8_000;\nconst TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT = 480;\n\nconst BUILTIN_AGENTS: AgentDefinition[] = [\n\t{\n\t\tname: \"general\",\n\t\tdescription: \"General-purpose implementation agent with coding tools\",\n\t\ttools: [...DEFAULT_AGENT_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"Work independently on the delegated task from start to finish.\",\n\t\t\t\"Inspect relevant repository instructions before changing files.\",\n\t\t\t\"Prefer editing existing files; never create documentation files unless the task explicitly asks for them.\",\n\t\t\t\"Keep changes focused, run appropriate verification, and report exact paths, checks, blockers, and remaining risks.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:general>\",\n\t\tbackend: \"sdk\",\n\t},\n\t{\n\t\tname: \"explorer\",\n\t\tdescription:\n\t\t\t'Fast read-only agent for finding files, searching code, and answering codebase questions. State thoroughness in the prompt: \"quick\" for a targeted lookup, \"medium\" for checking likely related locations, or \"very thorough\" for exhaustive sweeps across locations and naming conventions',\n\t\ttools: [...EXPLORER_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"You are a fast read-only exploration agent; return findings as quickly as possible.\",\n\t\t\t\"Explore the delegated question without modifying files.\",\n\t\t\t\"Use read and search tools to gather exact evidence, batching independent searches and reads instead of running them one at a time.\",\n\t\t\t\"Match the depth the caller requested: quick targets the direct question, medium checks likely related locations, and very thorough sweeps multiple locations and naming conventions.\",\n\t\t\t\"Return concise findings with precise paths, symbols, relationships, and unresolved uncertainties.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:explorer>\",\n\t\tbackend: \"sdk\",\n\t},\n];\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction findNearestProjectAgentsDir(cwd: string): string | undefined {\n\tlet current = cwd;\n\twhile (true) {\n\t\tconst candidate = join(current, CONFIG_DIR_NAME, \"agents\");\n\t\tif (isDirectory(candidate)) return candidate;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\nfunction parseTools(raw: string | undefined, filePath: string): string[] {\n\tif (!raw?.trim()) return [...DEFAULT_AGENT_TOOLS];\n\tconst tools = [\n\t\t...new Set(\n\t\t\traw\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((tool) => tool.trim())\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n\tconst unsupported = tools.filter((tool) => !BUILTIN_TOOL_SET.has(tool));\n\tif (unsupported.length > 0) {\n\t\tthrow new Error(`Unsupported tool(s) ${unsupported.join(\", \")} in ${filePath}.`);\n\t}\n\treturn tools;\n}\n\n// Frontmatter model/thinking keys are intentionally ignored: agent files\n// travel across machines (project repos), so a pinned model rarely exists\n// in the reader's environment. Model and thinking come from /agents\n// overrides or default to the parent session.\nfunction parseAgentFile(filePath: string, source: Exclude<AgentSource, \"builtin\">): AgentDefinition {\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);\n\tconst name = frontmatter.name?.trim() ?? \"\";\n\tconst description = frontmatter.description?.trim() ?? \"\";\n\tif (!name) throw new Error(\"Missing required frontmatter field: name.\");\n\tif (!AGENT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(`Agent name \"${name}\" must use lowercase letters, digits, hyphens, or underscores.`);\n\t}\n\tif (!description) throw new Error(\"Missing required frontmatter field: description.\");\n\tif (!body.trim()) throw new Error(\"Agent prompt body must not be empty.\");\n\tconst backend = frontmatter.backend?.trim();\n\tif (backend && backend !== \"sdk\") throw new Error(`Backend \"${backend}\" is not implemented; use \"sdk\".`);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\ttools: parseTools(frontmatter.tools, filePath),\n\t\tsystemPrompt: body.trim(),\n\t\tsource,\n\t\tfilePath,\n\t\tbackend: \"sdk\",\n\t};\n}\n\nfunction loadAgentDirectory(\n\tdir: string,\n\tsource: Exclude<AgentSource, \"builtin\">,\n): { agents: AgentDefinition[]; diagnostics: AgentDiagnostic[] } {\n\tif (!existsSync(dir)) return { agents: [], diagnostics: [] };\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));\n\t} catch (error) {\n\t\treturn {\n\t\t\tagents: [],\n\t\t\tdiagnostics: [{ path: dir, source, message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\tconst agents: AgentDefinition[] = [];\n\tconst diagnostics: AgentDiagnostic[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.name.endsWith(\".md\") || (!entry.isFile() && !entry.isSymbolicLink())) continue;\n\t\tconst filePath = join(dir, entry.name);\n\t\ttry {\n\t\t\tagents.push(parseAgentFile(filePath, source));\n\t\t} catch (error) {\n\t\t\tdiagnostics.push({\n\t\t\t\tpath: filePath,\n\t\t\t\tsource,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t}\n\treturn { agents, diagnostics };\n}\n\nexport function discoverAgents(\n\tcwd: string,\n\toptions: { projectTrusted: boolean; agentDir?: string },\n): AgentDiscoveryResult {\n\tconst userDir = join(options.agentDir ?? getAgentDir(), \"agents\");\n\tconst projectAgentsDir = findNearestProjectAgentsDir(cwd);\n\tconst user = loadAgentDirectory(userDir, \"user\");\n\tconst project =\n\t\toptions.projectTrusted && projectAgentsDir\n\t\t\t? loadAgentDirectory(projectAgentsDir, \"project\")\n\t\t\t: { agents: [], diagnostics: [] };\n\tconst agents = new Map(BUILTIN_AGENTS.map((agent) => [agent.name, { ...agent, tools: [...agent.tools] }]));\n\tfor (const agent of user.agents) agents.set(agent.name, agent);\n\tfor (const agent of project.agents) agents.set(agent.name, agent);\n\treturn {\n\t\tagents: [...agents.values()],\n\t\tdiagnostics: [...user.diagnostics, ...project.diagnostics],\n\t\tprojectAgentsDir,\n\t\tprojectAgentsTrusted: options.projectTrusted,\n\t};\n}\n\nexport function subagentToolDescription(discovery: AgentDiscoveryResult): string {\n\tconst agentLines: string[] = [];\n\tlet agentListLength = 0;\n\tfor (const [index, agent] of discovery.agents.entries()) {\n\t\tconst normalizedDescription = agent.description.replace(/\\s+/gu, \" \").trim();\n\t\tconst description =\n\t\t\tBuffer.byteLength(normalizedDescription, \"utf8\") <= TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT\n\t\t\t\t? normalizedDescription\n\t\t\t\t: `${utf8Prefix(normalizedDescription, TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT - Buffer.byteLength(\"…\", \"utf8\"))}…`;\n\t\tconst defaultLabel = agent.name === \"general\" ? \" (default)\" : \"\";\n\t\tconst tools = agent.tools.length > 0 ? agent.tools.join(\", \") : \"none\";\n\t\tconst line = `- ${agent.name}${defaultLabel}: ${description} (Tools: ${tools})`;\n\t\tconst lineLength = Buffer.byteLength(line, \"utf8\") + 1;\n\t\tif (agentListLength + lineLength > TOOL_DESCRIPTION_AGENT_LIST_LIMIT) {\n\t\t\tlet omitted = discovery.agents.length - index;\n\t\t\tlet notice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\twhile (\n\t\t\t\tagentLines.length > 0 &&\n\t\t\t\tagentListLength + Buffer.byteLength(notice, \"utf8\") + 1 > TOOL_DESCRIPTION_AGENT_LIST_LIMIT\n\t\t\t) {\n\t\t\t\tconst removed = agentLines.pop();\n\t\t\t\tif (!removed) break;\n\t\t\t\tagentListLength -= Buffer.byteLength(removed, \"utf8\") + 1;\n\t\t\t\tomitted++;\n\t\t\t\tnotice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\t}\n\t\t\tagentLines.push(notice);\n\t\t\tbreak;\n\t\t}\n\t\tagentLines.push(line);\n\t\tagentListLength += lineLength;\n\t}\n\n\treturn [\n\t\t\"Delegate bounded work to isolated one-shot subagents. Choose exactly one mode: prompt for one task, or tasks for independent parallel work. For sequential work, call this tool again with the previous result folded into the next briefing.\",\n\t\t\"\",\n\t\t\"Available agent profiles:\",\n\t\t...agentLines,\n\t\t\"\",\n\t\t\"When not to delegate:\",\n\t\t\"- Read a known file directly with read, or search for a known symbol directly with grep.\",\n\t\t\"- Do not delegate a trivial task when the coordination overhead exceeds the work.\",\n\t\t\"\",\n\t\t\"Writing the briefing:\",\n\t\t\"- Brief the worker like a capable colleague entering the project now: include the objective, relevant context, exact paths or symbols already known, constraints, and expected output.\",\n\t\t\"- Never delegate understanding with vague instructions such as 'fix this based on your findings'; state what must be investigated or changed and whether the worker should research, implement, or review.\",\n\t\t\"- Ask for a concise report when only findings are needed. Workers cannot see the parent conversation or ask the end user questions.\",\n\t\t\"\",\n\t\t\"Subagent results are reports for you to interpret and relay. Surface the important findings, changes, verification, and unresolved risks to the user.\",\n\t].join(\"\\n\");\n}\n"]}
|
|
1
|
+
{"version":3,"file":"agents.js","sourceRoot":"","sources":["../../../src/extensions/subagent/agents.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Dirent, existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { CONFIG_DIR_NAME, getAgentDir } from \"../../config.ts\";\nimport { parseFrontmatter } from \"../../utils/frontmatter.ts\";\nimport { utf8Prefix } from \"./activity.ts\";\nimport { BUILTIN_TOOL_NAMES, DEFAULT_AGENT_TOOLS, EXPLORER_TOOLS, MAX_CONCURRENCY, MAX_TASKS } from \"./constants.ts\";\nimport type { AgentDefinition, AgentDiagnostic, AgentDiscoveryResult, AgentSource } from \"./types.ts\";\n\nconst AGENT_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]{0,79}$/u;\nconst BUILTIN_TOOL_SET = new Set<string>(BUILTIN_TOOL_NAMES);\nconst TOOL_DESCRIPTION_AGENT_LIST_LIMIT = 8_000;\nconst TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT = 480;\n\nconst BUILTIN_AGENTS: AgentDefinition[] = [\n\t{\n\t\tname: \"general\",\n\t\tdescription:\n\t\t\t\"Implementation agent for bounded coding tasks: edits, fixes, refactors, and verification in a scoped area. Use when the task changes files; use explorer for read-only questions\",\n\t\ttools: [...DEFAULT_AGENT_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"Work independently on the delegated task from start to finish.\",\n\t\t\t\"Inspect relevant repository instructions before changing files.\",\n\t\t\t\"Prefer editing existing files; never create documentation files unless the task explicitly asks for them.\",\n\t\t\t\"Keep changes focused, run appropriate verification, and report exact paths, checks, blockers, and remaining risks.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:general>\",\n\t\tbackend: \"sdk\",\n\t},\n\t{\n\t\tname: \"explorer\",\n\t\tdescription:\n\t\t\t'Fast read-only agent for finding files, searching code, and answering codebase questions. Can inspect git history (log, blame, diff) via read-only bash. State thoroughness in the prompt: \"quick\" for a targeted lookup, \"medium\" for checking likely related locations, or \"very thorough\" for exhaustive sweeps across locations and naming conventions',\n\t\ttools: [...EXPLORER_TOOLS],\n\t\tsystemPrompt: [\n\t\t\t\"You are a fast read-only exploration agent; return findings as quickly as possible.\",\n\t\t\t\"Explore the delegated question without modifying files.\",\n\t\t\t\"Use read and search tools to gather exact evidence, batching independent searches and reads instead of running them one at a time.\",\n\t\t\t\"bash is for read-only inspection only: git log/diff/blame/show/status, ls, wc, head, tail, cat, and similar.\",\n\t\t\t\"Never run anything that modifies state: no file creation or deletion, no redirect (>, >>) or heredoc writes, no temp files, no git commands that write (add, commit, checkout, restore, stash, clean), no installs, no network access.\",\n\t\t\t\"Match the depth the caller requested: quick targets the direct question, medium checks likely related locations, and very thorough sweeps multiple locations and naming conventions.\",\n\t\t\t\"Return concise findings with precise paths, symbols, relationships, and unresolved uncertainties.\",\n\t\t].join(\"\\n\"),\n\t\tsource: \"builtin\",\n\t\tfilePath: \"<builtin:explorer>\",\n\t\tbackend: \"sdk\",\n\t\tomitContextFiles: true,\n\t},\n];\n\nfunction isDirectory(path: string): boolean {\n\ttry {\n\t\treturn statSync(path).isDirectory();\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction findNearestProjectAgentsDir(cwd: string): string | undefined {\n\tlet current = cwd;\n\twhile (true) {\n\t\tconst candidate = join(current, CONFIG_DIR_NAME, \"agents\");\n\t\tif (isDirectory(candidate)) return candidate;\n\t\tconst parent = dirname(current);\n\t\tif (parent === current) return undefined;\n\t\tcurrent = parent;\n\t}\n}\n\nfunction parseTools(raw: string | undefined, filePath: string): string[] {\n\tif (!raw?.trim()) return [...DEFAULT_AGENT_TOOLS];\n\tconst tools = [\n\t\t...new Set(\n\t\t\traw\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((tool) => tool.trim())\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n\tconst unsupported = tools.filter((tool) => !BUILTIN_TOOL_SET.has(tool));\n\tif (unsupported.length > 0) {\n\t\tthrow new Error(`Unsupported tool(s) ${unsupported.join(\", \")} in ${filePath}.`);\n\t}\n\treturn tools;\n}\n\n// Frontmatter model/thinking keys are intentionally ignored: agent files\n// travel across machines (project repos), so a pinned model rarely exists\n// in the reader's environment. Model and thinking come from /agents\n// overrides or default to the parent session.\nfunction parseAgentFile(filePath: string, source: Exclude<AgentSource, \"builtin\">): AgentDefinition {\n\tconst content = readFileSync(filePath, \"utf8\");\n\tconst { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);\n\tconst name = frontmatter.name?.trim() ?? \"\";\n\tconst description = frontmatter.description?.trim() ?? \"\";\n\tif (!name) throw new Error(\"Missing required frontmatter field: name.\");\n\tif (!AGENT_NAME_PATTERN.test(name)) {\n\t\tthrow new Error(`Agent name \"${name}\" must use lowercase letters, digits, hyphens, or underscores.`);\n\t}\n\tif (!description) throw new Error(\"Missing required frontmatter field: description.\");\n\tif (!body.trim()) throw new Error(\"Agent prompt body must not be empty.\");\n\tconst backend = frontmatter.backend?.trim();\n\tif (backend && backend !== \"sdk\") throw new Error(`Backend \"${backend}\" is not implemented; use \"sdk\".`);\n\treturn {\n\t\tname,\n\t\tdescription,\n\t\ttools: parseTools(frontmatter.tools, filePath),\n\t\tsystemPrompt: body.trim(),\n\t\tsource,\n\t\tfilePath,\n\t\tbackend: \"sdk\",\n\t};\n}\n\nfunction loadAgentDirectory(\n\tdir: string,\n\tsource: Exclude<AgentSource, \"builtin\">,\n): { agents: AgentDefinition[]; diagnostics: AgentDiagnostic[] } {\n\tif (!existsSync(dir)) return { agents: [], diagnostics: [] };\n\tlet entries: Dirent[];\n\ttry {\n\t\tentries = readdirSync(dir, { withFileTypes: true }).sort((left, right) => left.name.localeCompare(right.name));\n\t} catch (error) {\n\t\treturn {\n\t\t\tagents: [],\n\t\t\tdiagnostics: [{ path: dir, source, message: error instanceof Error ? error.message : String(error) }],\n\t\t};\n\t}\n\tconst agents: AgentDefinition[] = [];\n\tconst diagnostics: AgentDiagnostic[] = [];\n\tfor (const entry of entries) {\n\t\tif (!entry.name.endsWith(\".md\") || (!entry.isFile() && !entry.isSymbolicLink())) continue;\n\t\tconst filePath = join(dir, entry.name);\n\t\ttry {\n\t\t\tagents.push(parseAgentFile(filePath, source));\n\t\t} catch (error) {\n\t\t\tdiagnostics.push({\n\t\t\t\tpath: filePath,\n\t\t\t\tsource,\n\t\t\t\tmessage: error instanceof Error ? error.message : String(error),\n\t\t\t});\n\t\t}\n\t}\n\treturn { agents, diagnostics };\n}\n\nexport function discoverAgents(\n\tcwd: string,\n\toptions: { projectTrusted: boolean; agentDir?: string },\n): AgentDiscoveryResult {\n\tconst userDir = join(options.agentDir ?? getAgentDir(), \"agents\");\n\tconst projectAgentsDir = findNearestProjectAgentsDir(cwd);\n\tconst user = loadAgentDirectory(userDir, \"user\");\n\tconst project =\n\t\toptions.projectTrusted && projectAgentsDir\n\t\t\t? loadAgentDirectory(projectAgentsDir, \"project\")\n\t\t\t: { agents: [], diagnostics: [] };\n\tconst agents = new Map(BUILTIN_AGENTS.map((agent) => [agent.name, { ...agent, tools: [...agent.tools] }]));\n\tfor (const agent of user.agents) agents.set(agent.name, agent);\n\tfor (const agent of project.agents) agents.set(agent.name, agent);\n\treturn {\n\t\tagents: [...agents.values()],\n\t\tdiagnostics: [...user.diagnostics, ...project.diagnostics],\n\t\tprojectAgentsDir,\n\t\tprojectAgentsTrusted: options.projectTrusted,\n\t};\n}\n\nexport function subagentToolDescription(discovery: AgentDiscoveryResult): string {\n\tconst agentLines: string[] = [];\n\tlet agentListLength = 0;\n\tfor (const [index, agent] of discovery.agents.entries()) {\n\t\tconst normalizedDescription = agent.description.replace(/\\s+/gu, \" \").trim();\n\t\tconst description =\n\t\t\tBuffer.byteLength(normalizedDescription, \"utf8\") <= TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT\n\t\t\t\t? normalizedDescription\n\t\t\t\t: `${utf8Prefix(normalizedDescription, TOOL_DESCRIPTION_AGENT_SUMMARY_LIMIT - Buffer.byteLength(\"…\", \"utf8\"))}…`;\n\t\tconst defaultLabel = agent.name === \"general\" ? \" (default)\" : \"\";\n\t\tconst tools = agent.tools.length > 0 ? agent.tools.join(\", \") : \"none\";\n\t\tconst line = `- ${agent.name}${defaultLabel}: ${description} (Tools: ${tools})`;\n\t\tconst lineLength = Buffer.byteLength(line, \"utf8\") + 1;\n\t\tif (agentListLength + lineLength > TOOL_DESCRIPTION_AGENT_LIST_LIMIT) {\n\t\t\tlet omitted = discovery.agents.length - index;\n\t\t\tlet notice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\twhile (\n\t\t\t\tagentLines.length > 0 &&\n\t\t\t\tagentListLength + Buffer.byteLength(notice, \"utf8\") + 1 > TOOL_DESCRIPTION_AGENT_LIST_LIMIT\n\t\t\t) {\n\t\t\t\tconst removed = agentLines.pop();\n\t\t\t\tif (!removed) break;\n\t\t\t\tagentListLength -= Buffer.byteLength(removed, \"utf8\") + 1;\n\t\t\t\tomitted++;\n\t\t\t\tnotice = `- ${omitted} additional profile${omitted === 1 ? \"\" : \"s\"} omitted from this bounded description; /agents lists every profile.`;\n\t\t\t}\n\t\t\tagentLines.push(notice);\n\t\t\tbreak;\n\t\t}\n\t\tagentLines.push(line);\n\t\tagentListLength += lineLength;\n\t}\n\n\treturn [\n\t\t`Delegate bounded work to isolated one-shot subagents. Delegation keeps intermediate tool output (file dumps, search results) out of your context: you receive only the final report. Choose exactly one mode: prompt for one task, or tasks for independent parallel work (up to ${MAX_TASKS} per call; ${MAX_CONCURRENCY} run concurrently, the rest queue). For sequential work, call this tool again with the previous result folded into the next briefing.`,\n\t\t\"\",\n\t\t\"Available agent profiles:\",\n\t\t...agentLines,\n\t\t\"\",\n\t\t\"When not to delegate:\",\n\t\t\"- Read a known file directly with read, or search for a known symbol directly with grep.\",\n\t\t\"- Prefer direct tools when a directed lookup answers the question; delegate when the investigation will clearly take more than ~3 searches or would flood your context with intermediate output.\",\n\t\t\"- Do not delegate a trivial task when the coordination overhead exceeds the work.\",\n\t\t\"\",\n\t\t\"Writing the briefing:\",\n\t\t\"- Brief the worker like a capable colleague entering the project now: include the objective, relevant context, exact paths or symbols already known, constraints, and expected output.\",\n\t\t\"- Never delegate understanding with vague instructions such as 'fix this based on your findings'; state what must be investigated or changed and whether the worker should research, implement, or review.\",\n\t\t\"- Lookups: hand over the exact command or file. Investigations: hand over the question — prescribed steps become dead weight when the premise is wrong.\",\n\t\t'- If you need a short answer, say so (e.g. \"report in under 200 words\"). Workers cannot see the parent conversation or ask the end user questions.',\n\t\t'- Example briefing (explorer): \"Quick: which commit introduced the retry loop in src/net/client.ts? Use git log/blame; report the hash and a one-line summary.\"',\n\t\t\"\",\n\t\t\"The subagent's report is not shown to the user. Interpret it and relay the important findings, changes, verification, and unresolved risks in your own reply.\",\n\t].join(\"\\n\");\n}\n"]}
|
|
@@ -9,7 +9,7 @@ export declare const TASK_RETRY_LIMIT = 2;
|
|
|
9
9
|
export declare const TASK_RETRY_BASE_DELAY_MS = 1000;
|
|
10
10
|
export declare const BUILTIN_TOOL_NAMES: readonly ["read", "bash", "edit", "write", "grep", "find", "ls"];
|
|
11
11
|
export declare const DEFAULT_AGENT_TOOLS: readonly ["read", "bash", "edit", "write"];
|
|
12
|
-
export declare const EXPLORER_TOOLS: readonly ["read", "grep", "find", "ls"];
|
|
12
|
+
export declare const EXPLORER_TOOLS: readonly ["read", "grep", "find", "ls", "bash"];
|
|
13
13
|
export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
|
|
14
14
|
export declare const LIVE_TEXT_LIMIT: number;
|
|
15
15
|
export declare const ACTIVITY_LIMIT = 80;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAC7C,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,eAAe,IAAI,CAAC;AAKjC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,eAAO,MAAM,kBAAkB,kEAAmE,CAAC;AAEnG,eAAO,MAAM,mBAAmB,4CAA6C,CAAC;
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/extensions/subagent/constants.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,kBAAkB,aAAa,CAAC;AAC7C,eAAO,MAAM,mBAAmB,aAAa,CAAC;AAC9C,eAAO,MAAM,qBAAqB,WAAW,CAAC;AAC9C,eAAO,MAAM,uBAAuB,IAAI,CAAC;AACzC,eAAO,MAAM,oBAAoB,kBAAkB,CAAC;AAEpD,eAAO,MAAM,SAAS,IAAI,CAAC;AAC3B,eAAO,MAAM,eAAe,IAAI,CAAC;AAKjC,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAClC,eAAO,MAAM,wBAAwB,OAAQ,CAAC;AAE9C,eAAO,MAAM,kBAAkB,kEAAmE,CAAC;AAEnG,eAAO,MAAM,mBAAmB,4CAA6C,CAAC;AAG9E,eAAO,MAAM,cAAc,iDAAkD,CAAC;AAE9E,eAAO,MAAM,eAAe,sEAQiB,CAAC;AAE9C,eAAO,MAAM,eAAe,QAAW,CAAC;AACxC,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAC7C,eAAO,MAAM,mBAAmB,QAAY,CAAC;AAC7C,eAAO,MAAM,0BAA0B,QAAY,CAAC;AACpD,eAAO,MAAM,qBAAqB,QAAY,CAAC;AAC/C,eAAO,MAAM,gBAAgB,QAAW,CAAC;AACzC,eAAO,MAAM,oBAAoB,QAAa,CAAC;AAG/C,eAAO,MAAM,sBAAsB,KAAK,CAAC","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\n\nexport const SUBAGENT_TOOL_NAME = \"subagent\";\nexport const SUBAGENT_TOOL_LABEL = \"Subagent\";\nexport const SUBAGENT_COMMAND_NAME = \"agents\";\nexport const SUBAGENT_CONFIG_VERSION = 1;\nexport const SUBAGENT_CONFIG_FILE = \"subagent.json\";\n\nexport const MAX_TASKS = 8;\nexport const MAX_CONCURRENCY = 5;\n\n// Task-level retry for failures that bypass the session's own auto-retry\n// (preflight throws such as auth checks). Only runs that produced nothing\n// are retried, so a retry never discards partial work.\nexport const TASK_RETRY_LIMIT = 2;\nexport const TASK_RETRY_BASE_DELAY_MS = 1_000;\n\nexport const BUILTIN_TOOL_NAMES = [\"read\", \"bash\", \"edit\", \"write\", \"grep\", \"find\", \"ls\"] as const;\n// Matches the parent session's default toolset; bash covers search needs.\nexport const DEFAULT_AGENT_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"] as const;\n// Read-only agents get the standalone search tools plus bash for read-only\n// inspection (git history, counting); the system prompt constrains bash.\nexport const EXPLORER_TOOLS = [\"read\", \"grep\", \"find\", \"ls\", \"bash\"] as const;\n\nexport const THINKING_LEVELS = [\n\t\"off\",\n\t\"minimal\",\n\t\"low\",\n\t\"medium\",\n\t\"high\",\n\t\"xhigh\",\n\t\"max\",\n] as const satisfies readonly ThinkingLevel[];\n\nexport const LIVE_TEXT_LIMIT = 8 * 1024;\nexport const ACTIVITY_LIMIT = 80;\nexport const ACTIVITY_TEXT_LIMIT = 24 * 1024;\nexport const SINGLE_OUTPUT_LIMIT = 32 * 1024;\nexport const PARALLEL_TASK_OUTPUT_LIMIT = 12 * 1024;\nexport const PARALLEL_OUTPUT_LIMIT = 48 * 1024;\nexport const ERROR_TEXT_LIMIT = 8 * 1024;\nexport const DETAILS_OUTPUT_LIMIT = 120 * 1024;\n// Bounded per run inside DETAILS_OUTPUT_LIMIT; each activity costs up to\n// ~600 bytes, so 12 keeps an 8-run parallel batch from starving outputs.\nexport const DETAILS_ACTIVITY_LIMIT = 12;\n"]}
|