@astralyn/pi 1.4.9 → 1.4.11

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 +69 -0
  2. package/dist/bundle/chunks/{chunk-BAGHIP5J.js → chunk-NUQMVNKQ.js} +3 -3
  3. package/dist/bundle/chunks/{chunk-3PKXUKTB.js → chunk-PUU43PDV.js} +121 -136
  4. package/dist/bundle/chunks/{chunk-F66AY3WR.js → chunk-TH3QDDPD.js} +1 -1
  5. package/dist/bundle/chunks/{execute-P22VMM2H.js → execute-VLAIP26K.js} +1 -1
  6. package/dist/bundle/chunks/{virtual-modules-VKMBQTR2.js → virtual-modules-63XNTSVN.js} +1 -1
  7. package/dist/bundle/cli.js +1 -1
  8. package/dist/bundle/index.js +1 -1
  9. package/dist/bundle/rpc-entry.js +1 -1
  10. package/dist/core/agent-session.d.ts +34 -0
  11. package/dist/core/agent-session.d.ts.map +1 -1
  12. package/dist/core/agent-session.js +99 -5
  13. package/dist/core/agent-session.js.map +1 -1
  14. package/dist/core/extensions/index.d.ts +1 -1
  15. package/dist/core/extensions/index.d.ts.map +1 -1
  16. package/dist/core/extensions/index.js.map +1 -1
  17. package/dist/core/extensions/loader.d.ts.map +1 -1
  18. package/dist/core/extensions/loader.js +14 -7
  19. package/dist/core/extensions/loader.js.map +1 -1
  20. package/dist/core/isolated-session.d.ts +7 -2
  21. package/dist/core/isolated-session.d.ts.map +1 -1
  22. package/dist/core/isolated-session.js +7 -3
  23. package/dist/core/isolated-session.js.map +1 -1
  24. package/dist/core/session-manager.d.ts +17 -1
  25. package/dist/core/session-manager.d.ts.map +1 -1
  26. package/dist/core/session-manager.js +29 -0
  27. package/dist/core/session-manager.js.map +1 -1
  28. package/dist/core/tasks/delivery.d.ts +31 -12
  29. package/dist/core/tasks/delivery.d.ts.map +1 -1
  30. package/dist/core/tasks/delivery.js +97 -36
  31. package/dist/core/tasks/delivery.js.map +1 -1
  32. package/dist/core/tasks/execution.d.ts +27 -14
  33. package/dist/core/tasks/execution.d.ts.map +1 -1
  34. package/dist/core/tasks/execution.js +90 -86
  35. package/dist/core/tasks/execution.js.map +1 -1
  36. package/dist/core/tasks/limits.d.ts +7 -11
  37. package/dist/core/tasks/limits.d.ts.map +1 -1
  38. package/dist/core/tasks/limits.js +8 -16
  39. package/dist/core/tasks/limits.js.map +1 -1
  40. package/dist/core/tasks/output.d.ts +9 -1
  41. package/dist/core/tasks/output.d.ts.map +1 -1
  42. package/dist/core/tasks/output.js +23 -10
  43. package/dist/core/tasks/output.js.map +1 -1
  44. package/dist/core/tasks/presentation.d.ts +1 -1
  45. package/dist/core/tasks/presentation.d.ts.map +1 -1
  46. package/dist/core/tasks/presentation.js +6 -4
  47. package/dist/core/tasks/presentation.js.map +1 -1
  48. package/dist/core/tasks/record.d.ts +41 -29
  49. package/dist/core/tasks/record.d.ts.map +1 -1
  50. package/dist/core/tasks/record.js +82 -37
  51. package/dist/core/tasks/record.js.map +1 -1
  52. package/dist/core/tasks/reminder.js +2 -2
  53. package/dist/core/tasks/reminder.js.map +1 -1
  54. package/dist/core/tasks/runtime.d.ts +15 -23
  55. package/dist/core/tasks/runtime.d.ts.map +1 -1
  56. package/dist/core/tasks/runtime.js +50 -178
  57. package/dist/core/tasks/runtime.js.map +1 -1
  58. package/dist/core/tasks/scheduler.d.ts +3 -1
  59. package/dist/core/tasks/scheduler.d.ts.map +1 -1
  60. package/dist/core/tasks/scheduler.js +16 -12
  61. package/dist/core/tasks/scheduler.js.map +1 -1
  62. package/dist/core/tasks/session.d.ts +24 -6
  63. package/dist/core/tasks/session.d.ts.map +1 -1
  64. package/dist/core/tasks/session.js +70 -22
  65. package/dist/core/tasks/session.js.map +1 -1
  66. package/dist/core/tasks/store.d.ts +17 -4
  67. package/dist/core/tasks/store.d.ts.map +1 -1
  68. package/dist/core/tasks/store.js +45 -48
  69. package/dist/core/tasks/store.js.map +1 -1
  70. package/dist/core/tasks/types.d.ts +64 -93
  71. package/dist/core/tasks/types.d.ts.map +1 -1
  72. package/dist/core/tasks/types.js +7 -0
  73. package/dist/core/tasks/types.js.map +1 -1
  74. package/dist/core/tools/shell-execution.d.ts.map +1 -1
  75. package/dist/core/tools/shell-execution.js +2 -1
  76. package/dist/core/tools/shell-execution.js.map +1 -1
  77. package/dist/core/tools/shell-tool.d.ts.map +1 -1
  78. package/dist/core/tools/shell-tool.js +20 -13
  79. package/dist/core/tools/shell-tool.js.map +1 -1
  80. package/dist/extensions/agent/activity-lines.d.ts +10 -0
  81. package/dist/extensions/agent/activity-lines.d.ts.map +1 -0
  82. package/dist/extensions/agent/activity-lines.js +76 -0
  83. package/dist/extensions/agent/activity-lines.js.map +1 -0
  84. package/dist/extensions/agent/activity.d.ts +25 -4
  85. package/dist/extensions/agent/activity.d.ts.map +1 -1
  86. package/dist/extensions/agent/activity.js +76 -21
  87. package/dist/extensions/agent/activity.js.map +1 -1
  88. package/dist/extensions/agent/artifacts.d.ts +15 -0
  89. package/dist/extensions/agent/artifacts.d.ts.map +1 -0
  90. package/dist/extensions/agent/artifacts.js +44 -0
  91. package/dist/extensions/agent/artifacts.js.map +1 -0
  92. package/dist/extensions/agent/progress.d.ts +30 -4
  93. package/dist/extensions/agent/progress.d.ts.map +1 -1
  94. package/dist/extensions/agent/progress.js +84 -11
  95. package/dist/extensions/agent/progress.js.map +1 -1
  96. package/dist/extensions/agent/render.d.ts.map +1 -1
  97. package/dist/extensions/agent/render.js +8 -24
  98. package/dist/extensions/agent/render.js.map +1 -1
  99. package/dist/extensions/agent/report.d.ts +11 -3
  100. package/dist/extensions/agent/report.d.ts.map +1 -1
  101. package/dist/extensions/agent/report.js +32 -7
  102. package/dist/extensions/agent/report.js.map +1 -1
  103. package/dist/extensions/agent/tool.d.ts.map +1 -1
  104. package/dist/extensions/agent/tool.js +20 -5
  105. package/dist/extensions/agent/tool.js.map +1 -1
  106. package/dist/extensions/agent/types.d.ts +2 -0
  107. package/dist/extensions/agent/types.d.ts.map +1 -1
  108. package/dist/extensions/agent/types.js.map +1 -1
  109. package/dist/extensions/agent/worker.d.ts +7 -0
  110. package/dist/extensions/agent/worker.d.ts.map +1 -1
  111. package/dist/extensions/agent/worker.js +9 -3
  112. package/dist/extensions/agent/worker.js.map +1 -1
  113. package/dist/extensions/cached-compaction/summary.d.ts +1 -1
  114. package/dist/extensions/cached-compaction/summary.d.ts.map +1 -1
  115. package/dist/extensions/cached-compaction/summary.js +13 -16
  116. package/dist/extensions/cached-compaction/summary.js.map +1 -1
  117. package/dist/extensions/search/index.d.ts.map +1 -1
  118. package/dist/extensions/search/index.js +6 -7
  119. package/dist/extensions/search/index.js.map +1 -1
  120. package/dist/extensions/tasks/tool/actions.d.ts +1 -2
  121. package/dist/extensions/tasks/tool/actions.d.ts.map +1 -1
  122. package/dist/extensions/tasks/tool/actions.js +12 -80
  123. package/dist/extensions/tasks/tool/actions.js.map +1 -1
  124. package/dist/extensions/tasks/tool/constants.d.ts +1 -3
  125. package/dist/extensions/tasks/tool/constants.d.ts.map +1 -1
  126. package/dist/extensions/tasks/tool/constants.js +1 -3
  127. package/dist/extensions/tasks/tool/constants.js.map +1 -1
  128. package/dist/extensions/tasks/tool/schema.d.ts +2 -3
  129. package/dist/extensions/tasks/tool/schema.d.ts.map +1 -1
  130. package/dist/extensions/tasks/tool/schema.js +10 -18
  131. package/dist/extensions/tasks/tool/schema.js.map +1 -1
  132. package/dist/extensions/tasks/tool/types.d.ts +1 -17
  133. package/dist/extensions/tasks/tool/types.d.ts.map +1 -1
  134. package/dist/extensions/tasks/tool/types.js.map +1 -1
  135. package/dist/extensions/tasks/tool.d.ts +1 -2
  136. package/dist/extensions/tasks/tool.d.ts.map +1 -1
  137. package/dist/extensions/tasks/tool.js +5 -6
  138. package/dist/extensions/tasks/tool.js.map +1 -1
  139. package/dist/extensions/tasks/ui/completion-render.d.ts.map +1 -1
  140. package/dist/extensions/tasks/ui/completion-render.js +2 -2
  141. package/dist/extensions/tasks/ui/completion-render.js.map +1 -1
  142. package/dist/extensions/tasks/ui/footer.d.ts +37 -0
  143. package/dist/extensions/tasks/ui/footer.d.ts.map +1 -0
  144. package/dist/extensions/tasks/ui/footer.js +129 -0
  145. package/dist/extensions/tasks/ui/footer.js.map +1 -0
  146. package/dist/extensions/tasks/ui/frame.d.ts +36 -0
  147. package/dist/extensions/tasks/ui/frame.d.ts.map +1 -0
  148. package/dist/extensions/tasks/ui/frame.js +33 -0
  149. package/dist/extensions/tasks/ui/frame.js.map +1 -0
  150. package/dist/extensions/tasks/ui/help.d.ts +6 -0
  151. package/dist/extensions/tasks/ui/help.d.ts.map +1 -0
  152. package/dist/extensions/tasks/ui/help.js +53 -0
  153. package/dist/extensions/tasks/ui/help.js.map +1 -0
  154. package/dist/extensions/tasks/ui/inspector.d.ts +4 -3
  155. package/dist/extensions/tasks/ui/inspector.d.ts.map +1 -1
  156. package/dist/extensions/tasks/ui/inspector.js +25 -6
  157. package/dist/extensions/tasks/ui/inspector.js.map +1 -1
  158. package/dist/extensions/tasks/ui/layout.d.ts +15 -18
  159. package/dist/extensions/tasks/ui/layout.d.ts.map +1 -1
  160. package/dist/extensions/tasks/ui/layout.js +162 -255
  161. package/dist/extensions/tasks/ui/layout.js.map +1 -1
  162. package/dist/extensions/tasks/ui/list.d.ts +3 -1
  163. package/dist/extensions/tasks/ui/list.d.ts.map +1 -1
  164. package/dist/extensions/tasks/ui/list.js +19 -14
  165. package/dist/extensions/tasks/ui/list.js.map +1 -1
  166. package/dist/extensions/tasks/ui/manager.d.ts +17 -5
  167. package/dist/extensions/tasks/ui/manager.d.ts.map +1 -1
  168. package/dist/extensions/tasks/ui/manager.js +147 -90
  169. package/dist/extensions/tasks/ui/manager.js.map +1 -1
  170. package/dist/extensions/tasks/ui/model.d.ts +32 -5
  171. package/dist/extensions/tasks/ui/model.d.ts.map +1 -1
  172. package/dist/extensions/tasks/ui/model.js +7 -7
  173. package/dist/extensions/tasks/ui/model.js.map +1 -1
  174. package/dist/extensions/tasks/ui/panes.d.ts +40 -0
  175. package/dist/extensions/tasks/ui/panes.d.ts.map +1 -0
  176. package/dist/extensions/tasks/ui/panes.js +144 -0
  177. package/dist/extensions/tasks/ui/panes.js.map +1 -0
  178. package/dist/extensions/tasks/ui/render.d.ts +2 -16
  179. package/dist/extensions/tasks/ui/render.d.ts.map +1 -1
  180. package/dist/extensions/tasks/ui/render.js +13 -85
  181. package/dist/extensions/tasks/ui/render.js.map +1 -1
  182. package/dist/extensions/tasks/ui/viewport.d.ts +12 -4
  183. package/dist/extensions/tasks/ui/viewport.d.ts.map +1 -1
  184. package/dist/extensions/tasks/ui/viewport.js +23 -7
  185. package/dist/extensions/tasks/ui/viewport.js.map +1 -1
  186. package/dist/extensions/tasks/ui/views.d.ts +12 -6
  187. package/dist/extensions/tasks/ui/views.d.ts.map +1 -1
  188. package/dist/extensions/tasks/ui/views.js +39 -32
  189. package/dist/extensions/tasks/ui/views.js.map +1 -1
  190. package/dist/index.d.ts +1 -1
  191. package/dist/index.d.ts.map +1 -1
  192. package/dist/index.js.map +1 -1
  193. package/dist/modes/interactive/components/session-selector.d.ts +11 -1
  194. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  195. package/dist/modes/interactive/components/session-selector.js +43 -17
  196. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  197. package/dist/modes/print-mode.d.ts.map +1 -1
  198. package/dist/modes/print-mode.js +38 -2
  199. package/dist/modes/print-mode.js.map +1 -1
  200. package/dist/modes/rpc/rpc-client.d.ts +11 -0
  201. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  202. package/dist/modes/rpc/rpc-client.js +48 -0
  203. package/dist/modes/rpc/rpc-client.js.map +1 -1
  204. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  205. package/dist/modes/rpc/rpc-mode.js +2 -0
  206. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  207. package/dist/modes/rpc/rpc-types.d.ts +2 -0
  208. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  209. package/dist/modes/rpc/rpc-types.js.map +1 -1
  210. package/docs/bundled/extensions/agent.md +39 -7
  211. package/docs/bundled/extensions/statusline.md +1 -1
  212. package/docs/bundled/tasks.md +28 -37
  213. package/docs/bundled/tool-presentation.md +1 -1
  214. package/docs/extensions.md +15 -13
  215. package/docs/json.md +3 -0
  216. package/docs/models-configuration.md +1 -1
  217. package/docs/models.md +7 -85
  218. package/docs/rpc.md +14 -0
  219. package/docs/sdk.md +12 -2
  220. package/docs/session-format.md +11 -5
  221. package/docs/sessions.md +1 -1
  222. package/docs/usage.md +2 -0
  223. package/package.json +3 -4
  224. package/dist/modes/interactive/tool-view/tool-execution.d.ts +0 -14
  225. package/dist/modes/interactive/tool-view/tool-execution.d.ts.map +0 -1
  226. package/dist/modes/interactive/tool-view/tool-execution.js +0 -13
  227. package/dist/modes/interactive/tool-view/tool-execution.js.map +0 -1
  228. package/docs/images/doom-extension.png +0 -0
  229. package/docs/images/exy.png +0 -0
  230. package/npm-shrinkwrap.json +0 -4207
