@astralyn/pi 1.4.4 → 1.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -0
  3. package/dist/bundle/chunks/chunk-5M3YJ54Z.js +82 -0
  4. package/dist/bundle/chunks/chunk-6QGV3IWD.js +6 -0
  5. package/dist/bundle/chunks/chunk-ALHAFUHP.js +7 -0
  6. package/dist/bundle/chunks/chunk-AXFWZIHH.js +4 -0
  7. package/dist/bundle/chunks/chunk-EYKC6ESU.js +2 -0
  8. package/dist/bundle/chunks/chunk-KDO6L76C.js +230 -0
  9. package/dist/bundle/chunks/chunk-RBTJBQWX.js +1500 -0
  10. package/dist/bundle/chunks/chunk-RLNMABLM.js +9 -0
  11. package/dist/bundle/chunks/cli-FH77R7JR.js +51 -0
  12. package/dist/bundle/chunks/execute-5ZQUS52M.js +505 -0
  13. package/dist/bundle/chunks/runtime-R5CMHJ5P.js +2 -0
  14. package/dist/bundle/chunks/virtual-modules-KCQU7LOC.js +2 -0
  15. package/dist/bundle/cli.js +1 -1
  16. package/dist/bundle/index.js +1 -1
  17. package/dist/bundle/rpc-entry.js +1 -1
  18. package/dist/core/agent-session.d.ts.map +1 -1
  19. package/dist/core/agent-session.js +2 -0
  20. package/dist/core/agent-session.js.map +1 -1
  21. package/dist/core/extensions/index.d.ts +1 -1
  22. package/dist/core/extensions/index.d.ts.map +1 -1
  23. package/dist/core/extensions/index.js.map +1 -1
  24. package/dist/core/extensions/runner.d.ts +2 -0
  25. package/dist/core/extensions/runner.d.ts.map +1 -1
  26. package/dist/core/extensions/runner.js +18 -0
  27. package/dist/core/extensions/runner.js.map +1 -1
  28. package/dist/core/extensions/types.d.ts +6 -0
  29. package/dist/core/extensions/types.d.ts.map +1 -1
  30. package/dist/core/extensions/types.js.map +1 -1
  31. package/dist/core/isolated-session.d.ts +23 -0
  32. package/dist/core/isolated-session.d.ts.map +1 -0
  33. package/dist/core/isolated-session.js +55 -0
  34. package/dist/core/isolated-session.js.map +1 -0
  35. package/dist/core/model-config.d.ts +1 -3
  36. package/dist/core/model-config.d.ts.map +1 -1
  37. package/dist/core/model-config.js +1 -3
  38. package/dist/core/model-config.js.map +1 -1
  39. package/dist/core/settings-manager.d.ts +4 -0
  40. package/dist/core/settings-manager.d.ts.map +1 -1
  41. package/dist/core/settings-manager.js +38 -0
  42. package/dist/core/settings-manager.js.map +1 -1
  43. package/dist/core/settings-schema.d.ts +1 -0
  44. package/dist/core/settings-schema.d.ts.map +1 -1
  45. package/dist/core/settings-schema.js +3 -0
  46. package/dist/core/settings-schema.js.map +1 -1
  47. package/dist/core/tasks/codec.d.ts +12 -0
  48. package/dist/core/tasks/codec.d.ts.map +1 -0
  49. package/dist/core/tasks/codec.js +139 -0
  50. package/dist/core/tasks/codec.js.map +1 -0
  51. package/dist/core/tasks/execution.d.ts +64 -0
  52. package/dist/core/tasks/execution.d.ts.map +1 -0
  53. package/dist/core/tasks/execution.js +272 -0
  54. package/dist/core/tasks/execution.js.map +1 -0
  55. package/dist/core/tasks/output.d.ts +12 -5
  56. package/dist/core/tasks/output.d.ts.map +1 -1
  57. package/dist/core/tasks/output.js +38 -37
  58. package/dist/core/tasks/output.js.map +1 -1
  59. package/dist/core/tasks/presentation.d.ts +14 -5
  60. package/dist/core/tasks/presentation.d.ts.map +1 -1
  61. package/dist/core/tasks/presentation.js +56 -185
  62. package/dist/core/tasks/presentation.js.map +1 -1
  63. package/dist/core/tasks/runtime.d.ts +9 -9
  64. package/dist/core/tasks/runtime.d.ts.map +1 -1
  65. package/dist/core/tasks/runtime.js +63 -252
  66. package/dist/core/tasks/runtime.js.map +1 -1
  67. package/dist/core/tasks/scheduler.d.ts +16 -0
  68. package/dist/core/tasks/scheduler.d.ts.map +1 -0
  69. package/dist/core/tasks/scheduler.js +42 -0
  70. package/dist/core/tasks/scheduler.js.map +1 -0
  71. package/dist/core/tasks/session.d.ts +1 -0
  72. package/dist/core/tasks/session.d.ts.map +1 -1
  73. package/dist/core/tasks/session.js +15 -27
  74. package/dist/core/tasks/session.js.map +1 -1
  75. package/dist/core/tasks/store.js +4 -4
  76. package/dist/core/tasks/store.js.map +1 -1
  77. package/dist/core/tasks/types.d.ts +63 -49
  78. package/dist/core/tasks/types.d.ts.map +1 -1
  79. package/dist/core/tasks/types.js +3 -9
  80. package/dist/core/tasks/types.js.map +1 -1
  81. package/dist/core/tools/render-utils.d.ts +6 -4
  82. package/dist/core/tools/render-utils.d.ts.map +1 -1
  83. package/dist/core/tools/render-utils.js +34 -14
  84. package/dist/core/tools/render-utils.js.map +1 -1
  85. package/dist/core/tools/shell-execution.js +4 -4
  86. package/dist/core/tools/shell-execution.js.map +1 -1
  87. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  88. package/dist/core/tools/shell-tool.js +23 -30
  89. package/dist/core/tools/shell-tool.js.map +1 -1
  90. package/dist/core/usage-totals.d.ts +1 -3
  91. package/dist/core/usage-totals.d.ts.map +1 -1
  92. package/dist/core/usage-totals.js +17 -8
  93. package/dist/core/usage-totals.js.map +1 -1
  94. package/dist/extensions/agent/activity.d.ts +13 -0
  95. package/dist/extensions/agent/activity.d.ts.map +1 -0
  96. package/dist/extensions/agent/activity.js +75 -0
  97. package/dist/extensions/agent/activity.js.map +1 -0
  98. package/dist/extensions/agent/index.d.ts +4 -0
  99. package/dist/extensions/agent/index.d.ts.map +1 -0
  100. package/dist/extensions/agent/index.js +11 -0
  101. package/dist/extensions/agent/index.js.map +1 -0
  102. package/dist/extensions/agent/progress.d.ts +31 -0
  103. package/dist/extensions/agent/progress.d.ts.map +1 -0
  104. package/dist/extensions/agent/progress.js +145 -0
  105. package/dist/extensions/agent/progress.js.map +1 -0
  106. package/dist/extensions/agent/render.d.ts +6 -0
  107. package/dist/extensions/agent/render.d.ts.map +1 -0
  108. package/dist/extensions/agent/render.js +120 -0
  109. package/dist/extensions/agent/render.js.map +1 -0
  110. package/dist/extensions/agent/report.d.ts +9 -0
  111. package/dist/extensions/agent/report.d.ts.map +1 -0
  112. package/dist/extensions/agent/report.js +40 -0
  113. package/dist/extensions/agent/report.js.map +1 -0
  114. package/dist/extensions/agent/settings-panel.d.ts +43 -0
  115. package/dist/extensions/agent/settings-panel.d.ts.map +1 -0
  116. package/dist/extensions/agent/settings-panel.js +125 -0
  117. package/dist/extensions/agent/settings-panel.js.map +1 -0
  118. package/dist/extensions/agent/settings.d.ts +15 -0
  119. package/dist/extensions/agent/settings.d.ts.map +1 -0
  120. package/dist/extensions/agent/settings.js +201 -0
  121. package/dist/extensions/agent/settings.js.map +1 -0
  122. package/dist/extensions/agent/tool.d.ts +13 -0
  123. package/dist/extensions/agent/tool.d.ts.map +1 -0
  124. package/dist/extensions/agent/tool.js +84 -0
  125. package/dist/extensions/agent/tool.js.map +1 -0
  126. package/dist/extensions/agent/types.d.ts +43 -0
  127. package/dist/extensions/agent/types.d.ts.map +1 -0
  128. package/dist/extensions/agent/types.js +6 -0
  129. package/dist/extensions/agent/types.js.map +1 -0
  130. package/dist/extensions/agent/worker.d.ts +16 -0
  131. package/dist/extensions/agent/worker.d.ts.map +1 -0
  132. package/dist/extensions/agent/worker.js +68 -0
  133. package/dist/extensions/agent/worker.js.map +1 -0
  134. package/dist/extensions/codemode/execute.js +1 -1
  135. package/dist/extensions/codemode/execute.js.map +1 -1
  136. package/dist/extensions/codemode/execute.lazy.d.ts +2 -2
  137. package/dist/extensions/codemode/execute.lazy.d.ts.map +1 -1
  138. package/dist/extensions/codemode/execute.lazy.js +2 -2
  139. package/dist/extensions/codemode/execute.lazy.js.map +1 -1
  140. package/dist/extensions/index.d.ts.map +1 -1
  141. package/dist/extensions/index.js +2 -0
  142. package/dist/extensions/index.js.map +1 -1
  143. package/dist/extensions/mcp/cli.lazy.d.ts +2 -2
  144. package/dist/extensions/mcp/cli.lazy.d.ts.map +1 -1
  145. package/dist/extensions/mcp/cli.lazy.js +2 -2
  146. package/dist/extensions/mcp/cli.lazy.js.map +1 -1
  147. package/dist/extensions/mcp/index.d.ts.map +1 -1
  148. package/dist/extensions/mcp/index.js +2 -2
  149. package/dist/extensions/mcp/index.js.map +1 -1
  150. package/dist/extensions/mcp/runtime.lazy.d.ts +2 -2
  151. package/dist/extensions/mcp/runtime.lazy.d.ts.map +1 -1
  152. package/dist/extensions/mcp/runtime.lazy.js +2 -2
  153. package/dist/extensions/mcp/runtime.lazy.js.map +1 -1
  154. package/dist/extensions/provider/compat-fields.js +1 -1
  155. package/dist/extensions/provider/compat-fields.js.map +1 -1
  156. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  157. package/dist/extensions/tasks/tool/actions.js +1 -9
  158. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  159. package/dist/extensions/tasks/tool/schema.js +1 -1
  160. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  161. package/dist/extensions/tasks/tool/types.d.ts +2 -8
  162. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  163. package/dist/extensions/tasks/tool/types.js +0 -2
  164. package/dist/extensions/tasks/tool/types.js.map +1 -1
  165. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  166. package/dist/extensions/tasks/ui/completion-render.js +27 -26
  167. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  168. package/dist/extensions/tasks/ui/inspector.d.ts +5 -3
  169. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  170. package/dist/extensions/tasks/ui/inspector.js +18 -6
  171. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  172. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  173. package/dist/extensions/tasks/ui/layout.js +111 -75
  174. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  175. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  176. package/dist/extensions/tasks/ui/list.js +43 -28
  177. package/dist/extensions/tasks/ui/list.js.map +1 -1
  178. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  179. package/dist/extensions/tasks/ui/manager.js +8 -2
  180. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  181. package/dist/extensions/tasks/ui/model.d.ts +4 -0
  182. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  183. package/dist/extensions/tasks/ui/model.js +12 -1
  184. package/dist/extensions/tasks/ui/model.js.map +1 -1
  185. package/dist/extensions/tasks/ui/render.js +3 -4
  186. package/dist/extensions/tasks/ui/render.js.map +1 -1
  187. package/dist/extensions/tasks/ui/task-view.d.ts +0 -5
  188. package/dist/extensions/tasks/ui/task-view.d.ts.map +1 -1
  189. package/dist/extensions/tasks/ui/task-view.js +0 -7
  190. package/dist/extensions/tasks/ui/task-view.js.map +1 -1
  191. package/dist/extensions/tasks/ui/tree.js +1 -1
  192. package/dist/extensions/tasks/ui/tree.js.map +1 -1
  193. package/dist/extensions/tasks/ui/views.d.ts +10 -6
  194. package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
  195. package/dist/extensions/tasks/ui/views.js +64 -28
  196. package/dist/extensions/tasks/ui/views.js.map +1 -1
  197. package/dist/index.d.ts +2 -1
  198. package/dist/index.d.ts.map +1 -1
  199. package/dist/index.js.map +1 -1
  200. package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
  201. package/dist/modes/interactive/components/keybinding-hints.js +2 -1
  202. package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
  203. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  204. package/dist/modes/interactive/components/model-selector.js +7 -4
  205. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  206. package/dist/modes/interactive/components/thinking-selector.d.ts.map +1 -1
  207. package/dist/modes/interactive/components/thinking-selector.js +10 -3
  208. package/dist/modes/interactive/components/thinking-selector.js.map +1 -1
  209. package/docs/bundled/README.md +1 -0
  210. package/docs/bundled/extensions/agent.md +68 -0
  211. package/docs/bundled/extensions/statusline.md +1 -1
  212. package/docs/bundled/tasks.md +15 -14
  213. package/docs/docs.json +4 -0
  214. package/docs/extensions.md +33 -6
  215. package/docs/sdk.md +2 -2
  216. package/docs/session-format.md +27 -23
  217. package/npm-shrinkwrap.json +2 -2
  218. package/package.json +1 -1
  219. package/schemas/settings.schema.json +12 -0
  220. package/dist/bundle/chunks/chunk-SBVVM3NV.js +0 -2361
  221. package/dist/bundle/chunks/chunk-VGSZTBVJ.js +0 -2
  222. package/dist/bundle/chunks/virtual-modules-ETYFHSUG.js +0 -2
  223. package/dist/core/tasks/history.d.ts +0 -4
  224. package/dist/core/tasks/history.d.ts.map +0 -1
  225. package/dist/core/tasks/history.js +0 -121
  226. package/dist/core/tasks/history.js.map +0 -1
  227. package/dist/extensions/codemode/search.d.ts +0 -33
  228. package/dist/extensions/codemode/search.d.ts.map +0 -1
  229. package/dist/extensions/codemode/search.js +0 -117
  230. package/dist/extensions/codemode/search.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"report.js","sourceRoot":"","sources":["../../../src/extensions/agent/report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAEvD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAyB,MAAM,YAAY,CAAC;AAEvE,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,cAAuB;IAClE,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,MAAM,GAAG,cAAc;QAC5B,CAAC,CAAC,6CAA6C,cAAc,GAAG;QAChE,CAAC,CAAC,wDAAwD,CAAC;IAC5D,OAAO,SAAS,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC;AACjF,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC3C,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,KAA4B,EAAE,EAAE;QACzD,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,KAAK,CAAC;IAC1C,CAAC,CAAC,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAChC,OAAsC,EACtC,MAAc,EACd,KAAyB;IAEzB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,cAAc,KAAK,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IAC1G,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,kBAAkB;QAAE,OAAO,IAAI,CAAC;IAC/D,IAAI,IAAwB,CAAC;IAC7B,IAAI,CAAC;QACJ,IAAI,GAAG,MAAM,eAAe,CAAC,UAAU,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACtD,MAAM,KAAK,GAAG,IAAI,CAAC;QACnB,OAAO,CAAC,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC;QAC3D,OAAO,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACR,IAAI,IAAI;YAAE,MAAM,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;QACvD,OAAO,aAAa,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;AACF,CAAC","sourcesContent":["import { unlink } from \"node:fs/promises\";\nimport { boundText } from \"../../core/tasks/output.ts\";\nimport type { TaskControl } from \"../../core/tasks/types.ts\";\nimport { writeOutputFile } from \"../../utils/output-files.ts\";\nimport { AGENT_REPORT_BYTES, type AgentToolDetails } from \"./types.ts\";\n\nexport function boundedReport(text: string, fullOutputPath?: string): string {\n\tif (Buffer.byteLength(text) <= AGENT_REPORT_BYTES) return text;\n\tconst notice = fullOutputPath\n\t\t? `\\n\\n[Agent output truncated. Full output: ${fullOutputPath}]`\n\t\t: \"\\n\\n[Agent output truncated. Full output unavailable.]\";\n\treturn boundText(text, AGENT_REPORT_BYTES - Buffer.byteLength(notice)) + notice;\n}\n\nasync function removeOutputFile(path: string): Promise<void> {\n\tawait unlink(path).catch((error: NodeJS.ErrnoException) => {\n\t\tif (error.code !== \"ENOENT\") throw error;\n\t});\n}\n\n/**\n * The model-facing report. An oversized report keeps its beginning and names a managed\n * Markdown file with the complete text, which the task owns and cleans up.\n */\nexport async function finalReport(\n\tcontrol: TaskControl<AgentToolDetails>,\n\treport: string,\n\terror: string | undefined,\n): Promise<string> {\n\tconst text = !report ? (error ?? \"No report returned.\") : error ? `${report}\\n\\nError: ${error}` : report;\n\tif (Buffer.byteLength(text) <= AGENT_REPORT_BYTES) return text;\n\tlet path: string | undefined;\n\ttry {\n\t\tpath = await writeOutputFile(\"pi-agent\", \".md\", text);\n\t\tconst saved = path;\n\t\tcontrol.attachOutput(saved, () => removeOutputFile(saved));\n\t\treturn boundedReport(text, saved);\n\t} catch {\n\t\tif (path) await removeOutputFile(path).catch(() => {});\n\t\treturn boundedReport(text);\n\t}\n}\n"]}
