jeo-code 0.7.54 → 0.7.55
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.
- package/CHANGELOG.md +12 -0
- package/README.ja.md +1 -1
- package/README.ko.md +1 -1
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/package.json +1 -1
- package/src/tui/app.ts +32 -12
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
The README mirrors the latest 5 entries — regenerate with `bun run changelog:sync`.
|
|
8
8
|
|
|
9
|
+
## [0.7.55] - 2026-07-07
|
|
10
|
+
_Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end._
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`modelProviderLabel()` helper** (`src/tui/app.ts`) — DRY "model (provider)" formatting shared with the existing `renderModelBar`/status-bar convention, now threaded through all three Thinking-related surfaces: the live `currentActivity()` status line ("reasoning (…)"/"calling model (…)"), the live streaming Thinking block header, and the live placeholder Thinking block (signature-only reasoning models like opus-4-8 that stream no thought text).
|
|
14
|
+
- **`thinkingHeader()` optional 3rd param** (`modelLabel?: string`) for the persisted (scrollback-committed) Thinking header — fully backward-compatible; existing 2-arg call sites are unchanged and produce byte-identical output.
|
|
15
|
+
|
|
16
|
+
### Verified
|
|
17
|
+
- `bun run typecheck` clean; full suite 2675/2675 pass across 280 files (+3 new tests: `thinkingHeader` 3-arg unit test, a real `LaunchTui` persisted-header integration test, and a live-frame streaming-block test).
|
|
18
|
+
- End-to-end proof with a real `LaunchTui` instance (not just the pure function) across a cross-provider two-turn session: turn 1 (claude-haiku-4-5/anthropic) and turn 2 (gemini-2.5-pro/gemini) each show their own correct model+provider in both the live and persisted Thinking headers, confirming the label updates turn-to-turn rather than being fixed at session start.
|
|
19
|
+
- A pre-existing test asserting the OLD bare `"thinking · Ns"` format (`streaming-reasoning.test.ts`) was updated to the new model-labeled format — an intentional format change, not a loosened assertion.
|
|
20
|
+
|
|
9
21
|
## [0.7.54] - 2026-07-06
|
|
10
22
|
_Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead._
|
|
11
23
|
|
package/README.ja.md
CHANGED
|
@@ -259,11 +259,11 @@ CI は `.github/workflows/npm-publish.yml` で公開します — GitHub リリ
|
|
|
259
259
|
## 変更履歴 (Changelog)
|
|
260
260
|
|
|
261
261
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
262
|
+
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
262
263
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
263
264
|
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
264
265
|
- **[0.7.52]** (2026-07-06) — Two TUI visibility asks answered directly ("어느 모델이 라우팅됐는지 상시 표시" — persistently show which model routing picked, and "각 서브에이전트의 사고 과정도 보이게" — surface each subagent's own thinking) plus a Ponytail-mode minimal-code audit pass across six files that found one genuine correctness bug and five instances of dead/unreachable code.
|
|
265
266
|
- **[0.7.51]** (2026-07-06) — Closes a real correctness gap the user directly identified by asking "does routing only ever pick from models the user can actually use?" — the honest answer at v0.7.50 was no: `routePrompt` resolves a tier's model purely from config (`routing.tiers`/`roles.smol`/`roles.slow`/`defaultModel`) and never checks whether that model's provider has a usable credential. A user could configure `roles.smol`/`roles.slow` to a provider they never logged into (or whose OAuth token expired since setup), and routing would silently turn a WORKING session into a FAILING turn — `resolveCall` throwing `"No credential for provider …"` — the instant it engaged, even though the turn would have succeeded unrouted. Routing is opt-in specifically so it can never make things worse than routing being off; this closes that hole.
|
|
266
|
-
- **[0.7.50]** (2026-07-06) — Design-doc audit of v0.7.47's PromptRouter, dispatched as two parallel subagents (independent re-verification + gap implementation) against the original Korean-language design report. The core proposal was confirmed shipped correctly (heuristic classifier, escalation, `/model`-always-wins, tool-selection isolation — all independently re-derived from git history and grep evidence, not just re-read from the doc). Two gaps the design doc itself had flagged as open questions (§7 risks #2 and #4) were real and are fixed here; a third finding (an internal contradiction in the design doc's own §3.2 vs §3.4 text on image-attachment gating — the SHIPPED code was already correct, only the doc's prose disagreed with itself) required no code change.
|
|
267
267
|
|
|
268
268
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
269
269
|
<!-- CHANGELOG:END -->
|
package/README.ko.md
CHANGED
|
@@ -260,11 +260,11 @@ CI는 `.github/workflows/npm-publish.yml`로 배포합니다 — GitHub 릴리
|
|
|
260
260
|
## 변경 이력 (Changelog)
|
|
261
261
|
|
|
262
262
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
263
|
+
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
263
264
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
264
265
|
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
265
266
|
- **[0.7.52]** (2026-07-06) — Two TUI visibility asks answered directly ("어느 모델이 라우팅됐는지 상시 표시" — persistently show which model routing picked, and "각 서브에이전트의 사고 과정도 보이게" — surface each subagent's own thinking) plus a Ponytail-mode minimal-code audit pass across six files that found one genuine correctness bug and five instances of dead/unreachable code.
|
|
266
267
|
- **[0.7.51]** (2026-07-06) — Closes a real correctness gap the user directly identified by asking "does routing only ever pick from models the user can actually use?" — the honest answer at v0.7.50 was no: `routePrompt` resolves a tier's model purely from config (`routing.tiers`/`roles.smol`/`roles.slow`/`defaultModel`) and never checks whether that model's provider has a usable credential. A user could configure `roles.smol`/`roles.slow` to a provider they never logged into (or whose OAuth token expired since setup), and routing would silently turn a WORKING session into a FAILING turn — `resolveCall` throwing `"No credential for provider …"` — the instant it engaged, even though the turn would have succeeded unrouted. Routing is opt-in specifically so it can never make things worse than routing being off; this closes that hole.
|
|
267
|
-
- **[0.7.50]** (2026-07-06) — Design-doc audit of v0.7.47's PromptRouter, dispatched as two parallel subagents (independent re-verification + gap implementation) against the original Korean-language design report. The core proposal was confirmed shipped correctly (heuristic classifier, escalation, `/model`-always-wins, tool-selection isolation — all independently re-derived from git history and grep evidence, not just re-read from the doc). Two gaps the design doc itself had flagged as open questions (§7 risks #2 and #4) were real and are fixed here; a third finding (an internal contradiction in the design doc's own §3.2 vs §3.4 text on image-attachment gating — the SHIPPED code was already correct, only the doc's prose disagreed with itself) required no code change.
|
|
268
268
|
|
|
269
269
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
270
270
|
<!-- CHANGELOG:END -->
|
package/README.md
CHANGED
|
@@ -264,11 +264,11 @@ Huge thanks to [gajae-code](https://github.com/Yeachan-Heo/gajae-code) for the i
|
|
|
264
264
|
## Changelog
|
|
265
265
|
|
|
266
266
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
267
|
+
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
267
268
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
268
269
|
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
269
270
|
- **[0.7.52]** (2026-07-06) — Two TUI visibility asks answered directly ("어느 모델이 라우팅됐는지 상시 표시" — persistently show which model routing picked, and "각 서브에이전트의 사고 과정도 보이게" — surface each subagent's own thinking) plus a Ponytail-mode minimal-code audit pass across six files that found one genuine correctness bug and five instances of dead/unreachable code.
|
|
270
271
|
- **[0.7.51]** (2026-07-06) — Closes a real correctness gap the user directly identified by asking "does routing only ever pick from models the user can actually use?" — the honest answer at v0.7.50 was no: `routePrompt` resolves a tier's model purely from config (`routing.tiers`/`roles.smol`/`roles.slow`/`defaultModel`) and never checks whether that model's provider has a usable credential. A user could configure `roles.smol`/`roles.slow` to a provider they never logged into (or whose OAuth token expired since setup), and routing would silently turn a WORKING session into a FAILING turn — `resolveCall` throwing `"No credential for provider …"` — the instant it engaged, even though the turn would have succeeded unrouted. Routing is opt-in specifically so it can never make things worse than routing being off; this closes that hole.
|
|
271
|
-
- **[0.7.50]** (2026-07-06) — Design-doc audit of v0.7.47's PromptRouter, dispatched as two parallel subagents (independent re-verification + gap implementation) against the original Korean-language design report. The core proposal was confirmed shipped correctly (heuristic classifier, escalation, `/model`-always-wins, tool-selection isolation — all independently re-derived from git history and grep evidence, not just re-read from the doc). Two gaps the design doc itself had flagged as open questions (§7 risks #2 and #4) were real and are fixed here; a third finding (an internal contradiction in the design doc's own §3.2 vs §3.4 text on image-attachment gating — the SHIPPED code was already correct, only the doc's prose disagreed with itself) required no code change.
|
|
272
272
|
|
|
273
273
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
274
274
|
<!-- CHANGELOG:END -->
|
package/README.zh.md
CHANGED
|
@@ -259,11 +259,11 @@ CI 通过 `.github/workflows/npm-publish.yml` 发布 — GitHub 发布 release
|
|
|
259
259
|
## 更新日志 (Changelog)
|
|
260
260
|
|
|
261
261
|
<!-- CHANGELOG:START (auto-generated from CHANGELOG.md — run `bun run changelog:sync`) -->
|
|
262
|
+
- **[0.7.55]** (2026-07-07) — Cross-provider routing (PromptRouter, v0.7.47+) already named the routed tier in the status bar (v0.7.52), but nothing surfaced WHICH model/provider actually produced a turn's reasoning in the Thinking-block surfaces — a gap noticed while manually verifying the v0.7.52 status-bar work end-to-end.
|
|
262
263
|
- **[0.7.54]** (2026-07-06) — Root-cause fix for a live-reported GPT-5.5 (Codex/ChatGPT OAuth backend) failure: "Error: stream exceeded the overall deadline (JEO_STREAM_MAX_MS) — slow-drip stream aborted". Deep-dive traced this to a REGRESSION in v0.7.42 — a separate, correct fix for a genuinely-different bug (a connected-but-never-terminating stream) silently flipped `streamMaxMs()`'s default from opt-in-off to an ALWAYS-ON 300s overall wall-clock cap, which then killed any HIGH/XHIGH-reasoning-effort completion (GPT-5.5/o3-class) whose ACTIVELY-emitting generation legitimately ran past 5 minutes — OpenAI's own guidance states xhigh trades latency for depth by design. The non-streaming `call()` path (used by every subagent, compaction, and goal-verify call, since none wire `onModelStream`) carried the IDENTICAL bug with zero idle/activity tracking at all, exposed under a different, unhelpful raw `DOMException: The operation timed out.` message instead.
|
|
263
264
|
- **[0.7.53]** (2026-07-06) — Verified PromptRouter end-to-end (63 pre-existing tests re-run, all passing; a live `jeo doctor --json`/human-output smoke test confirms real wiring, not just mocks) and closed the one genuine remaining gap: the v0.7.51 per-turn credential-readiness veto protected a running session reactively, but nothing caught a misconfigured `roles.smol`/`roles.slow`/`routing.tiers.*.model` proactively at setup time.
|
|
264
265
|
- **[0.7.52]** (2026-07-06) — Two TUI visibility asks answered directly ("어느 모델이 라우팅됐는지 상시 표시" — persistently show which model routing picked, and "각 서브에이전트의 사고 과정도 보이게" — surface each subagent's own thinking) plus a Ponytail-mode minimal-code audit pass across six files that found one genuine correctness bug and five instances of dead/unreachable code.
|
|
265
266
|
- **[0.7.51]** (2026-07-06) — Closes a real correctness gap the user directly identified by asking "does routing only ever pick from models the user can actually use?" — the honest answer at v0.7.50 was no: `routePrompt` resolves a tier's model purely from config (`routing.tiers`/`roles.smol`/`roles.slow`/`defaultModel`) and never checks whether that model's provider has a usable credential. A user could configure `roles.smol`/`roles.slow` to a provider they never logged into (or whose OAuth token expired since setup), and routing would silently turn a WORKING session into a FAILING turn — `resolveCall` throwing `"No credential for provider …"` — the instant it engaged, even though the turn would have succeeded unrouted. Routing is opt-in specifically so it can never make things worse than routing being off; this closes that hole.
|
|
266
|
-
- **[0.7.50]** (2026-07-06) — Design-doc audit of v0.7.47's PromptRouter, dispatched as two parallel subagents (independent re-verification + gap implementation) against the original Korean-language design report. The core proposal was confirmed shipped correctly (heuristic classifier, escalation, `/model`-always-wins, tool-selection isolation — all independently re-derived from git history and grep evidence, not just re-read from the doc). Two gaps the design doc itself had flagged as open questions (§7 risks #2 and #4) were real and are fixed here; a third finding (an internal contradiction in the design doc's own §3.2 vs §3.4 text on image-attachment gating — the SHIPPED code was already correct, only the doc's prose disagreed with itself) required no code change.
|
|
267
267
|
|
|
268
268
|
See [CHANGELOG.md](CHANGELOG.md) for the full history.
|
|
269
269
|
<!-- CHANGELOG:END -->
|
package/package.json
CHANGED
package/src/tui/app.ts
CHANGED
|
@@ -158,11 +158,17 @@ export function clipReasoningLines(text: string, cap = THINKING_COMMIT_MAX_LINES
|
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/** gjc-style "thought for Ns" header for a committed/streaming Thinking block. Omits the
|
|
161
|
-
* duration when no step start is known (e.g. resumed/exported records).
|
|
162
|
-
|
|
161
|
+
* duration when no step start is known (e.g. resumed/exported records). The optional
|
|
162
|
+
* `modelLabel` (e.g. "gpt-4o-mini (openai)", built by `modelProviderLabel()`) names
|
|
163
|
+
* which routed model actually produced this committed thought — a cross-provider
|
|
164
|
+
* routed turn's scrollback record otherwise gives no way to tell, after the fact,
|
|
165
|
+
* which provider reasoned about which step. Omitted entirely when absent (e.g. the
|
|
166
|
+
* 2-arg legacy call, or a resumed/exported record with no model context). */
|
|
167
|
+
export function thinkingHeader(elapsedMs: number | undefined, unicode: boolean, modelLabel?: string): string {
|
|
163
168
|
const diamond = unicode ? "◇" : "*";
|
|
164
169
|
const secs = elapsedMs !== undefined && elapsedMs >= 0 ? `${(elapsedMs / 1000).toFixed(1)}s` : null;
|
|
165
|
-
|
|
170
|
+
const model = modelLabel ? ` · ${modelLabel}` : "";
|
|
171
|
+
return `${diamond} thinking${model}${secs ? ` · ${secs}` : ""}`;
|
|
166
172
|
}
|
|
167
173
|
|
|
168
174
|
/** Status animation palette while a tool/process runs (background verification): an
|
|
@@ -553,8 +559,10 @@ export class LaunchTui {
|
|
|
553
559
|
const style = (prose: string) => prose.split("\n").map(styleThought).join("\n");
|
|
554
560
|
const parts: string[] = [this.agentLabel()];
|
|
555
561
|
// gjc "thought for Ns" header: step-start → commit ≈ the model's think+gen time.
|
|
562
|
+
// Names the routed model/provider so a cross-provider routed turn's scrollback
|
|
563
|
+
// record stays legible after the fact, not just live in the model bar.
|
|
556
564
|
const elapsedMs = this.currentStepStartedAt ? Date.now() - this.currentStepStartedAt : undefined;
|
|
557
|
-
const header = thinkingHeader(elapsedMs, this.unicode);
|
|
565
|
+
const header = thinkingHeader(elapsedMs, this.unicode, this.modelProviderLabel());
|
|
558
566
|
parts.push(this.theme.color ? chalk.dim(header) : header);
|
|
559
567
|
if (willFlushThought) {
|
|
560
568
|
this.flushedThought = this.streamingThought;
|
|
@@ -943,6 +951,15 @@ export class LaunchTui {
|
|
|
943
951
|
* Replaces the per-tick cycling status text so the line shows genuine content (thinking
|
|
944
952
|
* about a real file/step) instead of churning decorative messages every 120ms.
|
|
945
953
|
*/
|
|
954
|
+
/** `model (provider)` — the same convention `renderModelBar` uses for the persistent
|
|
955
|
+
* status bar, reused here so the live/persisted "thinking" surfaces name which
|
|
956
|
+
* routed model+provider is actually reasoning right now (not just the bare model id,
|
|
957
|
+
* which alone doesn't distinguish e.g. a `gpt-4o-mini` served via openai vs. a
|
|
958
|
+
* same-named alias on an OpenAI-compatible provider). */
|
|
959
|
+
private modelProviderLabel(): string {
|
|
960
|
+
return `${this.footer.model}${this.footer.provider ? ` (${this.footer.provider})` : ""}`;
|
|
961
|
+
}
|
|
962
|
+
|
|
946
963
|
private currentActivity(): string {
|
|
947
964
|
const running = this.tools.currentTool();
|
|
948
965
|
// An in-flight tool's real target beats the workflow phase banner (gjc-style:
|
|
@@ -974,14 +991,14 @@ export class LaunchTui {
|
|
|
974
991
|
if (this.retryNotice) return `${this.retryNotice} (${elapsed}s)`;
|
|
975
992
|
// Reasoning is streaming → the live thought block already shows it; label the row.
|
|
976
993
|
if (this.streamingThought.trim() || this.streamingReasoning.trim()) {
|
|
977
|
-
return `reasoning (${this.
|
|
994
|
+
return `reasoning (${this.modelProviderLabel()}) (${elapsed}s)…`;
|
|
978
995
|
}
|
|
979
996
|
// No tokens after a few seconds: the model is almost certainly reasoning
|
|
980
997
|
// server-side (e.g. OpenAI hidden reasoning), NOT hung — say so instead of a
|
|
981
998
|
// frozen "calling model …" so a long silent wait still reads as progress.
|
|
982
999
|
const waited = this.currentStepStartedAt ? (Date.now() - this.currentStepStartedAt) / 1000 : 0;
|
|
983
|
-
if (waited >= 8) return `thinking (${this.
|
|
984
|
-
return `calling model (${this.
|
|
1000
|
+
if (waited >= 8) return `thinking (${this.modelProviderLabel()}) — reasoning, no token stream yet (${elapsed}s)…`;
|
|
1001
|
+
return `calling model (${this.modelProviderLabel()}) (${elapsed}s)…`;
|
|
985
1002
|
}
|
|
986
1003
|
if (running) {
|
|
987
1004
|
const last = this.forgeSummaries[this.forgeSummaries.length - 1];
|
|
@@ -1567,17 +1584,20 @@ export class LaunchTui {
|
|
|
1567
1584
|
// rectangle, so a short trace leaves no padded "hole" and a short terminal is spared.
|
|
1568
1585
|
const liveThink = this.streamingThought.trim() || this.streamingReasoning.trim();
|
|
1569
1586
|
if (isThinking && liveThink) {
|
|
1570
|
-
// gjc-parity: the Thinking block label carries
|
|
1571
|
-
//
|
|
1587
|
+
// gjc-parity: the Thinking block label carries the routed model/provider and a
|
|
1588
|
+
// running timer ("Thinking · gpt-4o-mini (openai) · Ns") — names which model is
|
|
1589
|
+
// actually reasoning right now, so a cross-provider routed turn is legible mid-turn,
|
|
1590
|
+
// not just after the fact in the status bar. Cache key stays the constant "Thinking"
|
|
1591
|
+
// so the per-frame wrap memo is unaffected by the model/provider text.
|
|
1572
1592
|
const liveMs = this.currentStepStartedAt ? Date.now() - this.currentStepStartedAt : undefined;
|
|
1573
|
-
const liveLabel = liveMs !== undefined ? `
|
|
1593
|
+
const liveLabel = `Thinking · ${this.modelProviderLabel()}${liveMs !== undefined ? ` · ${(liveMs / 1000).toFixed(1)}s` : ""}`;
|
|
1574
1594
|
tail.push(...this.renderLiveBlock(liveLabel, liveThink, cols, rows, 6, "Thinking"));
|
|
1575
1595
|
} else if (isThinking && this.thinkingActive) {
|
|
1576
1596
|
// Signature-only reasoning models (opus-4-7/4-8) open a thinking block but stream no
|
|
1577
1597
|
// thought text — show a live placeholder so the wait reads as active thinking, not a
|
|
1578
1598
|
// frozen screen. Replaced the instant any real thought/answer text streams (branch above).
|
|
1579
1599
|
const liveMs = this.currentStepStartedAt ? Date.now() - this.currentStepStartedAt : undefined;
|
|
1580
|
-
const liveLabel = liveMs !== undefined ? `
|
|
1600
|
+
const liveLabel = `Thinking · ${this.modelProviderLabel()}${liveMs !== undefined ? ` · ${(liveMs / 1000).toFixed(1)}s` : ""}`;
|
|
1581
1601
|
tail.push(...this.renderLiveBlock(liveLabel, "(thinking…)", cols, rows, 6, "Thinking"));
|
|
1582
1602
|
}
|
|
1583
1603
|
|
|
@@ -1645,7 +1665,7 @@ export class LaunchTui {
|
|
|
1645
1665
|
? Math.round((this.footer.contextUsedTokens / this.footer.contextMaxTokens) * 100)
|
|
1646
1666
|
: undefined;
|
|
1647
1667
|
return renderStatusBar({
|
|
1648
|
-
model:
|
|
1668
|
+
model: this.modelProviderLabel(),
|
|
1649
1669
|
thinking: this.thinkingLevel,
|
|
1650
1670
|
routedTier: this.routedTier,
|
|
1651
1671
|
branch: this.footer.branch,
|