elanous 0.2.25 → 0.2.28

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 (337) hide show
  1. package/apps/pwa/out/404/index.html +1 -1
  2. package/apps/pwa/out/404.html +1 -1
  3. package/apps/pwa/out/_next/static/chunks/{1454-37fd16f479f5554a.js → 1454-29d1d773d5996a49.js} +1 -1
  4. package/apps/pwa/out/_next/static/chunks/{599-a914cc0468f56143.js → 599-56f2c0a5cc4a7295.js} +1 -1
  5. package/apps/pwa/out/_next/static/chunks/app/approvals/page-5ab1e47978577c5e.js +1 -0
  6. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-24453f6a302816b4.js +1 -0
  7. package/apps/pwa/out/_next/static/chunks/app/board/page-6c131d30bb1cf871.js +1 -0
  8. package/apps/pwa/out/_next/static/chunks/app/botlab/{page-b12149c51f7d04b1.js → page-fa46d4588e8442c2.js} +1 -1
  9. package/apps/pwa/out/_next/static/chunks/app/bots/page-dc0772b11861af51.js +1 -0
  10. package/apps/pwa/out/_next/static/chunks/app/ceo/page-66ad46ed0279feb9.js +1 -0
  11. package/apps/pwa/out/_next/static/chunks/app/chat/page-5159dc8752c6cd29.js +1 -0
  12. package/apps/pwa/out/_next/static/chunks/app/consult/page-c5a2478861c08b87.js +1 -0
  13. package/apps/pwa/out/_next/static/chunks/app/control/page-f722a9dec084e08b.js +1 -0
  14. package/apps/pwa/out/_next/static/chunks/app/decisions/{page-305cd294e754906e.js → page-256ffd365d32e100.js} +1 -1
  15. package/apps/pwa/out/_next/static/chunks/app/design-check/{page-dea4b795741126fd.js → page-e0de78ae7b99f01c.js} +1 -1
  16. package/apps/pwa/out/_next/static/chunks/app/editor/page-cfbdc44b708d9801.js +1 -0
  17. package/apps/pwa/out/_next/static/chunks/app/exec/{page-45889e7070d11126.js → page-4c741eb760f2f77c.js} +1 -1
  18. package/apps/pwa/out/_next/static/chunks/app/field/{page-16a2e893f83ae4d0.js → page-e9ba98f5f1440a21.js} +1 -1
  19. package/apps/pwa/out/_next/static/chunks/app/inside/page-dafc901bb1b72b5f.js +1 -0
  20. package/apps/pwa/out/_next/static/chunks/app/intake/{page-56888bc744e08dac.js → page-2f6f303fa114ec24.js} +1 -1
  21. package/apps/pwa/out/_next/static/chunks/app/layout-1634081c5272006c.js +1 -0
  22. package/apps/pwa/out/_next/static/chunks/app/live/{page-952c6ceec6d9de38.js → page-ced0bcfc6542b3fc.js} +1 -1
  23. package/apps/pwa/out/_next/static/chunks/app/live-run/{page-6d0202af568f4c63.js → page-bb1f05cd51c38944.js} +1 -1
  24. package/apps/pwa/out/_next/static/chunks/app/loops/page-646b50f63b6fe732.js +1 -0
  25. package/apps/pwa/out/_next/static/chunks/app/market/page-db069b48a59c8c00.js +1 -0
  26. package/apps/pwa/out/_next/static/chunks/app/missions/[id]/{page-4fb6fc34e20c07b7.js → page-f736324afa2117c1.js} +1 -1
  27. package/apps/pwa/out/_next/static/chunks/app/morning/{page-e9502921f4f01b1f.js → page-6f131b51193a36f9.js} +1 -1
  28. package/apps/pwa/out/_next/static/chunks/app/{not-found-b6169ea2f09cf287.js → not-found-435f5e2faf02bc01.js} +1 -1
  29. package/apps/pwa/out/_next/static/chunks/app/observatory/{page-6a14333d1b1b3967.js → page-497e0eedf20e7890.js} +1 -1
  30. package/apps/pwa/out/_next/static/chunks/app/ops/checklist/{page-8c91a9a66c9ec90a.js → page-a8d28fdf995e16ea.js} +1 -1
  31. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-8966452228753c5e.js +1 -0
  32. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-fd5d18656cb432b6.js +1 -0
  33. package/apps/pwa/out/_next/static/chunks/app/outputs/page-5663779cb1a37609.js +1 -0
  34. package/apps/pwa/out/_next/static/chunks/app/{page-3d3fc73dd187ed52.js → page-66a67eb19ebd976b.js} +1 -1
  35. package/apps/pwa/out/_next/static/chunks/app/reflection/page-3b492aa78cf3c4a6.js +1 -0
  36. package/apps/pwa/out/_next/static/chunks/app/scheduler/{page-9c04dac0831c2bbb.js → page-c71267e7681da982.js} +1 -1
  37. package/apps/pwa/out/_next/static/chunks/app/sessions/page-a21d1e1797172692.js +1 -0
  38. package/apps/pwa/out/_next/static/chunks/app/settings/devices/{page-04de9ca6d52a3893.js → page-cb249e81ed339318.js} +1 -1
  39. package/apps/pwa/out/_next/static/chunks/app/settings/{page-62527677bbc2fdc4.js → page-781cfc5114e097da.js} +1 -1
  40. package/apps/pwa/out/_next/static/chunks/app/setup/done/{page-9a2e09c4a311764c.js → page-478157214db6a023.js} +1 -1
  41. package/apps/pwa/out/_next/static/chunks/app/setup/{page-bfeb35d69e8b24bb.js → page-86141f12cf090b7f.js} +1 -1
  42. package/apps/pwa/out/_next/static/chunks/app/share/{page-89cb33bced824e4a.js → page-7256c73bb1c36751.js} +1 -1
  43. package/apps/pwa/out/_next/static/chunks/app/showroom/page-5c738ca7adef3de5.js +1 -0
  44. package/apps/pwa/out/_next/static/chunks/app/tasks/page-0138c8091ec17224.js +1 -0
  45. package/apps/pwa/out/_next/static/chunks/app/term/page-cc2f24f16d85e735.js +1 -0
  46. package/apps/pwa/out/_next/static/chunks/app/today/{page-6445ac4cbb8dd869.js → page-979d318a534e92da.js} +1 -1
  47. package/apps/pwa/out/_next/static/chunks/app/trace/page-182d394f7e6e096b.js +1 -0
  48. package/apps/pwa/out/_next/static/chunks/app/vault/page-21050928a697ed7a.js +1 -0
  49. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-44b9d807005a9030.js +1 -0
  50. package/apps/pwa/out/_next/static/chunks/app/workflows/{page-20162174b77f96cf.js → page-601fb77340e63c9a.js} +1 -1
  51. package/apps/pwa/out/_next/static/chunks/app/workspace/page-75d3fb5d47af0edf.js +1 -0
  52. package/apps/pwa/out/_next/static/chunks/app/worktrees/{page-05a4b2c9b91034aa.js → page-11bf9e5725a72c22.js} +1 -1
  53. package/apps/pwa/out/approvals/index.html +1 -1
  54. package/apps/pwa/out/approvals/index.txt +13 -13
  55. package/apps/pwa/out/autopilot/index.html +1 -1
  56. package/apps/pwa/out/autopilot/index.txt +13 -13
  57. package/apps/pwa/out/board/index.html +1 -1
  58. package/apps/pwa/out/board/index.txt +13 -13
  59. package/apps/pwa/out/botlab/index.html +1 -1
  60. package/apps/pwa/out/botlab/index.txt +13 -13
  61. package/apps/pwa/out/bots/index.html +1 -1
  62. package/apps/pwa/out/bots/index.txt +13 -13
  63. package/apps/pwa/out/ceo/index.html +1 -1
  64. package/apps/pwa/out/ceo/index.txt +13 -13
  65. package/apps/pwa/out/chat/index.html +1 -1
  66. package/apps/pwa/out/chat/index.txt +13 -13
  67. package/apps/pwa/out/consult/index.html +1 -1
  68. package/apps/pwa/out/consult/index.txt +13 -13
  69. package/apps/pwa/out/control/index.html +1 -1
  70. package/apps/pwa/out/control/index.txt +13 -13
  71. package/apps/pwa/out/decisions/index.html +1 -1
  72. package/apps/pwa/out/decisions/index.txt +13 -13
  73. package/apps/pwa/out/design-check/index.html +1 -1
  74. package/apps/pwa/out/design-check/index.txt +13 -13
  75. package/apps/pwa/out/editor/index.html +1 -1
  76. package/apps/pwa/out/editor/index.txt +13 -13
  77. package/apps/pwa/out/exec/index.html +1 -1
  78. package/apps/pwa/out/exec/index.txt +13 -13
  79. package/apps/pwa/out/field/index.html +1 -1
  80. package/apps/pwa/out/field/index.txt +13 -13
  81. package/apps/pwa/out/healthz +1 -1
  82. package/apps/pwa/out/index.html +1 -1
  83. package/apps/pwa/out/index.txt +13 -13
  84. package/apps/pwa/out/inside/index.html +1 -1
  85. package/apps/pwa/out/inside/index.txt +13 -13
  86. package/apps/pwa/out/intake/index.html +1 -1
  87. package/apps/pwa/out/intake/index.txt +13 -13
  88. package/apps/pwa/out/live/index.html +1 -1
  89. package/apps/pwa/out/live/index.txt +13 -13
  90. package/apps/pwa/out/live-run/index.html +1 -1
  91. package/apps/pwa/out/live-run/index.txt +13 -13
  92. package/apps/pwa/out/loops/index.html +1 -1
  93. package/apps/pwa/out/loops/index.txt +13 -13
  94. package/apps/pwa/out/market/index.html +1 -1
  95. package/apps/pwa/out/market/index.txt +13 -13
  96. package/apps/pwa/out/missions/placeholder/index.html +1 -1
  97. package/apps/pwa/out/missions/placeholder/index.txt +13 -13
  98. package/apps/pwa/out/morning/index.html +1 -1
  99. package/apps/pwa/out/morning/index.txt +13 -13
  100. package/apps/pwa/out/observatory/index.html +1 -1
  101. package/apps/pwa/out/observatory/index.txt +13 -13
  102. package/apps/pwa/out/ops/checklist/index.html +1 -1
  103. package/apps/pwa/out/ops/checklist/index.txt +13 -13
  104. package/apps/pwa/out/ops/release/index.html +1 -1
  105. package/apps/pwa/out/ops/release/index.txt +13 -13
  106. package/apps/pwa/out/ops/seats/index.html +1 -1
  107. package/apps/pwa/out/ops/seats/index.txt +13 -13
  108. package/apps/pwa/out/outputs/index.html +1 -1
  109. package/apps/pwa/out/outputs/index.txt +13 -13
  110. package/apps/pwa/out/reflection/index.html +1 -1
  111. package/apps/pwa/out/reflection/index.txt +14 -14
  112. package/apps/pwa/out/scheduler/index.html +1 -1
  113. package/apps/pwa/out/scheduler/index.txt +13 -13
  114. package/apps/pwa/out/sessions/index.html +1 -1
  115. package/apps/pwa/out/sessions/index.txt +13 -13
  116. package/apps/pwa/out/settings/devices/index.html +1 -1
  117. package/apps/pwa/out/settings/devices/index.txt +13 -13
  118. package/apps/pwa/out/settings/index.html +1 -1
  119. package/apps/pwa/out/settings/index.txt +13 -13
  120. package/apps/pwa/out/setup/done/index.html +1 -1
  121. package/apps/pwa/out/setup/done/index.txt +13 -13
  122. package/apps/pwa/out/setup/index.html +1 -1
  123. package/apps/pwa/out/setup/index.txt +13 -13
  124. package/apps/pwa/out/share/index.html +1 -1
  125. package/apps/pwa/out/share/index.txt +13 -13
  126. package/apps/pwa/out/showroom/index.html +1 -1
  127. package/apps/pwa/out/showroom/index.txt +13 -13
  128. package/apps/pwa/out/tasks/index.html +1 -1
  129. package/apps/pwa/out/tasks/index.txt +13 -13
  130. package/apps/pwa/out/term/index.html +1 -1
  131. package/apps/pwa/out/term/index.txt +13 -13
  132. package/apps/pwa/out/today/index.html +1 -1
  133. package/apps/pwa/out/today/index.txt +13 -13
  134. package/apps/pwa/out/trace/index.html +1 -1
  135. package/apps/pwa/out/trace/index.txt +13 -13
  136. package/apps/pwa/out/vault/index.html +1 -1
  137. package/apps/pwa/out/vault/index.txt +13 -13
  138. package/apps/pwa/out/workflows/chat-ui/index.html +1 -1
  139. package/apps/pwa/out/workflows/chat-ui/index.txt +13 -13
  140. package/apps/pwa/out/workflows/index.html +1 -1
  141. package/apps/pwa/out/workflows/index.txt +13 -13
  142. package/apps/pwa/out/workspace/index.html +1 -1
  143. package/apps/pwa/out/workspace/index.txt +13 -13
  144. package/apps/pwa/out/worktrees/index.html +1 -1
  145. package/apps/pwa/out/worktrees/index.txt +13 -13
  146. package/graphs/implement-loop.yaml +38 -1
  147. package/graphs/steward/recipes.yaml +6 -0
  148. package/graphs/steward/release-day.yaml +23 -0
  149. package/graphs/steward/steward.yaml +9 -1
  150. package/graphs/work/code-pr.yaml +23 -0
  151. package/package.json +1 -1
  152. package/scripts/browser-observe-cycle.ts +76 -2
  153. package/scripts/ci-typecheck-changed.ts +119 -7
  154. package/scripts/coord-msg-bridge.ts +209 -0
  155. package/scripts/coord-post.sh +40 -7
  156. package/scripts/coord-requests-bridge.ts +10 -5
  157. package/scripts/detect-test-interference.ts +31 -1
  158. package/scripts/expose-rubric-suggest.ts +1 -1
  159. package/scripts/measure-tsc-affected-roots.ts +10 -1
  160. package/scripts/release-loop/docs-node.ts +51 -22
  161. package/scripts/release-loop/export-check-node.ts +8 -5
  162. package/scripts/release-loop/gate-node.ts +37 -4
  163. package/scripts/release-loop/node-verdict.ts +10 -3
  164. package/scripts/release-loop/publish-node.ts +3 -0
  165. package/scripts/release-loop/tui-node-checks.ts +5 -2
  166. package/scripts/skills/public-check.ts +5 -2
  167. package/scripts/test-deterministic.ts +520 -37
  168. package/scripts/ux-sim.ts +7 -1
  169. package/scripts/verify-kpack6-live.ts +230 -0
  170. package/src/acp/codex-plugins.ts +17 -0
  171. package/src/agent/task-notification.ts +32 -2
  172. package/src/agent-mission/in-agent-plugin.ts +8 -3
  173. package/src/agent-substrate/review-observation.ts +9 -2
  174. package/src/agent-substrate/self-review-cli.ts +62 -16
  175. package/src/boot/daemon-tools/self-implement.ts +72 -4
  176. package/src/briefing/brief-items.ts +151 -35
  177. package/src/budget/llm-cost.ts +30 -3
  178. package/src/budget/usage-outcomes.ts +32 -0
  179. package/src/claims/claims-ledger.ts +23 -0
  180. package/src/claims/claims-render.ts +22 -2
  181. package/src/cli/brief-cli.ts +131 -10
  182. package/src/cli/claims-cli.ts +24 -4
  183. package/src/cli/control-cli.ts +29 -0
  184. package/src/cli/doctor-cli.ts +90 -8
  185. package/src/cli/msg-cli.ts +177 -11
  186. package/src/cli/plugin-cli.ts +11 -3
  187. package/src/cli/pr-cli.ts +133 -18
  188. package/src/cli/pr-land-overlap-evidence.ts +18 -10
  189. package/src/cli/pr-land-refusal.ts +20 -0
  190. package/src/cli/release-cli.ts +34 -5
  191. package/src/cli/rfc-cli.ts +24 -0
  192. package/src/cli/seat-cli.ts +121 -0
  193. package/src/cli/self-utterances-cli.ts +140 -0
  194. package/src/cli/tailscale-serve.ts +5 -8
  195. package/src/cli/tasks-cli.ts +528 -31
  196. package/src/cli/usage-cli.ts +9 -4
  197. package/src/context-card/cell.ts +40 -0
  198. package/src/dashboard/boot-timing.ts +35 -0
  199. package/src/dashboard/first-screen-band.ts +63 -13
  200. package/src/dashboard/index.ts +94 -27
  201. package/src/dashboard/input/chat-main-plain-turn-runtime.ts +26 -0
  202. package/src/dashboard/skill-detection-runtime.ts +24 -4
  203. package/src/dashboard/slash-runtime/dashboard-handlers.ts +6 -0
  204. package/src/debug/log.ts +1 -1
  205. package/src/domains/morning-report.ts +3 -1
  206. package/src/domains/release-tool.ts +29 -12
  207. package/src/domains/surface-events.ts +16 -0
  208. package/src/elanous-config-dir.ts +2 -2
  209. package/src/fleet/host-doctor.ts +73 -2
  210. package/src/github/pr-labels.ts +10 -4
  211. package/src/graph-runner/runner.ts +104 -15
  212. package/src/harness/harness-clean.ts +21 -3
  213. package/src/harness/harness-cli-command.ts +68 -10
  214. package/src/harness/harness-pod-dispatch.ts +11 -4
  215. package/src/harness/harness-stop.ts +11 -7
  216. package/src/hq/seats.ts +17 -3
  217. package/src/index.ts +69 -9
  218. package/src/instance/current.ts +2 -6
  219. package/src/instance/resolve.ts +5 -6
  220. package/src/intelligence-map/model-bench-scores.ts +102 -0
  221. package/src/llm/openai-sampling-fields.ts +89 -0
  222. package/src/llm/runtime-model-family.ts +61 -0
  223. package/src/llm/zai-coding-plan.ts +27 -1
  224. package/src/llm.ts +13 -89
  225. package/src/loops/orchestrator/inbox.ts +73 -0
  226. package/src/loops/orchestrator/resync-shadow.ts +100 -12
  227. package/src/loops/orchestrator/tick.ts +73 -2
  228. package/src/machines/machine-ledger.ts +31 -3
  229. package/src/maturity/cli-maturity.ts +13 -3
  230. package/src/maturity/feature-maturity.ts +1 -1
  231. package/src/msg/msg-sse-server.ts +141 -0
  232. package/src/msg/msg-store.ts +149 -17
  233. package/src/ops/overview-collect.ts +3 -2
  234. package/src/ops/overview-owner.ts +29 -0
  235. package/src/patents/ledger.ts +128 -0
  236. package/src/plugin-hooks/shell-hook.ts +17 -2
  237. package/src/plugin-missions/evaluator-runner.ts +18 -2
  238. package/src/plugins/install/market-fetch.ts +32 -1
  239. package/src/plugins/install/plugin-install.ts +11 -1
  240. package/src/pod-lease/admission.ts +116 -41
  241. package/src/prompt-enhance/enhance.ts +11 -0
  242. package/src/release-loop/checklist.ts +52 -4
  243. package/src/release-loop/feature-store.ts +10 -9
  244. package/src/release-loop/merged-pr-checklist.ts +24 -5
  245. package/src/release-loop/rubric.ts +70 -0
  246. package/src/rfc-registry/registry.ts +88 -0
  247. package/src/seat-dispatch/seat-request-ledger.ts +4 -0
  248. package/src/seat-loop/knowhow-lint.ts +233 -0
  249. package/src/seat-loop/seat-loop.ts +5 -1
  250. package/src/seat-loop/seat-pack.ts +16 -4
  251. package/src/seat-loop/traffic-signal.ts +7 -0
  252. package/src/self-dev/ask-launch-flow.ts +48 -8
  253. package/src/self-dev/ask-path-candidates.ts +69 -14
  254. package/src/self-dev/decompose-proposal.ts +43 -1
  255. package/src/self-dev/draft-sweep.ts +23 -14
  256. package/src/self-dev/graph-journey-nodes.ts +2 -0
  257. package/src/self-dev/launch-preflight-text.ts +5 -1
  258. package/src/self-dev/launch-preflight.ts +143 -10
  259. package/src/self-dev/orchestrate.ts +6 -2
  260. package/src/self-dev/run-supervisor.ts +35 -1
  261. package/src/self-implement/gate-cli.ts +6 -2
  262. package/src/self-implement/goal-author.ts +5 -28
  263. package/src/self-implement/goal-command-execution.ts +26 -0
  264. package/src/self-implement/goal-new-paths.ts +4 -5
  265. package/src/self-implement/graph-authority.ts +17 -3
  266. package/src/self-implement/graph-yaml.ts +15 -7
  267. package/src/self-implement/headless-elanous-driver.ts +16 -1
  268. package/src/self-implement/host-regate.ts +44 -9
  269. package/src/self-implement/orchestrator.ts +5 -11
  270. package/src/self-implement/pwa-import-graph.ts +194 -7
  271. package/src/self-implement/rework-policy.ts +80 -2
  272. package/src/self-implement/self-implement-runtime.ts +126 -21
  273. package/src/self-implement/speed-claims.ts +145 -6
  274. package/src/session/index.ts +14 -4
  275. package/src/session-runtime/index.ts +55 -11
  276. package/src/skills/tools/persistent-grounding.ts +59 -4
  277. package/src/skills/tools/shell.ts +79 -1
  278. package/src/steward/rejudge-tick.ts +12 -1
  279. package/src/steward/release-day.ts +158 -0
  280. package/src/steward/resync-tick.ts +123 -0
  281. package/src/task-agent/actions.ts +1 -0
  282. package/src/task-agent/adopt-pr.ts +140 -0
  283. package/src/task-agent/board.ts +11 -1
  284. package/src/task-agent/card-evidence.ts +37 -5
  285. package/src/task-agent/cover.ts +105 -19
  286. package/src/task-agent/failure-notify.ts +61 -0
  287. package/src/task-agent/green-sweep.ts +170 -0
  288. package/src/task-agent/land-worktree.ts +52 -5
  289. package/src/task-agent/live-move-history.ts +1 -0
  290. package/src/task-agent/live-moves.ts +56 -17
  291. package/src/task-agent/parent-host.ts +1 -1
  292. package/src/task-agent/postland-card.ts +139 -0
  293. package/src/task-agent/rejudge-on-head.ts +321 -25
  294. package/src/task-agent/remote-rejudge-bind.ts +62 -0
  295. package/src/task-agent/repair-branch-cas.ts +182 -0
  296. package/src/task-agent/repair-cycle.ts +275 -0
  297. package/src/task-agent/repair-next-move.ts +31 -0
  298. package/src/task-agent/repair-review.ts +24 -0
  299. package/src/task-agent/repair-worker.ts +87 -0
  300. package/src/task-agent/review-result-capture.ts +66 -2
  301. package/src/task-agent/shadow.ts +150 -29
  302. package/src/task-agent/task-hand.ts +133 -8
  303. package/src/task-orchestrator/surfaces/pod-repair-commit.ts +96 -0
  304. package/src/task-orchestrator/surfaces/self-implement-pod.ts +71 -12
  305. package/src/telegram.ts +30 -1
  306. package/src/tool-runtime/tool-search-runtime.ts +25 -0
  307. package/src/tui.ts +20 -1
  308. package/src/user-config.ts +11 -60
  309. package/src/ux-sim/fault-sqlite-busy.ts +50 -0
  310. package/src/version/packed-revision.json +1 -1
  311. package/apps/pwa/out/_next/static/chunks/app/approvals/page-9360b1285b2a346e.js +0 -1
  312. package/apps/pwa/out/_next/static/chunks/app/autopilot/page-f08f6529d09ffae1.js +0 -1
  313. package/apps/pwa/out/_next/static/chunks/app/board/page-f000d54d258f9ef6.js +0 -1
  314. package/apps/pwa/out/_next/static/chunks/app/bots/page-22f674e7e4c2c9d5.js +0 -1
  315. package/apps/pwa/out/_next/static/chunks/app/ceo/page-8888733e40cea6d1.js +0 -1
  316. package/apps/pwa/out/_next/static/chunks/app/chat/page-9717ec6964b92276.js +0 -1
  317. package/apps/pwa/out/_next/static/chunks/app/consult/page-44eaad486bc98a45.js +0 -1
  318. package/apps/pwa/out/_next/static/chunks/app/control/page-97fa6cf3d34c7eb9.js +0 -1
  319. package/apps/pwa/out/_next/static/chunks/app/editor/page-35e05d7450461a67.js +0 -1
  320. package/apps/pwa/out/_next/static/chunks/app/inside/page-b2638013c0bf7dfd.js +0 -1
  321. package/apps/pwa/out/_next/static/chunks/app/layout-c44f93a41167536f.js +0 -1
  322. package/apps/pwa/out/_next/static/chunks/app/loops/page-1b810474507f3702.js +0 -1
  323. package/apps/pwa/out/_next/static/chunks/app/market/page-74366ae2693a7d95.js +0 -1
  324. package/apps/pwa/out/_next/static/chunks/app/ops/release/page-4e634c5b98fd4e93.js +0 -1
  325. package/apps/pwa/out/_next/static/chunks/app/ops/seats/page-ed3070d637850548.js +0 -1
  326. package/apps/pwa/out/_next/static/chunks/app/outputs/page-b9cc8a10bc6078b4.js +0 -1
  327. package/apps/pwa/out/_next/static/chunks/app/reflection/page-128458c8d86fbb5f.js +0 -1
  328. package/apps/pwa/out/_next/static/chunks/app/sessions/page-cf0c2b0183991d09.js +0 -1
  329. package/apps/pwa/out/_next/static/chunks/app/showroom/page-b008aff96be56654.js +0 -1
  330. package/apps/pwa/out/_next/static/chunks/app/tasks/page-814394dcbae789b1.js +0 -1
  331. package/apps/pwa/out/_next/static/chunks/app/term/page-6a87325c87f09dd2.js +0 -1
  332. package/apps/pwa/out/_next/static/chunks/app/trace/page-852170303c6cd755.js +0 -1
  333. package/apps/pwa/out/_next/static/chunks/app/vault/page-087ceeb975ef272b.js +0 -1
  334. package/apps/pwa/out/_next/static/chunks/app/workflows/chat-ui/page-97c7361cc2a19319.js +0 -1
  335. package/apps/pwa/out/_next/static/chunks/app/workspace/page-8c6901833f897496.js +0 -1
  336. /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_buildManifest.js +0 -0
  337. /package/apps/pwa/out/_next/static/{dRS6lEhSRRBr1abbzp7fJ → y1ltt7oCZxVpC6zVPhZ2O}/_ssgManifest.js +0 -0
