























@@ -37,6 +37,20 @@ function toFiniteNumber(value: unknown): number | undefined {
3737return typeof value === "number" && Number.isFinite(value) ? value : undefined;
3838}
393940+function normalizeStringArray(value: unknown): string[] {
41+if (!Array.isArray(value)) {
42+return [];
43+}
44+return value.filter((item): item is string => typeof item === "string" && item.length > 0);
45+}
46+47+function formatProxyEnvSummary(keys: string[]): string {
48+if (keys.length === 0) {
49+return "proxy env: none";
50+}
51+return `proxy env: ${keys.join(", ")}`;
52+}
53+4054function resolveAcpStreamLogPathFromSessionFile(sessionFile: string, sessionId: string): string {
4155const baseDir = path.dirname(path.resolve(sessionFile));
4256return path.join(baseDir, `${sessionId}.acp-stream.jsonl`);
@@ -243,6 +257,11 @@ export function startAcpSpawnParentStreamRelay(params: {
243257let pendingText = "";
244258let lastProgressAt = Date.now();
245259let stallNotified = false;
260+let promptSubmittedAt: number | undefined;
261+let firstRuntimeEventAt: number | undefined;
262+let firstVisibleOutputAt: number | undefined;
263+let lastRuntimeEventType: string | undefined;
264+let proxyEnvKeysAtPrompt: string[] = [];
246265let flushTimer: NodeJS.Timeout | undefined;
247266let relayLifetimeTimer: NodeJS.Timeout | undefined;
248267@@ -284,6 +303,34 @@ export function startAcpSpawnParentStreamRelay(params: {
284303flushTimer.unref?.();
285304};
286305306+const buildNoOutputNotice = () => {
307+const seconds = Math.round(noOutputNoticeMs / 1000);
308+if (!promptSubmittedAt) {
309+return {
310+summary: `No prompt submission observed for ${seconds}s after child start.`,
311+text: `${relayLabel} session started but no prompt submission was observed for ${seconds}s.`,
312+};
313+}
314+if (!firstRuntimeEventAt) {
315+const proxySummary = formatProxyEnvSummary(proxyEnvKeysAtPrompt);
316+return {
317+summary: `Prompt submitted but no ACP runtime event for ${seconds}s (${proxySummary}).`,
318+text: `${relayLabel} prompt was submitted but no ACP runtime event arrived for ${seconds}s (${proxySummary}). Check upstream connectivity, auth, or proxy/network access in the gateway child environment.`,
319+};
320+}
321+if (!firstVisibleOutputAt) {
322+const lastEvent = lastRuntimeEventType ? ` Last ACP event: ${lastRuntimeEventType}.` : "";
323+return {
324+summary: `ACP runtime active but no visible assistant output for ${seconds}s.${lastEvent}`,
325+text: `${relayLabel} has ACP runtime activity but no visible assistant output for ${seconds}s.${lastEvent} It may be working, blocked on a tool, or failing before visible output.`,
326+};
327+}
328+return {
329+summary: `No visible output for ${seconds}s. It may be waiting for input.`,
330+text: `${relayLabel} has produced no visible output for ${seconds}s. It may be waiting for interactive input.`,
331+};
332+};
333+287334const noOutputWatcherTimer = setInterval(() => {
288335if (disposed || noOutputNoticeMs <= 0) {
289336return;
@@ -295,17 +342,15 @@ export function startAcpSpawnParentStreamRelay(params: {
295342return;
296343}
297344stallNotified = true;
345+const notice = buildNoOutputNotice();
298346recordTaskRunProgressByRunId({
299347 runId,
300348runtime: "acp",
301349sessionKey: params.childSessionKey,
302350lastEventAt: Date.now(),
303-eventSummary: `No output for ${Math.round(noOutputNoticeMs / 1000)}s. It may be waiting for input.`,
351+eventSummary: notice.summary,
304352});
305-emit(
306-`${relayLabel} has produced no output for ${Math.round(noOutputNoticeMs / 1000)}s. It may be waiting for interactive input.`,
307-`${contextPrefix}:stall`,
308-);
353+emit(notice.text, `${contextPrefix}:stall`);
309354}, noOutputPollMs);
310355noOutputWatcherTimer.unref?.();
311356@@ -365,6 +410,7 @@ export function startAcpSpawnParentStreamRelay(params: {
365410}
366411367412lastProgressAt = Date.now();
413+firstVisibleOutputAt ??= lastProgressAt;
368414pendingText += delta;
369415if (pendingText.length > STREAM_BUFFER_MAX_CHARS) {
370416pendingText = pendingText.slice(-STREAM_BUFFER_MAX_CHARS);
@@ -377,6 +423,34 @@ export function startAcpSpawnParentStreamRelay(params: {
377423return;
378424}
379425426+if (event.stream === "acp") {
427+const data = event.data as
428+| {
429+phase?: unknown;
430+at?: unknown;
431+eventType?: unknown;
432+proxyEnvKeys?: unknown;
433+}
434+| undefined;
435+const phase = normalizeOptionalString(data?.phase);
436+logEvent("acp", { phase: phase ?? "unknown", data: event.data });
437+if (phase === "prompt_submitted") {
438+const at = toFiniteNumber(data?.at) ?? Date.now();
439+promptSubmittedAt ??= at;
440+proxyEnvKeysAtPrompt = normalizeStringArray(data?.proxyEnvKeys);
441+lastProgressAt = Date.now();
442+return;
443+}
444+if (phase === "runtime_event") {
445+const eventType = normalizeOptionalString(data?.eventType);
446+firstRuntimeEventAt ??= Date.now();
447+lastRuntimeEventType = eventType;
448+lastProgressAt = Date.now();
449+return;
450+}
451+return;
452+}
453+380454if (event.stream !== "lifecycle") {
381455return;
382456}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。