fix(agent): stabilize large tool results
Generic Container CI/CD / test-build-publish (push) Successful in 1m53s
Agent CI/CD v2 / build-test-publish-and-deploy (push) Successful in 1m53s

This commit is contained in:
2026-08-25 12:02:48 +08:00
parent 774f39cbbe
commit 004c9bb72d
17 changed files with 721 additions and 62 deletions
+45
View File
@@ -7,6 +7,10 @@ import { resolve } from "node:path";
import { config } from "../config.js";
import { logger } from "../logger.js";
import {
cleanupExpiredToolOutputs,
resolveOpencodeToolOutputDirectory,
} from "./opencodeToolOutputCleanup.js";
const isDevelopmentDebugLoggingEnabled = process.env.NODE_ENV === "development";
@@ -46,6 +50,7 @@ const getRuntimeMessageId = (message: RuntimeMessage) => message.info.id;
export class OpencodeRuntimeAdapter {
private clientPromise: Promise<OpencodeClient> | null = null;
private closeServer: (() => void) | null = null;
private toolOutputCleanupTimer: ReturnType<typeof setInterval> | null = null;
async ensureClient(): Promise<OpencodeClient> {
if (!this.clientPromise) {
@@ -380,12 +385,18 @@ export class OpencodeRuntimeAdapter {
}
async dispose(): Promise<void> {
if (this.toolOutputCleanupTimer) {
clearInterval(this.toolOutputCleanupTimer);
this.toolOutputCleanupTimer = null;
}
this.closeServer?.();
this.closeServer = null;
this.clientPromise = null;
}
private async bootstrapClient(): Promise<OpencodeClient> {
await this.cleanupToolOutputs();
// embedded 模式下,把服务内工具桥地址注入到 opencode 进程环境里,
// 这样 .opencode/tools 下的自定义工具可以回调本服务。
process.env.TJWATER_AGENT_INTERNAL_BASE_URL = `http://127.0.0.1:${config.PORT}`;
@@ -436,9 +447,39 @@ export class OpencodeRuntimeAdapter {
this.closeServer = () => {
runtime.server.close();
};
this.startToolOutputCleanupLoop();
return runtime.client;
}
private async cleanupToolOutputs(): Promise<void> {
const directory = resolveOpencodeToolOutputDirectory();
const ttlMs = config.RESULT_REF_TTL_HOURS * 60 * 60 * 1000;
try {
const result = await cleanupExpiredToolOutputs(directory, ttlMs);
if (result.removed > 0) {
logger.info(
{ directory, ...result },
"removed expired opencode tool output files",
);
}
} catch (error) {
logger.warn(
{ err: error, directory },
"failed to clean expired opencode tool output files",
);
}
}
private startToolOutputCleanupLoop(): void {
if (this.toolOutputCleanupTimer) {
return;
}
this.toolOutputCleanupTimer = setInterval(() => {
void this.cleanupToolOutputs();
}, config.RESULT_REF_CLEANUP_INTERVAL_MS);
this.toolOutputCleanupTimer.unref();
}
}
export const opencodeRuntime = new OpencodeRuntimeAdapter();
@@ -448,6 +489,10 @@ function buildOpencodeConfig(): Record<string, unknown> {
deepMerge(readProjectOpencodeConfig(), readEnvOpencodeConfig()),
{
model: config.OPENCODE_MODEL,
tool_output: {
max_bytes: config.MAX_INLINE_RESULT_BYTES,
max_lines: 2000,
},
},
);
}