cuelo 0.6.9 → 0.7.0

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 (59) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +10 -10
  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/server/app/_global-error/page_client-reference-manifest.js +1 -1
  8. package/.next/server/app/_global-error.html +1 -1
  9. package/.next/server/app/_global-error.rsc +1 -1
  10. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  17. package/.next/server/app/_not-found.html +1 -1
  18. package/.next/server/app/_not-found.rsc +2 -2
  19. package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  20. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  22. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  23. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  24. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  25. package/.next/server/app/api/updates/route.js +1 -1
  26. package/.next/server/app/index.html +1 -1
  27. package/.next/server/app/index.rsc +4 -4
  28. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  29. package/.next/server/app/index.segments/_full.segment.rsc +4 -4
  30. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  31. package/.next/server/app/index.segments/_index.segment.rsc +2 -2
  32. package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  33. package/.next/server/app/page.js +2 -2
  34. package/.next/server/app/page_client-reference-manifest.js +1 -1
  35. package/.next/server/app/recover/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/recover.html +1 -1
  37. package/.next/server/app/recover.rsc +2 -2
  38. package/.next/server/app/recover.segments/_full.segment.rsc +2 -2
  39. package/.next/server/app/recover.segments/_head.segment.rsc +1 -1
  40. package/.next/server/app/recover.segments/_index.segment.rsc +2 -2
  41. package/.next/server/app/recover.segments/_tree.segment.rsc +1 -1
  42. package/.next/server/app/recover.segments/recover/__PAGE__.segment.rsc +1 -1
  43. package/.next/server/app/recover.segments/recover.segment.rsc +1 -1
  44. package/.next/server/app-paths-manifest.json +10 -10
  45. package/.next/server/chunks/6429.js +2 -2
  46. package/.next/server/middleware-build-manifest.js +1 -1
  47. package/.next/server/pages/404.html +1 -1
  48. package/.next/server/pages/500.html +1 -1
  49. package/.next/server/server-reference-manifest.json +1 -1
  50. package/.next/static/chunks/app/{layout-0082ed8a34057701.js → layout-89b7963cbc4da94d.js} +1 -1
  51. package/.next/static/chunks/app/{page-ca1d4378b3ad4549.js → page-042cc56cc090bf73.js} +2 -2
  52. package/.next/trace +105 -105
  53. package/.next/trace-build +1 -1
  54. package/README.md +2 -1
  55. package/Tools/CUELO_Setup/files/native-runtime-patch.js +5 -5
  56. package/Tools/OMP_Global_Config/patches/apply-core-patch.mjs +113 -55
  57. package/package.json +7 -7
  58. /package/.next/static/{4swMbGViH4DcOvsX9-ZTC → JfkwRK2BKBsxwumh964am}/_buildManifest.js +0 -0
  59. /package/.next/static/{4swMbGViH4DcOvsX9-ZTC → JfkwRK2BKBsxwumh964am}/_ssgManifest.js +0 -0
