@pi-unipi/unipi 3.0.0-alpha.2 → 3.0.0-alpha.21

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 (359) hide show
  1. package/CHANGELOG.md +292 -0
  2. package/README.md +8 -11
  3. package/docs/prefix-cache-architecture.md +14 -0
  4. package/package.json +22 -24
  5. package/packages/ask-user/README.md +55 -107
  6. package/packages/ask-user/ask-ui.ts +306 -732
  7. package/packages/ask-user/clipboard.ts +50 -0
  8. package/packages/ask-user/config.ts +74 -78
  9. package/packages/ask-user/package.json +2 -2
  10. package/packages/ask-user/questions.ts +151 -0
  11. package/packages/ask-user/skills/ask-user/SKILL.md +59 -133
  12. package/packages/ask-user/tools.ts +198 -432
  13. package/packages/autocomplete/package.json +1 -1
  14. package/packages/autocomplete/src/constants.ts +38 -43
  15. package/packages/autocomplete/src/sorting.ts +8 -0
  16. package/packages/background-tasks/package.json +2 -2
  17. package/packages/background-tasks/src/config.ts +0 -73
  18. package/packages/background-tasks/src/index.ts +20 -16
  19. package/packages/background-tasks/src/registry.ts +1 -171
  20. package/packages/background-tasks/src/types.ts +0 -32
  21. package/packages/btw/README.md +13 -56
  22. package/packages/btw/extensions/btw.ts +403 -1796
  23. package/packages/btw/package.json +5 -2
  24. package/packages/btw/skills/btw/SKILL.md +7 -143
  25. package/packages/compactor/README.md +56 -287
  26. package/packages/compactor/package.json +5 -9
  27. package/packages/compactor/skills/compactor/SKILL.md +13 -20
  28. package/packages/compactor/src/card.ts +90 -0
  29. package/packages/compactor/src/commands/index.ts +73 -130
  30. package/packages/compactor/src/compaction/compact-args.ts +5 -3
  31. package/packages/compactor/src/compaction/filter-noise.ts +1 -1
  32. package/packages/compactor/src/compaction/hooks.ts +487 -311
  33. package/packages/compactor/src/compaction/source.ts +178 -0
  34. package/packages/compactor/src/compaction/summarize.ts +586 -52
  35. package/packages/compactor/src/config/manager.ts +130 -127
  36. package/packages/compactor/src/config/schema.ts +32 -48
  37. package/packages/compactor/src/index.ts +40 -431
  38. package/packages/compactor/src/info-screen.ts +44 -190
  39. package/packages/compactor/src/session/recall-blocks.ts +1 -1
  40. package/packages/compactor/src/stats.ts +76 -0
  41. package/packages/compactor/src/tools/context-budget.ts +17 -34
  42. package/packages/compactor/src/tools/ctx-doctor.ts +45 -36
  43. package/packages/compactor/src/tools/register.ts +29 -269
  44. package/packages/compactor/src/types.ts +47 -186
  45. package/packages/core/README.md +25 -0
  46. package/packages/core/child-agent.ts +1 -0
  47. package/packages/core/command-echo.ts +63 -0
  48. package/packages/core/compaction-context.ts +41 -0
  49. package/packages/core/constants.ts +8 -38
  50. package/packages/core/events.ts +0 -53
  51. package/packages/core/fusion-status.ts +4 -0
  52. package/packages/core/global.d.ts +10 -0
  53. package/packages/core/harness-messages.ts +392 -0
  54. package/packages/core/index.ts +14 -0
  55. package/packages/core/kanboard-status.ts +49 -0
  56. package/packages/core/long-horizon-owner-status.ts +46 -0
  57. package/packages/core/model-cache.ts +81 -7
  58. package/packages/core/package.json +6 -3
  59. package/packages/core/src/attach/detect.ts +163 -0
  60. package/packages/core/src/child-agent/child-args.ts +31 -0
  61. package/packages/core/src/child-agent/delivery.ts +41 -0
  62. package/packages/core/src/child-agent/index.ts +5 -0
  63. package/packages/core/src/child-agent/readers.ts +203 -0
  64. package/packages/core/src/child-agent/runtime.ts +584 -0
  65. package/packages/core/src/evidence.ts +78 -0
  66. package/packages/core/src/hints/browser.ts +278 -0
  67. package/packages/core/src/hints/crab-data.ts +19 -0
  68. package/packages/core/src/hints/index.ts +865 -0
  69. package/packages/core/src/hints/lines.ts +607 -0
  70. package/packages/core/src/hints/store.ts +120 -0
  71. package/packages/core/src/jev/chatter.ts +24 -0
  72. package/packages/core/src/jev/settings.ts +177 -14
  73. package/packages/core/src/package-colors.ts +2 -0
  74. package/packages/core/src/settings/catalog.ts +39 -15
  75. package/packages/core/src/settings/engine.ts +48 -2
  76. package/packages/core/src/settings/hub.ts +83 -20
  77. package/packages/core/src/settings/open.ts +49 -0
  78. package/packages/core/src/settings/schema.ts +27 -7
  79. package/packages/core/src/tui/hub-kit.ts +18 -5
  80. package/packages/core/src/tui/kit.ts +198 -0
  81. package/packages/core/src/tui/progress.ts +73 -0
  82. package/packages/core/src/turn/arbiter.ts +290 -0
  83. package/packages/footer/README.md +4 -6
  84. package/packages/footer/package.json +3 -3
  85. package/packages/footer/src/glance-editor.ts +19 -11
  86. package/packages/footer/src/help.ts +1 -1
  87. package/packages/footer/src/index.ts +36 -3
  88. package/packages/footer/src/presets.ts +3 -4
  89. package/packages/footer/src/rendering/icons.ts +0 -20
  90. package/packages/footer/src/segments/compactor.ts +52 -142
  91. package/packages/footer/src/segments/status-ext.ts +0 -1
  92. package/packages/fusion/README.md +14 -4
  93. package/packages/fusion/package.json +4 -3
  94. package/packages/fusion/src/child-args.ts +1 -0
  95. package/packages/fusion/src/index.ts +161 -8
  96. package/packages/fusion/src/pi-settings.ts +57 -0
  97. package/packages/fusion/src/picker.ts +186 -51
  98. package/packages/fusion/src/preset.ts +56 -2
  99. package/packages/fusion/src/prompts.ts +1 -1
  100. package/packages/fusion/src/sidekick-runtime.ts +1 -420
  101. package/packages/fusion/src/tools.ts +107 -128
  102. package/packages/fusion/src/transcript.ts +27 -85
  103. package/packages/info-screen/package.json +2 -2
  104. package/packages/input-shortcuts/README.md +18 -30
  105. package/packages/input-shortcuts/package.json +2 -2
  106. package/packages/input-shortcuts/src/burst.ts +88 -0
  107. package/packages/input-shortcuts/src/chord-overlay.ts +20 -70
  108. package/packages/input-shortcuts/src/cleared-input.ts +97 -0
  109. package/packages/input-shortcuts/src/index.ts +99 -193
  110. package/packages/input-shortcuts/src/last-response.ts +40 -0
  111. package/packages/input-shortcuts/src/registers.ts +8 -23
  112. package/packages/input-shortcuts/src/types.ts +4 -16
  113. package/packages/input-shortcuts/src/undo-redo.ts +59 -47
  114. package/packages/kanboard/README.md +51 -47
  115. package/packages/kanboard/index.ts +293 -55
  116. package/packages/kanboard/package.json +8 -8
  117. package/packages/kanboard/skills/kanboard/SKILL.md +61 -27
  118. package/packages/kanboard/src/badges.ts +93 -0
  119. package/packages/kanboard/src/bin.ts +4 -2
  120. package/packages/kanboard/src/commands.ts +218 -84
  121. package/packages/kanboard/src/debug.ts +20 -0
  122. package/packages/kanboard/src/guard.ts +267 -109
  123. package/packages/kanboard/src/monitor.ts +330 -0
  124. package/packages/kanboard/src/notice-buffer.ts +74 -0
  125. package/packages/kanboard/src/progress.ts +27 -0
  126. package/packages/kanboard/src/reminders.ts +234 -0
  127. package/packages/kanboard/src/settings.ts +69 -15
  128. package/packages/kanboard/src/shapes.ts +5 -0
  129. package/packages/long-horizon/index.ts +190 -13
  130. package/packages/long-horizon/package.json +3 -3
  131. package/packages/long-horizon/src/commands.ts +103 -7
  132. package/packages/long-horizon/src/compaction-brief.ts +35 -0
  133. package/packages/long-horizon/src/engine/continuation.ts +84 -15
  134. package/packages/long-horizon/src/engine/goal-state.ts +64 -13
  135. package/packages/long-horizon/src/engine/nudge-stash.ts +71 -0
  136. package/packages/long-horizon/src/engine/ralph.ts +3 -2
  137. package/packages/long-horizon/src/engine/runaway.ts +68 -11
  138. package/packages/long-horizon/src/engine/verifier.ts +19 -0
  139. package/packages/long-horizon/src/gate.ts +37 -12
  140. package/packages/long-horizon/src/judge/resolve.ts +1 -0
  141. package/packages/long-horizon/src/owner.ts +35 -2
  142. package/packages/long-horizon/src/progress.ts +87 -0
  143. package/packages/long-horizon/src/prompts/goal.ts +1 -1
  144. package/packages/long-horizon/src/runtime.ts +172 -18
  145. package/packages/long-horizon/src/settings.ts +54 -39
  146. package/packages/long-horizon/src/tools/goal.ts +6 -0
  147. package/packages/long-horizon/src/tools/graph.ts +1 -1
  148. package/packages/long-horizon/src/tools/swarm.ts +3 -3
  149. package/packages/mcp/package.json +2 -2
  150. package/packages/memory/commands.ts +7 -2
  151. package/packages/memory/index.ts +210 -32
  152. package/packages/memory/package.json +3 -3
  153. package/packages/memory/save-session.ts +264 -0
  154. package/packages/memory/settings.ts +17 -0
  155. package/packages/memory/tools.ts +253 -203
  156. package/packages/notify/package.json +2 -2
  157. package/packages/skill-registry/README.md +53 -16
  158. package/packages/skill-registry/index.ts +230 -0
  159. package/packages/skill-registry/package.json +19 -8
  160. package/packages/skill-registry/src/editor.ts +206 -0
  161. package/packages/skill-registry/src/judge.ts +289 -0
  162. package/packages/skill-registry/src/registry.ts +87 -0
  163. package/packages/skill-registry/src/settings.ts +259 -0
  164. package/packages/skill-registry/src/vault.ts +80 -0
  165. package/packages/subagents/README.md +39 -119
  166. package/packages/subagents/package.json +6 -13
  167. package/packages/subagents/skills/subagents/SKILL.md +18 -42
  168. package/packages/subagents/src/agents.ts +213 -0
  169. package/packages/subagents/src/cards.ts +182 -0
  170. package/packages/subagents/src/index.ts +609 -1084
  171. package/packages/subagents/src/manager.ts +429 -0
  172. package/packages/subagents/src/profiles.ts +130 -0
  173. package/packages/subagents/src/transcript.ts +154 -0
  174. package/packages/subagents/src/ui.ts +389 -0
  175. package/packages/unipi/bundled.js +39756 -45569
  176. package/packages/unipi/index.ts +55 -10
  177. package/packages/updater/package.json +2 -2
  178. package/packages/utility/README.md +76 -69
  179. package/packages/utility/package.json +2 -2
  180. package/packages/utility/skills/image/SKILL.md +37 -0
  181. package/packages/utility/skills/utility/SKILL.md +17 -60
  182. package/packages/utility/src/answer/extract.ts +128 -0
  183. package/packages/utility/src/answer/index.ts +213 -0
  184. package/packages/utility/src/answer/reply.ts +133 -0
  185. package/packages/utility/src/answer/web.ts +167 -0
  186. package/packages/utility/src/attach/index.ts +205 -0
  187. package/packages/utility/src/commands.ts +38 -142
  188. package/packages/utility/src/diagnostics/engine.ts +50 -5
  189. package/packages/utility/src/image/index.ts +33 -0
  190. package/packages/utility/src/image/models.ts +221 -0
  191. package/packages/{image/src → utility/src/image}/recognize.ts +2 -2
  192. package/packages/utility/src/image/settings.ts +178 -0
  193. package/packages/{image/src/image-source.ts → utility/src/image/source.ts} +1 -1
  194. package/packages/utility/src/image/tools.ts +168 -0
  195. package/packages/utility/src/image/transports.ts +186 -0
  196. package/packages/utility/src/index.ts +68 -389
  197. package/packages/utility/src/lifecycle/cleanup.ts +116 -311
  198. package/packages/utility/src/rename/gate.ts +102 -0
  199. package/packages/utility/src/rename/index.ts +191 -0
  200. package/packages/utility/src/rename/session.ts +170 -0
  201. package/packages/utility/src/render/delegated.ts +285 -0
  202. package/packages/utility/src/render/harness.ts +683 -0
  203. package/packages/utility/src/render/parse.ts +156 -0
  204. package/packages/utility/src/render/pi-settings.ts +38 -0
  205. package/packages/utility/src/render/reply-bg.ts +307 -0
  206. package/packages/utility/src/render/simple.ts +724 -0
  207. package/packages/utility/src/render/spacing.ts +235 -0
  208. package/packages/utility/src/render/styled.ts +251 -0
  209. package/packages/utility/src/render/tools.ts +353 -0
  210. package/packages/utility/src/settings.ts +166 -233
  211. package/packages/utility/src/types.ts +1 -222
  212. package/packages/watchdog/index.ts +17 -6
  213. package/packages/watchdog/package.json +3 -3
  214. package/packages/watchdog/src/config.ts +3 -2
  215. package/packages/web-api/package.json +2 -2
  216. package/packages/workflow/README.md +3 -0
  217. package/packages/workflow/index.ts +0 -2
  218. package/packages/workflow/package.json +2 -2
  219. package/packages/workflow/src/permission/decide.ts +6 -4
  220. package/packages/workflow/src/permission/index.ts +17 -7
  221. package/packages/workflow/src/permission/settings.ts +39 -4
  222. package/packages/workflow/src/plan/index.ts +19 -4
  223. package/packages/background-tasks/extensions/delegate-child.ts +0 -1
  224. package/packages/background-tasks/src/context-parent-snapshot.ts +0 -142
  225. package/packages/background-tasks/src/context-token-budget.ts +0 -903
  226. package/packages/background-tasks/src/context-visible-conversation-v2.ts +0 -551
  227. package/packages/background-tasks/src/delegate/artifacts.ts +0 -487
  228. package/packages/background-tasks/src/delegate/budget.ts +0 -415
  229. package/packages/background-tasks/src/delegate/hook-contract-evidence.json +0 -18
  230. package/packages/background-tasks/src/delegate/hook-contract.ts +0 -154
  231. package/packages/background-tasks/src/delegate/launch.ts +0 -484
  232. package/packages/background-tasks/src/delegate/result-package.ts +0 -459
  233. package/packages/background-tasks/src/delegate/runner.ts +0 -430
  234. package/packages/background-tasks/src/delegate/seed.ts +0 -423
  235. package/packages/background-tasks/src/delegate/types.ts +0 -323
  236. package/packages/background-tasks/src/delegate-child-extension.ts +0 -978
  237. package/packages/background-tasks/src/delegate-extension.ts +0 -654
  238. package/packages/background-tasks/src/fixtures/delegate-context-incident.json +0 -17
  239. package/packages/compactor/skills/compactor-detail/SKILL.md +0 -116
  240. package/packages/compactor/skills/compactor-doctor/SKILL.md +0 -71
  241. package/packages/compactor/skills/compactor-stats/SKILL.md +0 -51
  242. package/packages/compactor/src/compaction/build-sections.ts +0 -76
  243. package/packages/compactor/src/compaction/extract/goals.ts +0 -36
  244. package/packages/compactor/src/compaction/extract/preferences.ts +0 -40
  245. package/packages/compactor/src/compaction/format.ts +0 -53
  246. package/packages/compactor/src/compaction/merge.ts +0 -143
  247. package/packages/compactor/src/config/presets.ts +0 -160
  248. package/packages/compactor/src/executor/executor.ts +0 -233
  249. package/packages/compactor/src/executor/runtime.ts +0 -115
  250. package/packages/compactor/src/security/evaluator.ts +0 -89
  251. package/packages/compactor/src/security/policy.ts +0 -96
  252. package/packages/compactor/src/security/scanner.ts +0 -65
  253. package/packages/compactor/src/session/auto-inject.ts +0 -60
  254. package/packages/compactor/src/session/db.ts +0 -325
  255. package/packages/compactor/src/session/extract.ts +0 -144
  256. package/packages/compactor/src/session/resume-inject.ts +0 -64
  257. package/packages/compactor/src/session/snapshot.ts +0 -327
  258. package/packages/compactor/src/tools/ctx-batch-execute.ts +0 -41
  259. package/packages/compactor/src/tools/ctx-execute-file.ts +0 -23
  260. package/packages/compactor/src/tools/ctx-execute.ts +0 -23
  261. package/packages/compactor/src/tools/ctx-stats.ts +0 -96
  262. package/packages/image/README.md +0 -99
  263. package/packages/image/package.json +0 -61
  264. package/packages/image/skills/image/SKILL.md +0 -76
  265. package/packages/image/src/generate.ts +0 -256
  266. package/packages/image/src/index.ts +0 -135
  267. package/packages/image/src/models.ts +0 -519
  268. package/packages/image/src/openai-images-api.ts +0 -282
  269. package/packages/image/src/register-providers.ts +0 -209
  270. package/packages/image/src/settings.ts +0 -173
  271. package/packages/image/src/tools.ts +0 -326
  272. package/packages/input-shortcuts/src/clipboard.ts +0 -119
  273. package/packages/kanboard/src/runner.ts +0 -817
  274. package/packages/skill-registry/skills/auto/SKILL.md +0 -465
  275. package/packages/skill-registry/skills/brainstorm/SKILL.md +0 -219
  276. package/packages/skill-registry/skills/chore-create/SKILL.md +0 -315
  277. package/packages/skill-registry/skills/chore-execute/SKILL.md +0 -314
  278. package/packages/skill-registry/skills/consolidate/SKILL.md +0 -142
  279. package/packages/skill-registry/skills/consultant/SKILL.md +0 -97
  280. package/packages/skill-registry/skills/debug/SKILL.md +0 -228
  281. package/packages/skill-registry/skills/document/SKILL.md +0 -120
  282. package/packages/skill-registry/skills/fix/SKILL.md +0 -212
  283. package/packages/skill-registry/skills/gather-context/SKILL.md +0 -145
  284. package/packages/skill-registry/skills/plan/SKILL.md +0 -231
  285. package/packages/skill-registry/skills/quick-fix/SKILL.md +0 -135
  286. package/packages/skill-registry/skills/quick-work/SKILL.md +0 -110
  287. package/packages/skill-registry/skills/research/SKILL.md +0 -251
  288. package/packages/skill-registry/skills/review-work/SKILL.md +0 -187
  289. package/packages/skill-registry/skills/scan-issues/SKILL.md +0 -195
  290. package/packages/skill-registry/skills/work/SKILL.md +0 -218
  291. package/packages/skill-registry/skills/worktree-create/SKILL.md +0 -69
  292. package/packages/skill-registry/skills/worktree-list/SKILL.md +0 -78
  293. package/packages/skill-registry/skills/worktree-merge/SKILL.md +0 -89
  294. package/packages/subagents/agents/delegate.md +0 -14
  295. package/packages/subagents/agents/oracle.md +0 -78
  296. package/packages/subagents/agents/researcher.md +0 -52
  297. package/packages/subagents/agents/reviewer.md +0 -80
  298. package/packages/subagents/agents/scout.md +0 -50
  299. package/packages/subagents/agents/worker.md +0 -59
  300. package/packages/subagents/prompts/council.md +0 -48
  301. package/packages/subagents/prompts/gather-context-and-clarify.md +0 -13
  302. package/packages/subagents/prompts/parallel-cleanup.md +0 -59
  303. package/packages/subagents/prompts/parallel-research.md +0 -50
  304. package/packages/subagents/prompts/parallel-review.md +0 -54
  305. package/packages/subagents/prompts/review-loop.md +0 -43
  306. package/packages/subagents/skills/council-mode/SKILL.md +0 -230
  307. package/packages/subagents/skills/subagents/references/constraints-and-recipes.md +0 -259
  308. package/packages/subagents/skills/subagents/references/execution-controls.md +0 -454
  309. package/packages/subagents/skills/subagents/references/management-authoring-rpc.md +0 -161
  310. package/packages/subagents/skills/subagents/references/multi-lane-orchestration.md +0 -39
  311. package/packages/subagents/skills/subagents/references/prompting-and-roles.md +0 -267
  312. package/packages/subagents/src/acceptance.ts +0 -331
  313. package/packages/subagents/src/agent-manager.ts +0 -405
  314. package/packages/subagents/src/agent-memory.ts +0 -300
  315. package/packages/subagents/src/agent-overrides.ts +0 -183
  316. package/packages/subagents/src/agent-runner.ts +0 -271
  317. package/packages/subagents/src/async-runner.ts +0 -422
  318. package/packages/subagents/src/authority-policy.ts +0 -47
  319. package/packages/subagents/src/budgets.ts +0 -285
  320. package/packages/subagents/src/child-safety.ts +0 -140
  321. package/packages/subagents/src/config.ts +0 -249
  322. package/packages/subagents/src/conversation-viewer.ts +0 -281
  323. package/packages/subagents/src/core-compat.ts +0 -94
  324. package/packages/subagents/src/custom-agents.ts +0 -343
  325. package/packages/subagents/src/file-system-retry.ts +0 -50
  326. package/packages/subagents/src/fleet-data.ts +0 -105
  327. package/packages/subagents/src/fleet-view.ts +0 -322
  328. package/packages/subagents/src/foreground-detach.ts +0 -59
  329. package/packages/subagents/src/fork-context.ts +0 -285
  330. package/packages/subagents/src/global.d.ts +0 -7
  331. package/packages/subagents/src/guide.ts +0 -129
  332. package/packages/subagents/src/mission-state.ts +0 -133
  333. package/packages/subagents/src/mission-store.ts +0 -436
  334. package/packages/subagents/src/output-limits.ts +0 -142
  335. package/packages/subagents/src/parity-types.ts +0 -315
  336. package/packages/subagents/src/pi-args.ts +0 -167
  337. package/packages/subagents/src/result-files.ts +0 -232
  338. package/packages/subagents/src/result-watcher.ts +0 -221
  339. package/packages/subagents/src/retained-children.ts +0 -176
  340. package/packages/subagents/src/run-fanout-budget.ts +0 -356
  341. package/packages/subagents/src/scheduled-runs.ts +0 -349
  342. package/packages/subagents/src/schemas.ts +0 -263
  343. package/packages/subagents/src/slash-commands.ts +0 -80
  344. package/packages/subagents/src/supervisor-channel.ts +0 -249
  345. package/packages/subagents/src/tool-handler.ts +0 -1144
  346. package/packages/subagents/src/types.ts +0 -238
  347. package/packages/subagents/src/widget.ts +0 -457
  348. package/packages/subagents/src/workflow-script.ts +0 -737
  349. package/packages/subagents/src/workflow-worker.ts +0 -384
  350. package/packages/subagents/src/worktree.ts +0 -614
  351. package/packages/utility/src/analytics/collector.ts +0 -293
  352. package/packages/utility/src/info-screen.ts +0 -80
  353. package/packages/utility/src/lifecycle/process.ts +0 -162
  354. package/packages/utility/src/prefix-cache.ts +0 -263
  355. package/packages/utility/src/skill-discovery.ts +0 -542
  356. package/packages/utility/src/tools/env.ts +0 -113
  357. package/packages/utility/src/tui/name-badge-state.ts +0 -315
  358. package/packages/utility/src/tui/name-badge.ts +0 -109
  359. /package/packages/{subagents/src → core/src/child-agent}/pi-spawn.ts +0 -0
