Skip to content

Commit 6a15b1f

Browse files
committed
fix(daemon): keep stripping title markers in the post-close remainder of one delta
mrcfps's non-blocking thread on #6342 round-2 review (apps/daemon/src/title-marker.ts L97, 2026-08-02) noted that the previous implementation did emitTitle(buffer.slice(titleStart, closeIndex)); buffer = buffer.slice(closeIndex + TITLE_CLOSE_TAG.length); visible += buffer; buffer = ''; right after the first close tag, which forwarded the post-close remainder to `visible` without scanning it. Stream delta boundaries are transport-dependent, so identical model output could leak a raw `<od-title>Two</od-title>` depending on adapter chunking — breaking the "scanner remains active" invariant this PR introduced in the comment two lines above. Concretely, one call with `<od-title>One</od-title>A<od-title>Two</od-title>B` returned `A<od-title>Two</od-title>B`, whereas splitting the same bytes into two `strip()` calls removed both markers. Fix: drop the `visible += buffer; buffer = '';` flush and `continue` the while loop instead, so the post-close remainder re-enters the same single-marker scanner. Multiple markers in one delta are now stripped in the same pass; `emitted` still de-dupes title events across the run. Test: `apps/daemon/tests/title-marker.test.ts` gains a regression `title marker stripper strips every marker inside one delta (post-close remainder keeps scanning)` that asserts `<od-title>One</od-title>A<od-title>Two</od-title>B` returns `AB` and only `One` is emitted as a title; no marker remains in the visible output or in the post-flush leftover. 7/7 tests pass locally: pnpm --filter @open-design/daemon exec vitest run tests/title-marker.test.ts Signed-off-by: xxiaoxiong <2482929840@qq.com>
1 parent 7b9bc7a commit 6a15b1f

2 files changed

Lines changed: 32 additions & 5 deletions

File tree

apps/daemon/src/title-marker.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -94,11 +94,12 @@ export function createAgentTitleMarkerStripper(
9494

9595
emitTitle(buffer.slice(titleStart, closeIndex));
9696
buffer = buffer.slice(closeIndex + TITLE_CLOSE_TAG.length);
97-
// Keep scanning so subsequent markers in the same run are also
98-
// stripped. `emitted` prevents duplicate title events within
99-
// this stripper instance.
100-
visible += buffer;
101-
buffer = '';
97+
// Keep scanning so subsequent markers in the same run are
98+
// also stripped. `emitted` prevents duplicate title events
99+
// within this stripper instance. The while loop continues
100+
// with the remaining buffer, so a second marker in the same
101+
// delta is handled without leaking the raw tag through.
102+
continue;
102103
}
103104

104105
return visible;

apps/daemon/tests/title-marker.test.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,29 @@ test('title marker stripper strips across per-run instances when shouldEmitTitle
9494
'\n\nMore');
9595
assert.deepEqual(turn2.titles, []);
9696
});
97+
98+
test('title marker stripper strips every marker inside one delta (post-close remainder keeps scanning)', () => {
99+
// Regression for the mrcfps non-blocking thread on #6342 round-2 review
100+
// (2026-08-02): the prior implementation did
101+
// `visible += buffer; buffer = '';`
102+
// immediately after the first close tag, which forwarded the post-close
103+
// remainder without scanning it. Stream delta boundaries are
104+
// transport-dependent, so identical model output could leak a raw
105+
// `<od-title>Two</od-title>` depending on adapter chunking — breaking
106+
// the "scanner remains active" invariant this PR introduced.
107+
//
108+
// After the fix, the stripper keeps the post-close remainder in `buffer`
109+
// and continues the loop instead of flushing visible text and clearing,
110+
// so multiple markers in one delta are all stripped in the same pass.
111+
const { stripper, titles } = createStripper();
112+
113+
assert.equal(
114+
stripper.strip('<od-title>One</od-title>A<od-title>Two</od-title>B'),
115+
'AB',
116+
);
117+
// `emitted` only de-dupes title events from a single stripper instance;
118+
// the first marker wins, and the second is silently stripped without
119+
// firing a duplicate title (mirrors the multi-turn behavior above).
120+
assert.deepEqual(titles, ['One']);
121+
assert.equal(stripper.flush(), '');
122+
});

0 commit comments

Comments
 (0)