package/.next/trace-build CHANGED
@@ -1 +1 @@
1
- [{"name":"run-webpack","duration":101868985,"timestamp":684209,"id":14,"parentId":1,"tags":{},"startTime":1790818791514,"traceId":"b778babbdc8d61c8"},{"name":"run-typescript","duration":16676433,"timestamp":102902705,"id":10735,"parentId":1,"tags":{},"startTime":1790818893732,"traceId":"b778babbdc8d61c8"},{"name":"static-check","duration":4397314,"timestamp":119679483,"id":10738,"parentId":1,"tags":{},"startTime":1790818910508,"traceId":"b778babbdc8d61c8"},{"name":"static-generation","duration":11479379,"timestamp":124174322,"id":10892,"parentId":1,"tags":{},"startTime":1790818915003,"traceId":"b778babbdc8d61c8"},{"name":"collect-build-traces","duration":20134699,"timestamp":124144006,"id":10889,"parentId":1,"tags":{},"startTime":1790818914972,"traceId":"b778babbdc8d61c8"},{"name":"telemetry-flush","duration":89,"timestamp":144283259,"id":10901,"parentId":1,"tags":{},"startTime":1790818935111,"traceId":"b778babbdc8d61c8"},{"name":"next-build","duration":143711222,"timestamp":572151,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790818791402,"traceId":"b778babbdc8d61c8"}]
1
+ [{"name":"run-webpack","duration":115346157,"timestamp":815400,"id":14,"parentId":1,"tags":{},"startTime":1790828618583,"traceId":"3fb5eebabbbdaa86"},{"name":"run-typescript","duration":19156024,"timestamp":116502438,"id":10735,"parentId":1,"tags":{},"startTime":1790828734272,"traceId":"3fb5eebabbbdaa86"},{"name":"static-check","duration":4633736,"timestamp":135758863,"id":10738,"parentId":1,"tags":{},"startTime":1790828753528,"traceId":"3fb5eebabbbdaa86"},{"name":"static-generation","duration":12729889,"timestamp":140502034,"id":10892,"parentId":1,"tags":{},"startTime":1790828758272,"traceId":"3fb5eebabbbdaa86"},{"name":"collect-build-traces","duration":22205456,"timestamp":140471277,"id":10889,"parentId":1,"tags":{},"startTime":1790828758241,"traceId":"3fb5eebabbbdaa86"},{"name":"telemetry-flush","duration":83,"timestamp":162681492,"id":10901,"parentId":1,"tags":{},"startTime":1790828780451,"traceId":"3fb5eebabbbdaa86"},{"name":"next-build","duration":161988669,"timestamp":692932,"id":1,"tags":{"buildMode":"default","version":"16.2.12","bundler":"webpack","has-custom-webpack-config":"true","use-build-worker":"false"},"startTime":1790828618461,"traceId":"3fb5eebabbbdaa86"}]
package/README.md CHANGED
@@ -39,7 +39,8 @@ CUELO의 목적은 작업 중 확인한 실패와 막힘을 기억·작업 규
39
39
  - 프로젝트별로 지난 omp 세션을 찾아 이어 가고, 실시간으로 스트리밍되는 대화에서 도구 호출·비용·컨텍스트 사용량을 봅니다.
40
40
  - 이전 메시지에서 갈래를 나누거나(세션 안 분기), 별도 세션으로 fork합니다.
41
41
  - 작업 공간(프로젝트·worktree)을 바꾸면 그곳에서 마지막으로 열어 둔 세션으로 돌아갑니다.
42
- - goal 모드의 자동 이어 가기와 todo 진행 상황을 대화창 위에서 확인합니다.
42
+ - goal 모드의 자동 이어 가기와 todo 진행 상황을 대화창 위에서 확인합니다. 실행을 취소하면 자동 이어 가기가 멈추며, 일시정지된 목표는 `/goal resume`으로 재개합니다.
43
+ - 실행 중에 Steer로 지시를 바꾸면, 도구 호출이 없는 모델 요청은 서버의 전환 신호를 기다리지 않고 새 지시로 다시 요청합니다. 이미 보인 답변은 유지하며, 재요청에 따라 사용량이 늘 수 있습니다.
43
44
  - 작업 로그 패널에서 이번 턴의 과정 항목과 턴마다 쓴 파일을 따로 봅니다.
44
45
  - 입력창에 이미지·문서 외에 음성(받아쓰기), 코드·설정 파일(본문 첨부), 그 밖의 파일(저장 후 경로 첨부)을 붙여넣기·드롭·선택으로 넣습니다. 음성 받아쓰기에는 Google Antigravity 계정이 필요합니다.
45
46
  - 에이전트가 생성하거나 확인한 이미지가 그 턴의 대화 흐름에 썸네일로 보이고, 누르면 크게 열립니다.
