
























@@ -1194,6 +1194,110 @@ describe("runAgentTurnWithFallback", () => {
11941194});
11951195});
119611961197+it("emits an embedded lifecycle terminal backstop when the runner returns without one", async () => {
1198+const agentEvents = await import("../../infra/agent-events.js");
1199+const emitAgentEvent = vi.mocked(agentEvents.emitAgentEvent);
1200+state.runEmbeddedPiAgentMock.mockImplementationOnce(async (params: EmbeddedAgentParams) => {
1201+await params.onAgentEvent?.({
1202+stream: "lifecycle",
1203+data: { phase: "start", startedAt: 1_000 },
1204+});
1205+return {
1206+payloads: [{ text: "Request timed out before a response was generated.", isError: true }],
1207+meta: { aborted: true, livenessState: "blocked", replayInvalid: true },
1208+};
1209+});
1210+1211+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
1212+const result = await runAgentTurnWithFallback({
1213+commandBody: "hello",
1214+followupRun: createFollowupRun(),
1215+sessionCtx: {
1216+Provider: "whatsapp",
1217+MessageSid: "msg",
1218+} as unknown as TemplateContext,
1219+opts: { runId: "run-timeout" } as GetReplyOptions,
1220+typingSignals: createMockTypingSignaler(),
1221+blockReplyPipeline: null,
1222+blockStreamingEnabled: false,
1223+resolvedBlockStreamingBreak: "message_end",
1224+applyReplyToMode: (payload) => payload,
1225+shouldEmitToolResult: () => true,
1226+shouldEmitToolOutput: () => false,
1227+pendingToolTasks: new Set(),
1228+resetSessionAfterCompactionFailure: async () => false,
1229+resetSessionAfterRoleOrderingConflict: async () => false,
1230+isHeartbeat: false,
1231+sessionKey: "main",
1232+getActiveSessionEntry: () => undefined,
1233+resolvedVerboseLevel: "off",
1234+});
1235+1236+expect(result.kind).toBe("success");
1237+expect(emitAgentEvent).toHaveBeenCalledWith({
1238+runId: "run-timeout",
1239+sessionKey: "main",
1240+stream: "lifecycle",
1241+data: {
1242+phase: "end",
1243+startedAt: 1_000,
1244+endedAt: expect.any(Number),
1245+aborted: true,
1246+livenessState: "blocked",
1247+replayInvalid: true,
1248+},
1249+});
1250+});
1251+1252+it("does not duplicate embedded lifecycle terminal events already reported by the runner", async () => {
1253+const agentEvents = await import("../../infra/agent-events.js");
1254+const emitAgentEvent = vi.mocked(agentEvents.emitAgentEvent);
1255+state.runEmbeddedPiAgentMock.mockImplementationOnce(async (params: EmbeddedAgentParams) => {
1256+await params.onAgentEvent?.({
1257+stream: "lifecycle",
1258+data: { phase: "start", startedAt: 1_000 },
1259+});
1260+await params.onAgentEvent?.({
1261+stream: "lifecycle",
1262+data: { phase: "end", endedAt: 1_500 },
1263+});
1264+return { payloads: [{ text: "final" }], meta: {} };
1265+});
1266+1267+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
1268+const result = await runAgentTurnWithFallback({
1269+commandBody: "hello",
1270+followupRun: createFollowupRun(),
1271+sessionCtx: {
1272+Provider: "whatsapp",
1273+MessageSid: "msg",
1274+} as unknown as TemplateContext,
1275+opts: { runId: "run-complete" } as GetReplyOptions,
1276+typingSignals: createMockTypingSignaler(),
1277+blockReplyPipeline: null,
1278+blockStreamingEnabled: false,
1279+resolvedBlockStreamingBreak: "message_end",
1280+applyReplyToMode: (payload) => payload,
1281+shouldEmitToolResult: () => true,
1282+shouldEmitToolOutput: () => false,
1283+pendingToolTasks: new Set(),
1284+resetSessionAfterCompactionFailure: async () => false,
1285+resetSessionAfterRoleOrderingConflict: async () => false,
1286+isHeartbeat: false,
1287+sessionKey: "main",
1288+getActiveSessionEntry: () => undefined,
1289+resolvedVerboseLevel: "off",
1290+});
1291+1292+expect(result.kind).toBe("success");
1293+expect(emitAgentEvent).not.toHaveBeenCalledWith(
1294+expect.objectContaining({
1295+runId: "run-complete",
1296+stream: "lifecycle",
1297+}),
1298+);
1299+});
1300+11971301it("trims chatty GPT ack-turn final prose", async () => {
11981302state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => ({
11991303result: await params.run("openai", "gpt-5.4"),
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。