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

推荐订阅源

Stack Overflow Blog
Stack Overflow Blog
L
LangChain Blog
人人都是产品经理
人人都是产品经理
酷 壳 – CoolShell
酷 壳 – CoolShell
T
Tailwind CSS Blog
N
Netflix TechBlog - Medium
Microsoft Security Blog
Microsoft Security Blog
J
Java Code Geeks
博客园 - 【当耐特】
量子位
有赞技术团队
有赞技术团队
Jina AI
Jina AI
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
博客园_首页
C
Check Point Blog
B
Blog RSS Feed
M
MIT News - Artificial intelligence
H
Help Net Security
雷峰网
雷峰网
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 聂微东
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
A
About on SuperTechFans
腾讯CDC

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
perf: skip per-chunk live parsing for subagents · opencla...
2026-06-23 · via Recent Commits to openclaw:main
Original file line numberDiff line numberDiff line change

@@ -39,6 +39,7 @@ import { runEmbeddedAgent, type EmbeddedAgentRunResult } from "../embedded-agent

3939

import { FailoverError } from "../failover-error.js";

4040

import { runAgentHarnessBeforeMessageWriteHook } from "../harness/hook-helpers.js";

4141

import { resolveAvailableAgentHarnessPolicy } from "../harness/selection.js";

42+

import { AGENT_LANE_SUBAGENT } from "../lanes.js";

4243

import { resolveCliRuntimeExecutionProvider } from "../model-runtime-aliases.js";

4344

import { isCliProvider } from "../model-selection.js";

4445

import { resolveOpenAIRuntimeProvider } from "../openai-routing.js";