@@ -0,0 +1,102 @@
1
+ import { debug } from '../debug/log.js';
2
+ import type { ModelCatalog, ModelEntry } from './types.js';
3
+
4
+ const NUMERIC_COLUMNS = [
5
+ 'ctx', 'in$/1M', 'out$/1M', 'cacheRead$/1M', 'est_run$',
6
+ 'AA_intel', 'AA_coding', 'AA_agentic', 'SWE_verified', 'SWE_pro',
7
+ 'TerminalBench', 'LiveCodeBench', 'tool_use',
8
+ ] as const;
9
+
10
+ export type BenchNumericColumn = typeof NUMERIC_COLUMNS[number];
11
+ export type BenchScore = 'AA_coding' | 'AA_agentic' | 'SWE_verified' | 'TerminalBench';
12
+
13
+ export type BenchRow = {
14
+ id: string;
15
+ provider: string;
16
+ sources: string;
17
+ notes: string;
18
+ raw: Record<string, string>;
19
+ } & Record<BenchNumericColumn, number | null>;
20
+
21
+ export type ComparedBenchRow<T extends BenchRow = BenchRow> = T & {
22
+ value: number | null;
23
+ status: 'scored' | '미확인';
24
+ };
25
+
26
+ const UNKNOWN = new Set(['', '미확인', '미표기', '-']);
27
+ const NUMBER = /[-+]?(?:\d+(?:,\d{3})*(?:\.\d+)?|\.\d+)(?:[eE][-+]?\d+)?/g;
28
+
29
+ function parseNumber(raw: string): number | null {
30
+ const trimmed = raw.trim();
31
+ if (UNKNOWN.has(trimmed)) return null;
32
+ // A label may contain a version number ("AA TB4.0 33.3"); the final
33
+ // number is the measured value. Keep the full cell separately in raw.
34
+ const matches = [...trimmed.matchAll(NUMBER)];
35
+ const last = matches.at(-1)?.[0];
36
+ if (!last) return null;
37
+ const parsed = Number(last.replaceAll(',', ''));
38
+ return Number.isFinite(parsed) ? parsed : null;
39
+ }
40
+
41
+ /** Parse a caller-supplied, offline TSV. Column positions come only from the header. */
42
+ export function parseBenchScoresTsv(text: string): BenchRow[] {
43
+ const lines = text.replace(/^\uFEFF/, '').split(/\r?\n/);
44
+ const headers = (lines.shift() ?? '').split('\t').map((name) => name.trim());
45
+ if (!headers.includes('id')) throw new Error('bench scores TSV missing id header');
46
+ const rows: BenchRow[] = [];
47
+ let unknownCells = 0;
48
+ for (const line of lines) {
49
+ if (!line.trim()) continue;
50
+ const cells = line.split('\t');
51
+ const raw: Record<string, string> = {};
52
+ headers.forEach((header, index) => { raw[header] = cells[index] ?? ''; });
53
+ const numbers = {} as Record<BenchNumericColumn, number | null>;
54
+ for (const column of NUMERIC_COLUMNS) {
55
+ numbers[column] = parseNumber(raw[column] ?? '');
56
+ if (numbers[column] === null) unknownCells++;
57
+ }
58
+ rows.push({ id: raw.id?.trim() ?? '', provider: raw.provider ?? '',
59
+ sources: raw.sources ?? '', notes: raw.notes ?? '', raw, ...numbers });
60
+ }
61
+ debug.log('intelligence.bench-scores', 'parsed', { rows, unknownCells });
62
+ return rows;
63
+ }
64
+
65
+ /** An OpenRouter vendor/model id matches a catalog id only under its vendor.
66
+ * The builtin DeepSeek entries are `other`/`deepseek` but have the explicit
67
+ * OpenRouter route `deepseek/<id>` in their notes. */
68
+ function catalogIds(model: ModelEntry): string[] {
69
+ const ids = [model.id];
70
+ const vendor = model.provider === 'openai-codex' ? 'openai'
71
+ : model.provider === 'gemini' ? 'google'
72
+ : model.provider === 'grok' ? 'x-ai'
73
+ : model.provider === 'kimi' ? 'moonshotai'
74
+ : model.provider === 'glm' ? 'z-ai'
75
+ : model.provider === 'other' && model.family === 'deepseek' && model.notes?.includes(`OpenRouter deepseek/${model.id}`) ? 'deepseek'
76
+ : model.provider;
77
+ if (!model.local) ids.push(`${vendor}/${model.id}`, `openrouter/${vendor}/${model.id}`);
78
+ return ids;
79
+ }
80
+
81
+ export function joinWithCatalog<T extends BenchRow>(rows: readonly T[], catalog: ModelCatalog): (T & { inCatalog: boolean })[] {
82
+ const ids = new Set(catalog.models.flatMap(catalogIds));
83
+ return rows.map((row) => ({ ...row, inCatalog: ids.has(row.id) }));
84
+ }
85
+
86
+ /** Sort by score per estimated run dollar. Missing scores always come last;
87
+ * a known score without a usable denominator has an unknown value. */
88
+ export function compareRows<T extends BenchRow>(rows: readonly T[], opts: { score: BenchScore }): ComparedBenchRow<T>[] {
89
+ return rows.map((row) => {
90
+ const score = row[opts.score];
91
+ return { ...row,
92
+ value: score !== null && row.est_run$ !== null && row.est_run$ > 0
93
+ ? score / row.est_run$ : null,
94
+ status: score === null ? '미확인' as const : 'scored' as const,
95
+ };
96
+ }).sort((a, b) => {
97
+ if (a.status !== b.status) return a.status === '미확인' ? 1 : -1;
98
+ if (a.value === null) return b.value === null ? 0 : 1;
99
+ if (b.value === null) return -1;
100
+ return b.value - a.value;
101
+ });
102
+ }
@@ -0,0 +1,89 @@
1
+ /**
2
+ * ⛔⭐ OpenAI Chat Completions 의 «출력 상한» 칸 이름은 모델 세대로 갈린다.
3
+ *
4
+ * `gpt-5` 이후 계열은 `max_tokens` 를 ***거부한다*** — 400 `unsupported_parameter` 를 내고
5
+ * *"Use 'max_completion_tokens' instead"* 라고 말한다. `gpt-4o` 계열은 반대로 옛 이름만 받는다.
6
+ *
7
+ * 📏 2026-08-22 실측: `provider auto` 의 티어 사다리가 `gpt-5.6-*` 로 바뀐 뒤(`#11161`)
8
+ * 3시간 만에 이 400 이 **93건** 났고 «가속»했다(20h:2 → 21h:16 → 22h:30 → 23h:45).
9
+ * 7일 창에서 그 이전 발생은 ***0***이다. ⇒ 칸 이름을 모델로 갈라야 한다.
10
+ *
11
+ * ⚠️ 값을 «안 보내는» 선택은 하지 않는다 — 상한이 사라지면 비용이 조용히 는다.
12
+ */
13
+ /**
14
+ * ⛔⭐⭐ **브랜드마다 «칸 이름」이 다르다**(2026-09-12). `makeOpenAICompatProvider` 는 `grok` 과
15
+ * `openai` 를 «한 경로»로 태우는데, 종전엔 둘 다 옛 칸(`max_tokens`·`temperature`)을 «생으로» 박았다.
16
+ * ⇒ `openai` 브랜드의 새 세대(`gpt-5`+)는 그 둘을 «거부»한다 — 400 `unsupported_parameter`.
17
+ *
18
+ * 📏 실측 2026-09-12: `gpt-6-astra · maxTokens=2048 · api.openai.com/v1/chat/completions` 가 400 을 받았고,
19
+ * 그 400 이 `review.done` 미실행 57건 중 ***30건***의 사유였다(무인 리뷰가 그만큼 «안 돌았다»).
20
+ *
21
+ * ⭐ 자는 «이미» 있었다 — `openAiOutputTokenField`·`openAiTemperatureField`. ***이 호출부가 안 물었을 뿐이다.***
22
+ * 🪞 같은 파일의 `stripLocalLlmSpec` 이 「두 builder 중 하나만 정규화했다」로 난 사고의 처방이었다.
23
+ * ***같은 모양이 다시 났다*** — 그래서 이번에도 «순수 함수로 뽑아» 양쪽이 같은 자를 쓰게 한다.
24
+ *
25
+ * ⛔ grok 은 옛 칸을 그대로 받는다 — 바꾸지 않는다.
26
+ */
27
+ export function openAiCompatSamplingFields(
28
+ brand: string,
29
+ model: string,
30
+ temperature: number,
31
+ maxTokens: number,
32
+ ): Record<string, number> {
33
+ return brand === 'openai'
34
+ ? { ...openAiTemperatureField(model, temperature), ...openAiOutputTokenField(model, maxTokens) }
35
+ : { temperature, max_tokens: maxTokens };
36
+ }
37
+
38
+ export function openAiOutputTokenField(model: string, maxTokens: number): Record<string, number> {
39
+ return isNewGenerationOpenAiModel(model)
40
+ ? { max_completion_tokens: maxTokens }
41
+ : { max_tokens: maxTokens };
42
+ }
43
+
44
+ /** `gpt-5` 이후 계열 판정 — 옛 Chat Completions 파라미터를 거부하는 세대.
45
+ *
46
+ * 🩸⭐⭐ **2026-09-12 — 이 자가 «늙어서» 400 이 돌아왔다.** 종전 문면은 `/^(?:gpt-5|o[1-9])/` 라
47
+ * ***`gpt-6` 계열을 «못 봤다»***. 그래서 `gpt-6-astra` 가 `max_tokens` 로 나갔고 400 을 받았다:
48
+ * `Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens'`
49
+ * 📏 실측(2026-09-12 · 12시간 창): `review.done` 200행 중 `reviewed=false` 57, 그중 ***30***이 이 400 이다.
50
+ * ⊕ 요청 로그가 그것을 한 줄로 말한다 — `gpt-6-astra · maxTokens=2048 · api.openai.com/v1/chat/completions`.
51
+ *
52
+ * ⇒ ⭐ **세대를 「이름 목록」으로 세지 않는다.** 번호를 «범위»로 읽어 다음 세대가 와도 안 늙게 한다.
53
+ * `gpt-5` 이상(두 자리 포함) ⊕ `o1`~`o9`. ⛔ `gpt-4` 이하와 로컬 모델은 종전대로 옛 칸을 쓴다.
54
+ *
55
+ * 🌐 **외부 그라운딩**(2026-09-12 · omni-crawl `fc-dev`) — 같은 사고가 «업스트림에도» 있었다:
56
+ * · `quantumnous/new-api#7211` — *"GPT-6 Astra 未命中原来的 GPT-5 前缀判断"* (똑같은 접두 판정 누락)
57
+ * · `genkit-ai/genkit#6320` — *"max_tokens is sent verbatim and rejected by reasoning models"*
58
+ * · Azure AI docs — `gpt-6-astra`(2026-09-03) Chat Completions ⊕ Reasoning
59
+ * · overchat.ai — *"Astra does not support `temperature`, `top_p`, `top_logprobs`"*
60
+ * ⇒ ✅ 우리가 `temperature` 를 «생략»하는 것이 외부 사실과 «맞는다».
61
+ * ⚠️ `top_p`·`logprobs` 는 이 경로가 «안 보낸다»(local 프리셋 경로만 보낸다) — 그래서 조치 없음.
62
+ *
63
+ * ⚖️ ⛔ **알려진 트레이드오프 — new-api 는 «반대» 결론을 냈다.** 그들은
64
+ * *"모든 미래 GPT 메이저를 GPT-5 로 묶으면 서로 다른 모델의 파라미터 규칙이 엮인다"* 며
65
+ * ***미지의 미래 메이저는 추론하지 않는다***로 갔다(명시 목록 + 날짜 스냅샷).
66
+ * ⇒ 우리는 «반대»를 택했다. 이유: ***목록이 늙어서 이 사고가 났기 때문***이다
67
+ * (이 저장소에서 실제로 리뷰 미실행 30건을 냈다). 새 규칙은 «새 관례 쪽으로» 실패한다.
68
+ * 📌 그러므로 ***`gpt-N` 중 옛 칸을 «되찾는» 모델이 나오면 이 자가 틀린다.*** 그때는
69
+ * 여기서 갈지 말고 «모델별 능력 선언»으로 옮긴다(new-api 가 간 길). 지금은 그 표본이 0이다. */
70
+ export function isNewGenerationOpenAiModel(model: string): boolean {
71
+ const match = /^gpt-(\d+)/i.exec(model);
72
+ if (match) return Number.parseInt(match[1]!, 10) >= 5;
73
+ return /^o[1-9]/i.test(model);
74
+ }
75
+
76
+ /**
77
+ * ⛔⭐ 같은 세대가 `temperature` 도 거부한다 — 400 `unsupported_value`,
78
+ * *"Only the default (1) value is supported"*.
79
+ *
80
+ * 📏 2026-08-22 실측: `max_tokens` 를 고친 «2분 뒤»(00:13:03Z)부터 이 400 이 났고
81
+ * 90분에 **41건**이었다. ⇒ ***한 파라미터만 고치면 다음 파라미터에서 막힌다.***
82
+ * ⚠️ 그때 나는 「수리 뒤 400 이 0건」이라 보고했는데, 그 자가 `grep max_completion_tokens`
83
+ * 라서 «새 400»을 못 봤다 — ***좁은 자로 「나았다」를 읽었다.***
84
+ *
85
+ * ⇒ 값을 «1로 보내지» 않고 ***칸을 생략***한다. 서버 기본이 1이고, 보내면 또 다른 거부를 부른다.
86
+ */
87
+ export function openAiTemperatureField(model: string, temperature: number): Record<string, number> {
88
+ return isNewGenerationOpenAiModel(model) ? {} : { temperature };
89
+ }
@@ -0,0 +1,61 @@
1
+ import type { LLMProviderName } from '../user-config.js';
2
+
3
+ /** Lightweight model-id family — prefix/substring only. No catalog, no
4
+ * `src/llm/model-defaults.ts` (that module imports this file). */
5
+ export type RuntimeLlmModelFamily =
6
+ | 'grok' | 'anthropic' | 'openai' | 'openai-codex' | 'gemini' | 'local'
7
+ | 'kimi' | 'qwen' | 'glm' | 'openrouter' | 'bedrock' | 'unknown';
8
+
9
+ export function inferRuntimeLlmModelFamily(model: string | undefined): RuntimeLlmModelFamily {
10
+ if (!model) return 'unknown';
11
+ const m = model.trim().toLowerCase();
12
+ if (!m) return 'unknown';
13
+ // ⛔ 2026-09-23 — 게이트웨이 접두가 «먼저»다. 안 그러면 `openrouter/anthropic/claude-…` 가 `anthropic` 으로
14
+ // 읽혀 openrouter 와 «비호환»이 되고, `openrouter/z-ai/…` 는 `unknown` 이라 아무 provider 와도 «호환»이 됐다.
15
+ if (m.startsWith('openrouter/')) return 'openrouter';
16
+ // ⭐ BEDROCK-PROVIDER — Bedrock 전용 꼴(`anthropic.claude-…`·지역 접두·`bedrock/…`)이 `includes('claude')` 보다 «먼저».
17
+ // 1st-party id(`claude-…`)는 그대로 anthropic 이다(불변).
18
+ if (m.startsWith('bedrock/') || /^(?:[a-z]{2,6}\.)?anthropic\.claude-/.test(m)) return 'bedrock';
19
+ if (m.includes('grok')) return 'grok';
20
+ if (m.includes('claude')) return 'anthropic';
21
+ if (m.startsWith('gemini-') || m.includes('gemini')) return 'gemini';
22
+ if (m.startsWith('local:')) return 'local';
23
+ if (m.startsWith('kimi')) return 'kimi';
24
+ if (m.startsWith('qwen')) return 'qwen';
25
+ if (m.startsWith('glm')) return 'glm';
26
+ // openai-codex 구독 모델만 여기 — gpt-5.5 등 Chat Completions 모델은 openai.
27
+ // ⛔ openai 와 openai-codex 를 한 계열로 접지 마라. 서로 다른 엔드포인트다.
28
+ // ✅ 2026-09-23 (대표 ⒜ 결정) — ***`gpt-6` 를 여기 «더했다».***
29
+ // 종전엔 `gpt-6-*` 가 아래 `startsWith('gpt-')` 로 떨어져 `openai` 가 됐고, 그래서
30
+ // ***사다리가 «자기 가드가 거부하는 모델»을 가리켰다*** (`CODEX.loaded = gpt-6-astra`).
31
+ // 📏 구독 경로 실호출로 확인(codex-cli 0.155.1): gpt-6-sol · luna · astra 전부 응답.
32
+ // ⚠️ 이 셋은 API 로도 불린다(`/v1/models` 에 있다). 「계열」이 재는 것은 «가용성»이 아니라
33
+ // ***「우리가 어느 문으로 보내나」***다 — 5.6 계열도 API 에 있지만 여기로 온다.
34
+ if (m.includes('codex') || m.startsWith('gpt-5.6') || m.startsWith('gpt-6')) return 'openai-codex';
35
+ // Exact o1/o3/o4 ids are standard OpenAI models; prefix-only (`o1-`) misses them.
36
+ if (
37
+ m.startsWith('gpt-')
38
+ || m === 'o1' || m.startsWith('o1-')
39
+ || m === 'o3' || m.startsWith('o3-')
40
+ || m === 'o4' || m.startsWith('o4-')
41
+ ) return 'openai';
42
+ return 'unknown';
43
+ }
44
+
45
+ /** Cycle-safe compatibility: same-provider model overrides pass;
46
+ * cross-family ids fail. Unknown prefixes and `auto` stay silent.
47
+ * ⛔ `openai` 와 `openai-codex` 는 별개 provider — 양방향 호환으로 접지 않는다. */
48
+ export function isRuntimeLlmModelCompatibleWithProvider(
49
+ provider: LLMProviderName,
50
+ model: string | undefined,
51
+ ): boolean {
52
+ if (!model) return true;
53
+ if (provider === 'auto') return true;
54
+ const family = inferRuntimeLlmModelFamily(model);
55
+ if (family === 'unknown') return true;
56
+ if (provider === 'local') return family === 'local';
57
+ // bedrock 은 1st-party claude id 도 받는다(공급자가 `anthropic.` 접두로 바꿔 보낸다).
58
+ if (provider === 'bedrock') return family === 'bedrock' || family === 'anthropic';
59
+ return provider === family;
60
+ }
61
+
@@ -122,6 +122,26 @@ export interface ZaiErrorClass {
122
122
  resetRaw: string | null;
123
123
  }