@@ -17,6 +17,8 @@ export interface AgentActivity {
17
17
  /** Short display label derived from the original arguments; args remains the full bounded form. */
18
18
  target?: string;
19
19
  status: AgentActivityStatus;
20
+ /** Epoch milliseconds when the call began, so a running call can show its elapsed time. */
21
+ startedAt?: number;
20
22
  durationMs?: number;
21
23
  error?: string;
22
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAChD,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACzB;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,GAC7E;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACpE;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,eAAO,MAAM,wBAAwB,UAAU,CAAC;AAChD,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,kBAAkB,QAAY,CAAC;AAC5C,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,iBAAiB,IAAI,CAAC;AAEnC,MAAM,WAAW,aAAa;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,aAAa,CAAC;CACzB;AAED,MAAM,MAAM,mBAAmB,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,GAAG,WAAW,CAAC;AAE3E,MAAM,WAAW,aAAa;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,mGAAmG;IACnG,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GACzB;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,aAAa,EAAE,CAAA;CAAE,GAC7E;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,GACpE;IAAE,OAAO,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extensions/agent/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { TaskTerminalStatus } from \"../../core/tasks/types.ts\";\n\nexport const AGENT_SETTINGS_NAMESPACE = \"agent\";\nexport const AGENT_PROMPT_BYTES = 16 * 1024;\nexport const AGENT_REPORT_BYTES = 24 * 1024;\nexport const AGENT_MAX_ACTIVITIES = 50;\nexport const AGENT_CONCURRENCY = 4;\n\nexport interface AgentSettings {\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n}\n\nexport type AgentActivityStatus = \"running\" | \"ok\" | \"error\" | \"cancelled\";\n\nexport interface AgentActivity {\n\tid: string;\n\tname: string;\n\targs: string;\n\t/** Short display label derived from the original arguments; args remains the full bounded form. */\n\ttarget?: string;\n\tstatus: AgentActivityStatus;\n\tdurationMs?: number;\n\terror?: string;\n}\n\n/**\n * Agent tool-result details. Only progress updates carry activities; the persisted result\n * keeps the transcript row's facts, and the full history lives in the task's Output.\n */\nexport type AgentToolDetails =\n\t| { version: 2; state: \"running\"; taskId: string; activities: AgentActivity[] }\n\t| { version: 2; state: \"background\"; taskId: string; byUser: boolean }\n\t| { version: 2; state: TaskTerminalStatus; taskId: string; error?: string };\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/extensions/agent/types.ts"],"names":[],"mappings":"AAGA,MAAM,CAAC,MAAM,wBAAwB,GAAG,OAAO,CAAC;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,kBAAkB,GAAG,EAAE,GAAG,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AACvC,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { TaskTerminalStatus } from \"../../core/tasks/types.ts\";\n\nexport const AGENT_SETTINGS_NAMESPACE = \"agent\";\nexport const AGENT_PROMPT_BYTES = 16 * 1024;\nexport const AGENT_REPORT_BYTES = 24 * 1024;\nexport const AGENT_MAX_ACTIVITIES = 50;\nexport const AGENT_CONCURRENCY = 4;\n\nexport interface AgentSettings {\n\tmodel?: string;\n\tthinking?: ThinkingLevel;\n}\n\nexport type AgentActivityStatus = \"running\" | \"ok\" | \"error\" | \"cancelled\";\n\nexport interface AgentActivity {\n\tid: string;\n\tname: string;\n\targs: string;\n\t/** Short display label derived from the original arguments; args remains the full bounded form. */\n\ttarget?: string;\n\tstatus: AgentActivityStatus;\n\t/** Epoch milliseconds when the call began, so a running call can show its elapsed time. */\n\tstartedAt?: number;\n\tdurationMs?: number;\n\terror?: string;\n}\n\n/**\n * Agent tool-result details. Only progress updates carry activities; the persisted result\n * keeps the transcript row's facts, and the full history lives in the task's Output.\n */\nexport type AgentToolDetails =\n\t| { version: 2; state: \"running\"; taskId: string; activities: AgentActivity[] }\n\t| { version: 2; state: \"background\"; taskId: string; byUser: boolean }\n\t| { version: 2; state: TaskTerminalStatus; taskId: string; error?: string };\n"]}
@@ -2,6 +2,7 @@ import type { ThinkingLevel } from "@earendil-works/pi-agent-core";
2
2
  import type { Model } from "@earendil-works/pi-ai/compat";
