@tea-agent/loop-agent 0.44.0-next.1 → 0.44.0-next.10

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 (226) hide show
  1. package/CHANGELOG.md +379 -416
  2. package/dist/application/evaluation/budget.js +21 -0
  3. package/dist/application/evaluation/corpus-hash.js +10 -15
  4. package/dist/application/evaluation/corpus.js +2 -1
  5. package/dist/application/evaluation/frontend-browser-acceptance.js +77 -0
  6. package/dist/application/evaluation/frontend-corpus-browser-acceptance.js +175 -0
  7. package/dist/application/evaluation/frontend-gateway-evidence.js +226 -0
  8. package/dist/application/evaluation/frontend-pair-registration.js +143 -0
  9. package/dist/application/evaluation/frontend-paired-summary.js +150 -0
  10. package/dist/application/evaluation/frontend-run-observation.js +144 -0
  11. package/dist/application/evaluation/frontend-shared-evidence.js +105 -0
  12. package/dist/application/evaluation/types.js +45 -12
  13. package/dist/application/task-lifecycle/observe.js +26 -1
  14. package/dist/build-stamp.json +3 -3
  15. package/dist/cli/command-definitions.js +11 -0
  16. package/dist/cli/program.js +4 -0
  17. package/dist/commands/task-advance.js +3 -5
  18. package/dist/commands/task-source-prepare.js +13 -1
  19. package/dist/executors/dag-pi/guards.js +4 -0
  20. package/dist/executors/dag-pi/model-config.js +30 -0
  21. package/dist/executors/dag-pi/plan/fact-adoption.js +55 -0
  22. package/dist/{workflows/dag/frontend-plan-completeness.js → executors/dag-pi/plan/facts.js} +22 -28
  23. package/dist/executors/dag-pi/plan/finalize-tools.js +259 -0
  24. package/dist/executors/dag-pi/plan/ledger-contract.js +55 -0
  25. package/dist/executors/dag-pi/plan/record-tools.js +861 -0
  26. package/dist/executors/dag-pi/plan/schema.js +129 -0
  27. package/dist/executors/dag-pi/plan/session.js +1 -0
  28. package/dist/executors/dag-pi/plan/tool-helpers.js +16 -0
  29. package/dist/executors/dag-pi/tools/contract-tools.js +515 -0
  30. package/dist/executors/dag-pi/tools/design-terminal-tools.js +159 -0
  31. package/dist/executors/dag-pi/tools/plan-decision-tools.js +529 -0
  32. package/dist/executors/dag-pi/tools/review-terminal-tools.js +159 -0
  33. package/dist/executors/dag-pi/tools/scout-evidence-tools.js +270 -0
  34. package/dist/executors/dag-pi-executor.js +398 -3384
  35. package/dist/executors/pi-executor.js +6 -1
  36. package/dist/executors/pi-sdk-executor.js +112 -19
  37. package/dist/executors/shell-executor.js +88 -12
  38. package/dist/executors/shell-presets.js +1 -1
  39. package/dist/executors/shell-write-guard.js +26 -3
  40. package/dist/infrastructure/console/operation-store.js +48 -14
  41. package/dist/infrastructure/evaluation/corpus-store.js +37 -12
  42. package/dist/shared/file-identity.js +23 -0
  43. package/dist/shared/git-workspace-status.js +482 -0
  44. package/dist/shared/operator/capabilities.js +10 -5
  45. package/dist/shared/path-safety.js +2 -2
  46. package/dist/shared/wizard-local-telemetry.js +51 -0
  47. package/dist/task/config-types.js +22 -8
  48. package/dist/task/contract/project.js +13 -0
  49. package/dist/task/contract/schema.js +2 -7
  50. package/dist/task/frontend-preflight.js +1 -1
  51. package/dist/task/source-prepare/parse-intent.js +124 -5
  52. package/dist/task/source-prepare/prepare.js +6 -1
  53. package/dist/task/source-prepare/semantic-intake.js +18 -3
  54. package/dist/task/source-prepare/source-execution.js +65 -0
  55. package/dist/task/source-prepare/source-fidelity-pi.js +22 -9
  56. package/dist/task/source-prepare/source-provider-budget.js +290 -0
  57. package/dist/worker/console/chat/assistant-content.js +5 -34
  58. package/dist/worker/console/chat/chat-event-store.js +62 -10
  59. package/dist/worker/console/chat/context-insights.js +723 -0
  60. package/dist/worker/console/chat/conversation-nodes.js +383 -0
  61. package/dist/worker/console/chat/db-connections.js +854 -0
  62. package/dist/worker/console/chat/pi-runtime/custom-tools/operator-tools.js +1 -1
  63. package/dist/worker/console/chat/pi-runtime/custom-tools/sql-tools.js +655 -0
  64. package/dist/worker/console/chat/pi-runtime.js +445 -36
  65. package/dist/worker/console/chat/provider-error.js +0 -12
  66. package/dist/worker/console/chat/repo-browser.js +52 -4
  67. package/dist/worker/console/chat/routes.js +577 -72
  68. package/dist/worker/console/chat/sdd-data-alignment.js +8 -31
  69. package/dist/worker/console/chat/session-store.js +147 -19
  70. package/dist/worker/console/chat/shortcuts.js +7 -0
  71. package/dist/worker/console/chat/timeline-message-order.js +22 -0
  72. package/dist/worker/console/chat/tools.js +34 -0
  73. package/dist/worker/console/chat/turn-process.js +237 -66
  74. package/dist/worker/console/chat/user-turn-outline.js +19 -0
  75. package/dist/worker/console/console-update-runtime.js +2 -2
  76. package/dist/worker/console/dag-confirmation.js +3 -0
  77. package/dist/worker/console/dag-execution-receipt.js +3 -0
  78. package/dist/worker/console/operator-actions.js +32 -3
  79. package/dist/worker/console/operator-user-error.js +28 -1
  80. package/dist/worker/console/pi-readiness.js +4 -4
  81. package/dist/worker/console/prd-intake-bridge.js +5 -12
  82. package/dist/worker/console/recovery-cta.js +14 -14
  83. package/dist/worker/console/server.js +5 -1
  84. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-8-j6y-sd.js → abnfDiagram-N423BO3Z-r1NAPU_5.js} +1 -1
  85. package/dist/worker/console/static/assets/{arc-eoQiMvuk.js → arc-dT5T4sVL.js} +1 -1
  86. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-C4A3uMcI.js → architectureDiagram-T3A2C74G-CP_cOq46.js} +1 -1
  87. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-D4zD2F-Q.js → blockDiagram-VBNYF7ZC-sToEZxEf.js} +1 -1
  88. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-j1RkJziL.js → c4Diagram-5PPSVZJV-DSxwwi2m.js} +1 -1
  89. package/dist/worker/console/static/assets/channel-CyBY_yGk.js +1 -0
  90. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-YBHmhik1.js → chunk-2GRJ4B5K-B9fh0IkF.js} +1 -1
  91. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-COfWyo9P.js → chunk-2Q5K7J3B-CAUNl-A6.js} +1 -1
  92. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-I99OUkHY.js → chunk-5RXB4S5H-BomeqbNX.js} +1 -1
  93. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-XKxoJNJ4.js → chunk-5VM5RSS4-BNAuTOLE.js} +1 -1
  94. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DLT_cYx1.js → chunk-6Q2QTUOP-DfzjRD5y.js} +1 -1
  95. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-CxcKZ9mV.js → chunk-GF5L2VYU-C3uE-yc2.js} +1 -1
  96. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-V1EqXdjY.js → chunk-JWPE2WC7-C3sQMMYr.js} +1 -1
  97. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-DebTtdFp.js → chunk-KBJHAD2P-D_AtEYQL.js} +1 -1
  98. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-B-ivNRDf.js → chunk-RYQCIY6F-DW4TwhKv.js} +1 -1
  99. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-DC_Ds11b.js → chunk-XXDRQBXY-CTQDmJcp.js} +1 -1
  100. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-D5lN4E_E.js +1 -0
  101. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-D5lN4E_E.js +1 -0
  102. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-sWEqKwIb.js → cose-bilkent-JH36ORCC-iMqPuBsL.js} +1 -1
  103. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BXa_dcu4.js → cynefin-VYW2F7L2-DktIuDWs.js} +1 -1
  104. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-C-Mle84F.js → cynefinDiagram-MW4NZA55-BgVnjyEs.js} +1 -1
  105. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-CXPDBITe.js → dagre-VZM6K2ZE-CR25E4bu.js} +1 -1
  106. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-CC-WJQfa.js → diagram-7IWD3JNH-CPM2h5HY.js} +1 -1
  107. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-CDAV5Vs4.js → diagram-B4RE2ZJO-DqF0x2g1.js} +1 -1
  108. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CmFiAcNz.js → diagram-LBJQPF4R-G8BYp2eb.js} +1 -1
  109. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-DPBZHuyn.js → diagram-Q27KOJAE-BbC4kT_D.js} +1 -1
  110. package/dist/worker/console/static/assets/{diagram-UB23O5K3-jUlm_Ds3.js → diagram-UB23O5K3-CKZwZ-G5.js} +1 -1
  111. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-DWhQ3mfY.js → ebnfDiagram-BXEA7PRR-kJDmheia.js} +1 -1
  112. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-Tr2gMqet.js → erDiagram-JOGREHBK-DFTVHyxB.js} +1 -1
  113. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-DJjVQHPA.js → flowDiagram-UKHOOZJN-BqdN5_os.js} +1 -1
  114. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-D74dQ4u0.js → ganttDiagram-PKOTCBZU-SYDjVakh.js} +1 -1
  115. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-DwW0tZ0X.js → gitGraphDiagram-DS77QQ5N-Bf8bNpGA.js} +1 -1
  116. package/dist/worker/console/static/assets/index-B28Onmfy.css +1 -0
  117. package/dist/worker/console/static/assets/index-CTMZsDmh.js +486 -0
  118. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-ILCbxJyb.js → infoDiagram-6WML65LV-DIeAmJ45.js} +1 -1
  119. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-DeuWBQ89.js → ishikawaDiagram-WSZJBQD7-oikqUAlo.js} +1 -1
  120. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-CF5ih8Fk.js → journeyDiagram-NVQOT4AX-mKEF_xYT.js} +1 -1
  121. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-C7yOSuRO.js → kanban-definition-27J2QSJJ-BdWJHPnN.js} +1 -1
  122. package/dist/worker/console/static/assets/{linear-BDZ9riWi.js → linear-DGRlieMH.js} +1 -1
  123. package/dist/worker/console/static/assets/{mermaid.core-7pKqYtpZ.js → mermaid.core-4P9yPC9c.js} +5 -5
  124. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-LeJDybSU.js → mindmap-definition-FAOFIHXS-5PTSkos6.js} +1 -1
  125. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BJvT3pMD.js → pegDiagram-VL7TDLO6-DONIFpG5.js} +1 -1
  126. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-_rGqpMan.js → pieDiagram-7S7Q4E2Y-D_Z4S70M.js} +1 -1
  127. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-DPcSv5aA.js → quadrantDiagram-CIZ2JOQS-CAsjh8iY.js} +1 -1
  128. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-Drxx4hkJ.js → railroadDiagram-AXF67PYL-Cx4Dd6ac.js} +1 -1
  129. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BCTUdU4z.js → requirementDiagram-LRYGKXZP-cQb7mwyH.js} +1 -1
  130. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B6wzbZmB.js → sankeyDiagram-W5VNT64P-Cd-DhUdf.js} +1 -1
  131. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-BGt8d3QQ.js → sequenceDiagram-SI44F4Z6-AlKYRgIk.js} +1 -1
  132. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-7nlhJKo7.js → sizeCapture-X5ZJPWSS-CUy_ET4e.js} +1 -1
  133. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-Cv2stqMA.js → stateDiagram-OKZ733FA-CTuVe6Sa.js} +1 -1
  134. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BsWhs8O7.js +1 -0
  135. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-qDAo4Yc1.js → swimlanes-SLNWSIFB-ChFLJb-v.js} +2 -2
  136. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-CJcioYGH.js +8 -0
  137. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-CKbDNKTr.js → timeline-definition-Z64GVDOM-DZZeiAPr.js} +1 -1
  138. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DI-9EHic.js → vennDiagram-T6HMQDX7-t4O91cZU.js} +1 -1
  139. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-BrzzRDpX.js → wardleyDiagram-T6FBY63Y-CV5qGHZu.js} +1 -1
  140. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-BclH5hGh.js → xychartDiagram-ELKLHX3M-DyXbytUI.js} +1 -1
  141. package/dist/worker/console/static/index.html +2 -2
  142. package/dist/worker/console/static-src/app/console-types.js +9 -1
  143. package/dist/worker/console/static-src/operator-chat/animation-frame-batcher.js +38 -0
  144. package/dist/worker/console/static-src/operator-chat/chat-link.js +20 -0
  145. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +186 -5
  146. package/dist/worker/console/static-src/operator-chat/chat-stream-continuity.js +101 -0
  147. package/dist/worker/console/static-src/operator-chat/compaction-message.js +18 -3
  148. package/dist/worker/console/static-src/operator-chat/context-insights-store.js +64 -0
  149. package/dist/worker/console/static-src/operator-chat/details-rail-surfaces.js +98 -0
  150. package/dist/worker/console/static-src/operator-chat/file-palette-nav.js +81 -0
  151. package/dist/worker/console/static-src/operator-chat/pending-user-message.js +17 -3
  152. package/dist/worker/console/static-src/operator-chat/process-label.js +27 -5
  153. package/dist/worker/console/static-src/operator-chat/tools-catalog.js +16 -7
  154. package/dist/worker/console/static-src/operator-chat/transcript-mode.js +21 -0
  155. package/dist/worker/console/static-src/operator-chat/turn-group-equality.js +4 -1
  156. package/dist/worker/console/static-src/operator-chat/turn-process-disclosure.js +13 -5
  157. package/dist/worker/console/static-src/operator-chat/turn-state-projection.js +166 -0
  158. package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +56 -2
  159. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +211 -40
  160. package/dist/worker/console/static-src/operator-chat/useChatStream.js +124 -27
  161. package/dist/worker/console/static-src/operator-chat/useChatThread.js +88 -20
  162. package/dist/worker/console/static-src/operator-chat/useComposer.js +80 -6
  163. package/dist/worker/console/static-src/operator-chat/useRepoBrowser.js +13 -3
  164. package/dist/worker/console/static-src/operator-chat/useRuntimeControls.js +36 -17
  165. package/dist/worker/console/static-src/operator-chat/useRuntimeSnapshot.js +18 -0
  166. package/dist/worker/console/static-src/operator-chat/useWorkspaceBrowserGate.js +4 -0
  167. package/dist/worker/console/static-src/shell/console-update-reload.js +1 -1
  168. package/dist/worker/console/workspace-context.js +2 -0
  169. package/dist/worker/console/workspace-initialization.js +3 -3
  170. package/dist/worker/observability/read-model.js +23 -2
  171. package/dist/worker/observe/node-context-insights.js +479 -0
  172. package/dist/worker/observe/static/console-theme.css +174 -0
  173. package/dist/worker/observe/static/console-theme.js +36 -0
  174. package/dist/worker/observe/static/operator-chrome.css +85 -0
  175. package/dist/worker/observe/static/operator-chrome.js +51 -0
  176. package/dist/worker/scheduler/scheduled-goal-dispatch.js +3 -2
  177. package/dist/worker/scheduler/scheduled-goal-evidence.js +66 -3
  178. package/dist/worker/scheduler/scheduled-goal-store.js +10 -0
  179. package/dist/workflows/dag/budget-enforcement.js +31 -2
  180. package/dist/workflows/dag/frontend-closeout.js +3 -1
  181. package/dist/workflows/dag/frontend-contract-facts.js +11 -8
  182. package/dist/workflows/dag/frontend-design-policy.js +6 -6
  183. package/dist/workflows/dag/frontend-durable-tools.js +90 -70
  184. package/dist/workflows/dag/frontend-implementation-contract.js +146 -57
  185. package/dist/workflows/dag/frontend-plan-canary.js +66 -16
  186. package/dist/workflows/dag/frontend-plan-decision-contract.js +13 -21
  187. package/dist/workflows/dag/frontend-plan-progress.js +92 -0
  188. package/dist/workflows/dag/frontend-recovery-plan.js +10 -5
  189. package/dist/workflows/dag/frontend-recovery-run.js +51 -46
  190. package/dist/workflows/dag/frontend-repair-assertions.js +36 -0
  191. package/dist/workflows/dag/frontend-review-context.js +29 -1
  192. package/dist/workflows/dag/frontend-review-scopes.js +92 -2
  193. package/dist/workflows/dag/frontend-risk.js +8 -3
  194. package/dist/workflows/dag/frontend-root-observation.js +261 -0
  195. package/dist/workflows/dag/frontend-session-budget.js +52 -39
  196. package/dist/workflows/dag/frontend-session-context.js +10 -0
  197. package/dist/workflows/dag/frontend-test-execution-evidence.js +206 -48
  198. package/dist/workflows/dag/frontend-typed-event-store.js +11 -1
  199. package/dist/workflows/dag/frontend-verification-trace.js +6 -0
  200. package/dist/workflows/dag/frontend-writer-admission.js +3 -1
  201. package/dist/workflows/dag/init-hybrid.js +108 -37
  202. package/dist/workflows/dag/node-execution.js +11 -11
  203. package/dist/workflows/dag/output-protocol.js +1 -0
  204. package/dist/workflows/dag/rerun-feedback.js +35 -4
  205. package/dist/workflows/dag/rerun-task.js +62 -66
  206. package/dist/workflows/dag/runner.js +58 -12
  207. package/dist/workflows/dag/types.js +15 -8
  208. package/dist/workflows/loop/benchmark.js +11 -8
  209. package/docs/README.md +1 -1
  210. package/docs/architecture/runtime-boundaries.md +1 -1
  211. package/docs/governance/harness-methodology-verification.md +11 -0
  212. package/docs/templates/backend-test-dag.json +5 -4
  213. package/docs/templates/frontend-implementation-contract.schema.json +31 -11
  214. package/package.json +6 -4
  215. package/skills/frontend-design-review/SKILL.md +8 -11
  216. package/skills/frontend-design-review/references/review-checklist.md +3 -4
  217. package/skills/frontend-review/SKILL.md +5 -1
  218. package/skills/loop-agent/references/command-reference.md +8 -0
  219. package/skills/loop-agent/references/hybrid-dag.md +1 -1
  220. package/dist/worker/console/static/assets/channel-ChE7y-cx.js +0 -1
  221. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-C01TCf2X.js +0 -1
  222. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-C01TCf2X.js +0 -1
  223. package/dist/worker/console/static/assets/index-BWkIfcrK.css +0 -1
  224. package/dist/worker/console/static/assets/index-Cdkvw_H6.js +0 -469
  225. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-DC7V5vcq.js +0 -1
  226. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-Bwy4QUTO.js +0 -8