@@ -804,6 +805,9 @@ export function runAgentAttempt(params: {

804805

runId: params.runId,

805806

lifecycleGeneration: params.lifecycleGeneration,

806807

lane: params.opts.lane,

808+

// Subagents have no live stream consumer (result is read back from the

809+

// persisted transcript), so skip per-chunk live visible-text parsing.

810+

suppressLiveStreamOutput: params.opts.lane === AGENT_LANE_SUBAGENT,

807811

abortSignal: params.opts.abortSignal,

808812

extraSystemPrompt: params.opts.extraSystemPrompt,

809813

bootstrapContextMode: params.opts.bootstrapContextMode,

Original file line numberDiff line numberDiff line change

@@ -27,6 +27,7 @@ function firstAttemptParams(): {

2727

modelRun?: boolean;

2828

promptMode?: string;

2929

promptCacheKey?: string;

30+

suppressLiveStreamOutput?: boolean;

3031

} {

3132

const call = mockedRunEmbeddedAttempt.mock.calls[0] as

3233

| [

@@ -35,6 +36,7 @@ function firstAttemptParams(): {

3536

modelRun?: boolean;

3637

promptMode?: string;

3738

promptCacheKey?: string;

39+

suppressLiveStreamOutput?: boolean;

3840

},

3941

]

4042

| undefined;

@@ -187,4 +189,15 @@ describe("runEmbeddedAgent cron before_agent_reply seam", () => {

187189
188190

expect(firstAttemptParams().promptCacheKey).toBe("cron-cache-key");

189191

});

192+
193+

it("forwards suppressed live stream output into the embedded attempt", async () => {

194+

mockedRunEmbeddedAttempt.mockResolvedValueOnce(makeAttemptResult({ promptError: null }));

195+
196+

await runEmbeddedAgent({

197+

...overflowBaseRunParams,

198+

suppressLiveStreamOutput: true,

199+

});

200+
201+

expect(firstAttemptParams().suppressLiveStreamOutput).toBe(true);

202+

});

190203

});

Original file line numberDiff line numberDiff line change

@@ -2181,6 +2181,7 @@ async function runEmbeddedAgentInternal(

21812181

ownerNumbers: params.ownerNumbers,

21822182

enforceFinalTag: params.enforceFinalTag,

21832183

silentExpected: params.silentExpected,

2184+

suppressLiveStreamOutput: params.suppressLiveStreamOutput,

21842185

bootstrapContextMode: params.bootstrapContextMode,

21852186

bootstrapContextRunKind: params.bootstrapContextRunKind,

21862187

jobId: params.jobId,

Original file line numberDiff line numberDiff line change

@@ -3606,6 +3606,7 @@ export async function runEmbeddedAttempt(

36063606

},

36073607

enforceFinalTag: params.enforceFinalTag,

36083608

silentExpected: params.silentExpected,

3609+

suppressLiveStreamOutput: params.suppressLiveStreamOutput,

36093610

config: params.config,

36103611

sessionKey: sandboxSessionKey,

36113612

currentChannelId: params.currentChannelId,

Original file line numberDiff line numberDiff line change

@@ -256,6 +256,8 @@ export type RunEmbeddedAgentParams = {

256256

ownerNumbers?: string[];

257257

enforceFinalTag?: boolean;

258258

silentExpected?: boolean;

259+

/** Skip per-chunk live visible-text parsing when no live stream consumer exists (e.g. subagents). */

260+

suppressLiveStreamOutput?: boolean;

259261

/**

260262

* Treat a clean empty assistant stop as an intentional silent reply.

261263

* Only set when the caller's prompt policy already allows an exact NO_REPLY

Original file line numberDiff line numberDiff line change

@@ -694,15 +694,23 @@ export function handleMessageUpdate(

694694

if (isPhasePendingOpenAiResponsesTextItem) {

695695

return;

696696

}

697+

// Subagents have no live consumer; their final result is delivered from

698+

// message_end. Keep accumulating deltaBuffer, but skip per-chunk visible-text

699+

// parsing so long parallel subagent streams do not monopolize the event loop.

700+

const skipLiveStream = ctx.params.suppressLiveStreamOutput === true;

697701

const shouldUsePhaseAwareBlockReply = Boolean(deliveryPhase);

698702
699703

if (chunk) {

700704

ctx.state.deltaBuffer += chunk;

701-

if (!shouldUsePhaseAwareBlockReply) {

705+

if (!skipLiveStream && !shouldUsePhaseAwareBlockReply) {

702706

appendBlockReplyChunk(ctx, chunk);

703707

}

704708

}

705709
710+

if (skipLiveStream) {

711+

return;

712+

}

713+
706714

if (!suppressMessageToolOnlySourceReplyOutput && ctx.state.streamReasoning) {

707715

// Handle partial <think> tags: stream whatever reasoning is visible so far.

708716

ctx.emitReasoningStream(extractThinkingFromTaggedStream(ctx.state.deltaBuffer));

Original file line numberDiff line numberDiff line change

@@ -359,6 +359,29 @@ describe("subscribeEmbeddedAgentSession", () => {

359359

},

360360

);

361361
362+

it("suppressLiveStreamOutput skips per-chunk preview but still delivers final text", () => {

363+

const onAgentEvent = vi.fn();

364+

const { emit } = createSubscribedHarness({

365+

runId: "run",

366+

onAgentEvent,

367+

suppressLiveStreamOutput: true,

368+

});

369+
370+

emit({ type: "message_start", message: { role: "assistant" } });

371+

emitAssistantTextDelta(emit, "Hello ");

372+

emitAssistantTextDelta(emit, "world");

373+
374+

// No live preview events while suppressed (the per-chunk parsing path is skipped).

375+

expect(extractAgentEventPayloads(onAgentEvent.mock.calls)).toHaveLength(0);

376+
377+

const assistantMessage = {

378+

role: "assistant",

379+

content: [{ type: "text", text: "Hello world" }],

380+

} as AssistantMessage;

381+

emit({ type: "message_end", message: assistantMessage });

382+

expectSingleAgentEventText(onAgentEvent.mock.calls, "Hello world");

383+

});

384+
362385

it("blocks local MEDIA urls from case-variant tool names in verbose output", async () => {

363386

const onToolResult = vi.fn();

364387

const { emit } = createSubscribedHarness({

Original file line numberDiff line numberDiff line change

@@ -95,6 +95,13 @@ export type SubscribeEmbeddedAgentSessionParams = {

9595

onBeforeLifecycleTerminal?: () => void | Promise<void>;

9696

enforceFinalTag?: boolean;

9797

silentExpected?: boolean;

98+

/**

99+

* Skip per-chunk live visible-text parsing in handleMessageUpdate. Set for runs

100+

* with no live stream consumer — notably subagents, whose result is read back

101+

* from the final message_end path. Suppressing intermediate passes does not

102+

* change final output.

103+

*/

104+

suppressLiveStreamOutput?: boolean;

98105

config?: OpenClawConfig;

99106

sessionKey?: string;

100107

/** Current transport channel resolved for this run. */