@@ -0,0 +1,43 @@
1
+ import { type Component, type TUI, type TuiMouseEvent, type TuiMouseEventResult } from "@earendil-works/pi-tui";
2
+ import type { KeybindingsManager } from "../../core/keybindings.ts";
3
+ import type { Theme } from "../../modes/interactive/theme/theme.ts";
4
+ export type AgentSettingsAction = "model" | "thinking" | "reset";
5
+ /** The current value of a setting row; the reset action row carries no field. */
6
+ export interface AgentSettingsField {
7
+ value: string;
8
+ following?: boolean;
9
+ status?: string;
10
+ tone?: "warning" | "error";
11
+ }
12
+ export interface AgentSettingsRow {
13
+ action: AgentSettingsAction;
14
+ label: string;
15
+ field?: AgentSettingsField;
16
+ }
17
+ /** Aligned setting rows with one action row, navigated through the host keybindings. */
18
+ export declare class AgentSettingsPanel implements Component {
19
+ private readonly tui;
20
+ private readonly theme;
21
+ private readonly keys;
22
+ private readonly rows;
23
+ private readonly onSelect;
24
+ private readonly onCancel;
25
+ private readonly labelWidth;
26
+ private selectedIndex;
27
+ /** Line index of each row, recorded while rendering so click hit-testing cannot drift. */
28
+ private rowLines;
29
+ constructor(tui: TUI, theme: Theme, keys: KeybindingsManager, rows: AgentSettingsRow[], selected: AgentSettingsAction, onSelect: (action: AgentSettingsAction) => void, onCancel: () => void);
30
+ render(width: number): string[];
31
+ handleInput(data: string): void;
32
+ handleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined;
33
+ invalidate(): void;
34
+ private move;
35
+ private select;
36
+ private renderRow;
37
+ /** Values keep their room before the inheritance marker degrades, because that marker is the meaning. */
38
+ private renderValue;
39
+ private followText;
40
+ private hints;
41
+ private key;
42
+ }
43
+ //# sourceMappingURL=settings-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-panel.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/settings-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,aAAa,EAClB,KAAK,mBAAmB,EAIxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wCAAwC,CAAC;AAEpE,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAEjE,iFAAiF;AACjF,MAAM,WAAW,kBAAkB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAChC,MAAM,EAAE,mBAAmB,CAAC;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,kBAAkB,CAAC;CAC3B;AASD,wFAAwF;AACxF,qBAAa,kBAAmB,YAAW,SAAS;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAQ;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAqB;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwC;IACjE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAa;IACtC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,aAAa,CAAS;IAC9B,0FAA0F;IAC1F,OAAO,CAAC,QAAQ,CAAgB;gBAG/B,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,kBAAkB,EACxB,IAAI,EAAE,gBAAgB,EAAE,EACxB,QAAQ,EAAE,mBAAmB,EAC7B,QAAQ,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,EAC/C,QAAQ,EAAE,MAAM,IAAI;IAgBrB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAc/B,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAW/B,WAAW,CAAC,KAAK,EAAE,aAAa,GAAG,mBAAmB,GAAG,SAAS;IAalE,UAAU,IAAI,IAAI;IAIlB,OAAO,CAAC,IAAI;IAKZ,OAAO,CAAC,MAAM;IAKd,OAAO,CAAC,SAAS;IAQjB,yGAAyG;IACzG,OAAO,CAAC,WAAW;IAanB,OAAO,CAAC,UAAU;IAQlB,OAAO,CAAC,KAAK;IASb,OAAO,CAAC,GAAG;CAGX"}
@@ -0,0 +1,125 @@
1
+ import { truncateToWidth, visibleWidth, wrapTextWithAnsi, } from "@earendil-works/pi-tui";
2
+ import { keyLabel } from "../../modes/interactive/components/keybinding-hints.js";
3
+ const FOLLOW = " · Follow current session";
4
+ const FOLLOW_SHORT = " · follow";
5
+ /** Room the value keeps before the full inheritance marker is shown. */
6
+ const VALUE_PRIORITY_WIDTH = 12;
7
+ /** Room the value keeps once only the compact inheritance marker fits. */
8
+ const COMPACT_PRIORITY_WIDTH = 4;
9
+ /** Aligned setting rows with one action row, navigated through the host keybindings. */
10
+ export class AgentSettingsPanel {
11
+ constructor(tui, theme, keys, rows, selected, onSelect, onCancel) {
12
+ /** Line index of each row, recorded while rendering so click hit-testing cannot drift. */
13
+ this.rowLines = [];
14
+ this.tui = tui;
15
+ this.theme = theme;
16
+ this.keys = keys;
17
+ this.rows = rows;
18
+ this.onSelect = onSelect;
19
+ this.onCancel = onCancel;
20
+ this.selectedIndex = Math.max(0, rows.findIndex((row) => row.action === selected));
21
+ const labels = rows.flatMap((row) => (row.field ? [visibleWidth(row.label)] : []));
22
+ this.labelWidth = Math.max(0, ...labels) + 2;
23
+ }
24
+ render(width) {
25
+ if (width < 1)
26
+ return [];
27
+ const border = this.theme.fg("borderMuted", "─".repeat(width));
28
+ const lines = [this.theme.fg("accent", this.theme.bold("Agent Settings")), border];
29
+ this.rowLines = [];
30
+ for (const [index, row] of this.rows.entries()) {
31
+ if (lines.length > 2)
32
+ lines.push("");
33
+ this.rowLines.push(lines.length);
34
+ lines.push(this.renderRow(row, index === this.selectedIndex, width));
35
+ }
36
+ lines.push(border, ...wrapTextWithAnsi(this.theme.fg("dim", this.hints()), width));
37
+ return lines.map((line) => truncateToWidth(line, width));
38
+ }
39
+ handleInput(data) {
40
+ if (this.keys.matches(data, "tui.select.up"))
41
+ this.move(-1);
42
+ else if (this.keys.matches(data, "tui.select.down"))
43
+ this.move(1);
44
+ else if (this.keys.matches(data, "tui.select.confirm"))
45
+ this.select(this.selectedIndex);
46
+ else if (this.keys.matches(data, "tui.select.cancel")) {
47
+ this.onCancel();
48
+ return;
49
+ }
50
+ else
51
+ return;
52
+ this.tui.requestRender();
53
+ }
54
+ handleMouse(event) {
55
+ const index = this.rowLines.indexOf(event.y);
56
+ if (index < 0 || event.button !== "left")
57
+ return undefined;
58
+ if (event.type === "press") {
59
+ this.selectedIndex = index;
60
+ return { handled: true, focus: true };
61
+ }
62
+ if (event.type !== "click")
63
+ return undefined;
64
+ this.selectedIndex = index;
65
+ this.select(index);
66
+ return { handled: true, focus: true };
67
+ }
68
+ invalidate() {
69
+ this.rowLines = [];
70
+ }
71
+ move(delta) {
72
+ const count = this.rows.length;
73
+ this.selectedIndex = (this.selectedIndex + delta + count) % count;
74
+ }
75
+ select(index) {
76
+ const row = this.rows[index];
77
+ if (row)
78
+ this.onSelect(row.action);
79
+ }
80
+ renderRow(row, active, width) {
81
+ const cursor = active ? this.theme.fg("accent", "› ") : " ";
82
+ const label = row.field ? row.label + " ".repeat(this.labelWidth - visibleWidth(row.label)) : row.label;
83
+ const heading = cursor + this.theme.fg(active ? "accent" : "muted", label);
84
+ if (!row.field)
85
+ return truncateToWidth(heading, width);
86
+ return truncateToWidth(heading + this.renderValue(row.field, Math.max(0, width - visibleWidth(heading))), width);
87
+ }
88
+ /** Values keep their room before the inheritance marker degrades, because that marker is the meaning. */
89
+ renderValue(field, width) {
90
+ if (width < 1)
91
+ return "";
92
+ const follow = this.followText(field, width);
93
+ const status = field.status ?? "";
94
+ const statusWidth = status ? visibleWidth(status) + 1 : 0;
95
+ const value = truncateToWidth(field.value, Math.max(0, width - visibleWidth(follow) - statusWidth), "…");
96
+ const head = value + (status ? `${value ? " " : ""}${status}` : "");
97
+ const styled = this.theme.fg(field.tone ?? "text", truncateToWidth(head, width));
98
+ if (!follow)
99
+ return styled;
100
+ const room = width - visibleWidth(styled);
101
+ return room >= visibleWidth(follow) ? styled + this.theme.fg("dim", follow) : styled;
102
+ }
103
+ followText(field, width) {
104
+ if (!field.following)
105
+ return "";
106
+ const available = width - (field.status ? visibleWidth(field.status) + 1 : 0);
107
+ if (visibleWidth(FOLLOW) + VALUE_PRIORITY_WIDTH <= available)
108
+ return FOLLOW;
109
+ if (visibleWidth(FOLLOW_SHORT) + COMPACT_PRIORITY_WIDTH <= available)
110
+ return FOLLOW_SHORT;
111
+ return "";
112
+ }
113
+ hints() {
114
+ const navigation = [this.key("tui.select.up"), this.key("tui.select.down")].filter(Boolean).join("/");
115
+ const confirm = this.key("tui.select.confirm");
116
+ const cancel = this.key("tui.select.cancel");
117
+ return [navigation && `${navigation} navigate`, confirm && `${confirm} change`, cancel && `${cancel} close`]
118
+ .filter(Boolean)
119
+ .join(" · ");
120
+ }
121
+ key(action) {
122
+ return keyLabel(action, { keybindings: this.keys });
123
+ }
124
+ }
125
+ //# sourceMappingURL=settings-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-panel.js","sourceRoot":"","sources":["../../../src/extensions/agent/settings-panel.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype Component,\n\ttype TUI,\n\ttype TuiMouseEvent,\n\ttype TuiMouseEventResult,\n\ttruncateToWidth,\n\tvisibleWidth,\n\twrapTextWithAnsi,\n} from \"@earendil-works/pi-tui\";\nimport type { KeybindingsManager } from \"../../core/keybindings.ts\";\nimport { keyLabel } from \"../../modes/interactive/components/keybinding-hints.ts\";\nimport type { Theme } from \"../../modes/interactive/theme/theme.ts\";\n\nexport type AgentSettingsAction = \"model\" | \"thinking\" | \"reset\";\n\n/** The current value of a setting row; the reset action row carries no field. */\nexport interface AgentSettingsField {\n\tvalue: string;\n\tfollowing?: boolean;\n\tstatus?: string;\n\ttone?: \"warning\" | \"error\";\n}\n\nexport interface AgentSettingsRow {\n\taction: AgentSettingsAction;\n\tlabel: string;\n\tfield?: AgentSettingsField;\n}\n\nconst FOLLOW = \" · Follow current session\";\nconst FOLLOW_SHORT = \" · follow\";\n/** Room the value keeps before the full inheritance marker is shown. */\nconst VALUE_PRIORITY_WIDTH = 12;\n/** Room the value keeps once only the compact inheritance marker fits. */\nconst COMPACT_PRIORITY_WIDTH = 4;\n\n/** Aligned setting rows with one action row, navigated through the host keybindings. */\nexport class AgentSettingsPanel implements Component {\n\tprivate readonly tui: TUI;\n\tprivate readonly theme: Theme;\n\tprivate readonly keys: KeybindingsManager;\n\tprivate readonly rows: AgentSettingsRow[];\n\tprivate readonly onSelect: (action: AgentSettingsAction) => void;\n\tprivate readonly onCancel: () => void;\n\tprivate readonly labelWidth: number;\n\tprivate selectedIndex: number;\n\t/** Line index of each row, recorded while rendering so click hit-testing cannot drift. */\n\tprivate rowLines: number[] = [];\n\n\tconstructor(\n\t\ttui: TUI,\n\t\ttheme: Theme,\n\t\tkeys: KeybindingsManager,\n\t\trows: AgentSettingsRow[],\n\t\tselected: AgentSettingsAction,\n\t\tonSelect: (action: AgentSettingsAction) => void,\n\t\tonCancel: () => void,\n\t) {\n\t\tthis.tui = tui;\n\t\tthis.theme = theme;\n\t\tthis.keys = keys;\n\t\tthis.rows = rows;\n\t\tthis.onSelect = onSelect;\n\t\tthis.onCancel = onCancel;\n\t\tthis.selectedIndex = Math.max(\n\t\t\t0,\n\t\t\trows.findIndex((row) => row.action === selected),\n\t\t);\n\t\tconst labels = rows.flatMap((row) => (row.field ? [visibleWidth(row.label)] : []));\n\t\tthis.labelWidth = Math.max(0, ...labels) + 2;\n\t}\n\n\trender(width: number): string[] {\n\t\tif (width < 1) return [];\n\t\tconst border = this.theme.fg(\"borderMuted\", \"─\".repeat(width));\n\t\tconst lines = [this.theme.fg(\"accent\", this.theme.bold(\"Agent Settings\")), border];\n\t\tthis.rowLines = [];\n\t\tfor (const [index, row] of this.rows.entries()) {\n\t\t\tif (lines.length > 2) lines.push(\"\");\n\t\t\tthis.rowLines.push(lines.length);\n\t\t\tlines.push(this.renderRow(row, index === this.selectedIndex, width));\n\t\t}\n\t\tlines.push(border, ...wrapTextWithAnsi(this.theme.fg(\"dim\", this.hints()), width));\n\t\treturn lines.map((line) => truncateToWidth(line, width));\n\t}\n\n\thandleInput(data: string): void {\n\t\tif (this.keys.matches(data, \"tui.select.up\")) this.move(-1);\n\t\telse if (this.keys.matches(data, \"tui.select.down\")) this.move(1);\n\t\telse if (this.keys.matches(data, \"tui.select.confirm\")) this.select(this.selectedIndex);\n\t\telse if (this.keys.matches(data, \"tui.select.cancel\")) {\n\t\t\tthis.onCancel();\n\t\t\treturn;\n\t\t} else return;\n\t\tthis.tui.requestRender();\n\t}\n\n\thandleMouse(event: TuiMouseEvent): TuiMouseEventResult | undefined {\n\t\tconst index = this.rowLines.indexOf(event.y);\n\t\tif (index < 0 || event.button !== \"left\") return undefined;\n\t\tif (event.type === \"press\") {\n\t\t\tthis.selectedIndex = index;\n\t\t\treturn { handled: true, focus: true };\n\t\t}\n\t\tif (event.type !== \"click\") return undefined;\n\t\tthis.selectedIndex = index;\n\t\tthis.select(index);\n\t\treturn { handled: true, focus: true };\n\t}\n\n\tinvalidate(): void {\n\t\tthis.rowLines = [];\n\t}\n\n\tprivate move(delta: number): void {\n\t\tconst count = this.rows.length;\n\t\tthis.selectedIndex = (this.selectedIndex + delta + count) % count;\n\t}\n\n\tprivate select(index: number): void {\n\t\tconst row = this.rows[index];\n\t\tif (row) this.onSelect(row.action);\n\t}\n\n\tprivate renderRow(row: AgentSettingsRow, active: boolean, width: number): string {\n\t\tconst cursor = active ? this.theme.fg(\"accent\", \"› \") : \" \";\n\t\tconst label = row.field ? row.label + \" \".repeat(this.labelWidth - visibleWidth(row.label)) : row.label;\n\t\tconst heading = cursor + this.theme.fg(active ? \"accent\" : \"muted\", label);\n\t\tif (!row.field) return truncateToWidth(heading, width);\n\t\treturn truncateToWidth(heading + this.renderValue(row.field, Math.max(0, width - visibleWidth(heading))), width);\n\t}\n\n\t/** Values keep their room before the inheritance marker degrades, because that marker is the meaning. */\n\tprivate renderValue(field: AgentSettingsField, width: number): string {\n\t\tif (width < 1) return \"\";\n\t\tconst follow = this.followText(field, width);\n\t\tconst status = field.status ?? \"\";\n\t\tconst statusWidth = status ? visibleWidth(status) + 1 : 0;\n\t\tconst value = truncateToWidth(field.value, Math.max(0, width - visibleWidth(follow) - statusWidth), \"…\");\n\t\tconst head = value + (status ? `${value ? \" \" : \"\"}${status}` : \"\");\n\t\tconst styled = this.theme.fg(field.tone ?? \"text\", truncateToWidth(head, width));\n\t\tif (!follow) return styled;\n\t\tconst room = width - visibleWidth(styled);\n\t\treturn room >= visibleWidth(follow) ? styled + this.theme.fg(\"dim\", follow) : styled;\n\t}\n\n\tprivate followText(field: AgentSettingsField, width: number): string {\n\t\tif (!field.following) return \"\";\n\t\tconst available = width - (field.status ? visibleWidth(field.status) + 1 : 0);\n\t\tif (visibleWidth(FOLLOW) + VALUE_PRIORITY_WIDTH <= available) return FOLLOW;\n\t\tif (visibleWidth(FOLLOW_SHORT) + COMPACT_PRIORITY_WIDTH <= available) return FOLLOW_SHORT;\n\t\treturn \"\";\n\t}\n\n\tprivate hints(): string {\n\t\tconst navigation = [this.key(\"tui.select.up\"), this.key(\"tui.select.down\")].filter(Boolean).join(\"/\");\n\t\tconst confirm = this.key(\"tui.select.confirm\");\n\t\tconst cancel = this.key(\"tui.select.cancel\");\n\t\treturn [navigation && `${navigation} navigate`, confirm && `${confirm} change`, cancel && `${cancel} close`]\n\t\t\t.filter(Boolean)\n\t\t\t.join(\" · \");\n\t}\n\n\tprivate key(action: Parameters<typeof keyLabel>[0]): string {\n\t\treturn keyLabel(action, { keybindings: this.keys });\n\t}\n}\n"]}
@@ -0,0 +1,15 @@
1
+ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
+ import { type Model } from "@earendil-works/pi-ai/compat";
3
+ import type { ExtensionCommandContext, ExtensionContext } from "../../core/extensions/types.ts";
4
+ import { type AgentSettings } from "./types.ts";
5
+ type ModelContext = Pick<ExtensionContext, "model" | "modelRuntime" | "thinkingLevel">;
6
+ export declare function readAgentSettings(ctx: Pick<ExtensionContext, "getExtensionSettings">): AgentSettings;
7
+ export declare function resolveAgentConfiguration(ctx: ModelContext & Pick<ExtensionContext, "getExtensionSettings">): {
8
+ model: Model<any>;
9
+ thinking: ThinkingLevel;
10
+ settings: AgentSettings;
11
+ };
12
+ /** The native pickers save only Agent overrides; reset clears both in one write. */
13
+ export declare function openAgentSettings(ctx: ExtensionCommandContext): Promise<void>;
14
+ export {};
15
+ //# sourceMappingURL=settings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/settings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,EAAkD,KAAK,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAE1G,OAAO,KAAK,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAUhG,OAAO,EAA4B,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAG1E,KAAK,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,OAAO,GAAG,cAAc,GAAG,eAAe,CAAC,CAAC;AA8BvF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,IAAI,CAAC,gBAAgB,EAAE,sBAAsB,CAAC,GAAG,aAAa,CAOpG;AAgCD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,IAAI,CAAC,gBAAgB,EAAE,sBAAsB,CAAC,GAAG;IAC9G,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,QAAQ,EAAE,aAAa,CAAC;CACxB,CAYA;AAmGD,oFAAoF;AACpF,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,uBAAuB,GAAG,OAAO,CAAC,IAAI,CAAC,CAgEnF"}
@@ -0,0 +1,201 @@
1
+ import { clampThinkingLevel, getSupportedThinkingLevels } from "@earendil-works/pi-ai/compat";
2
+ import { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from "../../core/defaults.js";
3
+ import { truncateHead } from "../../core/tools/truncate.js";
4
+ import { ModelSelectorComponent } from "../../modes/interactive/components/model-selector.js";
5
+ import { ThinkingSelectorComponent } from "../../modes/interactive/components/thinking-selector.js";
6
+ import { AgentSettingsPanel, } from "./settings-panel.js";
7
+ import { AGENT_SETTINGS_NAMESPACE } from "./types.js";
8
+ function inspectAgentSettings(ctx) {
9
+ const raw = ctx.getExtensionSettings(AGENT_SETTINGS_NAMESPACE);
10
+ let model;
11
+ let invalidModel;
12
+ if (raw.model !== undefined) {
13
+ if (typeof raw.model === "string" && raw.model.includes("/")) {
14
+ model = raw.model;
15
+ }
16
+ else {
17
+ invalidModel = raw.model;
18
+ }
19
+ }
20
+ let thinking;
21
+ let invalidThinking;
22
+ if (raw.thinking !== undefined) {
23
+ if (typeof raw.thinking === "string" && THINKING_LEVEL_OPTIONS.includes(raw.thinking)) {
24
+ thinking = raw.thinking;
25
+ }
26
+ else {
27
+ invalidThinking = raw.thinking;
28
+ }
29
+ }
30
+ return { model, thinking, invalidModel, invalidThinking };
31
+ }
32
+ export function readAgentSettings(ctx) {
33
+ const inspection = inspectAgentSettings(ctx);
34
+ if (inspection.invalidModel !== undefined)
35
+ throw new Error("Invalid Agent model setting. Choose a model with /agent.");
36
+ if (inspection.invalidThinking !== undefined)
37
+ throw new Error("Invalid Agent effort setting. Choose an effort level with /agent.");
38
+ return { model: inspection.model, thinking: inspection.thinking };
39
+ }
40
+ function resolveAgentModel(ctx, reference) {
41
+ if (!reference)
42
+ return ctx.model ? { model: ctx.model, available: true } : undefined;
43
+ const slash = reference.indexOf("/");
44
+ if (slash <= 0)
45
+ return undefined;
46
+ const model = ctx.modelRuntime.getModel(reference.slice(0, slash), reference.slice(slash + 1));
47
+ if (!model)
48
+ return undefined;
49
+ const available = ctx.modelRuntime
50
+ .getAvailableSnapshot()
51
+ .some((item) => item.provider === model.provider && item.id === model.id);
52
+ return { model, available };
53
+ }
54
+ function requestedEffort(ctx, settings) {
55
+ return settings.thinking ?? ctx.thinkingLevel ?? DEFAULT_THINKING_LEVEL;
56
+ }
57
+ /** Clamp a requested level to what the model supports. */
58
+ function supportedEffort(model, requested) {
59
+ return clampThinkingLevel(model, requested);
60
+ }
61
+ export function resolveAgentConfiguration(ctx) {
62
+ const settings = readAgentSettings(ctx);
63
+ const resolution = resolveAgentModel(ctx, settings.model);
64
+ if (!resolution) {
65
+ if (settings.model)
66
+ throw new Error(`Agent model is unavailable: ${settings.model}`);
67
+ throw new Error("Agent has no model to follow. Choose one with /agent.");
68
+ }
69
+ return {
70
+ model: resolution.model,
71
+ thinking: supportedEffort(resolution.model, requestedEffort(ctx, settings)),
72
+ settings,
73
+ };
74
+ }
75
+ async function saveAgentSettings(ctx, patch) {
76
+ const next = { ...ctx.getExtensionSettings(AGENT_SETTINGS_NAMESPACE) };
77
+ if (patch.model === null || patch.model === "")
78
+ delete next.model;
79
+ else if (patch.model !== undefined)
80
+ next.model = patch.model;
81
+ if (patch.thinking === null)
82
+ delete next.thinking;
83
+ else if (patch.thinking !== undefined)
84
+ next.thinking = patch.thinking;
85
+ await ctx.setExtensionSettings(AGENT_SETTINGS_NAMESPACE, next);
86
+ }
87
+ async function selectAgentModel(ctx, current) {
88
+ // Preselect the saved reference even when it is unavailable, so the picker can repair it.
89
+ const saved = resolveAgentModel(ctx, current)?.model;
90
+ const selected = await ctx.ui.custom((tui, _theme, _keys, done) => new ModelSelectorComponent(tui, saved ?? ctx.model, ctx.modelRuntime, ctx.scopedModels, done, () => done(undefined)));
91
+ return selected ? `${selected.provider}/${selected.id}` : undefined;
92
+ }
93
+ async function selectAgentThinking(ctx, settings, model) {
94
+ const requested = requestedEffort(ctx, settings);
95
+ const current = model ? supportedEffort(model, requested) : requested;
96
+ const available = model ? getSupportedThinkingLevels(model) : [...THINKING_LEVEL_OPTIONS];
97
+ return ctx.ui.custom((_tui, _theme, _keys, done) => new ThinkingSelectorComponent(current, available, done, () => done(undefined)));
98
+ }
99
+ function formatInvalidValue(value) {
100
+ let text = "";
101
+ try {
102
+ text = typeof value === "string" ? value : (JSON.stringify(value) ?? "");
103
+ }
104
+ catch { }
105
+ return truncateHead(text, { maxLines: 1, maxBytes: 80 }).content;
106
+ }
107
+ function invalidField(raw) {
108
+ return { value: formatInvalidValue(raw), status: "[invalid]", tone: "error" };
109
+ }
110
+ function describeModel(inspection, resolution) {
111
+ if (inspection.invalidModel !== undefined)
112
+ return invalidField(inspection.invalidModel);
113
+ if (!resolution)
114
+ return { value: inspection.model ?? "", status: "[unavailable]", tone: "warning" };
115
+ return {
116
+ value: `${resolution.model.provider}/${resolution.model.id}`,
117
+ following: inspection.model === undefined,
118
+ ...(resolution.available ? {} : { status: "[unavailable]", tone: "warning" }),
119
+ };
120
+ }
121
+ function describeEffort(ctx, inspection, model) {
122
+ if (inspection.invalidThinking !== undefined)
123
+ return invalidField(inspection.invalidThinking);
124
+ const requested = requestedEffort(ctx, inspection);
125
+ const following = inspection.thinking === undefined;
126
+ if (!model)
127
+ return { value: requested, following, status: "[unresolved]", tone: "warning" };
128
+ const effective = supportedEffort(model, requested);
129
+ if (effective === requested)
130
+ return { value: requested, following };
131
+ return { value: `${requested} → ${effective}`, following, tone: "warning" };
132
+ }
133
+ function hasOverrides(inspection) {
134
+ return (inspection.model !== undefined ||
135
+ inspection.thinking !== undefined ||
136
+ inspection.invalidModel !== undefined ||
137
+ inspection.invalidThinking !== undefined);
138
+ }
139
+ function settingsRows(ctx, inspection, resolution) {
140
+ return [
141
+ { action: "model", label: "Model", field: describeModel(inspection, resolution) },
142
+ { action: "thinking", label: "Effort", field: describeEffort(ctx, inspection, resolution?.model) },
143
+ { action: "reset", label: "Reset to follow current session" },
144
+ ];
145
+ }
146
+ /** The native pickers save only Agent overrides; reset clears both in one write. */
147
+ export async function openAgentSettings(ctx) {
148
+ if (ctx.mode !== "tui") {
149
+ try {
150
+ const settings = readAgentSettings(ctx);
151
+ ctx.ui.notify(`Agent model: ${settings.model ?? "Follow current session"} · Effort: ${settings.thinking ?? "Follow current session"}`, "info");
152
+ }
153
+ catch (error) {
154
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
155
+ }
156
+ return;
157
+ }
158
+ let selectedAction = "model";
159
+ while (true) {
160
+ let inspection;
161
+ try {
162
+ inspection = inspectAgentSettings(ctx);
163
+ }
164
+ catch (error) {
165
+ ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
166
+ return;
167
+ }
168
+ const resolution = inspection.invalidModel !== undefined ? undefined : resolveAgentModel(ctx, inspection.model);
169
+ const action = await ctx.ui.custom((tui, theme, keys, done) => new AgentSettingsPanel(tui, theme, keys, settingsRows(ctx, inspection, resolution), selectedAction, done, () => done(undefined)));
170
+ if (!action)
171
+ return;
172
+ selectedAction = action;
173
+ try {
174
+ if (action === "reset") {
175
+ if (!hasOverrides(inspection))
176
+ continue;
177
+ await saveAgentSettings(ctx, { model: null, thinking: null });
178
+ ctx.ui.notify("Agent settings: Follow current session", "info");
179
+ }
180
+ else if (action === "model") {
181
+ const selected = await selectAgentModel(ctx, inspection.model ?? "");
182
+ if (selected === undefined || selected === inspection.model)
183
+ continue;
184
+ await saveAgentSettings(ctx, { model: selected });
185
+ ctx.ui.notify(`Agent model: ${selected}`, "info");
186
+ }
187
+ else if (action === "thinking") {
188
+ const selected = await selectAgentThinking(ctx, inspection, resolution?.model);
189
+ if (selected === undefined ||
190
+ (selected === inspection.thinking && inspection.invalidThinking === undefined))
191
+ continue;
192
+ await saveAgentSettings(ctx, { thinking: selected });
193
+ ctx.ui.notify(`Agent effort: ${selected}`, "info");
194
+ }
195
+ }
196
+ catch (error) {
197
+ ctx.ui.notify(`Could not save Agent settings: ${error instanceof Error ? error.message : String(error)}`, "error");
198
+ }
199
+ }
200
+ }
201
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/extensions/agent/settings.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport { clampThinkingLevel, getSupportedThinkingLevels, type Model } from \"@earendil-works/pi-ai/compat\";\nimport { DEFAULT_THINKING_LEVEL, THINKING_LEVEL_OPTIONS } from \"../../core/defaults.ts\";\nimport type { ExtensionCommandContext, ExtensionContext } from \"../../core/extensions/types.ts\";\nimport { truncateHead } from \"../../core/tools/truncate.ts\";\nimport { ModelSelectorComponent } from \"../../modes/interactive/components/model-selector.ts\";\nimport { ThinkingSelectorComponent } from \"../../modes/interactive/components/thinking-selector.ts\";\nimport {\n\ttype AgentSettingsAction,\n\ttype AgentSettingsField,\n\tAgentSettingsPanel,\n\ttype AgentSettingsRow,\n} from \"./settings-panel.ts\";\nimport { AGENT_SETTINGS_NAMESPACE, type AgentSettings } from \"./types.ts\";\n\ntype SettingsContext = Pick<ExtensionContext, \"getExtensionSettings\" | \"setExtensionSettings\">;\ntype ModelContext = Pick<ExtensionContext, \"model\" | \"modelRuntime\" | \"thinkingLevel\">;\n\ninterface InspectedAgentSettings extends AgentSettings {\n\tinvalidModel?: unknown;\n\tinvalidThinking?: unknown;\n}\n\nfunction inspectAgentSettings(ctx: Pick<ExtensionContext, \"getExtensionSettings\">): InspectedAgentSettings {\n\tconst raw = ctx.getExtensionSettings(AGENT_SETTINGS_NAMESPACE);\n\tlet model: string | undefined;\n\tlet invalidModel: unknown;\n\tif (raw.model !== undefined) {\n\t\tif (typeof raw.model === \"string\" && raw.model.includes(\"/\")) {\n\t\t\tmodel = raw.model;\n\t\t} else {\n\t\t\tinvalidModel = raw.model;\n\t\t}\n\t}\n\tlet thinking: ThinkingLevel | undefined;\n\tlet invalidThinking: unknown;\n\tif (raw.thinking !== undefined) {\n\t\tif (typeof raw.thinking === \"string\" && THINKING_LEVEL_OPTIONS.includes(raw.thinking as ThinkingLevel)) {\n\t\t\tthinking = raw.thinking as ThinkingLevel;\n\t\t} else {\n\t\t\tinvalidThinking = raw.thinking;\n\t\t}\n\t}\n\treturn { model, thinking, invalidModel, invalidThinking };\n}\n\nexport function readAgentSettings(ctx: Pick<ExtensionContext, \"getExtensionSettings\">): AgentSettings {\n\tconst inspection = inspectAgentSettings(ctx);\n\tif (inspection.invalidModel !== undefined)\n\t\tthrow new Error(\"Invalid Agent model setting. Choose a model with /agent.\");\n\tif (inspection.invalidThinking !== undefined)\n\t\tthrow new Error(\"Invalid Agent effort setting. Choose an effort level with /agent.\");\n\treturn { model: inspection.model, thinking: inspection.thinking };\n}\n\ninterface AgentModelResolution {\n\tmodel: Model<any>;\n\t/** Listed by `/model` right now. The availability snapshot can lag auth changes, so this is display-only. */\n\tavailable: boolean;\n}\n\nfunction resolveAgentModel(\n\tctx: Pick<ModelContext, \"model\" | \"modelRuntime\">,\n\treference?: string,\n): AgentModelResolution | undefined {\n\tif (!reference) return ctx.model ? { model: ctx.model, available: true } : undefined;\n\tconst slash = reference.indexOf(\"/\");\n\tif (slash <= 0) return undefined;\n\tconst model = ctx.modelRuntime.getModel(reference.slice(0, slash), reference.slice(slash + 1));\n\tif (!model) return undefined;\n\tconst available = ctx.modelRuntime\n\t\t.getAvailableSnapshot()\n\t\t.some((item) => item.provider === model.provider && item.id === model.id);\n\treturn { model, available };\n}\n\nfunction requestedEffort(ctx: Pick<ModelContext, \"thinkingLevel\">, settings: AgentSettings): ThinkingLevel {\n\treturn settings.thinking ?? ctx.thinkingLevel ?? DEFAULT_THINKING_LEVEL;\n}\n\n/** Clamp a requested level to what the model supports. */\nfunction supportedEffort(model: Model<any>, requested: ThinkingLevel): ThinkingLevel {\n\treturn clampThinkingLevel(model, requested) as ThinkingLevel;\n}\n\nexport function resolveAgentConfiguration(ctx: ModelContext & Pick<ExtensionContext, \"getExtensionSettings\">): {\n\tmodel: Model<any>;\n\tthinking: ThinkingLevel;\n\tsettings: AgentSettings;\n} {\n\tconst settings = readAgentSettings(ctx);\n\tconst resolution = resolveAgentModel(ctx, settings.model);\n\tif (!resolution) {\n\t\tif (settings.model) throw new Error(`Agent model is unavailable: ${settings.model}`);\n\t\tthrow new Error(\"Agent has no model to follow. Choose one with /agent.\");\n\t}\n\treturn {\n\t\tmodel: resolution.model,\n\t\tthinking: supportedEffort(resolution.model, requestedEffort(ctx, settings)),\n\t\tsettings,\n\t};\n}\n\nasync function saveAgentSettings(\n\tctx: SettingsContext,\n\tpatch: { model?: string | null; thinking?: ThinkingLevel | null },\n): Promise<void> {\n\tconst next = { ...ctx.getExtensionSettings(AGENT_SETTINGS_NAMESPACE) };\n\tif (patch.model === null || patch.model === \"\") delete next.model;\n\telse if (patch.model !== undefined) next.model = patch.model;\n\tif (patch.thinking === null) delete next.thinking;\n\telse if (patch.thinking !== undefined) next.thinking = patch.thinking;\n\tawait ctx.setExtensionSettings(AGENT_SETTINGS_NAMESPACE, next);\n}\n\nasync function selectAgentModel(ctx: ExtensionCommandContext, current: string): Promise<string | undefined> {\n\t// Preselect the saved reference even when it is unavailable, so the picker can repair it.\n\tconst saved = resolveAgentModel(ctx, current)?.model;\n\tconst selected = await ctx.ui.custom<Model<any> | undefined>(\n\t\t(tui, _theme, _keys, done) =>\n\t\t\tnew ModelSelectorComponent(tui, saved ?? ctx.model, ctx.modelRuntime, ctx.scopedModels, done, () =>\n\t\t\t\tdone(undefined),\n\t\t\t),\n\t);\n\treturn selected ? `${selected.provider}/${selected.id}` : undefined;\n}\n\nasync function selectAgentThinking(\n\tctx: ExtensionCommandContext,\n\tsettings: AgentSettings,\n\tmodel: Model<any> | undefined,\n): Promise<ThinkingLevel | undefined> {\n\tconst requested = requestedEffort(ctx, settings);\n\tconst current = model ? supportedEffort(model, requested) : requested;\n\tconst available = model ? getSupportedThinkingLevels(model) : [...THINKING_LEVEL_OPTIONS];\n\treturn ctx.ui.custom<ThinkingLevel | undefined>(\n\t\t(_tui, _theme, _keys, done) => new ThinkingSelectorComponent(current, available, done, () => done(undefined)),\n\t);\n}\n\nfunction formatInvalidValue(value: unknown): string {\n\tlet text = \"\";\n\ttry {\n\t\ttext = typeof value === \"string\" ? value : (JSON.stringify(value) ?? \"\");\n\t} catch {}\n\treturn truncateHead(text, { maxLines: 1, maxBytes: 80 }).content;\n}\n\nfunction invalidField(raw: unknown): AgentSettingsField {\n\treturn { value: formatInvalidValue(raw), status: \"[invalid]\", tone: \"error\" };\n}\n\nfunction describeModel(\n\tinspection: InspectedAgentSettings,\n\tresolution: AgentModelResolution | undefined,\n): AgentSettingsField {\n\tif (inspection.invalidModel !== undefined) return invalidField(inspection.invalidModel);\n\tif (!resolution) return { value: inspection.model ?? \"\", status: \"[unavailable]\", tone: \"warning\" };\n\treturn {\n\t\tvalue: `${resolution.model.provider}/${resolution.model.id}`,\n\t\tfollowing: inspection.model === undefined,\n\t\t...(resolution.available ? {} : { status: \"[unavailable]\", tone: \"warning\" as const }),\n\t};\n}\n\nfunction describeEffort(\n\tctx: ModelContext,\n\tinspection: InspectedAgentSettings,\n\tmodel: Model<any> | undefined,\n): AgentSettingsField {\n\tif (inspection.invalidThinking !== undefined) return invalidField(inspection.invalidThinking);\n\tconst requested = requestedEffort(ctx, inspection);\n\tconst following = inspection.thinking === undefined;\n\tif (!model) return { value: requested, following, status: \"[unresolved]\", tone: \"warning\" };\n\tconst effective = supportedEffort(model, requested);\n\tif (effective === requested) return { value: requested, following };\n\treturn { value: `${requested} → ${effective}`, following, tone: \"warning\" };\n}\n\nfunction hasOverrides(inspection: InspectedAgentSettings): boolean {\n\treturn (\n\t\tinspection.model !== undefined ||\n\t\tinspection.thinking !== undefined ||\n\t\tinspection.invalidModel !== undefined ||\n\t\tinspection.invalidThinking !== undefined\n\t);\n}\n\nfunction settingsRows(\n\tctx: ModelContext,\n\tinspection: InspectedAgentSettings,\n\tresolution: AgentModelResolution | undefined,\n): AgentSettingsRow[] {\n\treturn [\n\t\t{ action: \"model\", label: \"Model\", field: describeModel(inspection, resolution) },\n\t\t{ action: \"thinking\", label: \"Effort\", field: describeEffort(ctx, inspection, resolution?.model) },\n\t\t{ action: \"reset\", label: \"Reset to follow current session\" },\n\t];\n}\n\n/** The native pickers save only Agent overrides; reset clears both in one write. */\nexport async function openAgentSettings(ctx: ExtensionCommandContext): Promise<void> {\n\tif (ctx.mode !== \"tui\") {\n\t\ttry {\n\t\t\tconst settings = readAgentSettings(ctx);\n\t\t\tctx.ui.notify(\n\t\t\t\t`Agent model: ${settings.model ?? \"Follow current session\"} · Effort: ${settings.thinking ?? \"Follow current session\"}`,\n\t\t\t\t\"info\",\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t}\n\t\treturn;\n\t}\n\tlet selectedAction: AgentSettingsAction = \"model\";\n\twhile (true) {\n\t\tlet inspection: InspectedAgentSettings;\n\t\ttry {\n\t\t\tinspection = inspectAgentSettings(ctx);\n\t\t} catch (error) {\n\t\t\tctx.ui.notify(error instanceof Error ? error.message : String(error), \"error\");\n\t\t\treturn;\n\t\t}\n\t\tconst resolution = inspection.invalidModel !== undefined ? undefined : resolveAgentModel(ctx, inspection.model);\n\t\tconst action = await ctx.ui.custom<AgentSettingsAction | undefined>(\n\t\t\t(tui, theme, keys, done) =>\n\t\t\t\tnew AgentSettingsPanel(\n\t\t\t\t\ttui,\n\t\t\t\t\ttheme,\n\t\t\t\t\tkeys,\n\t\t\t\t\tsettingsRows(ctx, inspection, resolution),\n\t\t\t\t\tselectedAction,\n\t\t\t\t\tdone,\n\t\t\t\t\t() => done(undefined),\n\t\t\t\t),\n\t\t);\n\t\tif (!action) return;\n\t\tselectedAction = action;\n\t\ttry {\n\t\t\tif (action === \"reset\") {\n\t\t\t\tif (!hasOverrides(inspection)) continue;\n\t\t\t\tawait saveAgentSettings(ctx, { model: null, thinking: null });\n\t\t\t\tctx.ui.notify(\"Agent settings: Follow current session\", \"info\");\n\t\t\t} else if (action === \"model\") {\n\t\t\t\tconst selected = await selectAgentModel(ctx, inspection.model ?? \"\");\n\t\t\t\tif (selected === undefined || selected === inspection.model) continue;\n\t\t\t\tawait saveAgentSettings(ctx, { model: selected });\n\t\t\t\tctx.ui.notify(`Agent model: ${selected}`, \"info\");\n\t\t\t} else if (action === \"thinking\") {\n\t\t\t\tconst selected = await selectAgentThinking(ctx, inspection, resolution?.model);\n\t\t\t\tif (\n\t\t\t\t\tselected === undefined ||\n\t\t\t\t\t(selected === inspection.thinking && inspection.invalidThinking === undefined)\n\t\t\t\t)\n\t\t\t\t\tcontinue;\n\t\t\t\tawait saveAgentSettings(ctx, { thinking: selected });\n\t\t\t\tctx.ui.notify(`Agent effort: ${selected}`, \"info\");\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tctx.ui.notify(\n\t\t\t\t`Could not save Agent settings: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t\"error\",\n\t\t\t);\n\t\t}\n\t}\n}\n"]}
@@ -0,0 +1,13 @@
1
+ import { Type } from "typebox";
2
+ import type { ToolDefinition } from "../../core/extensions/types.ts";
3
+ import { type AgentToolDetails } from "./types.ts";
4
+ declare const agentSchema: Type.TObject<{
5
+ prompt: Type.TString;
6
+ description: Type.TOptional<Type.TString>;
7
+ background: Type.TOptional<Type.TBoolean>;
8
+ }>;
9
+ export declare function createAgentTool(options?: {
10
+ concurrency?: number;
11
+ }): ToolDefinition<typeof agentSchema, AgentToolDetails>;
12
+ export {};
13
+ //# sourceMappingURL=tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC/B,OAAO,KAAK,EAAmB,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAMtF,OAAO,EAAyC,KAAK,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAG1F,QAAA,MAAM,WAAW;;;;EAYhB,CAAC;AAmBF,wBAAgB,eAAe,CAC9B,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAO,GACpC,cAAc,CAAC,OAAO,WAAW,EAAE,gBAAgB,CAAC,CAmDtD"}
@@ -0,0 +1,84 @@
1
+ import { Type } from "typebox";
2
+ import { defineTool } from "../../core/extensions/types.js";
3
+ import { clipText } from "./activity.js";
4
+ import { agentRenderers } from "./render.js";
5
+ import { resolveAgentConfiguration } from "./settings.js";
6
+ import { AGENT_CONCURRENCY, AGENT_PROMPT_BYTES } from "./types.js";
7
+ import { runWorker } from "./worker.js";
8
+ const agentSchema = Type.Object({
9
+ prompt: Type.String({
10
+ minLength: 1,
11
+ description: "Complete, self-contained task briefing; the Agent cannot see this conversation",
12
+ }),
13
+ description: Type.Optional(Type.String({ description: "Short task label for the transcript and Tasks panel" })),
14
+ background: Type.Optional(Type.Boolean({ description: "Return a task ID and deliver the final report asynchronously" })),
15
+ }, { additionalProperties: false });
16
+ /** The model-facing handoff: who moved the Agent, whether it waits for a slot, and how to follow it. */
17
+ function handoffResult(task, byUser) {
18
+ const moved = byUser
19
+ ? `The user moved this Agent to the background while it was running: ${task.id}. It continues unchanged.`
20
+ : `Agent running in background: ${task.id}.`;
21
+ const queued = task.status === "queued" ? " It is queued until an Agent slot frees." : "";
22
+ return {
23
+ content: [
24
+ {
25
+ type: "text",
26
+ text: `${moved}${queued} The report will be delivered automatically. Use tasks read/wait/kill to inspect, wait or stop.`,
27
+ },
28
+ ],
29
+ details: { version: 2, state: "background", taskId: task.id, byUser },
30
+ };
31
+ }
32
+ export function createAgentTool(options = {}) {
33
+ const limit = options.concurrency ?? AGENT_CONCURRENCY;
34
+ return defineTool({
35
+ name: "Agent",
36
+ label: "Agent",
37
+ description: "Delegate independent work to a temporary isolated Agent when separate context or parallel execution offers a clear benefit. Use sparingly; handle known-path reads and small edits directly. The Agent cannot see the parent conversation, so include all necessary context and desired verification in prompt. Foreground returns the final report; background returns a task ID and delivers it automatically.",
38
+ promptSnippet: "Delegate an independent task",
39
+ promptGuidelines: [
40
+ "Give Agent a complete, self-contained briefing with relevant paths, constraints and expected verification; use parallel calls only for independent, non-overlapping work.",
41
+ ],
42
+ parameters: agentSchema,
43
+ constrainedSampling: { type: "json_schema", strict: "prefer" },
44
+ executionMode: "parallel",
45
+ async execute(toolCallId, params, signal, onUpdate, ctx) {
46
+ if (!params.prompt.trim() || Buffer.byteLength(params.prompt) > AGENT_PROMPT_BYTES)
47
+ throw new Error("Agent prompt must contain text and fit within 16 KiB.");
48
+ const { model, thinking } = resolveAgentConfiguration(ctx);
49
+ const auth = await ctx.modelRuntime.getAuth(model, { signal });
50
+ if (!auth)
51
+ throw new Error(`No authentication for Agent model ${model.provider}/${model.id}`);
52
+ const outcome = await ctx.tasks.execute({
53
+ kind: "agent",
54
+ label: "Agent",
55
+ title: clipText((params.description?.trim() || params.prompt).replace(/\s+/gu, " ").trim(), 160),
56
+ output: "report",
57
+ input: { label: "Prompt", text: params.prompt, truncated: false },
58
+ facts: [
59
+ ["Model", `${model.provider}/${model.id}`],
60
+ ["Thinking", thinking],
61
+ ["Directory", ctx.cwd],
62
+ ],
63
+ concurrency: { key: "agent", limit },
64
+ toolCallId,
65
+ background: params.background,
66
+ signal,
67
+ onUpdate,
68
+ run: (control) => runWorker(control, {
69
+ prompt: params.prompt,
70
+ cwd: ctx.cwd,
71
+ model,
72
+ thinking,
73
+ modelRuntime: ctx.modelRuntime,
74
+ projectTrusted: ctx.isProjectTrusted(),
75
+ }),
76
+ });
77
+ if (outcome.kind === "result")
78
+ return outcome.result;
79
+ return handoffResult(outcome.task, params.background !== true);
80
+ },
81
+ ...agentRenderers,
82
+ });
83
+ }
84
+ //# sourceMappingURL=tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool.js","sourceRoot":"","sources":["../../../src/extensions/agent/tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAE/B,OAAO,EAAE,UAAU,EAAE,MAAM,gCAAgC,CAAC;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAE,kBAAkB,EAAyB,MAAM,YAAY,CAAC;AAC1F,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAExC,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAC9B;IACC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;QACnB,SAAS,EAAE,CAAC;QACZ,WAAW,EAAE,gFAAgF;KAC7F,CAAC;IACF,WAAW,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,qDAAqD,EAAE,CAAC,CAAC;IAC/G,UAAU,EAAE,IAAI,CAAC,QAAQ,CACxB,IAAI,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,8DAA8D,EAAE,CAAC,CAC7F;CACD,EACD,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAC/B,CAAC;AAEF,wGAAwG;AACxG,SAAS,aAAa,CAAC,IAAkB,EAAE,MAAe;IACzD,MAAM,KAAK,GAAG,MAAM;QACnB,CAAC,CAAC,qEAAqE,IAAI,CAAC,EAAE,2BAA2B;QACzG,CAAC,CAAC,gCAAgC,IAAI,CAAC,EAAE,GAAG,CAAC;IAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,0CAA0C,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1F,OAAO;QACN,OAAO,EAAE;YACR;gBACC,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,GAAG,KAAK,GAAG,MAAM,iGAAiG;aACxH;SACD;QACD,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE;KACrE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAC9B,UAAoC,EAAE;IAEtC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,IAAI,iBAAiB,CAAC;IACvD,OAAO,UAAU,CAAC;QACjB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,OAAO;QACd,WAAW,EACV,kZAAkZ;QACnZ,aAAa,EAAE,8BAA8B;QAC7C,gBAAgB,EAAE;YACjB,2KAA2K;SAC3K;QACD,UAAU,EAAE,WAAW;QACvB,mBAAmB,EAAE,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,QAAQ,EAAE;QAC9D,aAAa,EAAE,UAAU;QACzB,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG;YACtD,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,kBAAkB;gBACjF,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;YAC1E,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,yBAAyB,CAAC,GAAG,CAAC,CAAC;YAC3D,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,YAAY,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;YAC/D,IAAI,CAAC,IAAI;gBAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;YAC9F,MAAM,OAAO,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC,OAAO,CAAmB;gBACzD,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,OAAO;gBACd,KAAK,EAAE,QAAQ,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,GAAG,CAAC;gBAChG,MAAM,EAAE,QAAQ;gBAChB,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE;gBACjE,KAAK,EAAE;oBACN,CAAC,OAAO,EAAE,GAAG,KAAK,CAAC,QAAQ,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;oBAC1C,CAAC,UAAU,EAAE,QAAQ,CAAC;oBACtB,CAAC,WAAW,EAAE,GAAG,CAAC,GAAG,CAAC;iBACtB;gBACD,WAAW,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE;gBACpC,UAAU;gBACV,UAAU,EAAE,MAAM,CAAC,UAAU;gBAC7B,MAAM;gBACN,QAAQ;gBACR,GAAG,EAAE,CAAC,OAAO,EAAE,EAAE,CAChB,SAAS,CAAC,OAAO,EAAE;oBAClB,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,GAAG,EAAE,GAAG,CAAC,GAAG;oBACZ,KAAK;oBACL,QAAQ;oBACR,YAAY,EAAE,GAAG,CAAC,YAAY;oBAC9B,cAAc,EAAE,GAAG,CAAC,gBAAgB,EAAE;iBACtC,CAAC;aACH,CAAC,CAAC;YACH,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,OAAO,CAAC,MAAM,CAAC;YACrD,OAAO,aAAa,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,UAAU,KAAK,IAAI,CAAC,CAAC;QAChE,CAAC;QACD,GAAG,cAAc;KACjB,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import { Type } from \"typebox\";\nimport type { AgentToolResult, ToolDefinition } from \"../../core/extensions/types.ts\";\nimport { defineTool } from \"../../core/extensions/types.ts\";\nimport type { TaskSnapshot } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { agentRenderers } from \"./render.ts\";\nimport { resolveAgentConfiguration } from \"./settings.ts\";\nimport { AGENT_CONCURRENCY, AGENT_PROMPT_BYTES, type AgentToolDetails } from \"./types.ts\";\nimport { runWorker } from \"./worker.ts\";\n\nconst agentSchema = Type.Object(\n\t{\n\t\tprompt: Type.String({\n\t\t\tminLength: 1,\n\t\t\tdescription: \"Complete, self-contained task briefing; the Agent cannot see this conversation\",\n\t\t}),\n\t\tdescription: Type.Optional(Type.String({ description: \"Short task label for the transcript and Tasks panel\" })),\n\t\tbackground: Type.Optional(\n\t\t\tType.Boolean({ description: \"Return a task ID and deliver the final report asynchronously\" }),\n\t\t),\n\t},\n\t{ additionalProperties: false },\n);\n\n/** The model-facing handoff: who moved the Agent, whether it waits for a slot, and how to follow it. */\nfunction handoffResult(task: TaskSnapshot, byUser: boolean): AgentToolResult<AgentToolDetails> {\n\tconst moved = byUser\n\t\t? `The user moved this Agent to the background while it was running: ${task.id}. It continues unchanged.`\n\t\t: `Agent running in background: ${task.id}.`;\n\tconst queued = task.status === \"queued\" ? \" It is queued until an Agent slot frees.\" : \"\";\n\treturn {\n\t\tcontent: [\n\t\t\t{\n\t\t\t\ttype: \"text\",\n\t\t\t\ttext: `${moved}${queued} The report will be delivered automatically. Use tasks read/wait/kill to inspect, wait or stop.`,\n\t\t\t},\n\t\t],\n\t\tdetails: { version: 2, state: \"background\", taskId: task.id, byUser },\n\t};\n}\n\nexport function createAgentTool(\n\toptions: { concurrency?: number } = {},\n): ToolDefinition<typeof agentSchema, AgentToolDetails> {\n\tconst limit = options.concurrency ?? AGENT_CONCURRENCY;\n\treturn defineTool({\n\t\tname: \"Agent\",\n\t\tlabel: \"Agent\",\n\t\tdescription:\n\t\t\t\"Delegate independent work to a temporary isolated Agent when separate context or parallel execution offers a clear benefit. Use sparingly; handle known-path reads and small edits directly. The Agent cannot see the parent conversation, so include all necessary context and desired verification in prompt. Foreground returns the final report; background returns a task ID and delivers it automatically.\",\n\t\tpromptSnippet: \"Delegate an independent task\",\n\t\tpromptGuidelines: [\n\t\t\t\"Give Agent a complete, self-contained briefing with relevant paths, constraints and expected verification; use parallel calls only for independent, non-overlapping work.\",\n\t\t],\n\t\tparameters: agentSchema,\n\t\tconstrainedSampling: { type: \"json_schema\", strict: \"prefer\" },\n\t\texecutionMode: \"parallel\",\n\t\tasync execute(toolCallId, params, signal, onUpdate, ctx) {\n\t\t\tif (!params.prompt.trim() || Buffer.byteLength(params.prompt) > AGENT_PROMPT_BYTES)\n\t\t\t\tthrow new Error(\"Agent prompt must contain text and fit within 16 KiB.\");\n\t\t\tconst { model, thinking } = resolveAgentConfiguration(ctx);\n\t\t\tconst auth = await ctx.modelRuntime.getAuth(model, { signal });\n\t\t\tif (!auth) throw new Error(`No authentication for Agent model ${model.provider}/${model.id}`);\n\t\t\tconst outcome = await ctx.tasks.execute<AgentToolDetails>({\n\t\t\t\tkind: \"agent\",\n\t\t\t\tlabel: \"Agent\",\n\t\t\t\ttitle: clipText((params.description?.trim() || params.prompt).replace(/\\s+/gu, \" \").trim(), 160),\n\t\t\t\toutput: \"report\",\n\t\t\t\tinput: { label: \"Prompt\", text: params.prompt, truncated: false },\n\t\t\t\tfacts: [\n\t\t\t\t\t[\"Model\", `${model.provider}/${model.id}`],\n\t\t\t\t\t[\"Thinking\", thinking],\n\t\t\t\t\t[\"Directory\", ctx.cwd],\n\t\t\t\t],\n\t\t\t\tconcurrency: { key: \"agent\", limit },\n\t\t\t\ttoolCallId,\n\t\t\t\tbackground: params.background,\n\t\t\t\tsignal,\n\t\t\t\tonUpdate,\n\t\t\t\trun: (control) =>\n\t\t\t\t\trunWorker(control, {\n\t\t\t\t\t\tprompt: params.prompt,\n\t\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\tthinking,\n\t\t\t\t\t\tmodelRuntime: ctx.modelRuntime,\n\t\t\t\t\t\tprojectTrusted: ctx.isProjectTrusted(),\n\t\t\t\t\t}),\n\t\t\t});\n\t\t\tif (outcome.kind === \"result\") return outcome.result;\n\t\t\treturn handoffResult(outcome.task, params.background !== true);\n\t\t},\n\t\t...agentRenderers,\n\t});\n}\n"]}