@@ -48,6 +48,8 @@ import { BrowserAutomationService } from "./browser-automation.js";
48
48
  import { buildTodoContinuationContext, } from "./todos.js";
49
49
  import { buildPersistentTerminalTools } from "./terminal-tools.js";
50
50
  import { buildScmTools } from "./scm-tools.js";
51
+ import { DbConnectionRegistry } from "./db-connections.js";
52
+ import { buildSqlTools } from "./pi-runtime/custom-tools/sql-tools.js";
51
53
  import { buildGoalContinuationContext, } from "./goals.js";
52
54
  import { injectWizardLocalHeaders, } from "./sdd-data-alignment.js";
53
55
  import { buildScheduledGoalTools } from "./pi-runtime/custom-tools/scheduled-goal-tools.js";
@@ -189,6 +191,25 @@ async function bindSessionExtensions(session) {
189
191
  return;
190
192
  await session.bindExtensions(createConsoleExtensionBindings());
191
193
  }
194
+ export function branchForkedSessionManager(sessionManager, throughUserMessageIndex) {
195
+ const userEntries = (sessionManager.getBranch?.() ?? []).filter((entry) => {
196
+ if (!entry || typeof entry !== "object")
197
+ return false;
198
+ const candidate = entry;
199
+ return candidate.type === "message" && candidate.message?.role === "user";
200
+ });
201
+ const target = userEntries[throughUserMessageIndex];
202
+ if (!target || typeof target.id !== "string") {
203
+ throw new Error("FORK_MESSAGE_ENTRY_NOT_FOUND");
204
+ }
205
+ sessionManager.branch(target.id);
206
+ if (typeof sessionManager.appendCustomEntry !== "function") {
207
+ throw new Error("FORK_MESSAGE_ENTRY_PERSIST_UNSUPPORTED");
208
+ }
209
+ sessionManager.appendCustomEntry("loop-agent-fork-point", {
210
+ throughUserMessageIndex,
211
+ });
212
+ }
192
213
  function pinOperatorChatTools(session, sessionMode = DEFAULT_CONSOLE_CHAT_SESSION_MODE) {
193
214
  session.setActiveToolsByName(computeChatActiveToolNames(session, sessionMode));
194
215
  }