@@ -9,12 +9,12 @@ const MEMORY_RE = /(const phase1Model = await resolveMemoryModel\(\{[^}]*?fallba
9
9
  const MEMORY_DONE = /const phase1Model = await resolveMemoryModel\(\{[^}]*?fallbackRole: "smol"/;
10
10
  const EXPECTED = {
11
11
  name: 'cuelo',
12
- version: '0.6.9',
12
+ version: '0.7.0',
13
13
  distribution: 'cuelo',
14
- coreVersion: '18.4.5',
14
+ coreVersion: '18.4.6',
15
15
  };
16
16
 
17
- // OMP core 18.4.5 `src/sdk.ts`: session-scoped AsyncJobManager for a process
17
+ // OMP core 18.4.6 `src/sdk.ts`: session-scoped AsyncJobManager for a process
18
18
  // that hosts several top-level sessions (CUELO opens one per browser session).
19
19
  // Upstream lets only the first top-level session construct a manager; every
20
20
  // later one got `asyncJobManager: undefined`, so its `task` calls logged
@@ -23,7 +23,7 @@ const EXPECTED = {
23
23
  // fix: it is disposed with its owning session (CUELO idle-shuts sessions
24
24
  // after 10 minutes) and would cancel every other session's jobs, and a
25
25
  // disposed manager throws on the next register(). Each edit is an exact text
26
- // anchor of the pristine 18.4.5 source (also present after core patch) and fails closed when it drifts.
26
+ // anchor of the pristine 18.4.6 source (also present after core patch) and fails closed when it drifts.
27
27
  // `insertBefore` edits keep their anchor (the helper is inserted in front of
28
28
  // it), so their anchor count stays 1 after patching.
29
29
  const SDK_FILE = path.join('node_modules', '@oh-my-pi', 'pi-coding-agent', 'src', 'sdk.ts');
@@ -177,7 +177,7 @@ function readNativePackage(target) {
177
177
  throw new Error(`unexpected native package ${packageJson.name}@${packageJson.version}`);
178
178
  }
179
179
  if (!build || build.distribution !== EXPECTED.distribution || build.coreVersion !== EXPECTED.coreVersion) {
180
- throw new Error('native cueloBuild metadata does not match cuelo / core 18.4.5');
180
+ throw new Error('native cueloBuild metadata does not match cuelo / core 18.4.6');
181
181
  }
182
182
  return packageJson;
183
183
  }
@@ -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") 비어 있고
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cuelo",
3
- "version": "0.6.9",
3
+ "version": "0.7.0",
4
4
  "description": "CUELO — open-source AI coding agent workspace and harness for omp (oh-my-pi)",
5
5
  "homepage": "https://github.com/gim47656-ship-it/CUELO#readme",
6
6
  "repository": {
@@ -30,7 +30,7 @@
30
30
  "license": "MIT",
31
31
  "cueloBuild": {
32
32
  "distribution": "cuelo",
33
- "coreVersion": "18.4.5"
33
+ "coreVersion": "18.4.6"
34
34
  },
35
35
  "engines": {
36
36
  "node": ">=22.19.0",
@@ -88,11 +88,11 @@
88
88
  "test:coverage": "bun test --coverage ./app ./components ./hooks ./lib ./public ./bin ./install.test.mjs"
89
89
  },
90
90
  "dependencies": {
91
- "@oh-my-pi/pi-agent-core": "18.4.5",
92
- "@oh-my-pi/pi-ai": "18.4.5",
93
- "@oh-my-pi/pi-coding-agent": "18.4.5",
94
- "@oh-my-pi/pi-tui": "18.4.5",
95
- "@oh-my-pi/pi-utils": "18.4.5",
91
+ "@oh-my-pi/pi-agent-core": "18.4.6",
92
+ "@oh-my-pi/pi-ai": "18.4.6",
93
+ "@oh-my-pi/pi-coding-agent": "18.4.6",
94
+ "@oh-my-pi/pi-tui": "18.4.6",
95
+ "@oh-my-pi/pi-utils": "18.4.6",
96
96
  "@seed-design/css": "2.8.0",
97
97
  "@seed-design/react": "2.4.1",
98
98
  "@seed-design/tailwind4-theme": "2.4.0",