惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
Vercel News
Vercel News
D
DataBreaches.Net
MongoDB | Blog
MongoDB | Blog
H
Help Net Security
小众软件
小众软件
美团技术团队
T
The Blog of Author Tim Ferriss
爱范儿
爱范儿
D
Docker
Martin Fowler
Martin Fowler
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
Blog — PlanetScale
Blog — PlanetScale
H
Hackread – Cybersecurity News, Data Breaches, AI and More
罗磊的独立博客
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
V2EX
S
SegmentFault 最新的问题
云风的 BLOG
云风的 BLOG
B
Blog
雷峰网
雷峰网
The Cloudflare Blog

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(agents): flush final block tag fragments (#74065) · o...
steipete · 2026-04-29 · via Recent Commits to openclaw:main

@@ -700,13 +700,18 @@ export function subscribeEmbeddedPiSession(params: SubscribeEmbeddedPiSessionPar

700700

return output;

701701

};

702702703-

const emitBlockChunk = (text: string, options?: { assistantMessageIndex?: number }) => {

703+

const emitBlockChunk = (

704+

text: string,

705+

options?: { assistantMessageIndex?: number; final?: boolean },

706+

) => {

704707

if (state.suppressBlockChunks || params.silentExpected) {

705708

return;

706709

}

707710

// Strip <think> and <final> blocks across chunk boundaries to avoid leaking reasoning.

708711

// Also strip downgraded tool call text ([Tool Call: ...], [Historical context: ...], etc.).

709-

const chunk = stripDowngradedToolCallText(stripBlockTags(text, state.blockState)).trimEnd();

712+

const chunk = stripDowngradedToolCallText(

713+

stripBlockTags(text, state.blockState, { final: options?.final === true }),

714+

).trimEnd();

710715

if (!chunk) {

711716

return;

712717

}

@@ -769,17 +774,42 @@ export function subscribeEmbeddedPiSession(params: SubscribeEmbeddedPiSessionPar

769774770775

const flushBlockReplyBuffer = (options?: {

771776

assistantMessageIndex?: number;

777+

final?: boolean;

772778

}): void | Promise<void> => {

773779

if (!params.onBlockReply) {

774780

return;

775781

}

776782

if (blockChunker?.hasBuffered()) {

777-

blockChunker.drain({ force: true, emit: (text) => emitBlockChunk(text, options) });

783+

if (options?.final) {

784+

let pendingChunk: string | undefined;

785+

blockChunker.drain({

786+

force: true,

787+

emit: (text) => {

788+

if (pendingChunk !== undefined) {

789+

emitBlockChunk(pendingChunk, {

790+

assistantMessageIndex: options.assistantMessageIndex,

791+

});

792+

}

793+

pendingChunk = text;

794+

},

795+

});

796+

if (pendingChunk !== undefined) {

797+

emitBlockChunk(pendingChunk, {

798+

assistantMessageIndex: options.assistantMessageIndex,

799+

final: true,

800+

});

801+

}

802+

} else {

803+

blockChunker.drain({ force: true, emit: (text) => emitBlockChunk(text, options) });

804+

}

778805

blockChunker.reset();

779806

} else if (state.blockBuffer.length > 0) {

780807

emitBlockChunk(state.blockBuffer, options);

781808

state.blockBuffer = "";

782809

}

810+

if (options?.final) {

811+

emitBlockChunk("", options);

812+

}

783813

if (pendingBlockReplyTasks.size === 0) {

784814

return;

785815

}