124
124
 
125
+ /** Provider-neutral signal shape for supervisors coordinating plan-limit recovery. */
126
+ export interface ProviderPlanLimitSignal {
127
+ provider: string;
128
+ kind: 'plan-limit';
129
+ resetAt: number | null;
130
+ overage: string;
131
+ }
132
+
133
+ /** Extract the structured recovery signal from a Z.ai 1308 response; unrelated errors return null. */
134
+ export function extractZaiPlanLimitSignal(
135
+ status: number,
136
+ bodyText: string,
137
+ overage: string,
138
+ ): ProviderPlanLimitSignal | null {
139
+ const classified = classifyZaiError(status, bodyText);
140
+ if (!classified || classified.code !== 1308 || classified.kind !== 'plan-limit') return null;
141
+ return { provider: 'glm', kind: 'plan-limit', resetAt: classified.resetAt, overage };
142
+ }
143
+
144
+
125
145
  const PLAN_LIMIT = new Set([1308, 1310]);
126
146
  const BALANCE_LIMIT = new Set([1113, 1316, 1317, 1318, 1319, 1320, 1321]);
127
147
  const PLAN_UNAVAILABLE = new Set([1309, 1311, 1313, 1314, 1315]);
@@ -433,13 +453,15 @@ export class ZaiCodingPlanLimitError extends Error {
433
453
  readonly code: number;
434
454
  readonly limitKind: ZaiLimitKind;
435
455
  readonly resetAt: number | null;
436
- constructor(opts: { code: number; limitKind: ZaiLimitKind; resetAt: number | null; policy: ZaiOveragePolicy; reason: string }) {
456
+ readonly planLimitSignal?: ProviderPlanLimitSignal;
457
+ constructor(opts: { code: number; limitKind: ZaiLimitKind; resetAt: number | null; policy: ZaiOveragePolicy; reason: string; planLimitSignal?: ProviderPlanLimitSignal }) {
437
458
  const when = opts.resetAt ? ` · 리셋 ${new Date(opts.resetAt).toISOString()}` : '';
438
459
  super(`GLM Coding Plan 한도(code ${opts.code} · ${opts.limitKind}${when}) — 정책 llm.zaiCodingPlan.overage=${opts.policy}: ${opts.reason}`);
439
460
  this.name = 'ZaiCodingPlanLimitError';
440
461
  this.code = opts.code;
441
462
  this.limitKind = opts.limitKind;
442
463
  this.resetAt = opts.resetAt;
464
+ if (opts.planLimitSignal) this.planLimitSignal = opts.planLimitSignal;
443
465
  }
444
466
  }
445
467
 
@@ -575,6 +597,9 @@ export function makeZaiCodingPlanProvider(cfg: UCLLMConfig, deps: ZaiProviderDep
575
597
  const status = (error as { status?: unknown })?.status;
576
598
  const bodyText = (error as { bodyText?: unknown })?.bodyText;
577
599
  const cls = typeof status === 'number' && typeof bodyText === 'string' ? classifyZaiError(status, bodyText) : null;
600
+ const planLimitSignal = typeof status === 'number' && typeof bodyText === 'string'
601
+ ? extractZaiPlanLimitSignal(status, bodyText, settings.overage)
602
+ : null;
578
603
  if (!cls || cls.kind === 'rate' || cls.kind === 'other') {
579
604
  if (cls) debug.log('zai.coding-plan', 'error', { code: cls.code, kind: cls.kind, model: wireModel }, { level: 'warn' });
580
605
  throw error;
@@ -588,6 +613,7 @@ export function makeZaiCodingPlanProvider(cfg: UCLLMConfig, deps: ZaiProviderDep
588
613
  if (action === 'stop' || emitted) {
589
614
  throw new ZaiCodingPlanLimitError({
590
615
  code: cls.code, limitKind: cls.kind, resetAt: cls.resetAt, policy: settings.overage,
616
+ ...(planLimitSignal ? { planLimitSignal } : {}),
591
617
  reason: emitted ? '출력이 이미 나간 뒤라 폴백하지 않는다' : '리셋까지 멈춘다',
592
618
  });
593
619
  }
package/src/llm.ts CHANGED
@@ -11699,92 +11699,16 @@ export function getProviderForConfig(
11699
11699
  import { getModelFamily } from './models/prompts.js';
11700
11700
  import type { ModelFamily } from './models/prompts.js';
11701
11701
 
11702
- /**
11703
- * ⛔⭐ OpenAI Chat Completions 의 «출력 상한» 칸 이름은 모델 세대로 갈린다.
11704
- *
11705
- * `gpt-5` 이후 계열은 `max_tokens` 를 ***거부한다*** — 400 `unsupported_parameter` 를 내고
11706
- * *"Use 'max_completion_tokens' instead"* 라고 말한다. `gpt-4o` 계열은 반대로 옛 이름만 받는다.
11707
- *
11708
- * 📏 2026-08-22 실측: `provider auto` 의 티어 사다리가 `gpt-5.6-*` 로 바뀐 뒤(`#11161`)
11709
- * 3시간 만에 이 400 이 **93건** 났고 «가속»했다(20h:2 → 21h:16 → 22h:30 → 23h:45).
11710
- * 7일 창에서 그 이전 발생은 ***0***이다. ⇒ 칸 이름을 모델로 갈라야 한다.
11711
- *
11712
- * ⚠️ 값을 «안 보내는» 선택은 하지 않는다 — 상한이 사라지면 비용이 조용히 는다.
11713
- */
11714
- /**
11715
- * ⛔⭐⭐ **브랜드마다 «칸 이름」이 다르다**(2026-09-12). `makeOpenAICompatProvider` 는 `grok` 과
11716
- * `openai` 를 «한 경로»로 태우는데, 종전엔 둘 다 옛 칸(`max_tokens`·`temperature`)을 «생으로» 박았다.
11717
- * ⇒ `openai` 브랜드의 새 세대(`gpt-5`+)는 그 둘을 «거부»한다 — 400 `unsupported_parameter`.
11718
- *
11719
- * 📏 실측 2026-09-12: `gpt-6-astra · maxTokens=2048 · api.openai.com/v1/chat/completions` 가 400 을 받았고,
11720
- * 그 400 이 `review.done` 미실행 57건 중 ***30건***의 사유였다(무인 리뷰가 그만큼 «안 돌았다»).
11721
- *
11722
- * ⭐ 자는 «이미» 있었다 — `openAiOutputTokenField`·`openAiTemperatureField`. ***이 호출부가 안 물었을 뿐이다.***
11723
- * 🪞 같은 파일의 `stripLocalLlmSpec` 이 「두 builder 중 하나만 정규화했다」로 난 사고의 처방이었다.
11724
- * ***같은 모양이 다시 났다*** — 그래서 이번에도 «순수 함수로 뽑아» 양쪽이 같은 자를 쓰게 한다.
11725
- *
11726
- * ⛔ grok 은 옛 칸을 그대로 받는다 — 바꾸지 않는다.
11727
- */
11728
- export function openAiCompatSamplingFields(
11729
- brand: string,
11730
- model: string,
11731
- temperature: number,
11732
- maxTokens: number,
11733
- ): Record<string, number> {
11734
- return brand === 'openai'
11735
- ? { ...openAiTemperatureField(model, temperature), ...openAiOutputTokenField(model, maxTokens) }
11736
- : { temperature, max_tokens: maxTokens };
11737
- }
11738
-
11739
- export function openAiOutputTokenField(model: string, maxTokens: number): Record<string, number> {
11740
- return isNewGenerationOpenAiModel(model)
11741
- ? { max_completion_tokens: maxTokens }
11742
- : { max_tokens: maxTokens };
11743
- }
11744
-
11745
- /** `gpt-5` 이후 계열 판정 — 옛 Chat Completions 파라미터를 거부하는 세대.
11746
- *
11747
- * 🩸⭐⭐ **2026-09-12 — 이 자가 «늙어서» 400 이 돌아왔다.** 종전 문면은 `/^(?:gpt-5|o[1-9])/` 라
11748
- * ***`gpt-6` 계열을 «못 봤다»***. 그래서 `gpt-6-astra` 가 `max_tokens` 로 나갔고 400 을 받았다:
11749
- * `Unsupported parameter: 'max_tokens' is not supported with this model. Use 'max_completion_tokens'`
11750
- * 📏 실측(2026-09-12 · 12시간 창): `review.done` 200행 중 `reviewed=false` 57, 그중 ***30***이 이 400 이다.
11751
- * ⊕ 요청 로그가 그것을 한 줄로 말한다 — `gpt-6-astra · maxTokens=2048 · api.openai.com/v1/chat/completions`.
11752
- *
11753
- * ⇒ ⭐ **세대를 「이름 목록」으로 세지 않는다.** 번호를 «범위»로 읽어 다음 세대가 와도 안 늙게 한다.
11754
- * `gpt-5` 이상(두 자리 포함) ⊕ `o1`~`o9`. ⛔ `gpt-4` 이하와 로컬 모델은 종전대로 옛 칸을 쓴다.
11755
- *
11756
- * 🌐 **외부 그라운딩**(2026-09-12 · omni-crawl `fc-dev`) — 같은 사고가 «업스트림에도» 있었다:
11757
- * · `quantumnous/new-api#7211` — *"GPT-6 Astra 未命中原来的 GPT-5 前缀判断"* (똑같은 접두 판정 누락)
11758
- * · `genkit-ai/genkit#6320` — *"max_tokens is sent verbatim and rejected by reasoning models"*
11759
- * · Azure AI docs — `gpt-6-astra`(2026-09-03) Chat Completions ⊕ Reasoning
11760
- * · overchat.ai — *"Astra does not support `temperature`, `top_p`, `top_logprobs`"*
11761
- * ⇒ ✅ 우리가 `temperature` 를 «생략»하는 것이 외부 사실과 «맞는다».
11762
- * ⚠️ `top_p`·`logprobs` 는 이 경로가 «안 보낸다»(local 프리셋 경로만 보낸다) — 그래서 조치 없음.
11763
- *
11764
- * ⚖️ ⛔ **알려진 트레이드오프 — new-api 는 «반대» 결론을 냈다.** 그들은
11765
- * *"모든 미래 GPT 메이저를 GPT-5 로 묶으면 서로 다른 모델의 파라미터 규칙이 엮인다"* 며
11766
- * ***미지의 미래 메이저는 추론하지 않는다***로 갔다(명시 목록 + 날짜 스냅샷).
11767
- * ⇒ 우리는 «반대»를 택했다. 이유: ***목록이 늙어서 이 사고가 났기 때문***이다
11768
- * (이 저장소에서 실제로 리뷰 미실행 30건을 냈다). 새 규칙은 «새 관례 쪽으로» 실패한다.
11769
- * 📌 그러므로 ***`gpt-N` 중 옛 칸을 «되찾는» 모델이 나오면 이 자가 틀린다.*** 그때는
11770
- * 여기서 갈지 말고 «모델별 능력 선언»으로 옮긴다(new-api 가 간 길). 지금은 그 표본이 0이다. */
11771
- export function isNewGenerationOpenAiModel(model: string): boolean {
11772
- const match = /^gpt-(\d+)/i.exec(model);
11773
- if (match) return Number.parseInt(match[1]!, 10) >= 5;
11774
- return /^o[1-9]/i.test(model);
11775
- }
11776
-
11777
- /**
11778
- * ⛔⭐ 같은 세대가 `temperature` 도 거부한다 — 400 `unsupported_value`,
11779
- * *"Only the default (1) value is supported"*.
11780
- *
11781
- * 📏 2026-08-22 실측: `max_tokens` 를 고친 «2분 뒤»(00:13:03Z)부터 이 400 이 났고
11782
- * 90분에 **41건**이었다. ⇒ ***한 파라미터만 고치면 다음 파라미터에서 막힌다.***
11783
- * ⚠️ 그때 나는 「수리 뒤 400 이 0건」이라 보고했는데, 그 자가 `grep max_completion_tokens`
11784
- * 라서 «새 400»을 못 봤다 — ***좁은 자로 「나았다」를 읽었다.***
11785
- *
11786
- * ⇒ 값을 «1로 보내지» 않고 ***칸을 생략***한다. 서버 기본이 1이고, 보내면 또 다른 거부를 부른다.
11787
- */
11788
- export function openAiTemperatureField(model: string, temperature: number): Record<string, number> {
11789
- return isNewGenerationOpenAiModel(model) ? {} : { temperature };
11790
- }
11702
+ // COMPAT(llm-facade-openai-sampling-fields) · 기존 llm.ts 공개 API 유지.
11703
+ import {
11704
+ openAiCompatSamplingFields,
11705
+ openAiOutputTokenField,
11706
+ isNewGenerationOpenAiModel,
11707
+ openAiTemperatureField,
11708
+ } from './llm/openai-sampling-fields.js';
11709
+ export {
11710
+ openAiCompatSamplingFields,
11711
+ openAiOutputTokenField,
11712
+ isNewGenerationOpenAiModel,
11713
+ openAiTemperatureField,
11714
+ };
@@ -0,0 +1,73 @@
1
+ import { openMsgStore, type Message, type MsgStore } from '../../msg/msg-store.js';
2
+ import { classifySeatTrafficProposal } from '../../seat-loop/traffic-signal.js';
3
+ import { debug } from '../../debug/log.js';
4
+
5
+ const RECIPIENT = 'COORDINATOR';
6
+
7
+ export interface CoordinatorInboxResult { replied: number; acknowledged: number }
8
+
9
+ function trafficProposal(request: Message): 'hold' | 'UNHOLD' | null {
10
+ // A question mentioning a signal is not evidence that the signal occurred.
11
+ return request.kind === 'question' || /[??]|되나|됐나|맞나|풀어도|해제해도|확인 요청/.test(request.body)
12
+ ? null : classifySeatTrafficProposal(request.body);
13
+ }
14
+
15
+ /** This loop suggests traffic moves; it never changes traffic.json. */
16
+ export function coordinatorReply(request: Message): string {
17
+ const traffic = trafficProposal(request);
18
+ const proposal = traffic === 'hold' ? 'hold 제안' : traffic === 'UNHOLD' ? 'UNHOLD 제안' : '모름 — OP/자리 판단 필요';
19
+ const evidence = traffic === 'hold' ? '자리 메시지에 «손 구현 착수»가 있습니다.'
20
+ : traffic === 'UNHOLD' ? '자리 메시지에 «첫 줄 확정»이 있습니다.'
21
+ : '착수·첫 줄 확정을 확정 진술로 확인하지 못했습니다. 칸·traffic 근거를 사람이 확인해야 합니다.';
22
+ return `re #${request.id}\n제안: ${proposal}\n근거: ${evidence}\n실제 잠금 변경은 수행하지 않았습니다.`;
23
+ }
24
+
25
+ /** Single reply writer: prefer the durable thread link, while recognizing pre-migration body markers. */
26
+ function writeCoordinatorReply(store: MsgStore, request: Message): { id: number; posted: boolean } {
27
+ const marker = `re #${request.id}`;
28
+ const linked = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
29
+ AND reply_to = ? ORDER BY id LIMIT 1`).get(RECIPIENT, request.from, request.id) as { id: number } | null;
30
+ if (linked) return { id: linked.id, posted: false };
31
+ const legacy = store.db.query(`SELECT id FROM msg_messages WHERE sender = ? AND recipient = ?
32
+ AND reply_to IS NULL AND (body = ? OR substr(body, 1, ?) = ?) ORDER BY id LIMIT 1`)
33
+ .get(RECIPIENT, request.from, marker, marker.length + 1, `${marker}\n`) as { id: number } | null;
34
+ if (legacy) return { id: legacy.id, posted: false };
35
+ const reply = store.post({ from: RECIPIENT, to: request.from,
36
+ body: coordinatorReply(request).slice(marker.length + 1), kind: 'reply', replyTo: request.id });
37
+ return { id: reply.id, posted: true };
38
+ }
39
+
40
+ /** One transaction ties a reply to its acknowledgement. A retry finds the durable receipt. */
41
+ export function runCoordinatorInbox(inputStore?: MsgStore, limit = 100, path?: string): CoordinatorInboxResult {
42
+ const store = inputStore ?? openMsgStore(path);
43
+ const ownStore = inputStore === undefined;
44
+ let replied = 0;
45
+ let acknowledged = 0;
46
+ try {
47
+ const requests = store.listByRecipient(RECIPIENT, store.getCursor(RECIPIENT), limit);
48
+ for (const request of requests) {
49
+ // Broadcasts and replies are not new requests. Advancing past them keeps the cursor moving.
50
+ if (request.to !== RECIPIENT || request.from === RECIPIENT ||
51
+ (request.kind !== undefined && request.kind !== 'request' && request.kind !== 'question')) {
52
+ store.ack(RECIPIENT, request.id);
53
+ acknowledged++;
54
+ continue;
55
+ }
56
+ const key = `coord-inbox:${request.id}:${request.from}`;
57
+ const result = store.db.transaction(() => {
58
+ const existing = store.db.query('SELECT message_id FROM msg_provenance WHERE provenance_key = ?')
59
+ .get(key) as { message_id: number } | null;
60
+ const reply = existing ? { id: existing.message_id, posted: false } : writeCoordinatorReply(store, request);
61
+ if (!existing) store.db.query('INSERT INTO msg_provenance(provenance_key, message_id) VALUES (?, ?)').run(key, reply.id);
62
+ store.ack(RECIPIENT, request.id);
63
+ return { posted: reply.posted };
64
+ }).immediate();
65
+ if (result.posted) replied++;
66
+ acknowledged++;
67
+ debug.log('loop.coordinator-inbox', 'reply', { requestId: request.id, recipient: request.from,
68
+ proposal: trafficProposal(request) ?? 'unknown', duplicate: !result.posted });
69
+ }
70
+ debug.log('loop.coordinator-inbox', 'tick', { replied, acknowledged });
71
+ return { replied, acknowledged };
72
+ } finally { if (ownStore) store.close(); }
73
+ }