3
3
  import type { ModelRuntime } from "../../core/model-runtime.ts";
4
4
  import type { TaskCompletion, TaskControl } from "../../core/tasks/types.ts";
5
+ import { AgentProgress } from "./progress.ts";
5
6
  import type { AgentToolDetails } from "./types.ts";
6
7
  export interface AgentRequest {
7
8
  prompt: string;
@@ -10,6 +11,12 @@ export interface AgentRequest {
10
11
  thinking: ThinkingLevel;
11
12
  modelRuntime: ModelRuntime;
12
13
  projectTrusted: boolean;
14
+ /** The launching session's artifacts directory; without one (unsaved session) nothing is kept. */
15
+ sessionArtifactDir?: string;
16
+ /** The launching session file, recorded as the transcript's parent. */
17
+ parentSession?: string;
18
+ /** Receives the run's progress as soon as it exists, so a caller can render it live. */
19
+ onProgress?: (progress: AgentProgress) => void;
13
20
  }
14
21
  /** Run one delegated task in an isolated session and settle it with a self-contained report. */
15
22
  export declare function runWorker(control: TaskControl<AgentToolDetails>, request: AgentRequest): Promise<TaskCompletion<AgentToolDetails>>;
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAG1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAI7E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;CACxB;AAaD,gGAAgG;AAChG,wBAAsB,SAAS,CAC9B,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC,EACtC,OAAO,EAAE,YAAY,GACnB,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CA6C3C"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,8BAA8B,CAAC;AAG1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAG7E,OAAO,EAAE,aAAa,EAAsB,MAAM,eAAe,CAAC;AAElE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAInD,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC;IAClB,QAAQ,EAAE,aAAa,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,OAAO,CAAC;IACxB,kGAAkG;IAClG,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,wFAAwF;IACxF,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,IAAI,CAAC;CAC/C;AAaD,gGAAgG;AAChG,wBAAsB,SAAS,CAC9B,OAAO,EAAE,WAAW,CAAC,gBAAgB,CAAC,EACtC,OAAO,EAAE,YAAY,GACnB,OAAO,CAAC,cAAc,CAAC,gBAAgB,CAAC,CAAC,CAkD3C"}
@@ -1,5 +1,6 @@
1
1
  import { createIsolatedSession } from "../../core/isolated-session.js";
2
2
  import { clipText } from "./activity.js";
3
+ import { prepareArtifacts } from "./artifacts.js";
3
4
  import { AgentProgress, finalAssistantText } from "./progress.js";
4
5
  import { finalReport } from "./report.js";
5
6
  const WORKER_TOOLS = ["read", "bash", "edit", "write"];