@@ -1,654 +0,0 @@
1
- import { readFile } from 'node:fs/promises';
2
- import { packageAssetSearchHint, resolvePackageAsset } from './package-assets.js';
3
- import type {
4
- ExtensionAPI,
5
- ExtensionContext,
6
- Theme,
7
- ToolRenderResultOptions,
8
- } from '@earendil-works/pi-coding-agent';
9
- import { Text } from '@earendil-works/pi-tui';
10
- import { Type, type Static } from 'typebox';
11
- import type { BgTask, BgTaskSnapshot, StartDelegateTaskOptions } from './types.js';
12
- import { truncateChars } from './types.js';
13
- import { sha256Buffer } from './json-utils.js';
14
- import {
15
- DELEGATE_AUTO_DELIVER_MODES,
16
- DELEGATE_CAPABILITIES,
17
- DELEGATE_EXTENSION_MODES,
18
- DELEGATE_RESULT_TOOL_NAME,
19
- DELEGATE_TOOL_NAME,
20
- DelegateError,
21
- type DelegateAutoDeliverMode,
22
- type DelegateCapability,
23
- type DelegateDeliveryMode,
24
- type DelegateBudgetRouteSource,
25
- type DelegateExtensionMode,
26
- type DelegateRoute,
27
- } from './delegate/types.js';
28
- import {
29
- DELEGATE_INLINE_ANSWER_BYTES,
30
- DELEGATE_DEFAULT_MAX_TOOL_CALLS,
31
- DELEGATE_DEFAULT_MAX_TURNS,
32
- DELEGATE_DEFAULT_TIMEOUT_SECONDS,
33
- } from './delegate/budget.js';
34
- import { resolveDelegateRoute } from './delegate/launch.js';
35
- import {
36
- decideDelegateDelivery,
37
- evaluateDelegateTerminal,
38
- inlineTooLarge,
39
- prepareDelegateLaunch,
40
- } from './delegate/runner.js';
41
- import { loadDelegateHookContractEvidence } from './delegate/launch.js';
42
- import type { DelegateHookContractEvidence } from './delegate/hook-contract.js';
43
-
44
- /**
45
- * `bg_delegate` and `bg_result` registration.
46
- *
47
- * `bg_delegate` launches one background child Pi agent seeded with a frozen
48
- * projection of the current conversation. `bg_result` retrieves that child's
49
- * hash-verified answer. They ship together: a delegate without a safe retrieval
50
- * path would have no way to return its work.
51
- */
52
-
53
- /**
54
- * Shipped copy of the observed Pi hook-contract evidence.
55
- *
56
- * It is produced by executing a real Pi agent loop in
57
- * `tests/scripted-provider/pi-hook-contract.test.ts`, and a package test asserts
58
- * the shipped copy is byte-identical to the recorded one, so the runtime gate
59
- * and the gate that proved it can never drift apart.
60
- */
61
- const HOOK_EVIDENCE_RELATIVE_PATH = 'src/delegate/hook-contract-evidence.json';
62
-
63
- export const DelegateParams = Type.Object(
64
- {
65
- name: Type.String({
66
- description: 'Short human-readable task name shown in the bg footer dock. Use 2-6 words.',
67
- }),
68
- prompt: Type.String({
69
- description:
70
- 'Authoritative instruction for the delegate. The projected conversation is supporting background only.',
71
- }),
72
- route: Type.Optional(
73
- Type.Object(
74
- {
75
- provider: Type.String({ description: 'Exact provider name to pin.' }),
76
- model: Type.String({ description: 'Exact provider-local model id to pin.' }),
77
- },
78
- {
79
- additionalProperties: false,
80
- description: 'Explicit route. Defaults to the current model.',
81
- },
82
- ),
83
- ),
84
- capability: Type.Optional(
85
- Type.String({
86
- description: `Capability profile. Only "inspect" (read/search/list, no shell, no writes, no network, no recursion) is supported.`,
87
- }),
88
- ),
89
- extensionMode: Type.Optional(
90
- Type.String({
91
- description:
92
- 'Extension discovery: isolated | ambient. Default isolated. Ambient is for extension-registered providers and executes arbitrary discovered extension code, weakening process isolation.',
93
- }),
94
- ),
95
- maxTurns: Type.Optional(
96
- Type.Number({
97
- description: `Maximum agent turns. Default ${String(DELEGATE_DEFAULT_MAX_TURNS)}.`,
98
- }),
99
- ),
100
- maxToolCalls: Type.Optional(
101
- Type.Number({
102
- description: `Maximum tool calls. Default ${String(DELEGATE_DEFAULT_MAX_TOOL_CALLS)}.`,
103
- }),
104
- ),
105
- timeoutSeconds: Type.Optional(
106
- Type.Number({
107
- description: `Wall-clock timeout. Default ${String(DELEGATE_DEFAULT_TIMEOUT_SECONDS)}.`,
108
- }),
109
- ),
110
- autoDeliver: Type.Optional(
111
- Type.String({
112
- description:
113
- 'Whether the completion notification carries the answer: never | when_small | always. Default never; retrieve with bg_result.',
114
- }),
115
- ),
116
- notifyOnCompletion: Type.Optional(
117
- Type.Boolean({ description: 'Deliver the durable terminal notification. Default true.' }),
118
- ),
119
- triggerOnCompletion: Type.Optional(
120
- Type.Boolean({ description: 'Let that notification start a follow-up turn. Default true.' }),
121
- ),
122
- },
123
- { additionalProperties: false },
124
- );
125
-
126
- const ResultParams = Type.Object(
127
- {
128
- taskId: Type.String({
129
- description: 'Background delegate task id returned by bg_delegate.',
130
- }),
131
- delivery: Type.Optional(
132
- Type.String({
133
- description:
134
- 'inline returns the verified answer text; artifact returns metadata plus the artifact reference. Oversized answers are never truncated.',
135
- }),
136
- ),
137
- },
138
- { additionalProperties: false },
139
- );
140
-
141
- type DelegateParamsValue = Static<typeof DelegateParams>;
142
- type ResultParamsValue = Static<typeof ResultParams>;
143
-
144
- const DELEGATE_PARAM_KEYS = new Set([
145
- 'name',
146
- 'prompt',
147
- 'route',
148
- 'capability',
149
- 'extensionMode',
150
- 'maxTurns',
151
- 'maxToolCalls',
152
- 'timeoutSeconds',
153
- 'autoDeliver',
154
- 'notifyOnCompletion',
155
- 'triggerOnCompletion',
156
- ]);
157
-
158
- export interface DelegateLaunchDetails {
159
- schema_version: 'unipi-background-tasks.delegate-launch.v1';
160
- task: BgTaskSnapshot;
161
- route: { provider: string; model: string; qualified_id: string; origin: string };
162
- child_session_id: string;
163
- artifact_dir: string;
164
- seed_sha256: string;
165
- seed_utf8_bytes: number;
166
- budget: DelegateBudgetRouteSource;
167
- extension_mode: DelegateExtensionMode;
168
- auto_deliver: DelegateAutoDeliverMode;
169
- notify_on_completion: boolean;
170
- trigger_on_completion: boolean;
171
- }
172
-
173
- export type BackgroundResultDetails = DelegateResultDetails;
174
-
175
- export interface DelegateResultDetails {
176
- schema_version: 'unipi-background-tasks.delegate-result-view.v1';
177
- task_id: string;
178
- state: 'running' | 'committed' | 'failed' | 'cancelled';
179
- delivery: DelegateDeliveryMode | 'none';
180
- route?: { provider: string; model: string } | undefined;
181
- budget?: DelegateBudgetRouteSource | undefined;
182
- extension_mode?: DelegateExtensionMode | undefined;
183
- answer_bytes?: number | undefined;
184
- answer_sha256?: string | undefined;
185
- turns?: number | undefined;
186
- tool_calls?: number | undefined;
187
- usage?: { status: string } | undefined;
188
- artifact_dir?: string | undefined;
189
- error_code?: string | undefined;
190
- }
191
-
192
- function textContent(text: string) {
193
- return [{ type: 'text' as const, text }];
194
- }
195
-
196
- function isRecord(value: unknown): value is Record<PropertyKey, unknown> {
197
- return typeof value === 'object' && value !== null && !Array.isArray(value);
198
- }
199
-
200
- function requireCapability(value: unknown): DelegateCapability {
201
- if (value === undefined) return 'inspect';
202
- if (value === 'inspect') return 'inspect';
203
- throw new DelegateError(
204
- `bg_delegate capability must be one of ${DELEGATE_CAPABILITIES.join(', ')}. Writable profiles are deliberately out of scope in this version.`,
205
- { code: 'invalid_arguments', childCreated: false },
206
- );
207
- }
208
-
209
- function requireExtensionMode(value: unknown): DelegateExtensionMode {
210
- if (value === undefined) return 'isolated';
211
- if (value === 'isolated' || value === 'ambient') return value;
212
- throw new DelegateError(
213
- `bg_delegate extensionMode must be one of ${DELEGATE_EXTENSION_MODES.join(', ')}`,
214
- { code: 'invalid_arguments', childCreated: false },
215
- );
216
- }
217
-
218
- function requireAutoDeliver(value: unknown): DelegateAutoDeliverMode {
219
- if (value === undefined) return 'never';
220
- if (value === 'never' || value === 'when_small' || value === 'always') return value;
221
- throw new DelegateError(
222
- `bg_delegate autoDeliver must be one of ${DELEGATE_AUTO_DELIVER_MODES.join(', ')}`,
223
- { code: 'invalid_arguments', childCreated: false },
224
- );
225
- }
226
-
227
- function requireDelivery(value: unknown): DelegateDeliveryMode | undefined {
228
- if (value === undefined) return undefined;
229
- if (value === 'inline' || value === 'artifact') return value;
230
- throw new DelegateError('bg_result delivery must be inline or artifact', {
231
- code: 'invalid_arguments',
232
- childCreated: false,
233
- });
234
- }
235
-
236
- function requireRoute(value: unknown): DelegateRoute | undefined {
237
- if (value === undefined) return undefined;
238
- if (!isRecord(value)) {
239
- throw new DelegateError('bg_delegate route must be an object', {
240
- code: 'invalid_arguments',
241
- childCreated: false,
242
- });
243
- }
244
- const provider = value['provider'];
245
- const model = value['model'];
246
- if (typeof provider !== 'string' || provider.length === 0)
247
- throw new DelegateError('bg_delegate route.provider must be a non-empty string', {
248
- code: 'invalid_arguments',
249
- childCreated: false,
250
- });
251
- if (typeof model !== 'string' || model.length === 0)
252
- throw new DelegateError('bg_delegate route.model must be a non-empty string', {
253
- code: 'invalid_arguments',
254
- childCreated: false,
255
- });
256
- return { provider, model };
257
- }
258
-
259
- function optionalPositiveInteger(value: unknown, label: string): number | undefined {
260
- if (value === undefined) return undefined;
261
- if (
262
- typeof value !== 'number' ||
263
- !Number.isFinite(value) ||
264
- !Number.isInteger(value) ||
265
- value <= 0
266
- )
267
- throw new DelegateError(`bg_delegate ${label} must be a positive integer`, {
268
- code: 'invalid_arguments',
269
- childCreated: false,
270
- });
271
- return value;
272
- }
273
-
274
- export interface DelegateExtensionDependencies {
275
- startDelegateTask: (ctx: ExtensionContext, options: StartDelegateTaskOptions) => Promise<BgTask>;
276
- snapshot: (task: BgTask) => BgTaskSnapshot;
277
- resolveTask: (idOrPrefix: string) => BgTask;
278
- /** Overridable so tests can supply observed evidence without touching disk. */
279
- loadHookEvidence?: (() => Promise<DelegateHookContractEvidence>) | undefined;
280
- }
281
-
282
- async function defaultHookEvidence(): Promise<DelegateHookContractEvidence> {
283
- let raw: string;
284
- const evidencePath =
285
- resolvePackageAsset(HOOK_EVIDENCE_RELATIVE_PATH) ??
286
- packageAssetSearchHint(HOOK_EVIDENCE_RELATIVE_PATH);
287
- try {
288
- raw = await readFile(evidencePath, 'utf8');
289
- } catch (error) {
290
- throw new DelegateError(
291
- `bg_delegate cannot verify the Pi hook contract: the recorded evidence at ${evidencePath} is unreadable (${error instanceof Error ? error.message : String(error)}). No child was created.`,
292
- {
293
- code: 'delegate_hook_contract_unsupported',
294
- childCreated: false,
295
- remediation: [
296
- 'Run the Pi hook characterisation gate to regenerate the evidence for this Pi build.',
297
- 'The guard is never bypassed when its evidence is missing.',
298
- ],
299
- },
300
- );
301
- }
302
- return loadDelegateHookContractEvidence(raw);
303
- }
304
-
305
- export function registerDelegateExtension(
306
- pi: ExtensionAPI,
307
- deps: DelegateExtensionDependencies,
308
- ): void {
309
- const loadEvidence = deps.loadHookEvidence ?? defaultHookEvidence;
310
-
311
- pi.registerTool<typeof DelegateParams, DelegateLaunchDetails>({
312
- name: DELEGATE_TOOL_NAME,
313
- label: 'Background Delegate',
314
- description:
315
- 'Launch one background Pi agent seeded with a frozen projection of the current conversation, then return a launch receipt immediately. The child has its own session, a route pinned at launch that is never substituted, and read-only tools. Extension discovery is isolated by default; ambient mode supports extension-registered providers but executes arbitrary discovered extension code. Retrieve its verified answer with bg_result.',
316
- promptSnippet:
317
- 'Delegate an investigation to a background agent that already has this conversation as context',
318
- promptGuidelines: [
319
- 'Use bg_delegate when work should continue in the background and the worker needs what you already know: it is seeded with a projection of this conversation.',
320
- 'The prompt is authoritative. State exactly what you want investigated and what the answer should contain.',
321
- 'The delegate is inspect-only at the model-visible tool boundary: it can read, search, and list files, but cannot run shell commands, edit or write files, use the network, or delegate further.',
322
- 'Extension discovery is isolated by default. Use extensionMode:"ambient" only when the pinned provider is registered by an ambient user/project extension.',
323
- 'Ambient mode executes arbitrary discovered extension code in the child process. Tool allowlists do not sandbox extension code, so ambient mode weakens inspect-only process isolation.',
324
- 'Facts that exist only inside omitted tool output are not available to the delegate. Restate such findings in the prompt.',
325
- 'bg_delegate returns immediately. Do not poll; retrieve the answer with bg_result after the terminal notification arrives.',
326
- ],
327
- parameters: DelegateParams,
328
- prepareArguments(args): DelegateParamsValue {
329
- if (!isRecord(args))
330
- throw new DelegateError('bg_delegate arguments must be an object', {
331
- code: 'invalid_arguments',
332
- childCreated: false,
333
- });
334
- const unknownKeys = Object.keys(args).filter((key) => !DELEGATE_PARAM_KEYS.has(key));
335
- if (unknownKeys.length > 0) {
336
- throw new DelegateError(
337
- `bg_delegate contains unsupported key(s): ${unknownKeys.sort().join(', ')}`,
338
- { code: 'invalid_arguments', childCreated: false },
339
- );
340
- }
341
- const name = args['name'];
342
- const prompt = args['prompt'];
343
- if (typeof name !== 'string' || name.trim().length === 0)
344
- throw new DelegateError('bg_delegate requires a non-empty name', {
345
- code: 'invalid_arguments',
346
- childCreated: false,
347
- });
348
- if (typeof prompt !== 'string' || prompt.trim().length === 0)
349
- throw new DelegateError('bg_delegate requires a non-blank prompt', {
350
- code: 'invalid_arguments',
351
- childCreated: false,
352
- });
353
- const prepared: DelegateParamsValue = { name, prompt };
354
- const route = requireRoute(args['route']);
355
- if (route !== undefined) prepared.route = route;
356
- prepared.capability = requireCapability(args['capability']);
357
- prepared.extensionMode = requireExtensionMode(args['extensionMode']);
358
- prepared.autoDeliver = requireAutoDeliver(args['autoDeliver']);
359
- const maxTurns = optionalPositiveInteger(args['maxTurns'], 'maxTurns');
360
- if (maxTurns !== undefined) prepared.maxTurns = maxTurns;
361
- const maxToolCalls = optionalPositiveInteger(args['maxToolCalls'], 'maxToolCalls');
362
- if (maxToolCalls !== undefined) prepared.maxToolCalls = maxToolCalls;
363
- const timeoutSeconds = optionalPositiveInteger(args['timeoutSeconds'], 'timeoutSeconds');
364
- if (timeoutSeconds !== undefined) prepared.timeoutSeconds = timeoutSeconds;
365
- const notify = args['notifyOnCompletion'];
366
- if (typeof notify === 'boolean') prepared.notifyOnCompletion = notify;
367
- const trigger = args['triggerOnCompletion'];
368
- if (typeof trigger === 'boolean') prepared.triggerOnCompletion = trigger;
369
- return prepared;
370
- },
371
- async execute(toolCallId, params, _signal, _onUpdate, ctx) {
372
- const capability = requireCapability(params.capability);
373
- const extensionMode = requireExtensionMode(params.extensionMode);
374
- const autoDeliver = requireAutoDeliver(params.autoDeliver);
375
- const hookEvidence = await loadEvidence();
376
- const route = resolveDelegateRoute({
377
- requested: params.route,
378
- currentModel:
379
- ctx.model === undefined
380
- ? undefined
381
- : {
382
- provider: ctx.model.provider,
383
- id: ctx.model.id,
384
- contextWindow: ctx.model.contextWindow,
385
- },
386
- availableModels: ctx.modelRegistry.getAll().map((model) => ({
387
- provider: model.provider,
388
- id: model.id,
389
- contextWindow: model.contextWindow,
390
- })),
391
- thinkingLevel: pi.getThinkingLevel(),
392
- });
393
-
394
- const prepared = await prepareDelegateLaunch({
395
- ctx: {
396
- cwd: ctx.cwd,
397
- sessionManager: ctx.sessionManager,
398
- getSystemPrompt: () => ctx.getSystemPrompt(),
399
- },
400
- toolCallId,
401
- prompt: params.prompt,
402
- capability,
403
- extensionMode,
404
- route,
405
- limitOverrides: {
406
- maxTurns: params.maxTurns,
407
- maxToolCalls: params.maxToolCalls,
408
- timeoutSeconds: params.timeoutSeconds,
409
- },
410
- hookEvidence,
411
- cwd: ctx.cwd,
412
- sessionId: ctx.sessionManager.getSessionId(),
413
- autoDeliver,
414
- });
415
-
416
- const launchOptions: StartDelegateTaskOptions = {
417
- name: params.name,
418
- argv: prepared.argv,
419
- stdinBytes: prepared.stdinBytes,
420
- env: prepared.env,
421
- facts: prepared.facts,
422
- notifyOnCompletion: params.notifyOnCompletion ?? true,
423
- triggerOnCompletion: params.triggerOnCompletion ?? true,
424
- timeoutSeconds: prepared.preflight.limits.timeout_seconds,
425
- };
426
- const task = await deps.startDelegateTask(ctx, launchOptions);
427
-
428
- const details: DelegateLaunchDetails = {
429
- schema_version: 'unipi-background-tasks.delegate-launch.v1',
430
- task: deps.snapshot(task),
431
- route: {
432
- provider: route.provider,
433
- model: route.model,
434
- qualified_id: route.qualified_id,
435
- origin: route.origin,
436
- },
437
- child_session_id: prepared.preflight.childSessionId,
438
- artifact_dir: prepared.facts.artifactDir,
439
- seed_sha256: prepared.facts.seedSha256,
440
- seed_utf8_bytes: Buffer.byteLength(prepared.preflight.seed.serialized, 'utf8'),
441
- budget: prepared.facts.budget,
442
- extension_mode: extensionMode,
443
- auto_deliver: autoDeliver,
444
- notify_on_completion: launchOptions.notifyOnCompletion,
445
- trigger_on_completion: launchOptions.triggerOnCompletion,
446
- };
447
- return {
448
- content: textContent(
449
- [
450
- `Started delegate ${params.name} (${task.id})`,
451
- `Route pinned: ${route.qualified_id} (${route.origin}); it is never substituted.`,
452
- `Child session: ${prepared.preflight.childSessionId} (separate from this session)`,
453
- `Artifacts: ${prepared.facts.artifactDir}`,
454
- `Seed: ${String(Buffer.byteLength(prepared.preflight.seed.serialized, 'utf8'))} bytes, sha256 ${prepared.facts.seedSha256}`,
455
- `Child prompt: ${String(prepared.preflight.plan.child_prompt_utf8_bytes)} bytes; launch estimate ${String(prepared.preflight.plan.launch_input_tokens_upper_bound)} / ${String(prepared.preflight.plan.route.allowed_input_tokens)} allowed input tokens; protected retained-growth runway ${String(prepared.preflight.plan.retained_growth_budget_tokens)} tokens.`,
456
- `Estimator: family ${prepared.facts.budget.family}, source ${prepared.facts.budget.rate_source.source}, rate ${String(prepared.facts.budget.rate_source.effective_rate_bytes_per_token_x100)}/100 B/tok + ${String(prepared.facts.budget.rate_source.affine_f_tokens)} tokens${prepared.facts.budget.rate_source.warning === null ? '' : `; warning: ${prepared.facts.budget.rate_source.warning}`}`,
457
- `Capability: ${capability} (read/search/list only)`,
458
- `Extension mode: ${extensionMode}${extensionMode === 'ambient' ? ' — WARNING: arbitrary discovered extension code executes in the child; the tool allowlist does not sandbox it, so inspect-only process isolation is weakened.' : ' (ambient extension discovery disabled)'}`,
459
- `Limits: ${String(prepared.preflight.limits.max_turns)} turns, ${String(prepared.preflight.limits.max_tool_calls)} tool calls, ${String(prepared.preflight.limits.timeout_seconds)}s`,
460
- `Auto-deliver: ${autoDeliver}`,
461
- launchOptions.notifyOnCompletion
462
- ? `Terminal notification: enabled.${launchOptions.triggerOnCompletion ? ' It will start a follow-up turn.' : ' It will not start a turn.'}`
463
- : 'Terminal notification: disabled.',
464
- `Retrieve the verified answer with ${DELEGATE_RESULT_TOOL_NAME}({taskId:"${task.id}"}). Do not poll.`,
465
- ].join('\n'),
466
- ),
467
- details,
468
- };
469
- },
470
- renderCall(args, theme) {
471
- return new Text(
472
- `${theme.fg('toolTitle', theme.bold('bg_delegate '))}${theme.fg('muted', truncateChars(args.name, 60))}`,
473
- 0,
474
- 0,
475
- );
476
- },
477
- renderResult(result, _options, theme) {
478
- const details = result.details;
479
- return new Text(
480
- `${theme.fg('success', '✓ delegated')} ${theme.fg('accent', details.task.id)}\n${theme.fg('dim', `route ${details.route.qualified_id} · extensions ${details.extension_mode} · seed ${String(details.seed_utf8_bytes)}B · ${details.artifact_dir}`)}`,
481
- 0,
482
- 0,
483
- );
484
- },
485
- });
486
-
487
- pi.registerTool<typeof ResultParams, BackgroundResultDetails>({
488
- name: DELEGATE_RESULT_TOOL_NAME,
489
- label: 'Background Result',
490
- description:
491
- 'Retrieve a hash-verified result from a bg_delegate task. Never blocks: a running task returns a typed not-ready result. Oversized answers are never truncated.',
492
- promptSnippet: 'Retrieve the verified answer from a completed delegate task',
493
- promptGuidelines: [
494
- 'Call bg_result once the delegate terminal notification has arrived. It never blocks and must not be polled.',
495
- 'A not-ready result means the task is still running; end the turn and wait for the notification.',
496
- ],
497
- parameters: ResultParams,
498
- prepareArguments(args): ResultParamsValue {
499
- if (!isRecord(args))
500
- throw new DelegateError('bg_result arguments must be an object', {
501
- code: 'invalid_arguments',
502
- childCreated: false,
503
- });
504
- const taskId = args['taskId'];
505
- if (typeof taskId !== 'string' || taskId.trim().length === 0)
506
- throw new DelegateError('bg_result requires taskId', {
507
- code: 'invalid_arguments',
508
- childCreated: false,
509
- });
510
- const prepared: ResultParamsValue = { taskId };
511
- const delivery = requireDelivery(args['delivery']);
512
- if (delivery !== undefined) prepared.delivery = delivery;
513
- return prepared;
514
- },
515
- async execute(_toolCallId, params) {
516
- let task: BgTask;
517
- try {
518
- task = deps.resolveTask(params.taskId);
519
- } catch (error) {
520
- throw new DelegateError(
521
- `bg_result does not know task ${params.taskId}: ${error instanceof Error ? error.message : String(error)}`,
522
- { code: 'task_unknown', childCreated: false },
523
- );
524
- }
525
- const facts = task.delegate;
526
- if (facts === undefined) {
527
- throw new DelegateError(
528
- `bg_result task ${task.id} has no retrievable delegate result; use bg_logs for ordinary background tasks`,
529
- { code: 'task_unknown', childCreated: false },
530
- );
531
- }
532
- if (task.status === 'running') {
533
- const details: DelegateResultDetails = {
534
- schema_version: 'unipi-background-tasks.delegate-result-view.v1',
535
- task_id: task.id,
536
- state: 'running',
537
- delivery: 'none',
538
- artifact_dir: facts.artifactDir,
539
- budget: facts.budget,
540
- extension_mode: facts.extensionMode,
541
- };
542
- return {
543
- content: textContent(
544
- `Delegate ${task.id} is still running. This is not an error and bg_result never blocks. End this turn; the terminal notification will wake you, then call bg_result again.`,
545
- ),
546
- details,
547
- };
548
- }
549
-
550
- const terminal = await evaluateDelegateTerminal({
551
- artifactDirAbs: facts.artifactDirAbs,
552
- taskId: facts.taskId,
553
- launchNonce: facts.launchNonce,
554
- seedSha256: facts.seedSha256,
555
- route: { provider: facts.route.provider, model: facts.route.model },
556
- taskStatus: task.status === 'completed' ? 'completed' : task.status,
557
- taskError: task.error,
558
- taskOutputPath: task.outputPath,
559
- taskOutputAbsPath: task.outputAbsPath,
560
- });
561
-
562
- if (terminal.error !== undefined || terminal.result === undefined) {
563
- const failure =
564
- terminal.error ??
565
- new DelegateError(`delegate ${task.id} produced no verified answer`, {
566
- code: 'result_unavailable',
567
- childCreated: true,
568
- taskId: task.id,
569
- artifactDir: facts.artifactDir,
570
- });
571
- throw new Error(failure.describe(), { cause: failure });
572
- }
573
-
574
- const verified = terminal.result;
575
- const requestedDelivery = requireDelivery(params.delivery);
576
- const decision = decideDelegateDelivery(
577
- verified.package.answer.byte_length,
578
- requestedDelivery,
579
- );
580
- if (requestedDelivery === 'inline' && decision.mode === 'artifact') {
581
- const failure = inlineTooLarge(
582
- task.id,
583
- facts.artifactDir,
584
- verified.package.answer.byte_length,
585
- );
586
- throw new Error(failure.describe(), { cause: failure });
587
- }
588
-
589
- const details: DelegateResultDetails = {
590
- schema_version: 'unipi-background-tasks.delegate-result-view.v1',
591
- task_id: task.id,
592
- state: 'committed',
593
- delivery: decision.mode,
594
- route: verified.package.route,
595
- budget: facts.budget,
596
- extension_mode: facts.extensionMode,
597
- answer_bytes: verified.package.answer.byte_length,
598
- answer_sha256: verified.package.answer.sha256,
599
- turns: verified.package.turns,
600
- tool_calls: verified.package.tool_calls,
601
- usage: { status: verified.package.usage.status },
602
- artifact_dir: facts.artifactDir,
603
- };
604
- const header = [
605
- `Delegate ${task.id} completed on ${verified.package.route.provider}/${verified.package.route.model}.`,
606
- `Answer: ${String(verified.package.answer.byte_length)} bytes, sha256 ${verified.package.answer.sha256} (verified).`,
607
- `Turns: ${String(verified.package.turns)} · tool calls: ${String(verified.package.tool_calls)} · usage: ${verified.package.usage.status}`,
608
- `Artifacts: ${facts.artifactDir}`,
609
- `Estimator: family ${facts.budget.family}, source ${facts.budget.rate_source.source}, rate ${String(facts.budget.rate_source.effective_rate_bytes_per_token_x100)}/100 B/tok + ${String(facts.budget.rate_source.affine_f_tokens)} tokens${facts.budget.rate_source.warning === null ? '' : `; warning: ${facts.budget.rate_source.warning}`}`,
610
- ].join('\n');
611
- if (decision.mode === 'artifact') {
612
- return {
613
- content: textContent(
614
- `${header}\nDelivery: artifact (${decision.reason}). The complete verified answer is in ${facts.artifactDir}/result.json. It was not truncated.`,
615
- ),
616
- details,
617
- };
618
- }
619
- return { content: textContent(`${header}\n\n${verified.answer}`), details };
620
- },
621
- renderCall(args, theme) {
622
- return new Text(
623
- `${theme.fg('toolTitle', theme.bold('bg_result '))}${theme.fg('accent', args.taskId)}`,
624
- 0,
625
- 0,
626
- );
627
- },
628
- renderResult(result, options: ToolRenderResultOptions, theme: Theme) {
629
- void options;
630
- const details = result.details;
631
- if (details.state === 'running')
632
- return new Text(
633
- theme.fg('warning', `delegate ${details.task_id} still running`),
634
- 0,
635
- 0,
636
- );
637
- return new Text(
638
- `${theme.fg('success', '✓ delegate answer')} ${theme.fg('dim', `${String(details.answer_bytes ?? 0)}B · ${details.delivery}`)}`,
639
- 0,
640
- 0,
641
- );
642
- },
643
- });
644
-
645
- pi.on('session_start', () => {
646
- const active = pi.getActiveTools();
647
- const missing = [DELEGATE_TOOL_NAME, DELEGATE_RESULT_TOOL_NAME].filter(
648
- (name) => !active.includes(name),
649
- );
650
- if (missing.length > 0) pi.setActiveTools([...active, ...missing]);
651
- });
652
- }
653
-
654
- export { DELEGATE_INLINE_ANSWER_BYTES };
@@ -1,17 +0,0 @@
1
- {
2
- "schema_version": "pi-background-tasks.delegate-context-incident-fixture.v1",
3
- "incident_task_id": "d670700fdaab973ed6a41436d37f4ef2e",
4
- "child_prompt_sha256": "0dbf3ccf20e72150af56632fbd3e5fecf09ef5694561b6673f92b59fbdbbbc27",
5
- "child_prompt_utf8_bytes": 173740,
6
- "system_prompt_utf8_bytes": 1673,
7
- "launch_utf8_bytes": 175413,
8
- "launch_normal_bytes": 175152,
9
- "launch_multibyte_bytes": 261,
10
- "launch_dense_bytes": 0,
11
- "old_one_byte_normal_two_byte_multibyte_forecast": 175795,
12
- "provable_one_byte_per_token_forecast": 175925,
13
- "context_window_tokens": 372000,
14
- "allowed_input_tokens": 343328,
15
- "calibrated_rate_bytes_per_token_x100": 289,
16
- "finalization_reserve_tokens": 32768
17
- }