cuelo 0.6.9 → 0.7.1

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 (314) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +8 -7
  3. package/.next/build-manifest.json +2 -2
  4. package/.next/prerender-manifest.json +3 -3
  5. package/.next/required-server-files.js +2 -2
  6. package/.next/required-server-files.json +2 -2
  7. package/.next/routes-manifest.json +6 -0
  8. package/.next/server/app/_global-error/page.js +3 -3
  9. package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/_global-error.html +1 -1
  11. package/.next/server/app/_global-error.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  16. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  17. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  18. package/.next/server/app/_not-found/page.js +2 -2
  19. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/_not-found.html +1 -1
  21. package/.next/server/app/_not-found.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  23. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  25. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  26. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  27. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  28. package/.next/server/app/api/agent/[id]/account/route.js +1 -1
  29. package/.next/server/app/api/agent/[id]/bash-output/route.js +1 -1
  30. package/.next/server/app/api/agent/[id]/events/route.js +2 -2
  31. package/.next/server/app/api/agent/[id]/route.js +1 -1
  32. package/.next/server/app/api/agent/new/route.js +1 -1
  33. package/.next/server/app/api/agent/running/route.js +1 -1
  34. package/.next/server/app/api/attachments/route.js +1 -1
  35. package/.next/server/app/api/auth/all-providers/route.js +1 -1
  36. package/.next/server/app/api/auth/api-key/[provider]/route.js +1 -1
  37. package/.next/server/app/api/auth/login/[provider]/route.js +2 -2
  38. package/.next/server/app/api/auth/logout/[provider]/route.js +1 -1
  39. package/.next/server/app/api/auth/providers/route.js +1 -1
  40. package/.next/server/app/api/cwd/browse/route.js +1 -1
  41. package/.next/server/app/api/cwd/validate/route.js +1 -1
  42. package/.next/server/app/api/default-cwd/route.js +1 -1
  43. package/.next/server/app/api/display-settings/route.js +1 -1
  44. package/.next/server/app/api/document-text/route.js +1 -1
  45. package/.next/server/app/api/experiments/route.js +1 -1
  46. package/.next/server/app/api/file-index/route.js +1 -1
  47. package/.next/server/app/api/files/[...path]/route.js +1 -1
  48. package/.next/server/app/api/git/diff/route.js +2 -2
  49. package/.next/server/app/api/git/status/route.js +2 -2
  50. package/.next/server/app/api/gpt6/handles/route.js +1 -1
  51. package/.next/server/app/api/gpt6/reply/route.js +1 -1
  52. package/.next/server/app/api/gpt6/token/route.js +1 -1
  53. package/.next/server/app/api/gpt6/web6-session/route.js +1 -1
  54. package/.next/server/app/api/home/route.js +1 -1
  55. package/.next/server/app/api/live/call/[callId]/route.js +1 -1
  56. package/.next/server/app/api/live/call/[callId]/route.js.nft.json +1 -1
  57. package/.next/server/app/api/live/character-voice/route.js +1 -0
  58. package/.next/server/app/api/live/character-voice/route.js.nft.json +1 -0
  59. package/.next/server/app/api/live/character-voice/route_client-reference-manifest.js +1 -0
  60. package/.next/server/app/api/live/events/route.js +2 -2
  61. package/.next/server/app/api/live/events/route.js.nft.json +1 -1
  62. package/.next/server/app/api/live/offer/route.js +1 -1
  63. package/.next/server/app/api/live/offer/route.js.nft.json +1 -1
  64. package/.next/server/app/api/live/voices/route.js +1 -1
  65. package/.next/server/app/api/live/voices/route.js.nft.json +1 -1
  66. package/.next/server/app/api/lounge/events/route.js +2 -2
  67. package/.next/server/app/api/lounge/events/route.js.nft.json +1 -1
  68. package/.next/server/app/api/lounge/route.js +1 -1
  69. package/.next/server/app/api/lounge/route.js.nft.json +1 -1
  70. package/.next/server/app/api/mcp/route.js +2 -2
  71. package/.next/server/app/api/model-roles/route.js +1 -1
  72. package/.next/server/app/api/models/route.js +1 -1
  73. package/.next/server/app/api/models-config/catalog/route.js +1 -1
  74. package/.next/server/app/api/models-config/discover/route.js +1 -1
  75. package/.next/server/app/api/models-config/route.js +3 -3
  76. package/.next/server/app/api/models-config/test/route.js +1 -1
  77. package/.next/server/app/api/plugins/route.js +1 -1
  78. package/.next/server/app/api/plugins/route.js.nft.json +1 -1
  79. package/.next/server/app/api/project-trust/route.js +1 -1
  80. package/.next/server/app/api/projects/route.js +1 -1
  81. package/.next/server/app/api/runs/[runId]/route.js +1 -1
  82. package/.next/server/app/api/runs/route.js +1 -1
  83. package/.next/server/app/api/sessions/[id]/auto-name/route.js +1 -1
  84. package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
  85. package/.next/server/app/api/sessions/[id]/entries/[entryId]/thinking/route.js +1 -1
  86. package/.next/server/app/api/sessions/[id]/export/route.js +1 -1
  87. package/.next/server/app/api/sessions/[id]/route.js +1 -1
  88. package/.next/server/app/api/sessions/[id]/state/route.js +1 -1
  89. package/.next/server/app/api/sessions/route.js +1 -1
  90. package/.next/server/app/api/sessions/search/route.js +1 -1
  91. package/.next/server/app/api/settings/route.js +1 -1
  92. package/.next/server/app/api/sidecars/[service]/[...path]/route.js +1 -1
  93. package/.next/server/app/api/skills/check/route.js +1 -1
  94. package/.next/server/app/api/skills/install/route.js +2 -2
  95. package/.next/server/app/api/skills/route.js +1 -1
  96. package/.next/server/app/api/skills/search/route.js +1 -1
  97. package/.next/server/app/api/skills/update/route.js +1 -1
  98. package/.next/server/app/api/theme/route.js +1 -1
  99. package/.next/server/app/api/tool-image/route.js +1 -1
  100. package/.next/server/app/api/update-maintenance/route.js +3 -3
  101. package/.next/server/app/api/updates/route.js +1 -1
  102. package/.next/server/app/api/web-access/recovery/route.js +1 -1
  103. package/.next/server/app/api/web-access/route.js +1 -1
  104. package/.next/server/app/api/web6/consults/route.js +1 -1
  105. package/.next/server/app/api/worktrees/route.js +1 -1
  106. package/.next/server/app/favicon.ico/route.js +1 -1
  107. package/.next/server/app/index.html +1 -1
  108. package/.next/server/app/index.rsc +4 -4
  109. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  110. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  111. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  112. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  113. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  114. package/.next/server/app/manifest.webmanifest/route.js +2 -2
  115. package/.next/server/app/page.js +10 -10
  116. package/.next/server/app/page_client-reference-manifest.js +1 -1
  117. package/.next/server/app/recover/page.js +2 -2
  118. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  119. package/.next/server/app/recover.html +1 -1
  120. package/.next/server/app/recover.rsc +2 -2
  121. package/.next/server/app/recover.segments/_full.segment.rsc +2 -2
  122. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  123. package/.next/server/app/recover.segments/_index.segment.rsc +2 -2
  124. package/.next/server/app/recover.segments/_tree.segment.rsc +1 -1
  125. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  126. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  127. package/.next/server/app-paths-manifest.json +8 -7
  128. package/.next/server/chunks/205.js +6 -0
  129. package/.next/server/chunks/424.js +3 -0
  130. package/.next/server/chunks/4649.js +1 -0
  131. package/.next/server/chunks/5582.js +1 -1
  132. package/.next/server/chunks/6429.js +3 -3
  133. package/.next/server/chunks/7310.js +5 -0
  134. package/.next/server/chunks/9108.js +1 -1
  135. package/.next/server/chunks/9280.js +4 -4
  136. package/.next/server/middleware-build-manifest.js +1 -1
  137. package/.next/server/pages/404.html +1 -1
  138. package/.next/server/pages/500.html +1 -1
  139. package/.next/server/server-reference-manifest.json +1 -1
  140. package/.next/static/chunks/app/_global-error/{page-701a3390117d7557.js → page-2bfa6c2cae0dc17e.js} +1 -1
  141. package/.next/static/chunks/app/api/agent/[id]/account/{route-701a3390117d7557.js → route-2bfa6c2cae0dc17e.js} +1 -1
  142. package/.next/static/chunks/app/api/agent/[id]/bash-output/{route-701a3390117d7557.js → route-2bfa6c2cae0dc17e.js} +1 -1
  143. package/.next/static/chunks/app/api/agent/[id]/events/{route-701a3390117d7557.js → route-2bfa6c2cae0dc17e.js} +1 -1
  144. package/.next/static/chunks/app/api/agent/[id]/route-2bfa6c2cae0dc17e.js +1 -0
  145. package/.next/static/chunks/app/api/agent/new/route-2bfa6c2cae0dc17e.js +1 -0
  146. package/.next/static/chunks/app/api/agent/running/route-2bfa6c2cae0dc17e.js +1 -0
  147. package/.next/static/chunks/app/api/attachments/route-2bfa6c2cae0dc17e.js +1 -0
  148. package/.next/static/chunks/app/api/auth/all-providers/route-2bfa6c2cae0dc17e.js +1 -0
  149. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-2bfa6c2cae0dc17e.js +1 -0
  150. package/.next/static/chunks/app/api/auth/login/[provider]/route-2bfa6c2cae0dc17e.js +1 -0
  151. package/.next/static/chunks/app/api/auth/logout/[provider]/route-2bfa6c2cae0dc17e.js +1 -0
  152. package/.next/static/chunks/app/api/auth/providers/route-2bfa6c2cae0dc17e.js +1 -0
  153. package/.next/static/chunks/app/api/cwd/browse/route-2bfa6c2cae0dc17e.js +1 -0
  154. package/.next/static/chunks/app/api/cwd/validate/route-2bfa6c2cae0dc17e.js +1 -0
  155. package/.next/static/chunks/app/api/default-cwd/route-2bfa6c2cae0dc17e.js +1 -0
  156. package/.next/static/chunks/app/api/display-settings/route-2bfa6c2cae0dc17e.js +1 -0
  157. package/.next/static/chunks/app/api/document-text/route-2bfa6c2cae0dc17e.js +1 -0
  158. package/.next/static/chunks/app/api/experiments/route-2bfa6c2cae0dc17e.js +1 -0
  159. package/.next/static/chunks/app/api/file-index/route-2bfa6c2cae0dc17e.js +1 -0
  160. package/.next/static/chunks/app/api/files/[...path]/route-2bfa6c2cae0dc17e.js +1 -0
  161. package/.next/static/chunks/app/api/git/diff/route-2bfa6c2cae0dc17e.js +1 -0
  162. package/.next/static/chunks/app/api/git/status/route-2bfa6c2cae0dc17e.js +1 -0
  163. package/.next/static/chunks/app/api/gpt6/handles/route-2bfa6c2cae0dc17e.js +1 -0
  164. package/.next/static/chunks/app/api/gpt6/reply/route-2bfa6c2cae0dc17e.js +1 -0
  165. package/.next/static/chunks/app/api/gpt6/token/route-2bfa6c2cae0dc17e.js +1 -0
  166. package/.next/static/chunks/app/api/gpt6/web6-session/route-2bfa6c2cae0dc17e.js +1 -0
  167. package/.next/static/chunks/app/api/home/route-2bfa6c2cae0dc17e.js +1 -0
  168. package/.next/static/chunks/app/api/live/call/[callId]/route-2bfa6c2cae0dc17e.js +1 -0
  169. package/.next/static/chunks/app/api/live/character-voice/route-2bfa6c2cae0dc17e.js +1 -0
  170. package/.next/static/chunks/app/api/live/events/route-2bfa6c2cae0dc17e.js +1 -0
  171. package/.next/static/chunks/app/api/live/offer/route-2bfa6c2cae0dc17e.js +1 -0
  172. package/.next/static/chunks/app/api/live/voices/route-2bfa6c2cae0dc17e.js +1 -0
  173. package/.next/static/chunks/app/api/lounge/events/route-2bfa6c2cae0dc17e.js +1 -0
  174. package/.next/static/chunks/app/api/lounge/route-2bfa6c2cae0dc17e.js +1 -0
  175. package/.next/static/chunks/app/api/mcp/route-2bfa6c2cae0dc17e.js +1 -0
  176. package/.next/static/chunks/app/api/model-roles/route-2bfa6c2cae0dc17e.js +1 -0
  177. package/.next/static/chunks/app/api/models/route-2bfa6c2cae0dc17e.js +1 -0
  178. package/.next/static/chunks/app/api/models-config/catalog/route-2bfa6c2cae0dc17e.js +1 -0
  179. package/.next/static/chunks/app/api/models-config/discover/route-2bfa6c2cae0dc17e.js +1 -0
  180. package/.next/static/chunks/app/api/models-config/route-2bfa6c2cae0dc17e.js +1 -0
  181. package/.next/static/chunks/app/api/models-config/test/route-2bfa6c2cae0dc17e.js +1 -0
  182. package/.next/static/chunks/app/api/plugins/route-2bfa6c2cae0dc17e.js +1 -0
  183. package/.next/static/chunks/app/api/project-trust/route-2bfa6c2cae0dc17e.js +1 -0
  184. package/.next/static/chunks/app/api/projects/route-2bfa6c2cae0dc17e.js +1 -0
  185. package/.next/static/chunks/app/api/runs/[runId]/route-2bfa6c2cae0dc17e.js +1 -0
  186. package/.next/static/chunks/app/api/runs/route-2bfa6c2cae0dc17e.js +1 -0
  187. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-2bfa6c2cae0dc17e.js +1 -0
  188. package/.next/static/chunks/app/api/sessions/[id]/context/route-2bfa6c2cae0dc17e.js +1 -0
  189. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-2bfa6c2cae0dc17e.js +1 -0
  190. package/.next/static/chunks/app/api/sessions/[id]/export/route-2bfa6c2cae0dc17e.js +1 -0
  191. package/.next/static/chunks/app/api/sessions/[id]/route-2bfa6c2cae0dc17e.js +1 -0
  192. package/.next/static/chunks/app/api/sessions/[id]/state/route-2bfa6c2cae0dc17e.js +1 -0
  193. package/.next/static/chunks/app/api/sessions/route-2bfa6c2cae0dc17e.js +1 -0
  194. package/.next/static/chunks/app/api/sessions/search/route-2bfa6c2cae0dc17e.js +1 -0
  195. package/.next/static/chunks/app/api/settings/route-2bfa6c2cae0dc17e.js +1 -0
  196. package/.next/static/chunks/app/api/sidecars/[service]/[...path]/route-2bfa6c2cae0dc17e.js +1 -0
  197. package/.next/static/chunks/app/api/skills/check/route-2bfa6c2cae0dc17e.js +1 -0
  198. package/.next/static/chunks/app/api/skills/install/route-2bfa6c2cae0dc17e.js +1 -0
  199. package/.next/static/chunks/app/api/skills/route-2bfa6c2cae0dc17e.js +1 -0
  200. package/.next/static/chunks/app/api/skills/search/route-2bfa6c2cae0dc17e.js +1 -0
  201. package/.next/static/chunks/app/api/skills/update/route-2bfa6c2cae0dc17e.js +1 -0
  202. package/.next/static/chunks/app/api/theme/route-2bfa6c2cae0dc17e.js +1 -0
  203. package/.next/static/chunks/app/api/tool-image/route-2bfa6c2cae0dc17e.js +1 -0
  204. package/.next/static/chunks/app/api/update-maintenance/route-2bfa6c2cae0dc17e.js +1 -0
  205. package/.next/static/chunks/app/api/updates/route-2bfa6c2cae0dc17e.js +1 -0
  206. package/.next/static/chunks/app/api/web-access/recovery/route-2bfa6c2cae0dc17e.js +1 -0
  207. package/.next/static/chunks/app/api/web-access/route-2bfa6c2cae0dc17e.js +1 -0
  208. package/.next/static/chunks/app/api/web6/consults/route-2bfa6c2cae0dc17e.js +1 -0
  209. package/.next/static/chunks/app/api/worktrees/route-2bfa6c2cae0dc17e.js +1 -0
  210. package/.next/static/chunks/app/{layout-0082ed8a34057701.js → layout-ca001f1e875e854c.js} +1 -1
  211. package/.next/static/chunks/app/manifest.webmanifest/route-2bfa6c2cae0dc17e.js +1 -0
  212. package/.next/static/chunks/app/page-ce1990eb55a57ad6.js +22 -0
  213. package/.next/static/chunks/next/dist/client/components/builtin/app-error-2bfa6c2cae0dc17e.js +1 -0
  214. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-2bfa6c2cae0dc17e.js +1 -0
  215. package/.next/static/chunks/next/dist/client/components/builtin/not-found-2bfa6c2cae0dc17e.js +1 -0
  216. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-2bfa6c2cae0dc17e.js +1 -0
  217. package/.next/static/vl7SKOdL2Zksd2mJ3tjOQ/_buildManifest.js +1 -0
  218. package/.next/trace +105 -105
  219. package/.next/trace-build +1 -1
  220. package/.next/types/app/api/live/character-voice/route.ts +351 -0
  221. package/.next/types/routes.d.ts +2 -1
  222. package/.next/types/validator.ts +9 -0
  223. package/README.md +4 -3
  224. package/Tools/CUELO_Setup/files/native-runtime-patch.js +5 -5
  225. package/Tools/OMP_Global_Config/agent/extensions/jev-runtime.ts +277 -63
  226. package/Tools/OMP_Global_Config/agent/extensions/lib/maker-routing.ts +68 -17
  227. package/Tools/OMP_Global_Config/agent/extensions/lib/routing-ledger.ts +25 -1
  228. package/Tools/OMP_Global_Config/agent/rules/subagent.md +12 -1
  229. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +134 -55
  230. package/package.json +7 -7
  231. package/public/audio/live/ACML-1.0.txt +85 -0
  232. package/public/audio/live/hikari-reference.wav +0 -0
  233. package/public/audio/live/isana-reference.wav +0 -0
  234. package/public/audio/live/mio-reference.wav +0 -0
  235. package/public/audio/live/nova-reference.wav +0 -0
  236. package/public/audio/live/rin-reference.wav +0 -0
  237. package/public/audio/live/shion-reference.wav +0 -0
  238. package/public/audio/live/voices.json +275 -0
  239. package/public/audio/live/yuki-reference.wav +0 -0
  240. package/.next/server/chunks/3707.js +0 -5
  241. package/.next/server/chunks/6775.js +0 -6
  242. package/.next/static/4swMbGViH4DcOvsX9-ZTC/_buildManifest.js +0 -1
  243. package/.next/static/chunks/app/api/agent/[id]/route-701a3390117d7557.js +0 -1
  244. package/.next/static/chunks/app/api/agent/new/route-701a3390117d7557.js +0 -1
  245. package/.next/static/chunks/app/api/agent/running/route-701a3390117d7557.js +0 -1
  246. package/.next/static/chunks/app/api/attachments/route-701a3390117d7557.js +0 -1
  247. package/.next/static/chunks/app/api/auth/all-providers/route-701a3390117d7557.js +0 -1
  248. package/.next/static/chunks/app/api/auth/api-key/[provider]/route-701a3390117d7557.js +0 -1
  249. package/.next/static/chunks/app/api/auth/login/[provider]/route-701a3390117d7557.js +0 -1
  250. package/.next/static/chunks/app/api/auth/logout/[provider]/route-701a3390117d7557.js +0 -1
  251. package/.next/static/chunks/app/api/auth/providers/route-701a3390117d7557.js +0 -1
  252. package/.next/static/chunks/app/api/cwd/browse/route-701a3390117d7557.js +0 -1
  253. package/.next/static/chunks/app/api/cwd/validate/route-701a3390117d7557.js +0 -1
  254. package/.next/static/chunks/app/api/default-cwd/route-701a3390117d7557.js +0 -1
  255. package/.next/static/chunks/app/api/display-settings/route-701a3390117d7557.js +0 -1
  256. package/.next/static/chunks/app/api/document-text/route-701a3390117d7557.js +0 -1
  257. package/.next/static/chunks/app/api/experiments/route-701a3390117d7557.js +0 -1
  258. package/.next/static/chunks/app/api/file-index/route-701a3390117d7557.js +0 -1
  259. package/.next/static/chunks/app/api/files/[...path]/route-701a3390117d7557.js +0 -1
  260. package/.next/static/chunks/app/api/git/diff/route-701a3390117d7557.js +0 -1
  261. package/.next/static/chunks/app/api/git/status/route-701a3390117d7557.js +0 -1
  262. package/.next/static/chunks/app/api/gpt6/handles/route-701a3390117d7557.js +0 -1
  263. package/.next/static/chunks/app/api/gpt6/reply/route-701a3390117d7557.js +0 -1
  264. package/.next/static/chunks/app/api/gpt6/token/route-701a3390117d7557.js +0 -1
  265. package/.next/static/chunks/app/api/gpt6/web6-session/route-701a3390117d7557.js +0 -1
  266. package/.next/static/chunks/app/api/home/route-701a3390117d7557.js +0 -1
  267. package/.next/static/chunks/app/api/live/call/[callId]/route-701a3390117d7557.js +0 -1
  268. package/.next/static/chunks/app/api/live/events/route-701a3390117d7557.js +0 -1
  269. package/.next/static/chunks/app/api/live/offer/route-701a3390117d7557.js +0 -1
  270. package/.next/static/chunks/app/api/live/voices/route-701a3390117d7557.js +0 -1
  271. package/.next/static/chunks/app/api/lounge/events/route-701a3390117d7557.js +0 -1
  272. package/.next/static/chunks/app/api/lounge/route-701a3390117d7557.js +0 -1
  273. package/.next/static/chunks/app/api/mcp/route-701a3390117d7557.js +0 -1
  274. package/.next/static/chunks/app/api/model-roles/route-701a3390117d7557.js +0 -1
  275. package/.next/static/chunks/app/api/models/route-701a3390117d7557.js +0 -1
  276. package/.next/static/chunks/app/api/models-config/catalog/route-701a3390117d7557.js +0 -1
  277. package/.next/static/chunks/app/api/models-config/discover/route-701a3390117d7557.js +0 -1
  278. package/.next/static/chunks/app/api/models-config/route-701a3390117d7557.js +0 -1
  279. package/.next/static/chunks/app/api/models-config/test/route-701a3390117d7557.js +0 -1
  280. package/.next/static/chunks/app/api/plugins/route-701a3390117d7557.js +0 -1
  281. package/.next/static/chunks/app/api/project-trust/route-701a3390117d7557.js +0 -1
  282. package/.next/static/chunks/app/api/projects/route-701a3390117d7557.js +0 -1
  283. package/.next/static/chunks/app/api/runs/[runId]/route-701a3390117d7557.js +0 -1
  284. package/.next/static/chunks/app/api/runs/route-701a3390117d7557.js +0 -1
  285. package/.next/static/chunks/app/api/sessions/[id]/auto-name/route-701a3390117d7557.js +0 -1
  286. package/.next/static/chunks/app/api/sessions/[id]/context/route-701a3390117d7557.js +0 -1
  287. package/.next/static/chunks/app/api/sessions/[id]/entries/[entryId]/thinking/route-701a3390117d7557.js +0 -1
  288. package/.next/static/chunks/app/api/sessions/[id]/export/route-701a3390117d7557.js +0 -1
  289. package/.next/static/chunks/app/api/sessions/[id]/route-701a3390117d7557.js +0 -1
  290. package/.next/static/chunks/app/api/sessions/[id]/state/route-701a3390117d7557.js +0 -1
  291. package/.next/static/chunks/app/api/sessions/route-701a3390117d7557.js +0 -1
  292. package/.next/static/chunks/app/api/sessions/search/route-701a3390117d7557.js +0 -1
  293. package/.next/static/chunks/app/api/settings/route-701a3390117d7557.js +0 -1
  294. package/.next/static/chunks/app/api/sidecars/[service]/[...path]/route-701a3390117d7557.js +0 -1
  295. package/.next/static/chunks/app/api/skills/check/route-701a3390117d7557.js +0 -1
  296. package/.next/static/chunks/app/api/skills/install/route-701a3390117d7557.js +0 -1
  297. package/.next/static/chunks/app/api/skills/route-701a3390117d7557.js +0 -1
  298. package/.next/static/chunks/app/api/skills/search/route-701a3390117d7557.js +0 -1
  299. package/.next/static/chunks/app/api/skills/update/route-701a3390117d7557.js +0 -1
  300. package/.next/static/chunks/app/api/theme/route-701a3390117d7557.js +0 -1
  301. package/.next/static/chunks/app/api/tool-image/route-701a3390117d7557.js +0 -1
  302. package/.next/static/chunks/app/api/update-maintenance/route-701a3390117d7557.js +0 -1
  303. package/.next/static/chunks/app/api/updates/route-701a3390117d7557.js +0 -1
  304. package/.next/static/chunks/app/api/web-access/recovery/route-701a3390117d7557.js +0 -1
  305. package/.next/static/chunks/app/api/web-access/route-701a3390117d7557.js +0 -1
  306. package/.next/static/chunks/app/api/web6/consults/route-701a3390117d7557.js +0 -1
  307. package/.next/static/chunks/app/api/worktrees/route-701a3390117d7557.js +0 -1
  308. package/.next/static/chunks/app/manifest.webmanifest/route-701a3390117d7557.js +0 -1
  309. package/.next/static/chunks/app/page-ca1d4378b3ad4549.js +0 -22
  310. package/.next/static/chunks/next/dist/client/components/builtin/app-error-701a3390117d7557.js +0 -1
  311. package/.next/static/chunks/next/dist/client/components/builtin/forbidden-701a3390117d7557.js +0 -1
  312. package/.next/static/chunks/next/dist/client/components/builtin/not-found-701a3390117d7557.js +0 -1
  313. package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-701a3390117d7557.js +0 -1
  314. /package/.next/static/{4swMbGViH4DcOvsX9-ZTC → vl7SKOdL2Zksd2mJ3tjOQ}/_ssgManifest.js +0 -0
