Studio: render Codex parallel-calls synthesis AFTER the per-tab blocks
End-to-end probe of a 2-way parallel-calls Codex turn revealed the visible assistant message looked like: <synthesis text> [Codex tab 1/2] <tab 1 text> [Codex tab 2/2] <tab 2 text> --- Synthesis --- The synthesis came first (no label), then the tabs, then a trailing "--- Synthesis ---" line with nothing below it. The header comment in chat-adapter.ts said the intent was "[tabs] ... [synthesis]" but the implementation prepended cumulativeText (which carries the synthesis deltas the backend emits after codex_gather) before the tabs. Fix: split renderCodexBuffer into renderCodexTabsBlock (pure per-tab rendering, no trailing divider) and reorder renderFullContent so when Codex fan-out is active the output is: [Codex tab 1/N] <tab 1> [Codex tab N/N] <tab N> --- Synthesis --- <synthesis text from cumulativeText> The non-Codex case still returns cumulativeText unchanged.
This commit is contained in:
parent
c755d00c1f
commit
b7862388fa
1 changed files with 20 additions and 13 deletions
|
|
@ -1143,8 +1143,8 @@ export function createOpenAIStreamAdapter(): ChatModelAdapter {
|
|||
let codexTotalTabs = 0;
|
||||
let codexGatherEmitted = false;
|
||||
|
||||
function renderCodexBuffer(): string {
|
||||
if (codexTabBuffers.size === 0 && !codexGatherEmitted) return "";
|
||||
function renderCodexTabsBlock(): string {
|
||||
if (codexTabBuffers.size === 0) return "";
|
||||
const lines: string[] = [];
|
||||
const ids = [...codexTabBuffers.keys()].sort((a, b) => a - b);
|
||||
for (const id of ids) {
|
||||
|
|
@ -1159,21 +1159,28 @@ export function createOpenAIStreamAdapter(): ChatModelAdapter {
|
|||
lines.push("\n");
|
||||
}
|
||||
}
|
||||
if (codexGatherEmitted) {
|
||||
lines.push("\n--- Synthesis ---\n");
|
||||
}
|
||||
return lines.join("");
|
||||
}
|
||||
|
||||
// All chat-content yields go through this so the Codex per-tab
|
||||
// output is always concatenated with the normal SSE text. The
|
||||
// synthesis is emitted by the backend BOTH as a `codex_gather`
|
||||
// tool event AND as a normal content delta; rendering both
|
||||
// would duplicate it. Render the tabs above (header / tab text)
|
||||
// separately from cumulativeText (which carries the synthesis
|
||||
// content delta) so the user sees `[tabs] ... [synthesis]`.
|
||||
// Codex parallel-calls fan-out renders the labeled tab outputs
|
||||
// first, then a "--- Synthesis ---" divider, then the synthesis
|
||||
// text the backend streams as plain content deltas after the
|
||||
// `codex_gather` event. Earlier the synthesis came BEFORE the
|
||||
// tabs (since cumulativeText was prepended) which left the
|
||||
// trailing "--- Synthesis ---" line orphaned at the bottom with
|
||||
// no synthesis text under it, confusing users. When there is no
|
||||
// Codex fan-out (single-tab Codex turn or any other provider)
|
||||
// the function falls back to the plain cumulativeText.
|
||||
function renderFullContent(): string {
|
||||
return cumulativeText + renderCodexBuffer();
|
||||
const tabsBlock = renderCodexTabsBlock();
|
||||
if (!tabsBlock && !codexGatherEmitted) {
|
||||
return cumulativeText;
|
||||
}
|
||||
const parts: string[] = [];
|
||||
if (tabsBlock) parts.push(tabsBlock);
|
||||
if (codexGatherEmitted) parts.push("\n\n--- Synthesis ---\n\n");
|
||||
if (cumulativeText) parts.push(cumulativeText);
|
||||
return parts.join("");
|
||||
}
|
||||
// Tracks whether we are currently inside a `<think>` block opened by
|
||||
// a `delta.reasoning_content` chunk. Kimi (kimi-k2.6, kimi-k2-thinking)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue