






















@@ -2,6 +2,7 @@ import type { ReplyPayload } from "../auto-reply/reply-payload.js";
22import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
33import { formatErrorMessage } from "../infra/errors.js";
44import { createSubsystemLogger } from "../logging/subsystem.js";
5+import { isClaudeCliProvider } from "../plugin-sdk/anthropic-cli.js";
56import { buildAgentHookContextChannelFields } from "../plugins/hook-agent-context.js";
67import { resolveBlockMessage } from "../plugins/hook-decision-types.js";
78import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
@@ -11,6 +12,7 @@ import {
1112loadCliSessionHistoryMessages,
1213} from "./cli-runner/session-history.js";
1314import type { PreparedCliRunContext, RunCliAgentParams } from "./cli-runner/types.js";
15+import { claudeCliSessionTranscriptHasContent as claudeCliSessionTranscriptHasContentImpl } from "./command/attempt-execution.helpers.js";
1416import { classifyFailoverReason, isFailoverErrorMessage } from "./embedded-agent-helpers.js";
1517import type { EmbeddedAgentRunResult } from "./embedded-agent-runner.js";
1618import { FailoverError, isFailoverError, resolveFailoverStatus } from "./failover-error.js";
@@ -32,6 +34,39 @@ import { SessionManager } from "./sessions/index.js";
32343335const log = createSubsystemLogger("agents/cli-runner");
343637+const cliRunnerDeps = {
38+claudeCliSessionTranscriptHasContent: claudeCliSessionTranscriptHasContentImpl,
39+};
40+41+export function setCliRunnerTestDeps(overrides: Partial<typeof cliRunnerDeps>): void {
42+Object.assign(cliRunnerDeps, overrides);
43+}
44+45+export function restoreCliRunnerTestDeps(): void {
46+cliRunnerDeps.claudeCliSessionTranscriptHasContent = claudeCliSessionTranscriptHasContentImpl;
47+}
48+49+export async function isCliBindingFlushed(
50+sessionId: string | undefined,
51+provider: string | undefined,
52+): Promise<boolean> {
53+if (!provider || !isClaudeCliProvider(provider)) {
54+return true;
55+}
56+if (!sessionId) {
57+return false;
58+}
59+for (const delayMs of [0, 50, 150]) {
60+if (delayMs > 0) {
61+await new Promise((resolve) => setTimeout(resolve, delayMs));
62+}
63+if (await cliRunnerDeps.claudeCliSessionTranscriptHasContent({ sessionId })) {
64+return true;
65+}
66+}
67+return false;
68+}
69+3570function flushSessionManagerFile(sessionManager: SessionManager): void {
3671(sessionManager as unknown as { rewriteFile?: () => void }).rewriteFile?.();
3772}
@@ -503,10 +538,21 @@ export async function runPreparedCliAgent(
503538const buildCliRunResult = (resultParams: {
504539output: Awaited<ReturnType<typeof executePreparedCliRun>>;
505540effectiveCliSessionId?: string;
541+bindingFlushOk?: boolean;
506542}): EmbeddedAgentRunResult => {
507543const text = resultParams.output.text?.trim();
508544const rawText = resultParams.output.rawText?.trim();
509545const payloads = text ? [{ text }] : undefined;
546+const unflushedCliSessionId =
547+resultParams.effectiveCliSessionId && resultParams.bindingFlushOk === false
548+ ? resultParams.effectiveCliSessionId
549+ : undefined;
550+const persistedCliSessionId = unflushedCliSessionId
551+ ? undefined
552+ : resultParams.effectiveCliSessionId;
553+const agentSessionId = unflushedCliSessionId
554+ ? ""
555+ : (resultParams.effectiveCliSessionId ?? params.sessionId ?? "");
510556511557return {
512558 payloads,
@@ -545,15 +591,15 @@ export async function runPreparedCliAgent(
545591refusal: false,
546592},
547593agentMeta: {
548-sessionId: resultParams.effectiveCliSessionId ?? params.sessionId ?? "",
594+sessionId: agentSessionId,
549595provider: params.provider,
550596model: context.modelId,
551597usage: resultParams.output.usage,
552598 ...(resultParams.output.usage ? { lastCallUsage: resultParams.output.usage } : {}),
553- ...(resultParams.effectiveCliSessionId
599+ ...(persistedCliSessionId
554600 ? {
555601cliSessionBinding: {
556-sessionId: resultParams.effectiveCliSessionId,
602+sessionId: persistedCliSessionId,
557603 ...(context.effectiveAuthProfileId
558604 ? { authProfileId: context.effectiveAuthProfileId }
559605 : {}),
@@ -672,6 +718,7 @@ export async function runPreparedCliAgent(
672718 assistantText,
673719 output,
674720});
721+const bindingFlushOk = await isCliBindingFlushed(effectiveCliSessionId, params.provider);
675722await runCliAgentEndHook(params, {
676723event: {
677724messages: buildAgentEndMessages(lastAssistant),
@@ -681,7 +728,7 @@ export async function runPreparedCliAgent(
681728ctx: hookContext,
682729 hookRunner,
683730});
684-return buildCliRunResult({ output, effectiveCliSessionId });
731+return buildCliRunResult({ output, effectiveCliSessionId, bindingFlushOk });
685732} catch (err) {
686733if (isFailoverError(err)) {
687734const retryableSessionId = context.reusableCliSession.sessionId ?? params.cliSessionId;
@@ -704,6 +751,10 @@ export async function runPreparedCliAgent(
704751 assistantText,
705752 output,
706753});
754+const bindingFlushOk = await isCliBindingFlushed(
755+effectiveCliSessionId,
756+params.provider,
757+);
707758await runCliAgentEndHook(params, {
708759event: {
709760messages: buildAgentEndMessages(lastAssistant),
@@ -713,7 +764,7 @@ export async function runPreparedCliAgent(
713764ctx: hookContext,
714765 hookRunner,
715766});
716-return buildCliRunResult({ output, effectiveCliSessionId });
767+return buildCliRunResult({ output, effectiveCliSessionId, bindingFlushOk });
717768} catch (retryErr) {
718769const retryMessage = formatErrorMessage(retryErr);
719770await runCliAgentEndHook(params, {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。