@@ -418,6 +418,27 @@ export function workspaceOf(input: Record<string, unknown>, item: Record<string,
418
418
  const sharesCheckout = (left: Workspace | undefined, right: Workspace | undefined) =>
419
419
  left !== "isolated" && right !== "isolated";
420
420
 
421
+ /**
422
+ * 같은 checkout의 active owner 중 소유 경로가 겹치는 owner. 소유 경로 미상 active owner는 빈 소유로 보지 않고
423
+ * 공유 발주 전체와 충돌로 둔다.
424
+ */
425
+ function activeConflicts(ownedPaths: readonly string[], workspace: Workspace, owners: readonly Owner[]): Owner[] {
426
+ return owners.filter((owner) => owner.active === true && sharesCheckout(owner.workspace, workspace) && (
427
+ owner.ownershipUnknown === true
428
+ || owner.ownedPaths.some((owned) => ownedPaths.some((requested) => ownedPathsOverlap(owned, requested)))));
429
+ }
430
+
431
+ function activeConflictReason(conflicts: readonly Owner[]): string {
432
+ const unknown = conflicts.some((owner) => owner.ownershipUnknown === true);
433
+ return `현재 active owner의 소유 경로와 충돌합니다: ${conflicts.map((owner) => owner.name ?? "<unnamed>").join(", ")}. 오래된 owner index나 다른 경로 owner로 자동 배정하지 말고 현재 owner에게 지시하거나 maker_route로 placement를 다시 판단하세요.${unknown ? " 소유 경로가 기록되지 않은 과거 발주가 아직 실행 중이라 공유 작업공간의 어느 경로와도 겹칠 수 있다고 봅니다. 그 owner가 끝난 뒤 발주하거나 isolated로 발주하세요." : ""}`;
434
+ }
435
+
436
+ /** 두 소유 계약이 같은 checkout에서 겹치는 경로. 격리 worktree가 끼면 겹침이 없다. */
437
+ function sharedOwnedPaths(left: DispatchOwnership, right: DispatchOwnership): string[] {
438
+ if (!sharesCheckout(left.workspace, right.workspace)) return [];
439
+ return left.ownedPaths.filter((path) => right.ownedPaths.some((other) => ownedPathsOverlap(path, other)));
440
+ }
441
+
421
442
  function ownerRevision(owners: Owner[]): string {
422
443
  return JSON.stringify(owners.map((owner) => [
423
444
  owner.name,
@@ -520,6 +541,9 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
520
541
  // 새 초안은 항상 소유 계약을 싣는다. 원장의 과거 row만 ownership이 없을 수 있다.
521
542
  type DispatchDraft = Omit<DispatchRecord, "ts" | "ownership" | keyof AttemptIdentity> & { ownership: DispatchOwnership };
522
543
  const pendingDispatches = new Map<string, DispatchDraft>();
544
+ // 검사를 통과했지만 spawn 결과를 아직 받지 못한 task 호출의 소유 예약(toolCallId → 초안). 별도 task 호출의 admission이
545
+ // 이 예약과 충돌을 검사한다. spawn 관측(noteSpawned)은 실제 owner 목록으로 넘기며 지우고, spawn 없이 끝난 호출은 releaseCall이 지운다.
546
+ const reservations = new Map<string, { key: string; draft: DispatchDraft }[]>();
523
547
  // 거절 진단 전용 색인. 준비된 계약을 이름별로 시간순으로 모아 어긋난 필드를 지목하며,
524
548
  // 통과·차단 판정에는 관여하지 않는다.
525
549
  const preparedContracts = new Map<string, DispatchContract[]>();
@@ -532,6 +556,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
532
556
  generation++;
533
557
  bindings.clear();
534
558
  pendingDispatches.clear();
559
+ reservations.clear();
535
560
  preparedContracts.clear();
536
561
  decisionCache.clear();
537
562
  placementCache.clear();
@@ -875,7 +900,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
875
900
  const prepare = async (context: string, tasks: RouteTask[], ctx: ExtensionContext, signal?: AbortSignal) =>
876
901
  (await prepareBatch(context, tasks, ctx, signal)).routes;
877
902
 
878
- async function beforeTask(input: Record<string, unknown>, ctx: ExtensionContext) {
903
+ async function beforeTask(input: Record<string, unknown>, ctx: ExtensionContext, callId = "") {
879
904
  let canonicalInput: Record<string, unknown>;
880
905
  try {
881
906
  const sessionId = ctx.sessionManager?.getSessionId?.();
@@ -960,18 +985,8 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
960
985
  const recommendedEffort = selected.efforts.length === 1 ? selected.efforts[0] : answers?.[`effort${index}`]?.choice;
961
986
  const placement = placementOf(prepared, owners);
962
987
  const workspace = workspaceOf(canonicalInput, item);
963
- // 같은 checkout을 쓰는 active owner만 충돌이다. 소유 경로 미상 active owner는 빈 소유로 보지 않고 공유 발주 전체와 충돌로 둔다.
964
- const activeConflicts = [
965
- ...owners.filter((owner) => owner.active === true && sharesCheckout(owner.workspace, workspace)),
966
- ...allOwners.filter((owner) => owner.active === true && owner.ownershipUnknown === true && sharesCheckout(owner.workspace, workspace)),
967
- ];
968
- if (activeConflicts.length > 0) {
969
- const unknown = activeConflicts.some((owner) => owner.ownershipUnknown === true);
970
- return {
971
- block: true,
972
- reason: `현재 active owner의 소유 경로와 충돌합니다: ${activeConflicts.map((owner) => owner.name ?? "<unnamed>").join(", ")}. 오래된 owner index나 다른 경로 owner로 자동 배정하지 말고 현재 owner에게 지시하거나 maker_route로 placement를 다시 판단하세요.${unknown ? " 소유 경로가 기록되지 않은 과거 발주가 아직 실행 중이라 공유 작업공간의 어느 경로와도 겹칠 수 있다고 봅니다. 그 owner가 끝난 뒤 발주하거나 isolated로 발주하세요." : ""}`,
973
- };
974
- }
988
+ const conflicts = activeConflicts(contract.ownedPaths, workspace, allOwners);
989
+ if (conflicts.length > 0) return { block: true, reason: activeConflictReason(conflicts) };
975
990
  const existingOwner = placement.action === "instruct-existing" || placement.action === "retarget-existing";
976
991
  const changed = prepared.status !== "judged" || profile !== selected.profile || recommendedEffort !== effort || existingOwner;
977
992
  const routingReason = /^\s*ROUTING_REASON:\s*\S.+$/m.test(task);
@@ -999,9 +1014,7 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
999
1014
  const overlaps: string[] = [];
1000
1015
  for (const [leftIndex, [, left]] of drafts.entries()) {
1001
1016
  for (const [, right] of drafts.slice(leftIndex + 1)) {
1002
- if (!sharesCheckout(left.ownership.workspace, right.ownership.workspace)) continue;
1003
- const shared = left.ownership.ownedPaths.filter((path) =>
1004
- right.ownership.ownedPaths.some((other) => ownedPathsOverlap(path, other)));
1017
+ const shared = sharedOwnedPaths(left.ownership, right.ownership);
1005
1018
  if (shared.length > 0) overlaps.push(`'${clipped(left.name, 40)}' ↔ '${clipped(right.name, 40)}'(${clippedList(shared)})`);
1006
1019
  }
1007
1020
  }
@@ -1011,10 +1024,46 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
1011
1024
  reason: `같은 task 배치에서 공유 작업공간 Maker의 OWNED_PATHS가 겹칩니다: ${overlaps.slice(0, DIAGNOSTIC_LIST_LIMIT).join("; ")}. 배치 전체를 발주하지 않았습니다. 경로를 나누거나 한 owner에게 맡기거나, 겹치는 쪽을 순서대로 내거나 isolated로 발주하세요.`,
1012
1025
  };
1013
1026
  }
1027
+ // 여기부터 게시까지는 await가 없는 한 구간이다. 항목별 검사 뒤 다른 호출이 owner나 예약을 바꿨을 수 있으므로
1028
+ // 지금의 active owner와, 다른 task 호출이 승인받아 아직 spawn 결과를 기다리는 예약을 함께 다시 보고 통과한 호출만 예약한다.
1029
+ // core는 한 assistant 메시지의 task 호출을 차례로 준비하므로 앞 호출의 예약이 뒤 호출의 준비에 보인다.
1030
+ const currentOwners = drafts.length > 0 ? deps.owners(ctx) : [];
1031
+ for (const [, draft] of drafts) {
1032
+ const conflicts = activeConflicts(draft.ownership.ownedPaths, draft.ownership.workspace, currentOwners);
1033
+ if (conflicts.length > 0) return { block: true, reason: activeConflictReason(conflicts) };
1034
+ }
1035
+ const reserved: string[] = [];
1036
+ for (const [, draft] of drafts) {
1037
+ for (const [heldCall, held] of reservations) {
1038
+ if (heldCall === callId) continue;
1039
+ for (const { draft: other } of held) {
1040
+ const shared = sharedOwnedPaths(draft.ownership, other.ownership);
1041
+ if (shared.length > 0) reserved.push(`'${clipped(draft.name, 40)}' ↔ 승인 중 '${clipped(other.name, 40)}'(${clippedList(shared)})`);
1042
+ }
1043
+ }
1044
+ }
1045
+ if (reserved.length > 0) {
1046
+ return {
1047
+ block: true,
1048
+ reason: `다른 task 호출이 발주 승인을 받아 spawn 결과를 기다리는 공유 작업공간 OWNED_PATHS와 겹칩니다: ${reserved.slice(0, DIAGNOSTIC_LIST_LIMIT).join("; ")}. 이 호출은 발주하지 않았습니다. 그 호출의 결과가 돌아온 뒤 현재 owner를 확인해 다시 내거나, 경로를 나누거나 isolated로 발주하세요.`,
1049
+ };
1050
+ }
1014
1051
  for (const [key, draft] of drafts) pendingDispatches.set(key, draft);
1052
+ if (callId && drafts.length > 0) reservations.set(callId, drafts.map(([key, draft]) => ({ key, draft })));
1015
1053
  return canonicalInput === input ? undefined : { input: canonicalInput };
1016
1054
  }
1017
1055
 
1056
+ /**
1057
+ * spawn 없이 끝난 task 호출의 예약과 초안만 푼다. 하류 guard 거절·승인 거부·실행 전 abort·skip은 core가 tool_result 없이
1058
+ * tool_execution_end만 내고, task 실행 오류는 isError tool_result를 낸다. 다른 호출의 예약과 이미 이관된 owner는 건드리지 않는다.
1059
+ */
1060
+ function releaseCall(callId: string): void {
1061
+ for (const { key, draft } of reservations.get(callId) ?? []) {
1062
+ if (pendingDispatches.get(key) === draft) pendingDispatches.delete(key);
1063
+ }
1064
+ reservations.delete(callId);
1065
+ }
1066
+
1018
1067
  /**
1019
1068
  * task spawn 성공 경계. TaskGuard lock을 확립하고, 검사를 통과해 실제로 spawn된 발주만 이력에 남긴다.
1020
1069
  * 실제 attempt identity는 이 spawn의 task 호출 id·index·session으로만 캡처한다(준비 handle과 섞지 않는다).
@@ -1061,6 +1110,8 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
1061
1110
  known.set(name, { assignmentId, lastAttempt: attempt });
1062
1111
  }
1063
1112
  contractLock ??= candidateLock;
1113
+ // 시작한 child는 이제 호출부의 live owner 목록이 소유한다. 이 호출의 예약은 여기서 넘긴다.
1114
+ reservations.delete(callId);
1064
1115
  return dispatched;
1065
1116
  }
1066
1117
 
@@ -1085,5 +1136,5 @@ export function registerMakerRouting(pi: ExtensionAPI, deps: RoutingDeps) {
1085
1136
  },
1086
1137
  });
1087
1138
  }
1088
- return { prepare, prepareBatch, beforeTask, noteSpawned, reset, releaseContractLock };
1139
+ return { prepare, prepareBatch, beforeTask, releaseCall, noteSpawned, reset, releaseContractLock };
1089
1140
  }
@@ -60,8 +60,19 @@ export interface OutcomeRecord extends AttemptIdentity {
60
60
  /** 실행 상태일 뿐 품질 판정이 아니다. */
61
61
  status: "completed" | "failed" | "cancelled";
62
62
  durationSec: number | null;
63
+ /** Maker terminal report가 낸 원 revision. 관측한 경우에만 있다. 이 필드가 생기기 전 기록과 미관측은 미상이다. */
64
+ sourceRevision?: string;
63
65
  }
64
66
 
67
+ /**
68
+ * Main 검수 revision과 그 attempt의 Maker 원 revision의 관계. advisory 기록이며 수용 게이트가 아니다.
69
+ * - same: 검수 revision이 원 revision과 같다.
70
+ * - integrated: 다르지만 Main이 integratedFrom으로 이 attempt의 원 revision을 명시해 통합 검수로 연결했다.
71
+ * - mismatch: 다르고 연결 주장이 없거나 그 주장이 원 revision과 다르다.
72
+ * - unknown: 원 revision이 미관측이거나 검수 revision이 없다(held 등).
73
+ */
74
+ export type RevisionRelation = "same" | "integrated" | "mismatch" | "unknown";
75
+
65
76
  /**
66
77
  * Main의 명시 수용 판정. 실행 상태(outcome)와 따로 남기며 자동 추정으로 만들지 않는다.
67
78
  * - accepted: 그 attempt가 완료되었고 Main이 revision·evidence와 함께 수용했다.
@@ -72,11 +83,18 @@ export interface VerdictRecord extends AttemptIdentity {
72
83
  type: "verdict";
73
84
  ts: string;
74
85
  verdict: "accepted" | "rework" | "held";
86
+ /** Main이 실제로 검수한 revision. */
75
87
  revision: string | null;
76
88
  evidenceLocators: string[];
77
89
  reason: string;
78
90
  /** 그 attempt가 실제로 적용한 교훈의 Mnemopi 기억 id. Main이 적용 근거(evidenceLocators)와 함께 남긴다. */
79
91
  appliedLessons?: string[];
92
+ /** 판정 시점에 그 attempt에서 관측한 Maker 원 revision(미관측 null). 이 필드가 생기기 전 판정에는 없다. */
93
+ sourceRevision?: string | null;
94
+ /** revision과 sourceRevision의 관계. 이 필드가 생기기 전 판정에는 없으며 그 판정은 재작성하지 않는다. */
95
+ revisionRelation?: RevisionRelation;
96
+ /** Main이 통합 검수라고 명시한 원 revision. 연결 주장일 뿐이며 검수 근거는 reason·evidenceLocators다. */
97
+ integratedFrom?: string;
80
98
  }
81
99
 
82
100
  export type LedgerRecord = DispatchRecord | OutcomeRecord | VerdictRecord;
@@ -209,6 +227,8 @@ export interface ScopedAttempt {
209
227
  status: OutcomeRecord["status"] | "running";
210
228
  /** 그 attempt dispatch의 소유 계약. dispatch가 없거나 과거 형식이면 null(미상). */
211
229
  ownership: DispatchOwnership | null;
230
+ /** 최신 outcome이 남긴 Maker 원 revision. 없거나 과거 형식이면 null(미상)이며 추정으로 채우지 않는다. */
231
+ sourceRevision: string | null;
212
232
  }
213
233
 
214
234
  /** 같은 session에서 identity가 있는 attempt를 원장에서 복원한다. dispatch·outcome·verdict 어느 것으로도 등록된다. */
@@ -231,11 +251,15 @@ export function scopedAttempts(records: readonly LedgerRecord[], sessionId: stri
231
251
  name: "",
232
252
  status: "running",
233
253
  ownership: null,
254
+ sourceRevision: null,
234
255
  };
235
256
  if (record.type === "dispatch") {
236
257
  entry.name = record.name;
237
258
  entry.ownership = ownershipOf(record);
238
- } else if (record.type === "outcome") entry.status = record.status;
259
+ } else if (record.type === "outcome") {
260
+ entry.status = record.status;
261
+ entry.sourceRevision = typeof record.sourceRevision === "string" && record.sourceRevision.trim() ? record.sourceRevision.trim() : null;
262
+ }
239
263
  if (!byAttempt.has(key)) order.push(key);
240
264
  byAttempt.set(key, entry);
241
265
  }
@@ -87,7 +87,12 @@ description: SubAgent 위임 판단, 병렬 실행, 검수 계약과 Git·통신
87
87
  준비를 재사용하며 무관한 owner 변화·단순 진행 질문으로 난이도를 다시 묻지 않고, policy·후보가
88
88
  바뀌면 다시 준비하고 owner 조건만 바뀌면 placement만 다시 판단한다. active owner가 그 경로를
89
89
  소유하면 dispatch-new가 막히고 오래된 owner index로 자동 배정하지 않는다
90
- (`routing.modelSelection.preparedReference`·`judgmentReuse`).
90
+ (`routing.modelSelection.preparedReference`·`judgmentReuse`). 공유 작업공간 경로는 검사를 통과해
91
+ spawn 결과를 기다리는 **다른 task 호출의 예약**과도 겹치면 막힌다. 예약은 spawn 결과가 실제 owner로
92
+ 넘기고, 하류 guard 거절·승인 거부·실행 오류·미실행으로 끝난 호출은 그 호출 것만 푼다. 같은 메시지에서
93
+ 앞 호출이 하류 guard에 막혀도 그 메시지 동안은 뒤 호출이 보수적으로 막히며 다음 발주에서 풀린다.
94
+ 완료된 Maker도 REWORK·후속 지시로 그 canonical agentId의 job이 실제 실행 중이면 active owner다.
95
+ 원장 running row만으로는 잠그지 않는다.
91
96
  이 session에서 성공한 spawn의 canonical child id(`agent://<id>`)로 Maker(완료·parked 포함)에게
92
97
  자연어 지시를 보내는 경계에 런타임은 `pre-dispatch-existing-owner-message` advisory를 낸다.
93
98
  전송을 기다리게 하거나 차단하지 않고, 구조 신호만 owner·지시별로 중복 제거해 다음 continuation에
@@ -442,6 +447,12 @@ Task Guard lock·budget·소유권·`FINDING_ID`, exit status, 파일·권한·
442
447
  수용 조건을 확인한 뒤, `rework`는 근거 있는 재작업 판정에 사용하며 두 판정 모두 검수한 revision·
443
448
  evidence locator·이유를 남긴다. `held`는 같은 identity와 보류 이유를 남기고 후속 입력 뒤에도
444
449
  명시적으로 다시 판정할 수 있다. 저장 실패는 미기록으로 보고하며 발주 자체를 차단하지 않는다.
450
+ `revision`은 Main이 실제로 검수한 revision이다. 원장은 그 attempt의 terminal report revision
451
+ (`sourceRevision`, 미관측이면 `null`)과의 관계를 `same`·`integrated`·`mismatch`·`unknown`으로 함께
452
+ 남긴다. 통합 뒤 새 revision을 직접 검수했으면 `integratedFrom`에 그 attempt의 원 revision을 적어 연결을
453
+ 명시한다. `integratedFrom`은 연결 주장일 뿐이고 그 검수의 증명은 `reason`·`evidenceLocators`가 맡는다.
454
+ `mismatch`·`unknown`도 기록되며 거절하지 않고 `diagnostic`으로 알린다. 원 revision을 추정해 채우거나
455
+ 과거 판정·품질 집계를 다시 쓰지 않는다.
445
456
  준비 참조 재사용과 실행 attempt 재사용은 다르다. 재작업 후 수용은 새 attempt에 붙여 원래
446
457
  재작업 판정을 보존한다. 옛 name-only 기록은 보존하되 품질 집계에서 제외한다.
447
458
  `maker_route`의 history는 **Jev가 분류를 끝낸 뒤** Main에게 붙는 관측 건수 advisory다
@@ -8133,8 +8133,8 @@ function parentSubagentServiceTiers(
8133
8133
  // 계정에서는 400 뒤 재시도로만 복구된다. 내장 모델은 구워진 models.json 값을 그대로 쓰고, 규칙으로 새로 만드는
8134
8134
  // 모델(discovery 등)은 rules.json을 쓰므로 두 곳에 prefixBinding과 binding controls(beta)를 같이 채운다.
8135
8135
  // binding controls의 provider 범위는 그 버전 upstream Sonnet 5.5 규칙과 같게 둔다: 18.4.4는 Claude API·
8136
- // Cloudflare·Vertex, 18.4.5는 Vertex가 `thinking.adaptive.block_binding: Extra inputs are not permitted`(400)로
8137
- // 거절해 Claude API·Cloudflare만(classes/anthropic.kdl:128). wire의 block_binding은 prefixBinding과 binding
8136
+ // Cloudflare·Vertex, 18.4.5·18.4.6은 Vertex가 `thinking.adaptive.block_binding: Extra inputs are not permitted`(400)로
8137
+ // 거절해 Claude API·Cloudflare만(classes/anthropic.kdl:128, 18.4.6은 kdl:129). wire의 block_binding은 prefixBinding과 binding
8138
8138
  // controls가 둘 다 참일 때만 나간다(anthropic.ts prefixMismatchBehavior). models.yml은 thinking override의
8139
8139
  // prefixBinding을 스키마에서 조용히 버리고 공개 설치에는 없으므로 설정으로 켜지 않는다.
8140
8140
  {
@@ -8144,23 +8144,38 @@ function parentSubagentServiceTiers(
8144
8144
  patched: '"claude-opus-5-5":{"id":"claude-opus-5-5","name":"Claude Opus 5.5","api":"anthropic-messages","provider":"anthropic","baseUrl":"https://api.anthropic.com","reasoning":true,"input":["text","image"],"cost":{"input":4,"output":20,"cacheRead":0.2,"cacheWrite":5},"contextWindow":1000000,"maxTokens":128000,"int":57.6,"tps":95.2,"thinking":{"mode":"anthropic-adaptive","efforts":["low","medium","high","xhigh","max"],"supportsDisplay":true,"prefixBinding":true},"identity":{"class":"anthropic","family":"opus","revision":"5.5.0"},"requiresGlyphTokenization":true,"tokenizer":"claude-v5","supportsComputerUse":false,"compat":{"officialEndpoint":true,"signingEndpoint":true,"supportsContextManagement":true,"supportsServerCompaction":true,"firstPartyProvider":true,"supportsOutputEffort":true,"disableStrictTools":false,"disableAdaptiveThinking":false,"allowAnthropicHeaderOverrides":false,"supportsEagerToolInputStreaming":true,"supportsLongCacheRetention":true,"supportsMidConversationSystem":true,"supportsTurnScopedSystem":true,"supportsMidConversationToolChanges":true,"supportsPerMessageEffort":true,"supportsThinkingBindingControls":true',
8145
8145
  },
8146
8146
  {
8147
- // 모든 provider의 Opus 5.5 규칙 계보에 prefixBinding(Sonnet 5.5 kdl:69와 같은 모양). 18.4.4·18.4.5 공통 앵커.
8148
- // 18.4.4 적용본은 이 patched 바로 뒤에 binding controls 규칙이 붙어 있어 marker가 그대로 성립한다.
8147
+ // 모든 provider의 Opus 5.5 규칙 계보에 prefixBinding(Sonnet 5.5 규칙과 같은 모양). 18.4.6은 kdl 한 줄 이동으로
8148
+ // source가 kdl:61이고 규칙 본문은 같다. alternate는 18.4.4·18.4.5 공통 kdl:60 앵커다. 두 후보의 marker는 source가
8149
+ // 달라 서로의 결과·순정본에 들어 있지 않다. 18.4.4 적용본은 kdl:60 patched 바로 뒤에 binding controls 규칙이 붙어
8150
+ // 있어 alternate marker가 그대로 성립한다.
8149
8151
  file: "../pi-catalog/src/compat/rules.json",
8150
- marker: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8151
- anchor: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false}}',
8152
- patched: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8152
+ marker: '{"source":"classes/anthropic.kdl:61","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8153
+ anchor: '{"source":"classes/anthropic.kdl:61","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false}}',
8154
+ patched: '{"source":"classes/anthropic.kdl:61","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8155
+ alternates: [{
8156
+ file: "../pi-catalog/src/compat/rules.json",
8157
+ marker: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8158
+ anchor: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false}}',
8159
+ patched: '{"source":"classes/anthropic.kdl:60","class":"anthropic","family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsForcedToolChoice":false},"thinking":{"prefixBinding":true}}',
8160
+ }],
8153
8161
  },