@@ -16,14 +17,17 @@ function workerPrompt(base) {
16
17
  /** Run one delegated task in an isolated session and settle it with a self-contained report. */
17
18
  export async function runWorker(control, request) {
18
19
  const { signal } = control;
19
- const progress = new AgentProgress(control);
20
+ const progress = new AgentProgress(control, request.cwd);
21
+ request.onProgress?.(progress);
20
22
  let session;
21
23
  let unsubscribe;
24
+ let artifacts;
22
25
  const abort = () => {
23
26
  void session?.abort().catch(() => { });
24
27
  };
25
28
  signal.addEventListener("abort", abort, { once: true });
26
29
  try {
30
+ artifacts = await prepareArtifacts(request.sessionArtifactDir, control.id, request.parentSession);
27
31
  session = await createIsolatedSession({
28
32
  cwd: request.cwd,
29
33
  model: request.model,
@@ -32,6 +36,7 @@ export async function runWorker(control, request) {
32
36
  projectTrusted: request.projectTrusted,
33
37
  systemPrompt: workerPrompt,
34
38
  tools: WORKER_TOOLS,
39
+ transcript: artifacts && { path: artifacts.transcriptPath, parentSession: artifacts.parentSession },
35
40
  signal,
36
41
  });
37
42
  const worker = session;
@@ -47,7 +52,8 @@ export async function runWorker(control, request) {
47
52
  signal.throwIfAborted();
48
53
  await worker.prompt(request.prompt, { expandPromptTemplates: false });
49
54
  const { status, error } = progress.outcome();
50
- return progress.complete(status, error, await finalReport(control, finalAssistantText(worker.messages), error));
55
+ const report = await finalReport(control, finalAssistantText(worker.messages), error, artifacts);
56
+ return progress.complete(status, error, report, artifacts);
51
57
  }
52
58
  catch (error) {
53
59
  const status = signal.aborted ? "cancelled" : "failed";
@@ -55,7 +61,7 @@ export async function runWorker(control, request) {
55
61
  ? "Agent cancelled."
56
62
  : clipText(error instanceof Error ? error.message : String(error), 4096);
57
63
  const report = session ? finalAssistantText(session.messages) : "";
58
- return progress.complete(status, reason, await finalReport(control, report, reason));
64
+ return progress.complete(status, reason, await finalReport(control, report, reason, artifacts), artifacts);
59
65
  }
60
66
  finally {
61
67
  signal.removeEventListener("abort", abort);
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport { createIsolatedSession } from \"../../core/isolated-session.ts\";\nimport type { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport type { TaskCompletion, TaskControl } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { AgentProgress, finalAssistantText } from \"./progress.ts\";\nimport { finalReport } from \"./report.ts\";\nimport type { AgentToolDetails } from \"./types.ts\";\n\nconst WORKER_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\nexport interface AgentRequest {\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<any>;\n\tthinking: ThinkingLevel;\n\tmodelRuntime: ModelRuntime;\n\tprojectTrusted: boolean;\n}\n\nfunction workerPrompt(base: string | undefined): string {\n\treturn [\n\t\tbase,\n\t\t\"You are an Agent completing one delegated task in an isolated session. The first user message is the complete briefing from your caller. You cannot see the caller's conversation or ask it questions. If the briefing is ambiguous, choose a reasonable interpretation within scope and report it; stop only when ambiguity blocks meaningful progress.\",\n\t\t\"Use the assigned working directory and stay within the requested scope. Complete the task fully without expanding it. If the briefing asks only for investigation, do not modify files. Use read for known paths and bash for discovery, search, and shell commands. Prefer editing existing files; create new files only when the task requires them, and never create documentation or report files unless explicitly requested. Do not delegate or start background work. Run required commands in the foreground and wait for them.\",\n\t\t\"Your final message is the only output returned to the caller. Lead with the outcome, then include essential findings, files changed if any, verification actually run and its result, and blockers or remaining risks. Cite workspace-relative paths with line numbers when useful. Respect any length limit in the briefing and omit process narration.\",\n\t]\n\t\t.filter((part): part is string => Boolean(part?.trim()))\n\t\t.join(\"\\n\\n\");\n}\n\n/** Run one delegated task in an isolated session and settle it with a self-contained report. */\nexport async function runWorker(\n\tcontrol: TaskControl<AgentToolDetails>,\n\trequest: AgentRequest,\n): Promise<TaskCompletion<AgentToolDetails>> {\n\tconst { signal } = control;\n\tconst progress = new AgentProgress(control);\n\tlet session: AgentSession | undefined;\n\tlet unsubscribe: (() => void) | undefined;\n\tconst abort = () => {\n\t\tvoid session?.abort().catch(() => {});\n\t};\n\tsignal.addEventListener(\"abort\", abort, { once: true });\n\ttry {\n\t\tsession = await createIsolatedSession({\n\t\t\tcwd: request.cwd,\n\t\t\tmodel: request.model,\n\t\t\tthinkingLevel: request.thinking,\n\t\t\tmodelRuntime: request.modelRuntime,\n\t\t\tprojectTrusted: request.projectTrusted,\n\t\t\tsystemPrompt: workerPrompt,\n\t\t\ttools: WORKER_TOOLS,\n\t\t\tsignal,\n\t\t});\n\t\tconst worker = session;\n\t\tunsubscribe = worker.subscribe((event) => {\n\t\t\t// Cancellation during prompt preflight can precede the run's own abort controller.\n\t\t\tif (event.type === \"agent_start\" && signal.aborted) abort();\n\t\t\telse progress.handle(event);\n\t\t});\n\t\tprogress.publish();\n\t\tcontrol.accept();\n\t\tsignal.throwIfAborted();\n\t\tawait worker.prompt(request.prompt, { expandPromptTemplates: false });\n\t\tconst { status, error } = progress.outcome();\n\t\treturn progress.complete(status, error, await finalReport(control, finalAssistantText(worker.messages), error));\n\t} catch (error) {\n\t\tconst status = signal.aborted ? \"cancelled\" : \"failed\";\n\t\tconst reason =\n\t\t\tstatus === \"cancelled\"\n\t\t\t\t? \"Agent cancelled.\"\n\t\t\t\t: clipText(error instanceof Error ? error.message : String(error), 4096);\n\t\tconst report = session ? finalAssistantText(session.messages) : \"\";\n\t\treturn progress.complete(status, reason, await finalReport(control, report, reason));\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", abort);\n\t\tunsubscribe?.();\n\t\tsession?.dispose();\n\t}\n}\n"]}
1
+ {"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/extensions/agent/worker.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ThinkingLevel } from \"@earendil-works/pi-agent-core\";\nimport type { Model } from \"@earendil-works/pi-ai/compat\";\nimport type { AgentSession } from \"../../core/agent-session.ts\";\nimport { createIsolatedSession } from \"../../core/isolated-session.ts\";\nimport type { ModelRuntime } from \"../../core/model-runtime.ts\";\nimport type { TaskCompletion, TaskControl } from \"../../core/tasks/types.ts\";\nimport { clipText } from \"./activity.ts\";\nimport { type AgentArtifacts, prepareArtifacts } from \"./artifacts.ts\";\nimport { AgentProgress, finalAssistantText } from \"./progress.ts\";\nimport { finalReport } from \"./report.ts\";\nimport type { AgentToolDetails } from \"./types.ts\";\n\nconst WORKER_TOOLS = [\"read\", \"bash\", \"edit\", \"write\"];\n\nexport interface AgentRequest {\n\tprompt: string;\n\tcwd: string;\n\tmodel: Model<any>;\n\tthinking: ThinkingLevel;\n\tmodelRuntime: ModelRuntime;\n\tprojectTrusted: boolean;\n\t/** The launching session's artifacts directory; without one (unsaved session) nothing is kept. */\n\tsessionArtifactDir?: string;\n\t/** The launching session file, recorded as the transcript's parent. */\n\tparentSession?: string;\n\t/** Receives the run's progress as soon as it exists, so a caller can render it live. */\n\tonProgress?: (progress: AgentProgress) => void;\n}\n\nfunction workerPrompt(base: string | undefined): string {\n\treturn [\n\t\tbase,\n\t\t\"You are an Agent completing one delegated task in an isolated session. The first user message is the complete briefing from your caller. You cannot see the caller's conversation or ask it questions. If the briefing is ambiguous, choose a reasonable interpretation within scope and report it; stop only when ambiguity blocks meaningful progress.\",\n\t\t\"Use the assigned working directory and stay within the requested scope. Complete the task fully without expanding it. If the briefing asks only for investigation, do not modify files. Use read for known paths and bash for discovery, search, and shell commands. Prefer editing existing files; create new files only when the task requires them, and never create documentation or report files unless explicitly requested. Do not delegate or start background work. Run required commands in the foreground and wait for them.\",\n\t\t\"Your final message is the only output returned to the caller. Lead with the outcome, then include essential findings, files changed if any, verification actually run and its result, and blockers or remaining risks. Cite workspace-relative paths with line numbers when useful. Respect any length limit in the briefing and omit process narration.\",\n\t]\n\t\t.filter((part): part is string => Boolean(part?.trim()))\n\t\t.join(\"\\n\\n\");\n}\n\n/** Run one delegated task in an isolated session and settle it with a self-contained report. */\nexport async function runWorker(\n\tcontrol: TaskControl<AgentToolDetails>,\n\trequest: AgentRequest,\n): Promise<TaskCompletion<AgentToolDetails>> {\n\tconst { signal } = control;\n\tconst progress = new AgentProgress(control, request.cwd);\n\trequest.onProgress?.(progress);\n\tlet session: AgentSession | undefined;\n\tlet unsubscribe: (() => void) | undefined;\n\tlet artifacts: AgentArtifacts | undefined;\n\tconst abort = () => {\n\t\tvoid session?.abort().catch(() => {});\n\t};\n\tsignal.addEventListener(\"abort\", abort, { once: true });\n\ttry {\n\t\tartifacts = await prepareArtifacts(request.sessionArtifactDir, control.id, request.parentSession);\n\t\tsession = await createIsolatedSession({\n\t\t\tcwd: request.cwd,\n\t\t\tmodel: request.model,\n\t\t\tthinkingLevel: request.thinking,\n\t\t\tmodelRuntime: request.modelRuntime,\n\t\t\tprojectTrusted: request.projectTrusted,\n\t\t\tsystemPrompt: workerPrompt,\n\t\t\ttools: WORKER_TOOLS,\n\t\t\ttranscript: artifacts && { path: artifacts.transcriptPath, parentSession: artifacts.parentSession },\n\t\t\tsignal,\n\t\t});\n\t\tconst worker = session;\n\t\tunsubscribe = worker.subscribe((event) => {\n\t\t\t// Cancellation during prompt preflight can precede the run's own abort controller.\n\t\t\tif (event.type === \"agent_start\" && signal.aborted) abort();\n\t\t\telse progress.handle(event);\n\t\t});\n\t\tprogress.publish();\n\t\tcontrol.accept();\n\t\tsignal.throwIfAborted();\n\t\tawait worker.prompt(request.prompt, { expandPromptTemplates: false });\n\t\tconst { status, error } = progress.outcome();\n\t\tconst report = await finalReport(control, finalAssistantText(worker.messages), error, artifacts);\n\t\treturn progress.complete(status, error, report, artifacts);\n\t} catch (error) {\n\t\tconst status = signal.aborted ? \"cancelled\" : \"failed\";\n\t\tconst reason =\n\t\t\tstatus === \"cancelled\"\n\t\t\t\t? \"Agent cancelled.\"\n\t\t\t\t: clipText(error instanceof Error ? error.message : String(error), 4096);\n\t\tconst report = session ? finalAssistantText(session.messages) : \"\";\n\t\treturn progress.complete(status, reason, await finalReport(control, report, reason, artifacts), artifacts);\n\t} finally {\n\t\tsignal.removeEventListener(\"abort\", abort);\n\t\tunsubscribe?.();\n\t\tsession?.dispose();\n\t}\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import { type Message } from "@earendil-works/pi-ai";
2
- import type { CompactionDetails, FileOperations } from "../../core/compaction/index.ts";
2
+ import { type CompactionDetails, type FileOperations } from "../../core/compaction/index.ts";
3
3
  import { type SessionEntry } from "../../core/session-manager.ts";
4
4
  export interface KeptStart {
5
5
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../src/extensions/cached-compaction/summary.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAExF,OAAO,EAAoD,KAAK,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAEpH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AA2BD,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,OAAO,EAAE,GACrB,SAAS,GAAG,SAAS,CAevB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAoDvF;AAMD,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAAE,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAyBjD"}
1
+ {"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../../../src/extensions/cached-compaction/summary.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,EACN,KAAK,iBAAiB,EAEtB,KAAK,cAAc,EAEnB,MAAM,gCAAgC,CAAC;AAExC,OAAO,EAAoD,KAAK,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAEpH,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACd;AA2BD,wBAAgB,SAAS,CACxB,OAAO,EAAE,YAAY,EAAE,EACvB,gBAAgB,EAAE,MAAM,EACxB,YAAY,EAAE,OAAO,EAAE,GACrB,SAAS,GAAG,SAAS,CAevB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,EAAE,kBAAkB,CAAC,EAAE,MAAM,GAAG,MAAM,CAoDvF;AAMD,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,cAAc,EACvB,OAAO,EAAE,YAAY,EAAE,GACrB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,iBAAiB,CAAA;CAAE,CAqBjD"}
@@ -1,4 +1,5 @@
1
1
  import { contentText } from "@earendil-works/pi-ai";
2
+ import { computeFileLists, formatFileOperations, } from "../../core/compaction/index.js";
2
3
  import { convertToLlm } from "../../core/messages.js";
3
4
  import { buildSessionProjection, getLatestCompactionEntry } from "../../core/session-manager.js";
4
5
  function sameMessage(candidate, projected) {
@@ -99,33 +100,29 @@ function isPlainObject(value) {
99
100
  return typeof value === "object" && value !== null && !Array.isArray(value);
100
101
  }
101
102
  export function checkpointSummary(text, fileOps, entries) {
102
- const read = new Set(fileOps.read);
103
- const modified = new Set([...fileOps.written, ...fileOps.edited]);
103
+ const merged = {
104
+ read: new Set(fileOps.read),
105
+ written: new Set(fileOps.written),
106
+ edited: new Set(fileOps.edited),
107
+ };
104
108
  const previousDetails = getLatestCompactionEntry(entries)?.details;
105
109
  if (isPlainObject(previousDetails)) {
106
110
  const { readFiles, modifiedFiles } = previousDetails;
107
111
  if (Array.isArray(readFiles)) {
108
112
  for (const file of readFiles)
109
113
  if (typeof file === "string")
110
- read.add(file);
114
+ merged.read.add(file);
111
115
  }
112
116
  if (Array.isArray(modifiedFiles)) {
113
117
  for (const file of modifiedFiles)
114
118
  if (typeof file === "string")
115
- modified.add(file);
119
+ merged.edited.add(file);
116
120
  }
117
121
  }
118
- const details = {
119
- readFiles: [...read].filter((file) => !modified.has(file)).sort(),
120
- modifiedFiles: [...modified].sort(),
121
- };
122
- const sections = [
123
- text.replace(/<(read-files|modified-files)>[\s\S]*?<\/\1>/g, "").trim(),
124
- details.readFiles.length > 0 ? `<read-files>\n${details.readFiles.join("\n")}\n</read-files>` : "",
125
- details.modifiedFiles.length > 0
126
- ? `<modified-files>\n${details.modifiedFiles.join("\n")}\n</modified-files>`
127
- : "",
128
- ];
129
- return { summary: sections.filter(Boolean).join("\n\n"), details };
122
+ const details = computeFileLists(merged);
123
+ const body = text.replace(/<(read-files|modified-files)>[\s\S]*?<\/\1>/g, "").trim();
124
+ const operations = formatFileOperations(details.readFiles, details.modifiedFiles);
125
+ // The shared formatter prefixes a non-empty operation list; an empty summary body has no leading blank lines.
126
+ return { summary: body ? body + operations : operations.slice(2), details };
130
127
  }
131
128
  //# sourceMappingURL=summary.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../src/extensions/cached-compaction/summary.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { contentText, type Message } from \"@earendil-works/pi-ai\";\nimport type { CompactionDetails, FileOperations } from \"../../core/compaction/index.ts\";\nimport { convertToLlm } from \"../../core/messages.ts\";\nimport { buildSessionProjection, getLatestCompactionEntry, type SessionEntry } from \"../../core/session-manager.ts\";\n\nexport interface KeptStart {\n\ttext: string;\n\tfromEnd: number;\n\tcount: number;\n}\n\nfunction sameMessage(candidate: Message, projected: AgentMessage): boolean {\n\tconst serialized = JSON.stringify(candidate);\n\treturn convertToLlm([projected]).some((message) => JSON.stringify(message) === serialized);\n}\n\nfunction messagePreview(message: Message): string | undefined {\n\tlet text: string | undefined;\n\tif (message.role === \"user\") {\n\t\ttext = contentText(message.content);\n\t} else if (message.role === \"assistant\") {\n\t\ttext = message.content\n\t\t\t.flatMap((block) =>\n\t\t\t\tblock.type === \"text\"\n\t\t\t\t\t? [block.text]\n\t\t\t\t\t: block.type === \"toolCall\"\n\t\t\t\t\t\t? [`[tool call: ${block.name} ${JSON.stringify(block.arguments)}]`]\n\t\t\t\t\t\t: [],\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t}\n\ttext = text?.trim();\n\tif (!text) return undefined;\n\treturn text.length > 400 ? `${text.slice(0, 400)}…` : text;\n}\n\nexport function keptStart(\n\tentries: SessionEntry[],\n\tfirstKeptEntryId: string,\n\tconversation: Message[],\n): KeptStart | undefined {\n\tconst projected = buildSessionProjection(entries).entries;\n\tconst start = projected.findIndex((entry) => entry.sourceEntry.id === firstKeptEntryId);\n\tif (start === -1) return undefined;\n\tlet at = -1;\n\tfor (const message of projected.slice(start).flatMap((entry) => entry.messages)) {\n\t\tat = conversation.findLastIndex((candidate) => sameMessage(candidate, message));\n\t\tif (at !== -1) break;\n\t}\n\tif (at === -1) return undefined;\n\tconst previews = conversation.slice(at).map(messagePreview);\n\tconst text = previews[0];\n\treturn text\n\t\t? { text, fromEnd: previews.filter((preview) => preview === text).length, count: previews.length }\n\t\t: undefined;\n}\n\nexport function summaryInstruction(kept: KeptStart, customInstructions?: string): string {\n\tconst repeated =\n\t\tkept.fromEnd > 1\n\t\t\t? ` Several retained messages begin with this text. The boundary is occurrence ${kept.fromEnd}, counting backward from the end of the conversation.`\n\t\t\t: \"\";\n\tconst toolCalls = kept.text.includes(\"[tool call: \")\n\t\t? \" Tool calls are written as [tool call: name arguments].\"\n\t\t: \"\";\n\tconst focus = customInstructions?.trim() ? `\\n\\nAdditional focus from the user:\\n${customInstructions.trim()}` : \"\";\n\treturn `Stop working on the current task. Do not call any tools.\n\nWrite a structured context checkpoint summary of the earlier part of this conversation. Another LLM will continue the task from your summary, followed by the last ${kept.count} messages, which will remain in context verbatim.\n\nThe retained messages begin with the message that starts with this text.${repeated}${toolCalls}\n\n<kept-start>\n${kept.text}\n</kept-start>\n\nSummarize only the messages before that boundary, as if the conversation had ended immediately before it. Work occurring at or after the boundary has not happened as far as this summary is concerned: do not list it as completed. If it was already planned, include it under Next Steps instead.\n\nIf the conversation contains an earlier checkpoint summary, fold its still-relevant facts into this summary and update its progress and next steps.\n\nUse exactly this structure:\n\n## Goal\n[What the user is trying to accomplish. Include multiple goals if applicable.]\n\n## Constraints & Preferences\n- [Requirements, preferences, and explicit constraints from the user]\n- [Use \"(none)\" when appropriate]\n\n## Progress\n### Done\n- [x] [Work completed before the boundary]\n\n### In Progress\n- [ ] [Work underway at the boundary]\n\n### Blocked\n- [Issues preventing progress, or \"(none)\"]\n\n## Key Decisions\n- **[Decision]**: [Rationale]\n\n## Next Steps\n1. [Ordered steps needed to continue]\n\n## Critical Context\n- [Exact information needed to continue: file paths, symbols, commands, important tool results, error messages, and relevant technical details]\n\nBe concise but preserve information required to continue without rereading the original conversation. Keep exact file paths, function names, commands, and error messages. Do not include file-operation lists; they will be added automatically. Return only the summary.${focus}`;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function checkpointSummary(\n\ttext: string,\n\tfileOps: FileOperations,\n\tentries: SessionEntry[],\n): { summary: string; details: CompactionDetails } {\n\tconst read = new Set(fileOps.read);\n\tconst modified = new Set([...fileOps.written, ...fileOps.edited]);\n\tconst previousDetails: unknown = getLatestCompactionEntry(entries)?.details;\n\tif (isPlainObject(previousDetails)) {\n\t\tconst { readFiles, modifiedFiles } = previousDetails;\n\t\tif (Array.isArray(readFiles)) {\n\t\t\tfor (const file of readFiles) if (typeof file === \"string\") read.add(file);\n\t\t}\n\t\tif (Array.isArray(modifiedFiles)) {\n\t\t\tfor (const file of modifiedFiles) if (typeof file === \"string\") modified.add(file);\n\t\t}\n\t}\n\tconst details = {\n\t\treadFiles: [...read].filter((file) => !modified.has(file)).sort(),\n\t\tmodifiedFiles: [...modified].sort(),\n\t};\n\tconst sections = [\n\t\ttext.replace(/<(read-files|modified-files)>[\\s\\S]*?<\\/\\1>/g, \"\").trim(),\n\t\tdetails.readFiles.length > 0 ? `<read-files>\\n${details.readFiles.join(\"\\n\")}\\n</read-files>` : \"\",\n\t\tdetails.modifiedFiles.length > 0\n\t\t\t? `<modified-files>\\n${details.modifiedFiles.join(\"\\n\")}\\n</modified-files>`\n\t\t\t: \"\",\n\t];\n\treturn { summary: sections.filter(Boolean).join(\"\\n\\n\"), details };\n}\n"]}
1
+ {"version":3,"file":"summary.js","sourceRoot":"","sources":["../../../src/extensions/cached-compaction/summary.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@earendil-works/pi-agent-core\";\nimport { contentText, type Message } from \"@earendil-works/pi-ai\";\nimport {\n\ttype CompactionDetails,\n\tcomputeFileLists,\n\ttype FileOperations,\n\tformatFileOperations,\n} from \"../../core/compaction/index.ts\";\nimport { convertToLlm } from \"../../core/messages.ts\";\nimport { buildSessionProjection, getLatestCompactionEntry, type SessionEntry } from \"../../core/session-manager.ts\";\n\nexport interface KeptStart {\n\ttext: string;\n\tfromEnd: number;\n\tcount: number;\n}\n\nfunction sameMessage(candidate: Message, projected: AgentMessage): boolean {\n\tconst serialized = JSON.stringify(candidate);\n\treturn convertToLlm([projected]).some((message) => JSON.stringify(message) === serialized);\n}\n\nfunction messagePreview(message: Message): string | undefined {\n\tlet text: string | undefined;\n\tif (message.role === \"user\") {\n\t\ttext = contentText(message.content);\n\t} else if (message.role === \"assistant\") {\n\t\ttext = message.content\n\t\t\t.flatMap((block) =>\n\t\t\t\tblock.type === \"text\"\n\t\t\t\t\t? [block.text]\n\t\t\t\t\t: block.type === \"toolCall\"\n\t\t\t\t\t\t? [`[tool call: ${block.name} ${JSON.stringify(block.arguments)}]`]\n\t\t\t\t\t\t: [],\n\t\t\t)\n\t\t\t.join(\"\\n\");\n\t}\n\ttext = text?.trim();\n\tif (!text) return undefined;\n\treturn text.length > 400 ? `${text.slice(0, 400)}…` : text;\n}\n\nexport function keptStart(\n\tentries: SessionEntry[],\n\tfirstKeptEntryId: string,\n\tconversation: Message[],\n): KeptStart | undefined {\n\tconst projected = buildSessionProjection(entries).entries;\n\tconst start = projected.findIndex((entry) => entry.sourceEntry.id === firstKeptEntryId);\n\tif (start === -1) return undefined;\n\tlet at = -1;\n\tfor (const message of projected.slice(start).flatMap((entry) => entry.messages)) {\n\t\tat = conversation.findLastIndex((candidate) => sameMessage(candidate, message));\n\t\tif (at !== -1) break;\n\t}\n\tif (at === -1) return undefined;\n\tconst previews = conversation.slice(at).map(messagePreview);\n\tconst text = previews[0];\n\treturn text\n\t\t? { text, fromEnd: previews.filter((preview) => preview === text).length, count: previews.length }\n\t\t: undefined;\n}\n\nexport function summaryInstruction(kept: KeptStart, customInstructions?: string): string {\n\tconst repeated =\n\t\tkept.fromEnd > 1\n\t\t\t? ` Several retained messages begin with this text. The boundary is occurrence ${kept.fromEnd}, counting backward from the end of the conversation.`\n\t\t\t: \"\";\n\tconst toolCalls = kept.text.includes(\"[tool call: \")\n\t\t? \" Tool calls are written as [tool call: name arguments].\"\n\t\t: \"\";\n\tconst focus = customInstructions?.trim() ? `\\n\\nAdditional focus from the user:\\n${customInstructions.trim()}` : \"\";\n\treturn `Stop working on the current task. Do not call any tools.\n\nWrite a structured context checkpoint summary of the earlier part of this conversation. Another LLM will continue the task from your summary, followed by the last ${kept.count} messages, which will remain in context verbatim.\n\nThe retained messages begin with the message that starts with this text.${repeated}${toolCalls}\n\n<kept-start>\n${kept.text}\n</kept-start>\n\nSummarize only the messages before that boundary, as if the conversation had ended immediately before it. Work occurring at or after the boundary has not happened as far as this summary is concerned: do not list it as completed. If it was already planned, include it under Next Steps instead.\n\nIf the conversation contains an earlier checkpoint summary, fold its still-relevant facts into this summary and update its progress and next steps.\n\nUse exactly this structure:\n\n## Goal\n[What the user is trying to accomplish. Include multiple goals if applicable.]\n\n## Constraints & Preferences\n- [Requirements, preferences, and explicit constraints from the user]\n- [Use \"(none)\" when appropriate]\n\n## Progress\n### Done\n- [x] [Work completed before the boundary]\n\n### In Progress\n- [ ] [Work underway at the boundary]\n\n### Blocked\n- [Issues preventing progress, or \"(none)\"]\n\n## Key Decisions\n- **[Decision]**: [Rationale]\n\n## Next Steps\n1. [Ordered steps needed to continue]\n\n## Critical Context\n- [Exact information needed to continue: file paths, symbols, commands, important tool results, error messages, and relevant technical details]\n\nBe concise but preserve information required to continue without rereading the original conversation. Keep exact file paths, function names, commands, and error messages. Do not include file-operation lists; they will be added automatically. Return only the summary.${focus}`;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function checkpointSummary(\n\ttext: string,\n\tfileOps: FileOperations,\n\tentries: SessionEntry[],\n): { summary: string; details: CompactionDetails } {\n\tconst merged: FileOperations = {\n\t\tread: new Set(fileOps.read),\n\t\twritten: new Set(fileOps.written),\n\t\tedited: new Set(fileOps.edited),\n\t};\n\tconst previousDetails: unknown = getLatestCompactionEntry(entries)?.details;\n\tif (isPlainObject(previousDetails)) {\n\t\tconst { readFiles, modifiedFiles } = previousDetails;\n\t\tif (Array.isArray(readFiles)) {\n\t\t\tfor (const file of readFiles) if (typeof file === \"string\") merged.read.add(file);\n\t\t}\n\t\tif (Array.isArray(modifiedFiles)) {\n\t\t\tfor (const file of modifiedFiles) if (typeof file === \"string\") merged.edited.add(file);\n\t\t}\n\t}\n\tconst details = computeFileLists(merged);\n\tconst body = text.replace(/<(read-files|modified-files)>[\\s\\S]*?<\\/\\1>/g, \"\").trim();\n\tconst operations = formatFileOperations(details.readFiles, details.modifiedFiles);\n\t// The shared formatter prefixes a non-empty operation list; an empty summary body has no leading blank lines.\n\treturn { summary: body ? body + operations : operations.slice(2), details };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/search/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,OAAO,EAAkB,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AA8CvE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAW5E;AAED,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA8DrD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/extensions/search/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAKnE,OAAO,EAAkB,KAAK,SAAS,EAAa,MAAM,YAAY,CAAC;AA8CvE,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,GAAG,MAAM,CAW5E;AAED,MAAM,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,EAAE,YAAY,GAAG,IAAI,CA6DrD"}
@@ -16,10 +16,10 @@ import { isInside } from "./workspace.js";
16
16
  const WEB_EXCERPT_MAX_CHARS = 1500;
17
17
  const CodeSearchParams = Type.Object({
18
18
  query: Type.String({
19
- description: "Natural-language description of the behavior, flow, error, or concept to locate, in concise English. Keep identifiers, API names, and error text verbatim. Not for a bare symbol, filename, or literal.",
19
+ description: "One behavior, flow, or error to locate, in concise English. Keep identifiers and error text verbatim. Not for a bare symbol, filename, or literal.",
20
20
  }),
21
21
  path: Type.Optional(Type.String({
22
- description: "Subdirectory to search, relative to or inside the working directory. Defaults to the working directory.",
22
+ description: "Subdirectory inside the working directory; set it when you know the subsystem. Defaults to the working directory.",
23
23
  })),
24
24
  });
25
25
  const WebSearchParams = Type.Object({
@@ -58,12 +58,11 @@ export default function search(pi) {
58
58
  pi.registerTool({
59
59
  name: "code_search",
60
60
  label: "Code Search",
61
- description: "Find where behavior lives in the local repository from a description of it. " +
62
- "Returns candidate files with line ranges.",
63
- promptSnippet: "Find code by describing its behavior",
61
+ description: "Locate code from a plain-language description of a behavior, flow, or error. Returns up to 10 candidate files with line ranges, not every match.",
62
+ promptSnippet: "Describe a behavior and receive candidate files with line ranges",
64
63
  promptGuidelines: [
65
- "Use `code_search` when you cannot name the file or symbol you need; use `read`, `grep`, or `find` when you can.",
66
- "Read the returned ranges before editing; the locations are candidates, not answers.",
64
+ "Use `code_search` primarily to orient in unfamiliar code: where a behavior or error is handled, or how a flow crosses files. When you can name the file, symbol, or literal, search for it directly.",
65
+ "Treat `code_search` results as a reading list; grep identifiers found there when you need every occurrence, such as all call sites.",
67
66
  ],
68
67
  parameters: CodeSearchParams,
69
68
  renderCall: renderCodeSearchCall,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/search/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Devin Search: `code_search` and `web_search`, both authenticated by one Devin sign-in.\n *\n * Both tools stay registered so `/tools` and old transcripts know them; a session without a\n * credential starts with them inactive, and signing in or out through `/search` toggles them.\n */\nimport { resolve } from \"node:path\";\nimport { type Static, Type } from \"typebox\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { truncateHead } from \"../../core/tools/truncate.ts\";\nimport { codeSearch, formatLocations } from \"./code-search.ts\";\nimport { registerSearchCommand, syncTools } from \"./command.ts\";\nimport { getCredential } from \"./credential.ts\";\nimport { DevinAuthError, type WebResult, webSearch } from \"./devin.ts\";\nimport {\n\ttype CodeSearchDetails,\n\trenderCodeSearchCall,\n\trenderCodeSearchResult,\n\trenderWebSearchCall,\n\trenderWebSearchResult,\n\ttype WebSearchDetails,\n} from \"./render.ts\";\nimport { isInside } from \"./workspace.ts\";\n\nconst WEB_EXCERPT_MAX_CHARS = 1500;\n\nconst CodeSearchParams = Type.Object({\n\tquery: Type.String({\n\t\tdescription:\n\t\t\t\"Natural-language description of the behavior, flow, error, or concept to locate, in concise English. Keep identifiers, API names, and error text verbatim. Not for a bare symbol, filename, or literal.\",\n\t}),\n\tpath: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Subdirectory to search, relative to or inside the working directory. Defaults to the working directory.\",\n\t\t}),\n\t),\n});\n\nconst WebSearchParams = Type.Object({\n\tquery: Type.String({\n\t\tdescription: \"Web search query. Be specific: product names, versions, exact error text. English matches best.\",\n\t}),\n\tmax_results: Type.Optional(Type.Integer({ minimum: 1, maximum: 10, description: \"Results to return (default 5).\" })),\n});\n\nconst SIGN_IN_HINT = \"Ask the user to run /search to sign in to Devin.\";\n\n/** Run a Devin call with the current credential; credential failures tell the model what fixes them. */\nasync function withDevin<T>(run: (apiKey: string) => Promise<T>): Promise<T> {\n\tconst credential = getCredential();\n\tif (!credential) throw new Error(`Devin Search is not signed in. ${SIGN_IN_HINT}`);\n\ttry {\n\t\treturn await run(credential.apiKey);\n\t} catch (error) {\n\t\tthrow error instanceof DevinAuthError ? new Error(`${error.message} ${SIGN_IN_HINT}`) : error;\n\t}\n}\n\nexport function formatWebResults(query: string, results: WebResult[]): string {\n\tif (!results.length) return `No web results for \"${query}\".`;\n\tconst blocks = results.map((r, i) => {\n\t\tconst lines = [`${i + 1}. ${r.title ?? r.url}`, ` ${r.url}`];\n\t\tif (r.summary) {\n\t\t\tconst excerpt = r.summary.replace(/\\n\\s*\\n+/g, \"\\n\").trim();\n\t\t\tlines.push(excerpt.length > WEB_EXCERPT_MAX_CHARS ? `${excerpt.slice(0, WEB_EXCERPT_MAX_CHARS)}…` : excerpt);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t});\n\treturn truncateHead(`Web results for \"${query}\":\\n\\n${blocks.join(\"\\n\\n\")}`).content;\n}\n\nexport default function search(pi: ExtensionAPI): void {\n\tpi.registerTool<typeof CodeSearchParams, CodeSearchDetails>({\n\t\tname: \"code_search\",\n\t\tlabel: \"Code Search\",\n\t\tdescription:\n\t\t\t\"Find where behavior lives in the local repository from a description of it. \" +\n\t\t\t\"Returns candidate files with line ranges.\",\n\t\tpromptSnippet: \"Find code by describing its behavior\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `code_search` when you cannot name the file or symbol you need; use `read`, `grep`, or `find` when you can.\",\n\t\t\t\"Read the returned ranges before editing; the locations are candidates, not answers.\",\n\t\t],\n\t\tparameters: CodeSearchParams,\n\t\trenderCall: renderCodeSearchCall,\n\t\trenderResult: renderCodeSearchResult,\n\n\t\tasync execute(_toolCallId, params: Static<typeof CodeSearchParams>, signal, onUpdate, ctx) {\n\t\t\tconst root = resolve(ctx.cwd, params.path ?? \".\");\n\t\t\tif (!isInside(ctx.cwd, root)) throw new Error(`path must be inside the working directory (${ctx.cwd}).`);\n\t\t\tconst locations = await withDevin((apiKey) =>\n\t\t\t\tcodeSearch({\n\t\t\t\t\tapiKey,\n\t\t\t\t\tquery: params.query.trim(),\n\t\t\t\t\troot,\n\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\tsignal,\n\t\t\t\t\tonProgress: (text) => onUpdate?.({ content: [{ type: \"text\", text }], details: { locations: [] } }),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn { content: [{ type: \"text\", text: formatLocations(locations) }], details: { locations } };\n\t\t},\n\t});\n\n\t// Pi's system prompt carries no date, so models otherwise search with their training year.\n\tconst currentMonth = new Date().toLocaleDateString(\"en-US\", { month: \"long\", year: \"numeric\" });\n\tpi.registerTool<typeof WebSearchParams, WebSearchDetails>({\n\t\tname: \"web_search\",\n\t\tlabel: \"Web Search\",\n\t\tdescription:\n\t\t\t\"Search the live web for current information. Returns titles, URLs, and the page excerpts that match the query.\",\n\t\tpromptSnippet: \"Search the live web for current information\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `web_search` for information beyond your knowledge cutoff.\",\n\t\t\t`It is ${currentMonth}; put this year in \\`web_search\\` queries for recent releases, versions, or events, not the year your training data suggests.`,\n\t\t\t\"When an answer relies on `web_search` results, cite each result you used as a markdown link: [Title](URL).\",\n\t\t],\n\t\tparameters: WebSearchParams,\n\t\trenderCall: renderWebSearchCall,\n\t\trenderResult: renderWebSearchResult,\n\n\t\tasync execute(_toolCallId, params: Static<typeof WebSearchParams>, signal) {\n\t\t\tconst query = params.query.trim();\n\t\t\tconst results = await withDevin((apiKey) => webSearch(apiKey, query, params.max_results ?? 5, signal));\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: formatWebResults(query, results) }],\n\t\t\t\tdetails: { results: results.map(({ url, title }) => ({ url, title })) },\n\t\t\t};\n\t\t},\n\t});\n\n\tregisterSearchCommand(pi);\n\tpi.on(\"session_start\", async () => syncTools(pi));\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/extensions/search/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Devin Search: `code_search` and `web_search`, both authenticated by one Devin sign-in.\n *\n * Both tools stay registered so `/tools` and old transcripts know them; a session without a\n * credential starts with them inactive, and signing in or out through `/search` toggles them.\n */\nimport { resolve } from \"node:path\";\nimport { type Static, Type } from \"typebox\";\nimport type { ExtensionAPI } from \"../../core/extensions/types.ts\";\nimport { truncateHead } from \"../../core/tools/truncate.ts\";\nimport { codeSearch, formatLocations } from \"./code-search.ts\";\nimport { registerSearchCommand, syncTools } from \"./command.ts\";\nimport { getCredential } from \"./credential.ts\";\nimport { DevinAuthError, type WebResult, webSearch } from \"./devin.ts\";\nimport {\n\ttype CodeSearchDetails,\n\trenderCodeSearchCall,\n\trenderCodeSearchResult,\n\trenderWebSearchCall,\n\trenderWebSearchResult,\n\ttype WebSearchDetails,\n} from \"./render.ts\";\nimport { isInside } from \"./workspace.ts\";\n\nconst WEB_EXCERPT_MAX_CHARS = 1500;\n\nconst CodeSearchParams = Type.Object({\n\tquery: Type.String({\n\t\tdescription:\n\t\t\t\"One behavior, flow, or error to locate, in concise English. Keep identifiers and error text verbatim. Not for a bare symbol, filename, or literal.\",\n\t}),\n\tpath: Type.Optional(\n\t\tType.String({\n\t\t\tdescription:\n\t\t\t\t\"Subdirectory inside the working directory; set it when you know the subsystem. Defaults to the working directory.\",\n\t\t}),\n\t),\n});\n\nconst WebSearchParams = Type.Object({\n\tquery: Type.String({\n\t\tdescription: \"Web search query. Be specific: product names, versions, exact error text. English matches best.\",\n\t}),\n\tmax_results: Type.Optional(Type.Integer({ minimum: 1, maximum: 10, description: \"Results to return (default 5).\" })),\n});\n\nconst SIGN_IN_HINT = \"Ask the user to run /search to sign in to Devin.\";\n\n/** Run a Devin call with the current credential; credential failures tell the model what fixes them. */\nasync function withDevin<T>(run: (apiKey: string) => Promise<T>): Promise<T> {\n\tconst credential = getCredential();\n\tif (!credential) throw new Error(`Devin Search is not signed in. ${SIGN_IN_HINT}`);\n\ttry {\n\t\treturn await run(credential.apiKey);\n\t} catch (error) {\n\t\tthrow error instanceof DevinAuthError ? new Error(`${error.message} ${SIGN_IN_HINT}`) : error;\n\t}\n}\n\nexport function formatWebResults(query: string, results: WebResult[]): string {\n\tif (!results.length) return `No web results for \"${query}\".`;\n\tconst blocks = results.map((r, i) => {\n\t\tconst lines = [`${i + 1}. ${r.title ?? r.url}`, ` ${r.url}`];\n\t\tif (r.summary) {\n\t\t\tconst excerpt = r.summary.replace(/\\n\\s*\\n+/g, \"\\n\").trim();\n\t\t\tlines.push(excerpt.length > WEB_EXCERPT_MAX_CHARS ? `${excerpt.slice(0, WEB_EXCERPT_MAX_CHARS)}…` : excerpt);\n\t\t}\n\t\treturn lines.join(\"\\n\");\n\t});\n\treturn truncateHead(`Web results for \"${query}\":\\n\\n${blocks.join(\"\\n\\n\")}`).content;\n}\n\nexport default function search(pi: ExtensionAPI): void {\n\tpi.registerTool<typeof CodeSearchParams, CodeSearchDetails>({\n\t\tname: \"code_search\",\n\t\tlabel: \"Code Search\",\n\t\tdescription:\n\t\t\t\"Locate code from a plain-language description of a behavior, flow, or error. Returns up to 10 candidate files with line ranges, not every match.\",\n\t\tpromptSnippet: \"Describe a behavior and receive candidate files with line ranges\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `code_search` primarily to orient in unfamiliar code: where a behavior or error is handled, or how a flow crosses files. When you can name the file, symbol, or literal, search for it directly.\",\n\t\t\t\"Treat `code_search` results as a reading list; grep identifiers found there when you need every occurrence, such as all call sites.\",\n\t\t],\n\t\tparameters: CodeSearchParams,\n\t\trenderCall: renderCodeSearchCall,\n\t\trenderResult: renderCodeSearchResult,\n\n\t\tasync execute(_toolCallId, params: Static<typeof CodeSearchParams>, signal, onUpdate, ctx) {\n\t\t\tconst root = resolve(ctx.cwd, params.path ?? \".\");\n\t\t\tif (!isInside(ctx.cwd, root)) throw new Error(`path must be inside the working directory (${ctx.cwd}).`);\n\t\t\tconst locations = await withDevin((apiKey) =>\n\t\t\t\tcodeSearch({\n\t\t\t\t\tapiKey,\n\t\t\t\t\tquery: params.query.trim(),\n\t\t\t\t\troot,\n\t\t\t\t\tcwd: ctx.cwd,\n\t\t\t\t\tsignal,\n\t\t\t\t\tonProgress: (text) => onUpdate?.({ content: [{ type: \"text\", text }], details: { locations: [] } }),\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn { content: [{ type: \"text\", text: formatLocations(locations) }], details: { locations } };\n\t\t},\n\t});\n\n\t// Pi's system prompt carries no date, so models otherwise search with their training year.\n\tconst currentMonth = new Date().toLocaleDateString(\"en-US\", { month: \"long\", year: \"numeric\" });\n\tpi.registerTool<typeof WebSearchParams, WebSearchDetails>({\n\t\tname: \"web_search\",\n\t\tlabel: \"Web Search\",\n\t\tdescription:\n\t\t\t\"Search the live web for current information. Returns titles, URLs, and the page excerpts that match the query.\",\n\t\tpromptSnippet: \"Search the live web for current information\",\n\t\tpromptGuidelines: [\n\t\t\t\"Use `web_search` for information beyond your knowledge cutoff.\",\n\t\t\t`It is ${currentMonth}; put this year in \\`web_search\\` queries for recent releases, versions, or events, not the year your training data suggests.`,\n\t\t\t\"When an answer relies on `web_search` results, cite each result you used as a markdown link: [Title](URL).\",\n\t\t],\n\t\tparameters: WebSearchParams,\n\t\trenderCall: renderWebSearchCall,\n\t\trenderResult: renderWebSearchResult,\n\n\t\tasync execute(_toolCallId, params: Static<typeof WebSearchParams>, signal) {\n\t\t\tconst query = params.query.trim();\n\t\t\tconst results = await withDevin((apiKey) => webSearch(apiKey, query, params.max_results ?? 5, signal));\n\t\t\treturn {\n\t\t\t\tcontent: [{ type: \"text\", text: formatWebResults(query, results) }],\n\t\t\t\tdetails: { results: results.map(({ url, title }) => ({ url, title })) },\n\t\t\t};\n\t\t},\n\t});\n\n\tregisterSearchCommand(pi);\n\tpi.on(\"session_start\", async () => syncTools(pi));\n}\n"]}
@@ -2,11 +2,10 @@
2
2
  import type { AgentToolResult } from "../../../core/extensions/types.ts";
3
3
  import { type TaskSnapshot, type TasksContext } from "../../../core/tasks/types.ts";
4
4
  import { type TasksInput } from "./schema.ts";
5
- import type { TasksKillDetails, TasksListDetails, TasksReadDetails, TasksWaitDetails } from "./types.ts";
5
+ import type { TasksKillDetails, TasksListDetails, TasksReadDetails } from "./types.ts";
6
6
  export declare function boundedText(text: string): string;
7
7
  export declare function describeTaskLine(task: TaskSnapshot, now?: number): string;
8
8
  export declare function runRead(background: TasksContext, input: TasksInput): Promise<AgentToolResult<TasksReadDetails>>;
9
- export declare function runWait(background: TasksContext, input: TasksInput, signal?: AbortSignal, toolCallId?: string): Promise<AgentToolResult<TasksWaitDetails>>;
10
9
  export declare function runKill(background: TasksContext, input: TasksInput): AgentToolResult<TasksKillDetails>;
11
10
  export declare function runList(background: TasksContext): AgentToolResult<TasksListDetails>;
12
11
  //# sourceMappingURL=actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/tool/actions.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIzE,OAAO,EAIN,KAAK,YAAY,EACjB,KAAK,YAAY,EAEjB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAgB,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAa,GAAG,MAAM,CAE7E;AAwFD,wBAAsB,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAkBrH;AAkED,wBAAsB,OAAO,CAC5B,UAAU,EAAE,YAAY,EACxB,KAAK,EAAE,UAAU,EACjB,MAAM,CAAC,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAqB5C;AACD,wBAAgB,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAoBtG;AACD,wBAAgB,OAAO,CAAC,UAAU,EAAE,YAAY,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAmBnF"}
1
+ {"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../../../src/extensions/tasks/tool/actions.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAElF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AAIzE,OAAO,EAIN,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,MAAM,8BAA8B,CAAC;AAItC,OAAO,EAAkC,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9E,OAAO,KAAK,EAAgB,gBAAgB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAErG,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEhD;AAID,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,YAAY,EAAE,GAAG,SAAa,GAAG,MAAM,CAE7E;AAuFD,wBAAsB,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,eAAe,CAAC,gBAAgB,CAAC,CAAC,CAoBrH;AAED,wBAAgB,OAAO,CAAC,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAoBtG;AACD,wBAAgB,OAAO,CAAC,UAAU,EAAE,YAAY,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAmBnF"}
@@ -1,11 +1,11 @@
1
1
  /** Management only: execution and delivery belong to the session task runtime. */
2
2
  import { runtimeLabel } from "../../../core/tasks/format.js";
3
- import { clampReadBytes, clampWaitMs } from "../../../core/tasks/limits.js";
4
- import { boundText } from "../../../core/tasks/output.js";
3
+ import { clampReadBytes, defaultReadMode } from "../../../core/tasks/limits.js";
4
+ import { boundText, taskReadBytes, taskReadRange } from "../../../core/tasks/output.js";
5
5
  import { isTaskTerminal, TaskLookupError, } from "../../../core/tasks/types.js";
6
6
  import { truncateHead } from "../../../core/tools/truncate.js";
7
7
  import { sanitizeBinaryOutput } from "../../../utils/shell.js";
8
- import { TASKS_LIST_FINISHED_SHOWN, TASKS_WAIT_DELTA_BYTES } from "./constants.js";
8
+ import { TASKS_LIST_FINISHED_SHOWN } from "./constants.js";
9
9
  import { clampSinceBytes, requireTaskId } from "./schema.js";
10
10
  export function boundedText(text) {
11
11
  return truncateHead(sanitizeBinaryOutput(text), { maxBytes: 50 * 1024, maxLines: 2000 }).content;
@@ -66,12 +66,11 @@ function lookupFailure(background, id, error) {
66
66
  return new Error(`No task "${id}" in this session. IDs from other sessions are not valid here.\nCurrent background tasks:\n${lines}${foregroundOmissionNote(foregroundOmitted)}`);
67
67
  }
68
68
  /**
69
- * Where this slice sits in the output, so the next wait can continue from it.
70
- * A wait whose new output exceeds its budget returns the newest bytes and says what it skipped.
69
+ * Where this slice sits in the output, so the next read can continue from it.
70
+ * A tail read whose new output exceeds its budget returns the newest bytes and says what it skipped.
71
71
  */
72
72
  function rangeText(slice, sinceBytes) {
73
- const from = slice.fromByte ?? 0;
74
- const to = from + Buffer.byteLength(slice.text);
73
+ const { from, to } = taskReadRange(slice);
75
74
  const floor = sinceBytes === undefined || sinceBytes > slice.totalBytes ? 0 : sinceBytes;
76
75
  return [
77
76
  `bytes ${from}–${to} of ${slice.totalBytes}`,
@@ -97,13 +96,15 @@ function readText(header, slice) {
97
96
  export async function runRead(background, input) {
98
97
  const id = requireTaskId(input);
99
98
  try {
100
- const mode = input.mode ?? "tail";
101
- const slice = await background.read(id, { mode, bytes: clampReadBytes(input.bytes) });
102
- return result(readText(`[${describeTaskLine(slice.task)} · ${rangeText(slice)}]`, slice), {
99
+ const sinceBytes = clampSinceBytes(input.sinceBytes);
100
+ const slice = await background.read(id, { mode: input.mode, bytes: clampReadBytes(input.bytes), sinceBytes });
101
+ // The runtime resolved an omitted mode from this same snapshot, so report what it actually used.
102
+ const mode = input.mode ?? defaultReadMode(slice.task);
103
+ return result(readText(`[${describeTaskLine(slice.task)} · ${rangeText(slice, sinceBytes)}]`, slice), {
103
104
  action: "read",
104
105
  taskId: slice.task.id,
105
106
  mode,
106
- sliceBytes: Buffer.byteLength(slice.text),
107
+ sliceBytes: taskReadBytes(slice),
107
108
  totalBytes: slice.totalBytes,
108
109
  outputPath: slice.task.outputPath ?? "",
109
110
  kind: slice.task.kind,
@@ -114,75 +115,6 @@ export async function runRead(background, input) {
114
115
  throw lookupFailure(background, id, error);
115
116
  }
116
117
  }
117
- function stillRunningText(tasks) {
118
- return tasks.length > 0 ? `\n\n[still_running]\n${tasks.map((task) => describeTaskLine(task)).join("\n")}` : "";
119
- }
120
- function waitDetails({ outcome, waitedMs, task, read, running }) {
121
- return {
122
- action: "wait",
123
- // A closed host is told apart in the text; the stored outcome keeps its historical values.
124
- outcome: outcome === "closed" ? "timed_out" : outcome,
125
- ...(task ? { taskId: task.id, status: task.status, kind: task.kind } : {}),
126
- waitedMs,
127
- deltaBytes: read ? Buffer.byteLength(read.text) : 0,
128
- totalBytes: read?.totalBytes ?? 0,
129
- deltaTruncated: read?.truncated ?? false,
130
- outputPath: task?.outputPath ?? "",
131
- ...(running ? { running: running.length } : {}),
132
- };
133
- }
134
- function waitText(view, sinceBytes) {
135
- const { scope, outcome, task, read, running } = view;
136
- const still = stillRunningText(running ?? []);
137
- if (outcome === "no_tasks") {
138
- return "No background tasks are running, so there is nothing to wait for. Finished tasks report back via automatic notification.";
139
- }
140
- if (read && task) {
141
- const header = scope === "any"
142
- ? `${describeTaskLine(task)} · waitAny settled`
143
- : `${describeTaskLine(task)}${outcome === "closed"
144
- ? " · host closed; execution state unconfirmed"
145
- : outcome === "timed_out"
146
- ? " · wait window expired; execution continues"
147
- : ""}`;
148
- return `${readText(`[${header} · ${rangeText(read, sinceBytes)}]`, read)}${still}`;
149
- }
150
- if (scope === "task" && task) {
151
- return `[${describeTaskLine(task)} · interrupted by steering; execution continues]\nRead the new input before deciding whether to wait again; the task was not stopped.`;
152
- }
153
- const note = outcome === "closed"
154
- ? "The host closed; execution state is unconfirmed."
155
- : outcome === "interrupted"
156
- ? "New steering input ended this wait early. Read the new input before deciding what to do next; no task was stopped."
157
- : "The wait window expired; running tasks continue. Prefer other work over waiting again.";
158
- return `${note}${still}`;
159
- }
160
- function waitResult(view, sinceBytes) {
161
- return result(waitText(view, sinceBytes), waitDetails(view));
162
- }
163
- export async function runWait(background, input, signal, toolCallId) {
164
- const timeoutMs = clampWaitMs(input.waitMs);
165
- if (!input.taskId?.trim()) {
166
- if (input.sinceBytes !== undefined)
167
- throw new Error("action 'wait' without 'taskId' does not accept 'sinceBytes'; offsets belong to one task.");
168
- const any = await background.waitAny({ timeoutMs, signal, toolCallId, read: { bytes: TASKS_WAIT_DELTA_BYTES } });
169
- return waitResult({ scope: "any", ...any });
170
- }
171
- const id = requireTaskId(input);
172
- try {
173
- const sinceBytes = clampSinceBytes(input.sinceBytes);
174
- const one = await background.wait(id, {
175
- timeoutMs,
176
- signal,
177
- toolCallId,
178
- read: { bytes: TASKS_WAIT_DELTA_BYTES, sinceBytes },
179
- });
180
- return waitResult({ scope: "task", ...one }, sinceBytes);
181
- }
182
- catch (error) {
183
- throw lookupFailure(background, id, error);
184
- }
185
- }
186
118
  export function runKill(background, input) {
187
119
  const id = requireTaskId(input);
188
120
  try {