From da80ba1cb0ebf560ddec83f93fabb0e6fd7a658e Mon Sep 17 00:00:00 2001 From: yushen Date: Fri, 30 Jan 2026 11:52:01 +0800 Subject: [PATCH] refactor(agent): simplify AsyncAgent to use result.text instead of stream interception Replace stdout/stderr stream interception with direct result.text push to Channel. Also fix queued tasks still executing after close(). Co-Authored-By: Claude Opus 4.5 --- src/agent/async-agent.ts | 38 ++++++++------------------------------ 1 file changed, 8 insertions(+), 30 deletions(-) diff --git a/src/agent/async-agent.ts b/src/agent/async-agent.ts index f979fb8d..06f753bb 100644 --- a/src/agent/async-agent.ts +++ b/src/agent/async-agent.ts @@ -3,6 +3,8 @@ import { Agent } from "./runner.js"; import { Channel } from "./channel.js"; import type { AgentOptions, Message } from "./types.js"; +const devNull = { write: () => true } as NodeJS.WritableStream; + export class AsyncAgent { private readonly agent: Agent; private readonly channel = new Channel(); @@ -13,10 +15,7 @@ export class AsyncAgent { constructor(options?: AgentOptions) { this.agent = new Agent({ ...options, - logger: { - stdout: this.createChannelStream("[assistant] "), - stderr: this.createChannelStream("[tool] "), - }, + logger: { stdout: devNull, stderr: devNull }, }); this.sessionId = this.agent.sessionId; } @@ -31,12 +30,13 @@ export class AsyncAgent { this.queue = this.queue .then(async () => { + if (this._closed) return; const result = await this.agent.run(content); + if (result.text) { + this.channel.send({ id: uuidv7(), content: result.text }); + } if (result.error) { - this.channel.send({ - id: uuidv7(), - content: `[error] ${result.error}`, - }); + this.channel.send({ id: uuidv7(), content: `[error] ${result.error}` }); } }) .catch((err) => { @@ -56,26 +56,4 @@ export class AsyncAgent { this._closed = true; this.channel.close(); } - - private createChannelStream(prefix: string): NodeJS.WritableStream { - let buffer = ""; - return { - write: (chunk: any) => { - if (this._closed) return false; - const text = - typeof chunk === "string" - ? chunk - : chunk?.toString?.() ?? String(chunk); - if (!text) return true; - buffer += text; - const parts = buffer.split("\n"); - buffer = parts.pop() ?? ""; - for (const part of parts) { - if (part.length === 0) continue; - this.channel.send({ id: uuidv7(), content: `${prefix}${part}` }); - } - return true; - }, - } as NodeJS.WritableStream; - } }