8154
8162
  {
8155
8163
  // binding controls 규칙은 그 버전의 upstream Sonnet 5.5 binding 규칙 바로 뒤에 같은 provider 범위로 둔다.
8156
- // 18.4.5: kdl:128(anthropic·cloudflare). alternate 18.4.4: kdl:106(anthropic·cloudflare·vertex).
8157
- // 18.4.4 라이브 적용본은 옛 위치(kdl:60 뒤)에 같은 규칙이 있어 alternate marker로 applied이다. 그 적용본의
8158
- // --revert는 patched가 연속으로 없으므로 엔진의 백업 경로(~/.omp/core-patch-backup)를 쓴다.
8164
+ // 18.4.6: kdl:129, alternate 18.4.5: kdl:128(둘 다 anthropic·cloudflare, 규칙 본문 동일). alternate 18.4.4:
8165
+ // kdl:106(anthropic·cloudflare·vertex). 18.4.6·18.4.5 후보는 추가 규칙이 같아 marker를 앞 Sonnet 규칙까지 포함한
8166
+ // patched 전체로 둔다(같은 marker면 둘 다 applied라 ambiguous가 된다). 18.4.4 라이브 적용본은 옛 위치(kdl:60 뒤)에
8167
+ // 같은 규칙이 있어 그 alternate marker로 applied이다. 그 적용본의 --revert는 patched가 연속으로 없으므로 엔진의
8168
+ // 백업 경로(~/.omp/core-patch-backup)를 쓴다.
8159
8169
  file: "../pi-catalog/src/compat/rules.json",
8160
- marker: '{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8161
- anchor: '{"source":"classes/anthropic.kdl:128","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8162
- patched: '{"source":"classes/anthropic.kdl:128","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}},{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8170
+ marker: '{"source":"classes/anthropic.kdl:129","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}},{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8171
+ anchor: '{"source":"classes/anthropic.kdl:129","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8172
+ patched: '{"source":"classes/anthropic.kdl:129","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}},{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8163
8173
  alternates: [{
8174
+ file: "../pi-catalog/src/compat/rules.json",
8175
+ marker: '{"source":"classes/anthropic.kdl:128","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}},{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8176
+ anchor: '{"source":"classes/anthropic.kdl:128","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8177
+ patched: '{"source":"classes/anthropic.kdl:128","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsThinkingBindingControls":true}},{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8178
+ }, {
8164
8179
  file: "../pi-catalog/src/compat/rules.json",
8165
8180
  marker: '{"source":"cuelo:opus-5.5-thinking-binding","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway","google-vertex"],"family":"opus","revision":[{"op":">=","revision":"5.5.0"},{"op":"<","revision":"6.0.0"}],"wire":{"supportsThinkingBindingControls":true}}',
8166
8181
  anchor: '{"source":"classes/anthropic.kdl:106","class":"anthropic","providers":["anthropic","cloudflare-ai-gateway","google-vertex"],"family":"sonnet","revision":[{"op":">=","revision":"5.5.0"}],"wire":{"supportsMidConversationSystem":true,"supportsMidConversationToolChanges":true,"supportsTurnScopedSystem":true,"supportsPerMessageEffort":true,"supportsThinkingBindingControls":true}}',
@@ -8340,20 +8355,24 @@ function parentSubagentServiceTiers(
8340
8355
  anchor: 'import { createRatchetPrelude } from "./ratchet/prelude";',
8341
8356
  patched: 'import { createRatchetPrelude } from "./ratchet/prelude.ts";',
8342
8357
  },
8343
- // P55. genuine 사용자 steer 가 아직 보이는 출력(text·toolCall)이 없는 진행 중 모델 요청을 끝까지 기다리지 않게 한다.
8358
+ // P55. genuine 사용자 steer 가 진행 중 모델 요청을 끝까지 기다리지 않게 한다(사용자 결정: 즉시 반영, 재추론 사용량 감수).
8344
8359
  // 2026-10-01 사용자 관측: Astra(xhigh) 4분짜리 추론 요청 중 넣은 steer 가 그 요청이 끝날 때까지(98.8s·169.6s)
8345
8360
  // 큐에 머물렀고, Opus 는 바로 개입되는 것처럼 보였다. Agent.steer 는 큐에만 넣고 모델 스트림은 끊지 않으며
8346
8361
  // (도구 실행만 interrupt), Codex native turn lane 은 `response.steer` 를 거절(P48 sticky)하고 SSE·Anthropic 은
8347
- // live 주입이 없다. 그래서 "보이는 출력이 아직 없음 + live 채널 미부착이거나 claim reject·defer" 일 때만
8348
- // 요청 전용 AbortSignal(promptToolAbortController 와 같이 provider signal 에만 병합)로 그 provider 호출을 끊고,
8349
- // partial 은 message_end 없이 버린다(context·persist·replay 에 남지 않음, 웹은 다음 message_start 가 live
8350
- // bubble 을 교체). 같은 run·같은 turn 안에서 steering 을 경계 주입해 새 요청을 보낸다. session/agent/loop abort·
8351
- // goal pause 는 건드리지 않는다. 이미 text·toolCall 이 보였으면 기존대로 boundary 처리(2026-09-20 "보이던 답 끊김"
8352
- // 계약, core-steer-stream-test.ts). native accept·내부 IRC/advisory/custom/agent steer·follow-up 은 대상이 아니다.
8353
- // 회귀: patches/core-steer-stream-test.ts(실제 Agent 루프 + Codex/SSE wire fixture).
8362
+ // live 주입이 없다. r3(같은 날 두 번째 관측): native 가 steer 를 accept 해도 서버가 다음 output boundary 에서
8363
+ // incomplete(steered)로 멈춰야 진행되는데, 멈추지 않으면 사용자가 직접 취소할 때까지 기다렸다(accept 뒤 9.4s 무응답).
8364
+ // 그래서 tool call 이 아직 없는 요청이면 live 채널 미부착·claim reject·defer·accept 어느 쪽이든 요청 전용
8365
+ // AbortSignal(promptToolAbortController 와 같이 provider signal 에만 병합)로 그 provider 호출을 끊는다. 이미 보인
8366
+ // text 와 완료(_end)된 서명 reasoning 은 stop 으로 commit 하고 아직 스트리밍 중인 tail 만 버린다. 보인 것이 없으면
8367
+ // partial 은 message_end 없이 버린다(context·persist·replay 에 남지 않음, 웹은 다음 message_start 가 live bubble 을
8368
+ // 교체). 같은 run·같은 turn 안에서 steering(채널이 accept 한 것 포함, 정확히 한 번)을 경계 주입해 새 요청을 보낸다.
8369
+ // session/agent/loop abort·goal pause·실행 중 도구는 건드리지 않는다. tool call 이 이미 보였으면 기존대로 boundary
8370
+ // 처리. 내부 IRC/advisory/custom/agent steer·follow-up 은 대상이 아니다.
8371
+ // 회귀: patches/core-steer-stream-test.ts(실제 Agent 루프 + Codex/SSE wire fixture + 실제 AgentSession).
8354
8372
  {
8355
8373
  file: "../pi-agent-core/src/agent-loop.ts",
8356
- marker: "class SteeringRestartInterruption extends Error {",
8374
+ // r3 marker: r2 적용본(같은 class, 인자 없는 생성자)을 applied 로 보지 않는다.
8375
+ marker: " constructor(readonly committed?: AssistantMessage) {\n super(\"User steering restarted the in-flight model request\");",
8357
8376
  anchor: "class HarmonyLeakInterruption extends Error {",
8358
8377
  patched: `/** CUELO P55: race token for a request-only restart requested by genuine user steering. */
8359
8378
  const STEER_RESTART = Symbol("steer-restart");
@@ -8366,12 +8385,13 @@ const STEER_RESTART = Symbol("steer-restart");
8366
8385
  export const STEER_DISCARDED_PARTIAL = Symbol("pi-agent-core.steer-discarded-partial");
8367
8386
 
8368
8387
  /**
8369
- * CUELO P55: genuine user steering ended the in-flight request before it produced visible
8370
- * output. The partial was discarded (never committed, persisted or replayed); the loop delivers
8371
- * the steering at this boundary and re-requests in the same run.
8388
+ * CUELO P55: genuine user steering ended the in-flight request. Visible output that already
8389
+ * reached listeners is \`committed\` (stop); otherwise the partial was discarded (never committed,
8390
+ * persisted or replayed). The loop delivers the steering at this boundary and re-requests in the
8391
+ * same run.
8372
8392
  */
8373
8393
  class SteeringRestartInterruption extends Error {
8374
- constructor() {
8394
+ constructor(readonly committed?: AssistantMessage) {
8375
8395
  super("User steering restarted the in-flight model request");
8376
8396
  this.name = "SteeringRestartInterruption";
8377
8397
  }
@@ -8386,7 +8406,7 @@ function isGenuineUserSteer(message: AgentMessage): boolean {
8386
8406
  );
8387
8407
  }
8388
8408
 
8389
- /** CUELO P55: text or a tool call already reached listeners; such a partial is never discarded for steering. */
8409
+ /** CUELO P55: text or a tool call already reached listeners; such a partial is committed, never discarded. */
8390
8410
  function hasVisibleAssistantOutput(message: AssistantMessage | null): boolean {
8391
8411
  return (
8392
8412
  message?.content.some(
@@ -8413,7 +8433,7 @@ class HarmonyLeakInterruption extends Error {`,
8413
8433
  },
8414
8434
  {
8415
8435
  file: "../pi-agent-core/src/agent-loop.ts",
8416
- marker: "const discardForSteerRestart = async (): Promise<never> => {",
8436
+ marker: "const restartForSteering = async (): Promise<never> => {",
8417
8437
  anchor: ` detachAbortListener = () => requestSignal.removeEventListener("abort", onAbort);
8418
8438
  }
8419
8439
 
@@ -8439,31 +8459,42 @@ class HarmonyLeakInterruption extends Error {`,
8439
8459
  patched: ` detachAbortListener = () => requestSignal.removeEventListener("abort", onAbort);
8440
8460
  }
8441
8461
 
8442
- // CUELO P55: genuine user steering ends this request only while nothing visible streamed
8443
- // (no text, no tool call) and the provider cannot take it live: no pump attached to the
8444
- // channel (SSE, non-steering providers, before response.created) or the pump's claim was
8445
- // rejected/deferred (Codex native lane, P48). An accepted live steer keeps the request.
8462
+ // CUELO P55: genuine user steering ends this request unless a tool call already streamed
8463
+ // (that turn ends at its normal boundary, tool results first). A pump attached to the channel
8464
+ // may still take the steer live, so the request waits for its claim to settle; once the claim
8465
+ // is accepted, rejected or deferred, the request is replaced: an accepted steer only stops the
8466
+ // response at a server-chosen boundary that may never come.
8446
8467
  const steerChannel = providerCall.liveSteering;
8447
8468
  let steerRestartClosed = false;
8448
8469
  const requestSteerRestart = (): void => {
8449
8470
  if (!steerRestartController || steerRestartClosed || steerRestartController.signal.aborted) return;
8450
- if (hasVisibleAssistantOutput(partialMessage)) return;
8451
- if (steerChannel?.attached && steerChannel.deferred.length === 0) return;
8471
+ if (partialMessage?.content.some(block => block.type === "toolCall")) return;
8472
+ if (
8473
+ steerChannel?.attached &&
8474
+ steerChannel.deferred.length === 0 &&
8475
+ !steerChannel.accepted.some(isGenuineUserSteer)
8476
+ ) {
8477
+ return;
8478
+ }
8452
8479
  steerRestartController.abort();
8453
8480
  };
8454
8481
  const detachUserSteeringRestart = steerRestartController
8455
8482
  ? config.onUserSteeringQueued?.(requestSteerRestart)
8456
8483
  : undefined;
8457
8484
  if (steerRestartController && steerChannel) {
8458
- steerChannel.onDeferred = () => {
8459
- if (steerChannel.deferred.some(isGenuineUserSteer) || hasNewUserSteering?.() === true) {
8485
+ steerChannel.onClaimSettled = () => {
8486
+ if (
8487
+ steerChannel.accepted.some(isGenuineUserSteer) ||
8488
+ steerChannel.deferred.some(isGenuineUserSteer) ||
8489
+ hasNewUserSteering?.() === true
8490
+ ) {
8460
8491
  requestSteerRestart();
8461
8492
  }
8462
8493
  };
8463
8494
  }
8464
8495
  const detachSteerRestart = (): void => {
8465
8496
  detachUserSteeringRestart?.();
8466
- if (steerChannel) steerChannel.onDeferred = undefined;
8497
+ if (steerChannel) steerChannel.onClaimSettled = undefined;
8467
8498
  };
8468
8499
  let steerRestartRace: Promise<typeof STEER_RESTART> | undefined;
8469
8500
  if (steerRestartController) {
@@ -8471,18 +8502,36 @@ class HarmonyLeakInterruption extends Error {`,
8471
8502
  steerRestartController.signal.addEventListener("abort", () => resolve(STEER_RESTART), { once: true });
8472
8503
  steerRestartRace = promise;
8473
8504
  }
8474
- // Drop the partial without message_end: listeners never receive it as a message, so it is
8475
- // not committed, persisted or replayed (the next message_start replaces the live bubble).
8476
- const discardForSteerRestart = async (): Promise<never> => {
8505
+ // Visible text stays: commit it with the reasoning that completed before it (closed, signed
8506
+ // blocks) and drop only the still-streaming tail. Nothing visible: drop the partial without
8507
+ // message_end, so listeners never receive it as a message and it is not committed, persisted
8508
+ // or replayed (the next message_start replaces the live bubble).
8509
+ const restartForSteering = async (): Promise<never> => {
8477
8510
  steerRestartClosed = true;
8478
8511
  try {
8479
8512
  const cleanup = responseIterator.return?.();
8480
8513
  if (cleanup) void cleanup.catch(() => {});
8481
8514
  } catch {
8482
- // Provider cancellation failures cannot resurrect the discarded partial.
8515
+ // Provider cancellation failures cannot resurrect the discarded tail.
8483
8516
  }
8484
8517
  await speculationCoordinator?.discardAll("user steering restarted the request", "discarded");
8485
8518
  speculationSettled = true;
8519
+ if (addedPartial && partialMessage && hasVisibleAssistantOutput(partialMessage)) {
8520
+ const committed = snapshotAssistantMessage({
8521
+ ...partialMessage,
8522
+ content: partialMessage.content.filter((block, index) => {
8523
+ if (block.type === "text") return block.text.trim().length > 0;
8524
+ if (block.type === "thinking") return !openBlocks.has(index) && Boolean(block.thinkingSignature);
8525
+ if (block.type === "redactedThinking") return !openBlocks.has(index);
8526
+ return false;
8527
+ }),
8528
+ stopReason: "stop",
8529
+ });
8530
+ context.messages[context.messages.length - 1] = committed;
8531
+ addedPartial = false;
8532
+ stream.push({ type: "message_end", message: snapshotAssistantMessage(committed) });
8533
+ throw new SteeringRestartInterruption(committed);
8534
+ }
8486
8535
  if (addedPartial) {
8487
8536
  context.messages.pop();
8488
8537
  addedPartial = false;
@@ -8506,10 +8555,10 @@ class HarmonyLeakInterruption extends Error {`,
8506
8555
  if (result === ABORTED) {
8507
8556
  return await finishAbortedStream();
8508
8557
  }
8509
- // A chunk that raced the restart is dropped unseen: nothing visible had streamed.
8558
+ // A chunk that raced the restart is dropped: it never reached listeners.
8510
8559
  if (result === STEER_RESTART || steerRestartController?.signal.aborted) {
8511
8560
  if (requestSignal?.aborted) return await finishAbortedStream();
8512
- return await discardForSteerRestart();
8561
+ return await restartForSteering();
8513
8562
  }
8514
8563
  next = result;
8515
8564
  } else {
@@ -8536,23 +8585,25 @@ class HarmonyLeakInterruption extends Error {`,
8536
8585
  },
8537
8586
  {
8538
8587
  file: "../pi-agent-core/src/agent-loop.ts",
8539
- marker: "if (steerRestartController?.signal.aborted && !requestSignal?.aborted) await discardForSteerRestart();",
8588
+ marker: "if (steerRestartController?.signal.aborted && !requestSignal?.aborted) await restartForSteering();",
8540
8589
  anchor: ` try {
8541
8590
  let trailing = await response.result();`,
8542
- patched: ` // CUELO P55: the iterator ended after a restart was requested; discard instead of finalizing.
8543
- if (steerRestartController?.signal.aborted && !requestSignal?.aborted) await discardForSteerRestart();
8591
+ patched: ` // CUELO P55: the iterator ended after a restart was requested; restart instead of finalizing.
8592
+ if (steerRestartController?.signal.aborted && !requestSignal?.aborted) await restartForSteering();
8544
8593
  steerRestartClosed = true;
8545
8594
  try {
8546
8595
  let trailing = await response.result();`,
8547
8596
  },
8548
8597
  {
8549
8598
  file: "../pi-agent-core/src/agent-loop.ts",
8550
- marker: "if (err instanceof SteeringRestartInterruption) {",
8599
+ marker: "if (err.committed) newMessages.push(err.committed);",
8551
8600
  anchor: " if (!(err instanceof HarmonyLeakInterruption)) throw err;",
8552
8601
  patched: ` if (err instanceof SteeringRestartInterruption) {
8553
- // CUELO P55: the discarded partial never reached context or listeners. Deliver the
8602
+ // CUELO P55: the committed visible output (if any) is already in context and was
8603
+ // delivered with message_end; a discarded partial never reached either. Deliver the
8554
8604
  // steering (plus anything the live channel took for the aborted response) at this
8555
8605
  // boundary and re-request inside the same turn and run; run/goal state is untouched.
8606
+ if (err.committed) newMessages.push(err.committed);
8556
8607
  const channel = preparedProviderCall.liveSteering;
8557
8608
  const taken = channel ? [...channel.accepted.splice(0), ...channel.deferred.splice(0)] : [];
8558
8609
  const steering = [...taken, ...((await config.getSteeringMessages?.(signal)) || [])];
@@ -8569,12 +8620,12 @@ class HarmonyLeakInterruption extends Error {`,
8569
8620
  },
8570
8621
  {
8571
8622
  file: "../pi-agent-core/src/live-steering.ts",
8572
- marker: " attached = false;\n",
8623
+ marker: " onClaimSettled: (() => void) | undefined;\n",
8573
8624
  anchor: " readonly #queue: LiveSteeringQueue;\n",
8574
8625
  patched: ` /** CUELO P55: a provider pump pulls from this channel (set on its first wait). */
8575
8626
  attached = false;
8576
- /** CUELO P55: notified after input is deferred to the boundary (claim rejected or not convertible). */
8577
- onDeferred: (() => void) | undefined;
8627
+ /** CUELO P55: notified after a claim settles: input accepted live, rejected, or deferred to the boundary. */
8628
+ onClaimSettled: (() => void) | undefined;
8578
8629
  readonly #queue: LiveSteeringQueue;
8579
8630
  `,
8580
8631
  },
@@ -8586,15 +8637,22 @@ class HarmonyLeakInterruption extends Error {`,
8586
8637
  },
8587
8638
  {
8588
8639
  file: "../pi-agent-core/src/live-steering.ts",
8589
- marker: " this.deferred.push(...messages);\n this.onDeferred?.();\n return undefined;",
8640
+ marker: " this.deferred.push(...messages);\n this.onClaimSettled?.();\n return undefined;",
8590
8641
  anchor: " this.deferred.push(...messages);\n return undefined;",
8591
- patched: " this.deferred.push(...messages);\n this.onDeferred?.();\n return undefined;",
8642
+ patched: " this.deferred.push(...messages);\n this.onClaimSettled?.();\n return undefined;",
8592
8643
  },
8593
8644
  {
8594
8645
  file: "../pi-agent-core/src/live-steering.ts",
8595
- marker: " this.deferred.push(...messages);\n this.onDeferred?.();\n },",
8646
+ marker: " this.deferred.push(...messages);\n this.onClaimSettled?.();\n },",
8596
8647
  anchor: " this.deferred.push(...messages);\n },",
8597
- patched: " this.deferred.push(...messages);\n this.onDeferred?.();\n },",
8648
+ patched: " this.deferred.push(...messages);\n this.onClaimSettled?.();\n },",
8649
+ },
8650
+ {
8651
+ // r3: accept 도 claim 정산이다. 채널이 받은 genuine steer 로 진행 중 요청을 교체한다(위 requestSteerRestart).
8652
+ file: "../pi-agent-core/src/live-steering.ts",
8653
+ marker: " this.accepted.push(...messages);\n this.onClaimSettled?.();\n",
8654
+ anchor: " this.accepted.push(...messages);\n",
8655
+ patched: " this.accepted.push(...messages);\n this.onClaimSettled?.();\n",
8598
8656
  },
8599
8657
  // P55 r2: 버린 partial 은 Agent#runLoop 의 지역 `partial` 에 마지막 snapshot 으로 남는다(message_end 만 비운다).
8600
8658
  // 경계의 steering dequeue 가 던지거나(예: AgentSession usage preflight 의 "Usage preflight cancelled") 비어 있고
@@ -8618,6 +8676,27 @@ class HarmonyLeakInterruption extends Error {`,
8618
8676
  anchor: " const assistantPartial = partial?.role === \"assistant\" ? partial : undefined;",
8619
8677
  patched: " // CUELO P55: a partial discarded for a steering restart is not this error's content.\n const assistantPartial =\n partial?.role === \"assistant\" && Reflect.get(partial, STEER_DISCARDED_PARTIAL) !== true ? partial : undefined;",
8620
8678
  },
8679
+ // 이슈 #5: async-result 자동 전달의 details.jobs[]에 그 실행의 실제 terminal status를 싣는다. wait·`read proc://`의
8680
+ // snapshotJobs는 이미 status를 싣지만 자동 결과만 빠져, schema 없는 실패(예: 격리 준비 실패의 TaskJobError)를
8681
+ // consumer가 completed로 읽었다. entry.job은 정산된 그 실행 객체이므로 enqueue 시점의 status가 정본이다.
8682
+ {
8683
+ file: "src/session/async-job-delivery.ts",
8684
+ marker: "\t/** Actual terminal status of this run (completed|failed|cancelled); absent when the job row is gone. */",
8685
+ anchor: "\tdurationMs?: number;\n\t/** Source capture metadata belongs to this job, not to the enclosing delivery report. */",
8686
+ patched: "\tdurationMs?: number;\n\t/** Actual terminal status of this run (completed|failed|cancelled); absent when the job row is gone. */\n\tstatus?: AsyncJob[\"status\"];\n\t/** Source capture metadata belongs to this job, not to the enclosing delivery report. */",
8687
+ },
8688
+ {
8689
+ file: "src/session/async-job-delivery.ts",
8690
+ marker: "\t\t\tstatus: entry.job?.status,\n",
8691
+ anchor: "\t\t\tlabel: entry.job?.label,\n",
8692
+ patched: "\t\t\tlabel: entry.job?.label,\n\t\t\tstatus: entry.job?.status,\n",
8693
+ },
8694
+ {
8695
+ file: "src/session/async-job-delivery.ts",
8696
+ marker: "\t\t\t...(job.status ? { status: job.status } : {}),\n",
8697
+ anchor: "\t\t\tdurationMs: job.durationMs,\n\t\t\t...(job.meta ? { meta: job.meta } : {}),\n",
8698
+ patched: "\t\t\tdurationMs: job.durationMs,\n\t\t\t...(job.status ? { status: job.status } : {}),\n\t\t\t...(job.meta ? { meta: job.meta } : {}),\n",
8699
+ },
8621
8700
  ];
8622
8701
  // EDITS 문자열의 줄 끝을 LF로 통일한다. 이 파일의 작업 사본이 CRLF여도 core 파일(LF)과
8623
8702
  // 비교·치환이 어긋나지 않는다. core 파일 자체의 줄 끝은 건드리지 않는다.