@@ -294,7 +315,44 @@ export function createWizardLocalHeadersExtension(options) {
294
315
  }
295
316
  export { THINKING_LEVELS, RuntimeSnapshotUnavailableError, projectRuntimeSnapshot, };
296
317
  export { createDefaultPiSdkBindings } from "./pi-runtime/sdk-bindings.js";
318
+ /** Catalog listing must not load skills/extensions/context — those belong to reopen. */
319
+ const CATALOG_RESOURCE_LOADER_OPTIONS = Object.freeze({
320
+ noContextFiles: true,
321
+ noSkills: true,
322
+ noExtensions: true,
323
+ noPromptTemplates: true,
324
+ noThemes: true,
325
+ });
297
326
  export { extractAssistantContentBlocks, extractAssistantText, isAssistantSdkMessage };
327
+ export function buildRequestContextEvent(input) {
328
+ const systemPrompt = input.session.state?.systemPrompt ?? input.session.systemPrompt ?? "";
329
+ const activeTools = input.session.getActiveToolNames()
330
+ .filter((name) => typeof name === "string" && name.trim())
331
+ .slice(0, 256);
332
+ const provider = input.session.model?.provider;
333
+ const modelId = input.session.model?.modelId ?? input.session.model?.id;
334
+ const sources = ["system", "conversation"];
335
+ if (activeTools.length > 0)
336
+ sources.push("tools");
337
+ if (input.imageCount > 0)
338
+ sources.push("images");
339
+ return {
340
+ type: "request_context",
341
+ sessionId: input.sessionId,
342
+ requestId: `${input.turnId}:request:1`,
343
+ step: 1,
344
+ ...(provider && modelId ? { model: { provider, modelId } } : {}),
345
+ ...(input.session.thinkingLevel
346
+ ? { thinkingLevel: input.session.thinkingLevel }
347
+ : {}),
348
+ systemPromptHash: createHash("sha256").update(systemPrompt).digest("hex"),
349
+ systemPromptChars: systemPrompt.length,
350
+ activeTools,
351
+ inputChars: input.text.length,
352
+ imageCount: input.imageCount,
353
+ sources,
354
+ };
355
+ }
298
356
  function readSessionManagerId(manager) {
299
357
  if (!manager || typeof manager !== "object")
300
358
  return undefined;
@@ -409,6 +467,8 @@ export class ConsolePiRuntime {
409
467
  mainlineLeaves = new Map();
410
468
  /** Per-sessionId single-flight materialization (create fast-path / readiness fence). */
411
469
  sessionInit = new Map();
470
+ /** Concurrent reopen of the same historical JSONL shares one in-flight promise. */
471
+ reopenInFlight = new Map();
412
472
  /** Resolved model binding after materialization (create may return before this is known). */
413
473
  sessionModels = new Map();
414
474
  /** Durable session mode; record is the source of truth, this is the live handle cache. */
@@ -418,12 +478,14 @@ export class ConsolePiRuntime {
418
478
  compactionControllers = new Map();
419
479
  siftStates = new Map();
420
480
  /** Session-less tool definition caches (no AgentSession state). */
421
- operatorCustomToolsByMode = new Map();
481
+ operatorCustomToolsBySession = new Map();
422
482
  exploreCustomToolsPromise;
423
483
  exploreOrchestrator;
424
484
  bindings;
425
485
  browserAutomation;
426
486
  ownsBrowserAutomation;
487
+ dbConnections;
488
+ ownsDbConnections;
427
489
  constructor(options) {
428
490
  this.options = options;
429
491
  this.loader = createOperatorChatResourceLoader();
@@ -434,6 +496,12 @@ export class ConsolePiRuntime {
434
496
  downloadsDir: path.join(this.options.sessionDir, "..", "browser-downloads"),
435
497
  screenshotsDir: path.join(this.options.sessionDir, "..", "browser-screenshots"),
436
498
  });
499
+ // Governed DB connections are Console-global, not repository-scoped.
500
+ // This keeps named connections available when the user switches folders.
501
+ this.ownsDbConnections = options.dbConnections === undefined;
502
+ this.dbConnections =
503
+ options.dbConnections ??
504
+ new DbConnectionRegistry(path.join(options.globalAppDataRoot ?? path.resolve(this.options.sessionDir, ".."), "db"), undefined, undefined, path.join(this.options.sessionDir, "..", "db"));
437
505
  this.exploreOrchestrator = new ExploreOrchestrator({
438
506
  cwd: this.options.cwd,
439
507
  bindings: this.bindings,
@@ -1018,7 +1086,7 @@ export class ConsolePiRuntime {
1018
1086
  const loadWorkflowTools = shouldLoadWorkflowBusinessTools(sessionMode);
1019
1087
  const [operatorCustomTools, exploreCustomTools] = await Promise.all([
1020
1088
  loadWorkflowTools
1021
- ? this.loadOperatorCustomTools(sessionMode)
1089
+ ? this.loadOperatorCustomTools(sessionId, sessionMode)
1022
1090
  : Promise.resolve([]),
1023
1091
  this.loadExploreCustomTools(),
1024
1092
  ]);
@@ -1059,6 +1127,16 @@ export class ConsolePiRuntime {
1059
1127
  return [];
1060
1128
  })
1061
1129
  : [];
1130
+ const sqlTools = await buildSqlTools({
1131
+ sessionId,
1132
+ registry: this.dbConnections,
1133
+ ...(this.options.questionRegistry
1134
+ ? { questionRegistry: this.options.questionRegistry }
1135
+ : {}),
1136
+ }).catch((error) => {
1137
+ process.stderr.write(`[console] chat sql-tools build failed: ${error instanceof Error ? error.message : String(error)}\n`);
1138
+ return [];
1139
+ });
1062
1140
  const agentTool = await buildAgentCustomTool({
1063
1141
  parentSessionId: sessionId,
1064
1142
  orchestrator: this.exploreOrchestrator,
@@ -1092,25 +1170,28 @@ export class ConsolePiRuntime {
1092
1170
  ...terminalTools,
1093
1171
  ...scmTools,
1094
1172
  ...browserTools,
1173
+ ...sqlTools,
1095
1174
  ...(agentTool ? [agentTool] : []),
1096
1175
  ];
1097
1176
  }
1098
- loadOperatorCustomTools(sessionMode) {
1177
+ loadOperatorCustomTools(sessionId, sessionMode) {
1099
1178
  if (!this.options.actionContext)
1100
1179
  return Promise.resolve([]);
1101
- const cached = this.operatorCustomToolsByMode.get(sessionMode);
1180
+ const cacheKey = `${sessionId}:${sessionMode}`;
1181
+ const cached = this.operatorCustomToolsBySession.get(cacheKey);
1102
1182
  if (cached)
1103
1183
  return cached;
1104
1184
  const promise = buildCustomOperatorTools({
1105
1185
  actionContext: this.options.actionContext,
1186
+ sessionId,
1106
1187
  sessionMode,
1107
1188
  }).catch((error) => {
1108
1189
  process.stderr.write(`[console] chat custom-tools build failed: ${error instanceof Error ? error.message : String(error)}\n`);
1109
1190
  // Allow a later create/reopen to retry after a transient failure.
1110
- this.operatorCustomToolsByMode.delete(sessionMode);
1191
+ this.operatorCustomToolsBySession.delete(cacheKey);
1111
1192
  return [];
1112
1193
  });
1113
- this.operatorCustomToolsByMode.set(sessionMode, promise);
1194
+ this.operatorCustomToolsBySession.set(cacheKey, promise);
1114
1195
  return promise;
1115
1196
  }
1116
1197
  loadExploreCustomTools() {
@@ -1136,6 +1217,9 @@ export class ConsolePiRuntime {
1136
1217
  targetSessionDir: this.options.sessionDir,
1137
1218
  targetSessionId: sessionId,
1138
1219
  });
1220
+ if (init.throughUserMessageIndex !== undefined) {
1221
+ branchForkedSessionManager(sessionManager, init.throughUserMessageIndex);
1222
+ }
1139
1223
  const built = await this.buildSessionWithServices({
1140
1224
  sessionId,
1141
1225
  sessionManager,
@@ -1199,11 +1283,68 @@ export class ConsolePiRuntime {
1199
1283
  entries: manager.getBranch?.() ?? [],
1200
1284
  };
1201
1285
  }
1286
+ /**
1287
+ * Workspace-scoped model catalog. A live session's ModelRuntime is reused
1288
+ * when present; otherwise services are created without opening the Pi
1289
+ * conversation JSONL so the picker is not blocked on cold reopen.
1290
+ */
1291
+ workspaceModelRuntime;
1292
+ workspaceInspection;
1293
+ async getWorkspaceModelRuntime() {
1294
+ if (!this.workspaceModelRuntime) {
1295
+ this.workspaceModelRuntime = (async () => {
1296
+ const agentDir = await safeGetAgentDir(this.bindings);
1297
+ const { services } = await this.bindings.createServices({
1298
+ cwd: this.options.cwd,
1299
+ agentDir,
1300
+ resourceLoaderOptions: { ...CATALOG_RESOURCE_LOADER_OPTIONS },
1301
+ });
1302
+ return services.modelRuntime;
1303
+ })().catch((error) => {
1304
+ this.workspaceModelRuntime = undefined;
1305
+ throw error;
1306
+ });
1307
+ }
1308
+ return this.workspaceModelRuntime;
1309
+ }
1310
+ /**
1311
+ * Full OPEN-surface services for inspect UIs. No SessionManager / JSONL.
1312
+ * Cached without sessionId so todo/goal extensions stay off the shared scope.
1313
+ */
1314
+ async getWorkspaceInspectionServices() {
1315
+ if (!this.workspaceInspection) {
1316
+ this.workspaceInspection = (async () => {
1317
+ const agentDir = await safeGetAgentDir(this.bindings);
1318
+ const appendSystemPrompt = composeChatSystemPromptParts({
1319
+ sessionMode: DEFAULT_CONSOLE_CHAT_SESSION_MODE,
1320
+ workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
1321
+ });
1322
+ const { services } = await this.bindings.createServices({
1323
+ cwd: this.options.cwd,
1324
+ agentDir,
1325
+ resourceLoaderOptions: await this.buildResourceLoaderOptions({
1326
+ appendSystemPrompt,
1327
+ }),
1328
+ });
1329
+ return {
1330
+ modelRuntime: services.modelRuntime,
1331
+ resourceLoader: services
1332
+ .resourceLoader,
1333
+ settingsManager: services.settingsManager,
1334
+ };
1335
+ })().catch((error) => {
1336
+ this.workspaceInspection = undefined;
1337
+ throw error;
1338
+ });
1339
+ }
1340
+ return this.workspaceInspection;
1341
+ }
1202
1342
  async listModels(sessionId) {
1203
- await this.ensureSessionReady(sessionId);
1204
- const modelRuntime = this.modelRuntimes.get(sessionId);
1205
- if (!this.sessions.has(sessionId) || !modelRuntime)
1206
- throw new Error(`chat session not active: ${sessionId}`);
1343
+ const live = this.modelRuntimes.get(sessionId);
1344
+ if (live && this.sessions.has(sessionId)) {
1345
+ return this.bindings.listAvailableModels({ modelRuntime: live });
1346
+ }
1347
+ const modelRuntime = await this.getWorkspaceModelRuntime();
1207
1348
  return this.bindings.listAvailableModels({ modelRuntime });
1208
1349
  }
1209
1350
  async applyModel(sessionId, model) {
@@ -1466,11 +1607,11 @@ export class ConsolePiRuntime {
1466
1607
  return { ok: true, revision: this.revisions.get(sessionId) ?? 0 };
1467
1608
  }
1468
1609
  /**
1469
- * Project the unified live runtime snapshot (design §2.2). The current Pi
1470
- * session is the single source of truth: real system prompt, real model /
1471
- * thinking selection (auto + effective), the session modelRuntime model
1472
- * list, and the session ResourceLoader inventories. Undefined when the
1473
- * session is not active — callers fail closed instead of fabricating data.
1610
+ * Project the unified runtime snapshot (design §2.2). A live Pi session is
1611
+ * the source of truth when present. Inspect GETs may pass
1612
+ * `workspaceProjection` to render ResourceLoader inventories without
1613
+ * opening the conversation JSONL. Unknown ids without that hint stay
1614
+ * undefined so callers fail closed.
1474
1615
  */
1475
1616
  /**
1476
1617
  * ConsolePiRuntime.listSlashCommands
@@ -1489,18 +1630,27 @@ export class ConsolePiRuntime {
1489
1630
  return collectSlashCommands({ session, resourceLoader });
1490
1631
  }
1491
1632
  async getRuntimeSnapshot(sessionId, options) {
1492
- try {
1493
- await this.ensureSessionReady(sessionId);
1494
- }
1495
- catch (error) {
1496
- if (error instanceof PiSessionInitFailedError)
1497
- throw error;
1498
- // Inactive / unknown session: fail closed with undefined (no fabricated snapshot).
1499
- return undefined;
1633
+ const initializing = this.sessionInit.get(sessionId)?.status === "initializing";
1634
+ if (this.sessions.has(sessionId) || initializing) {
1635
+ try {
1636
+ await this.ensureSessionReady(sessionId);
1637
+ }
1638
+ catch (error) {
1639
+ if (error instanceof PiSessionInitFailedError)
1640
+ throw error;
1641
+ if (options?.workspaceProjection) {
1642
+ return this.projectWorkspaceRuntimeSnapshot(sessionId, options);
1643
+ }
1644
+ return undefined;
1645
+ }
1500
1646
  }
1501
1647
  const session = this.sessions.get(sessionId);
1502
- if (!session)
1648
+ if (!session) {
1649
+ if (options?.workspaceProjection) {
1650
+ return this.projectWorkspaceRuntimeSnapshot(sessionId, options);
1651
+ }
1503
1652
  return undefined;
1653
+ }
1504
1654
  const services = this.serviceScopes.get(sessionId);
1505
1655
  const modelRuntime = this.modelRuntimes.get(sessionId);
1506
1656
  const resourceLoader = services?.resourceLoader;
@@ -1601,6 +1751,116 @@ export class ConsolePiRuntime {
1601
1751
  hasBash: true,
1602
1752
  });
1603
1753
  }
1754
+ resolveWorkspaceThinkingSelection(sessionId, stored) {
1755
+ const live = this.thinkingSelections.get(sessionId);
1756
+ if (live)
1757
+ return live;
1758
+ if (!stored || stored === "auto")
1759
+ return "auto";
1760
+ if (THINKING_LEVELS.includes(stored)) {
1761
+ return stored;
1762
+ }
1763
+ return "auto";
1764
+ }
1765
+ /**
1766
+ * Inspect projection without SessionManager.open. Used only when the Agent
1767
+ * is not live and the caller confirmed a durable session record.
1768
+ */
1769
+ async projectWorkspaceRuntimeSnapshot(sessionId, options) {
1770
+ const hint = options.workspaceProjection ?? {};
1771
+ const sessionMode = hint.sessionMode ?? this.sessionModeOf(sessionId);
1772
+ let inspection;
1773
+ try {
1774
+ inspection = await this.getWorkspaceInspectionServices();
1775
+ }
1776
+ catch (error) {
1777
+ throw new RuntimeSnapshotUnavailableError(`workspace runtime projection failed: ${error instanceof Error ? error.message : String(error)}`);
1778
+ }
1779
+ const resourceLoader = inspection.resourceLoader;
1780
+ const settingsManager = inspection.settingsManager;
1781
+ const thinkingSelection = this.resolveWorkspaceThinkingSelection(sessionId, hint.thinkingLevel);
1782
+ const effectiveThinkingLevel = settingsManager?.getDefaultThinkingLevel?.() ??
1783
+ (thinkingSelection === "auto" ? undefined : thinkingSelection);
1784
+ const rawSystemPrompt = resourceLoader?.getSystemPrompt?.() ||
1785
+ composeChatSystemPrompt({
1786
+ sessionMode,
1787
+ workflowPrompt: OPERATOR_CHAT_SYSTEM_PROMPT_BASE,
1788
+ });
1789
+ if (!rawSystemPrompt) {
1790
+ throw new RuntimeSnapshotUnavailableError("system prompt projection failed: workspace prompt was empty");
1791
+ }
1792
+ let models = [];
1793
+ try {
1794
+ models = this.bindings
1795
+ .listAvailableModels({ modelRuntime: inspection.modelRuntime })
1796
+ .map((entry) => ({
1797
+ provider: entry.provider,
1798
+ id: entry.id,
1799
+ ...(entry.name ? { name: entry.name } : {}),
1800
+ hasCredentials: entry.hasCredentials,
1801
+ }));
1802
+ }
1803
+ catch (error) {
1804
+ throw new RuntimeSnapshotUnavailableError(`model enumeration failed: ${error instanceof Error ? error.message : String(error)}`);
1805
+ }
1806
+ const thinkingLevels = [
1807
+ { value: "auto" },
1808
+ ...THINKING_LEVELS.map((value) => ({ value })),
1809
+ ];
1810
+ let skillPrefs = { schemaVersion: 1, skills: {} };
1811
+ let skillPrefsError;
1812
+ if (resourceLoader) {
1813
+ try {
1814
+ skillPrefs = await this.loadSkillAutoInvocationPreferences();
1815
+ }
1816
+ catch (error) {
1817
+ skillPrefsError = error;
1818
+ }
1819
+ }
1820
+ const activeTools = chatActiveToolBaseline(sessionMode);
1821
+ const inventories = await collectRuntimeInventories({
1822
+ resourceLoader,
1823
+ skillPrefs,
1824
+ skillPrefsError,
1825
+ agentDir: await safeGetAgentDir(this.bindings),
1826
+ cwd: this.options.cwd,
1827
+ tools: [],
1828
+ activeToolNames: activeTools,
1829
+ });
1830
+ const storedModel = this.sessionModels.get(sessionId);
1831
+ const provider = storedModel?.provider ?? hint.modelProvider;
1832
+ const modelId = storedModel?.modelId ?? hint.modelId;
1833
+ return projectRuntimeSnapshot({
1834
+ sessionId,
1835
+ revision: this.revisions.get(sessionId) ?? 0,
1836
+ loadedAt: new Date().toISOString(),
1837
+ selection: {
1838
+ ...(provider && modelId
1839
+ ? { model: { provider, id: modelId } }
1840
+ : {}),
1841
+ thinkingSelection,
1842
+ ...(effectiveThinkingLevel
1843
+ ? { effectiveThinkingLevel: effectiveThinkingLevel }
1844
+ : {}),
1845
+ },
1846
+ models,
1847
+ thinkingLevels,
1848
+ systemPrompt: {
1849
+ ...(options.includeRaw ? { raw: rawSystemPrompt } : {}),
1850
+ text: rawSystemPrompt,
1851
+ sha256: createHash("sha256").update(rawSystemPrompt).digest("hex"),
1852
+ characters: rawSystemPrompt.length,
1853
+ },
1854
+ activeTools,
1855
+ contextFiles: inventories.contextFiles,
1856
+ skills: inventories.skills,
1857
+ extensions: inventories.extensions,
1858
+ packages: inventories.packages,
1859
+ mcp: inventories.mcp,
1860
+ diagnostics: inventories.diagnostics,
1861
+ hasBash: true,
1862
+ });
1863
+ }
1604
1864
  /**
1605
1865
  * Re-open a previously persisted Chat session after Console restart or
1606
1866
  * browser refresh (roadmap M1-S04 / S05).
@@ -1615,6 +1875,19 @@ export class ConsolePiRuntime {
1615
1875
  * than silently creating a fresh empty session and losing prior context.
1616
1876
  */
1617
1877
  async reopenSession(init) {
1878
+ const sessionId = init.sessionId;
1879
+ const existing = this.reopenInFlight.get(sessionId);
1880
+ if (existing)
1881
+ return existing;
1882
+ const pending = this.reopenSessionExclusive(init).finally(() => {
1883
+ if (this.reopenInFlight.get(sessionId) === pending) {
1884
+ this.reopenInFlight.delete(sessionId);
1885
+ }
1886
+ });
1887
+ this.reopenInFlight.set(sessionId, pending);
1888
+ return pending;
1889
+ }
1890
+ async reopenSessionExclusive(init) {
1618
1891
  await this.syncAimaxAuthToken();
1619
1892
  const sessionId = init.sessionId;
1620
1893
  const sessionMode = this.rememberSessionMode(sessionId, init.sessionMode ?? this.sessionModeOf(sessionId));
@@ -1954,6 +2227,14 @@ export class ConsolePiRuntime {
1954
2227
  };
1955
2228
  emitContextUsage();
1956
2229
  await this.runPrePromptCompaction(sessionId, session, text, options?.images?.length ?? 0, onEvent);
2230
+ onEvent(buildRequestContextEvent({
2231
+ sessionId,
2232
+ turnId: options?.turnId ?? `${sessionId}:active`,
2233
+ session,
2234
+ text,
2235
+ imageCount: options?.images?.length ?? 0,
2236
+ }));
2237
+ let step = 0;
1957
2238
  let stepStartedAt;
1958
2239
  let firstTokenAt;
1959
2240
  let pendingProviderError;
@@ -1962,12 +2243,24 @@ export class ConsolePiRuntime {
1962
2243
  const emitPendingProviderError = () => {
1963
2244
  if (!pendingProviderError)
1964
2245
  return;
1965
- onEvent(pendingProviderError);
2246
+ const error = pendingProviderError;
2247
+ onEvent(error);
2248
+ onEvent({
2249
+ type: "turn_error",
2250
+ sessionId,
2251
+ step: Math.max(1, step),
2252
+ ...(error.providerError.code === undefined
2253
+ ? {}
2254
+ : { code: String(error.providerError.code) }),
2255
+ message: error.message,
2256
+ });
1966
2257
  pendingProviderError = undefined;
1967
2258
  providerErrorEmitted = true;
1968
2259
  };
1969
2260
  unsub = session.subscribe((event) => {
1970
2261
  const observedAt = Date.now();
2262
+ if (event.type === "turn_start")
2263
+ step += 1;
1971
2264
  if (event.type === "message_start" && isUserSdkMessage(event.message)) {
1972
2265
  if (!initialUserMessageStarted) {
1973
2266
  // The first user message_start belongs to session.prompt(text), not
@@ -1998,7 +2291,7 @@ export class ConsolePiRuntime {
1998
2291
  const compactionId = event.type === "compaction_start" || event.type === "compaction_end"
1999
2292
  ? activeCompaction?.compactionId ?? newCompactionId(sessionId)
2000
2293
  : undefined;
2001
- const mapped = mapSdkEvent(sessionId, event, compactionId);
2294
+ const mapped = mapSdkEvent(sessionId, event, compactionId, Math.max(1, step));
2002
2295
  if (event.type === "compaction_end")
2003
2296
  activeCompaction = undefined;
2004
2297
  if (mapped?.type === "error") {
@@ -2023,7 +2316,7 @@ export class ConsolePiRuntime {
2023
2316
  if (mapped?.type === "agent_settled") {
2024
2317
  emitPendingProviderError();
2025
2318
  }
2026
- if (mapped?.type === "agent_start") {
2319
+ if (mapped?.type === "step_start" || mapped?.type === "agent_start") {
2027
2320
  stepStartedAt = observedAt;
2028
2321
  firstTokenAt = undefined;
2029
2322
  }
@@ -2051,6 +2344,13 @@ export class ConsolePiRuntime {
2051
2344
  : { outputTokens: usage.outputTokens }),
2052
2345
  };
2053
2346
  onEvent({ ...mapped, ...(timing ? { timing } : {}) });
2347
+ if (mapped.stopReason === "length") {
2348
+ onEvent({
2349
+ type: "turn_max_tokens",
2350
+ sessionId,
2351
+ step: mapped.step ?? Math.max(1, step),
2352
+ });
2353
+ }
2054
2354
  if (usage)
2055
2355
  onEvent({ type: "usage", sessionId, usage });
2056
2356
  emitContextUsage();
@@ -2232,6 +2532,36 @@ export class ConsolePiRuntime {
2232
2532
  const result = await session.compact(customInstructions);
2233
2533
  return projectCompactSnapshot(result ?? {});
2234
2534
  }
2535
+ listDatabaseConnections() {
2536
+ return this.dbConnections.list();
2537
+ }
2538
+ addDatabaseConnection(input) {
2539
+ return this.dbConnections.add(input);
2540
+ }
2541
+ updateDatabaseConnection(currentName, input) {
2542
+ return this.dbConnections.update(currentName, input);
2543
+ }
2544
+ removeDatabaseConnection(name) {
2545
+ return this.dbConnections.remove(name);
2546
+ }
2547
+ exportDatabaseConnections() {
2548
+ return this.dbConnections.exportConfig();
2549
+ }
2550
+ importDatabaseConnections(input, conflict) {
2551
+ return this.dbConnections.importConfig(input, conflict);
2552
+ }
2553
+ testDatabaseConnection(name) {
2554
+ return this.dbConnections.test(name);
2555
+ }
2556
+ listDatabaseDatabases(name) {
2557
+ return this.dbConnections.listDatabases(name);
2558
+ }
2559
+ listDatabaseTables(name, database) {
2560
+ return this.dbConnections.listTables(name, database);
2561
+ }
2562
+ browseDatabaseTable(name, table, page, pageSize, database) {
2563
+ return this.dbConnections.browseTable(name, table, page, pageSize, database);
2564
+ }
2235
2565
  dispose(sessionId) {
2236
2566
  // Mark disposed first so a late materialization never registers ready.
2237
2567
  this.disposedSessions.add(sessionId);
@@ -2239,6 +2569,11 @@ export class ConsolePiRuntime {
2239
2569
  this.sessionInit.delete(sessionId);
2240
2570
  this.compactionControllers.delete(sessionId);
2241
2571
  this.siftStates.delete(sessionId);
2572
+ for (const key of this.operatorCustomToolsBySession.keys()) {
2573
+ if (key.startsWith(`${sessionId}:`)) {
2574
+ this.operatorCustomToolsBySession.delete(key);
2575
+ }
2576
+ }
2242
2577
  const session = this.sessions.get(sessionId);
2243
2578
  if (session) {
2244
2579
  try {
@@ -2269,9 +2604,11 @@ export class ConsolePiRuntime {
2269
2604
  void this.exploreOrchestrator.abortAll();
2270
2605
  if (this.ownsBrowserAutomation)
2271
2606
  void this.browserAutomation.dispose();
2607
+ if (this.ownsDbConnections)
2608
+ this.dbConnections.dispose();
2272
2609
  }
2273
2610
  }
2274
- function mapAssistantMessageEvent(type, sessionId, message) {
2611
+ function mapAssistantMessageEvent(type, sessionId, message, step) {
2275
2612
  const record = message !== null && typeof message === "object"
2276
2613
  ? message
2277
2614
  : undefined;
@@ -2295,6 +2632,10 @@ function mapAssistantMessageEvent(type, sessionId, message) {
2295
2632
  sessionId,
2296
2633
  text: extractAssistantText(message),
2297
2634
  ...(content.length > 0 ? { content } : {}),
2635
+ step,
2636
+ ...(type === "message_end" && typeof record?.stopReason === "string"
2637
+ ? { stopReason: record.stopReason }
2638
+ : {}),
2298
2639
  };
2299
2640
  }
2300
2641
  function isUserSdkMessage(message) {
@@ -2302,10 +2643,12 @@ function isUserSdkMessage(message) {
2302
2643
  typeof message === "object" &&
2303
2644
  message.role === "user");
2304
2645
  }
2305
- function mapSdkEvent(sessionId, event, compactionId) {
2646
+ export function mapSdkEvent(sessionId, event, compactionId, step = 1) {
2306
2647
  switch (event.type) {
2307
2648
  case "agent_start":
2308
2649
  return { type: "agent_start", sessionId };
2650
+ case "turn_start":
2651
+ return { type: "step_start", sessionId, step };
2309
2652
  case "agent_end":
2310
2653
  return {
2311
2654
  type: "agent_end",
@@ -2315,15 +2658,50 @@ function mapSdkEvent(sessionId, event, compactionId) {
2315
2658
  case "message_update":
2316
2659
  if (!isAssistantSdkMessage(event.message))
2317
2660
  return undefined;
2318
- return mapAssistantMessageEvent("message_update", sessionId, event.message);
2661
+ return mapAssistantMessageEvent("message_update", sessionId, event.message, step);
2319
2662
  case "message_end":
2320
2663
  if (!isAssistantSdkMessage(event.message))
2321
2664
  return undefined;
2322
- return mapAssistantMessageEvent("message_end", sessionId, event.message);
2323
- case "turn_end":
2324
- // Usage is emitted from message_end (see prompt subscribe). turn_end
2325
- // carries the same final assistant message and would double-count.
2326
- return undefined;
2665
+ return mapAssistantMessageEvent("message_end", sessionId, event.message, step);
2666
+ case "turn_end": {
2667
+ const record = event.message && typeof event.message === "object"
2668
+ ? event.message
2669
+ : undefined;
2670
+ const reason = record?.stopReason;
2671
+ return {
2672
+ type: "step_end",
2673
+ sessionId,
2674
+ step,
2675
+ outcome: reason === "error"
2676
+ ? "failed"
2677
+ : reason === "aborted"
2678
+ ? "interrupted"
2679
+ : "completed",
2680
+ };
2681
+ }
2682
+ case "auto_retry_start":
2683
+ return {
2684
+ type: "model_retry",
2685
+ sessionId,
2686
+ step,
2687
+ attempt: event.attempt,
2688
+ maxAttempts: event.maxAttempts,
2689
+ delayMs: event.delayMs,
2690
+ errorMessage: redactRuntimeText(event.errorMessage, 600),
2691
+ state: "scheduled",
2692
+ };
2693
+ case "auto_retry_end":
2694
+ return {
2695
+ type: "model_retry",
2696
+ sessionId,
2697
+ step,
2698
+ attempt: event.attempt,
2699
+ state: event.success ? "completed" : "failed",
2700
+ success: event.success,
2701
+ ...(event.finalError
2702
+ ? { errorMessage: redactRuntimeText(event.finalError, 600) }
2703
+ : {}),
2704
+ };
2327
2705
  case "tool_execution_start":
2328
2706
  return {
2329
2707
  type: "tool_call",
@@ -2331,6 +2709,22 @@ function mapSdkEvent(sessionId, event, compactionId) {
2331
2709
  toolCallId: event.toolCallId,
2332
2710
  toolName: event.toolName,
2333
2711
  args: event.args,
2712
+ step,
2713
+ ...(event.parentToolCallId
2714
+ ? { parentToolCallId: event.parentToolCallId }
2715
+ : {}),
2716
+ };
2717
+ case "tool_execution_update":
2718
+ return {
2719
+ type: "tool_update",
2720
+ sessionId,
2721
+ toolCallId: event.toolCallId,
2722
+ toolName: event.toolName,
2723
+ partialResult: event.partialResult,
2724
+ step,
2725
+ ...(event.parentToolCallId
2726
+ ? { parentToolCallId: event.parentToolCallId }
2727
+ : {}),
2334
2728
  };
2335
2729
  case "tool_execution_end":
2336
2730
  return {
@@ -2340,6 +2734,10 @@ function mapSdkEvent(sessionId, event, compactionId) {
2340
2734
  toolName: event.toolName,
2341
2735
  result: event.result,
2342
2736
  isError: event.isError,
2737
+ step,
2738
+ ...(event.parentToolCallId
2739
+ ? { parentToolCallId: event.parentToolCallId }
2740
+ : {}),
2343
2741
  };
2344
2742
  case "agent_settled":
2345
2743
  return { type: "agent_settled", sessionId };
@@ -2386,8 +2784,19 @@ function mapSdkEvent(sessionId, event, compactionId) {
2386
2784
  : {}),
2387
2785
  };
2388
2786
  }
2389
- default:
2787
+ case "message_start":
2788
+ case "queue_update":
2390
2789
  return undefined;
2790
+ default:
2791
+ {
2792
+ const unknownEvent = event;
2793
+ return {
2794
+ type: "unknown",
2795
+ sessionId,
2796
+ eventType: String(unknownEvent.type ?? "unknown"),
2797
+ value: unknownEvent,
2798
+ };
2799
+ }
2391
2800
  }
2392
2801
  }
2393
2802
  function newCompactionId(sessionId) {