






















@@ -4,7 +4,10 @@ import {
44} from "../infra/outbound/best-effort-delivery.js";
55import { sendMessage } from "../infra/outbound/message.js";
66import { isCronSessionKey, isSubagentSessionKey } from "../sessions/session-key-utils.js";
7-import { normalizeLowercaseStringOrEmpty } from "../shared/string-coerce.js";
7+import {
8+normalizeLowercaseStringOrEmpty,
9+normalizeOptionalString,
10+} from "../shared/string-coerce.js";
811import { isGatewayMessageChannel, normalizeMessageChannel } from "../utils/message-channel.js";
912import { buildExecApprovalFollowupIdempotencyKey } from "./bash-tools.exec-approval-followup-state.js";
1013import {
@@ -124,6 +127,51 @@ function buildSessionResumeFallbackPrefix(): string {
124127return "Automatic session resume failed, so sending the status directly.\n\n";
125128}
126129130+function readGatewayStatus(value: unknown): string | undefined {
131+return value && typeof value === "object" && !Array.isArray(value)
132+ ? normalizeOptionalString((value as { status?: unknown }).status)
133+ : undefined;
134+}
135+136+function readGatewayRunId(value: unknown): string | undefined {
137+return value && typeof value === "object" && !Array.isArray(value)
138+ ? normalizeOptionalString((value as { runId?: unknown }).runId)
139+ : undefined;
140+}
141+142+function buildFollowupWaitError(params: { status?: string; error?: unknown }): Error {
143+const suffix =
144+typeof params.error === "string" && params.error.trim()
145+ ? `: ${params.error.trim()}`
146+ : params.status
147+ ? `: ${params.status}`
148+ : "";
149+return new Error(`exec approval followup session resume failed${suffix}`);
150+}
151+152+function isSuccessfulFollowupStatus(status: string | undefined): boolean {
153+return status === "ok";
154+}
155+156+async function waitForAgentFollowupRun(params: {
157+runId: string;
158+timeoutMs: number;
159+}): Promise<void> {
160+const wait = await callGatewayTool(
161+"agent.wait",
162+{ timeoutMs: params.timeoutMs + 2_000 },
163+{
164+runId: params.runId,
165+timeoutMs: params.timeoutMs,
166+},
167+);
168+const status = readGatewayStatus(wait);
169+if (isSuccessfulFollowupStatus(status)) {
170+return;
171+}
172+throw buildFollowupWaitError({ status, error: wait.error });
173+}
174+127175function shouldPrefixDirectFollowupWithSessionResumeFailure(params: {
128176resultText: string;
129177sessionError: unknown;
@@ -249,25 +297,34 @@ export async function sendExecApprovalFollowup(
249297250298if (sessionKey && params.direct !== true) {
251299try {
252-await callGatewayTool(
253-"agent",
254-{ timeoutMs: 60_000 },
255-buildAgentFollowupArgs({
256-approvalId: params.approvalId,
257- sessionKey,
258- resultText,
259- deliveryTarget,
260- sessionOnlyOriginChannel,
261-turnSourceChannel: params.turnSourceChannel,
262-turnSourceTo: params.turnSourceTo,
263-turnSourceAccountId: params.turnSourceAccountId,
264-turnSourceThreadId: params.turnSourceThreadId,
265-internalRuntimeHandoffId: params.internalRuntimeHandoffId,
266-idempotencyKey: params.idempotencyKey,
267-}),
268-{ expectFinal: true },
269-);
270-return true;
300+const agentArgs = buildAgentFollowupArgs({
301+approvalId: params.approvalId,
302+ sessionKey,
303+ resultText,
304+ deliveryTarget,
305+ sessionOnlyOriginChannel,
306+turnSourceChannel: params.turnSourceChannel,
307+turnSourceTo: params.turnSourceTo,
308+turnSourceAccountId: params.turnSourceAccountId,
309+turnSourceThreadId: params.turnSourceThreadId,
310+internalRuntimeHandoffId: params.internalRuntimeHandoffId,
311+idempotencyKey: params.idempotencyKey,
312+});
313+const accepted = await callGatewayTool("agent", { timeoutMs: 60_000 }, agentArgs);
314+const status = readGatewayStatus(accepted);
315+if (isSuccessfulFollowupStatus(status)) {
316+return true;
317+}
318+if (status === "accepted" || status === "in_flight" || status === "pending") {
319+const runId =
320+readGatewayRunId(accepted) ?? normalizeOptionalString(agentArgs.idempotencyKey);
321+if (!runId) {
322+throw buildFollowupWaitError({ status: "missing-run-id" });
323+}
324+await waitForAgentFollowupRun({ runId, timeoutMs: 60_000 });
325+return true;
326+}
327+throw buildFollowupWaitError({ status, error: accepted.error });
271328} catch (err) {
272329sessionError = err;
273330}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。