

























@@ -327,6 +327,31 @@ type FallbackRunnerParams = {
327327type EmbeddedAgentParams = {
328328lifecycleGeneration?: string;
329329onExecutionStarted?: (info?: { lifecycleGeneration?: string }) => void;
330+onExecutionPhase?: (info: {
331+phase:
332+| "runner_entered"
333+| "workspace"
334+| "runtime_plugins"
335+| "before_agent_reply"
336+| "model_resolution"
337+| "auth"
338+| "context_engine"
339+| "attempt_dispatch"
340+| "context_assembled"
341+| "turn_accepted"
342+| "process_spawned"
343+| "tool_execution_started"
344+| "assistant_output_started"
345+| "model_call_started";
346+provider?: string;
347+model?: string;
348+backend?: string;
349+source?: string;
350+tool?: string;
351+toolCallId?: string;
352+itemId?: string;
353+firstModelCallStarted?: boolean;
354+}) => void;
330355onBlockReply?: (payload: { text?: string; mediaUrls?: string[] }) => Promise<void> | void;
331356onToolResult?: (payload: { text?: string; mediaUrls?: string[] }) => Promise<void> | void;
332357onItemEvent?: (payload: {
@@ -361,6 +386,7 @@ function createMockTypingSignaler(): TypingSignaler {
361386signalTextDelta: vi.fn(async () => {}),
362387signalReasoningDelta: vi.fn(async () => {}),
363388signalToolStart: vi.fn(async () => {}),
389+signalExecutionActivity: vi.fn(async () => {}),
364390};
365391}
366392@@ -515,6 +541,7 @@ function createMinimalRunAgentTurnParams(overrides?: {
515541opts?: GetReplyOptions;
516542replyOperation?: ReplyOperation;
517543sessionCtx?: TemplateContext;
544+typingSignals?: TypingSignaler;
518545}) {
519546return {
520547commandBody: "fix it",
@@ -527,7 +554,7 @@ function createMinimalRunAgentTurnParams(overrides?: {
527554} as unknown as TemplateContext),
528555opts: overrides?.opts ?? ({} satisfies GetReplyOptions),
529556replyOperation: overrides?.replyOperation,
530-typingSignals: createMockTypingSignaler(),
557+typingSignals: overrides?.typingSignals ?? createMockTypingSignaler(),
531558blockReplyPipeline: null,
532559blockStreamingEnabled: false,
533560resolvedBlockStreamingBreak: "message_end" as const,
@@ -1327,6 +1354,73 @@ describe("runAgentTurnWithFallback", () => {
13271354});
13281355});
132913561357+it("signals typing from embedded harness execution phases before assistant text", async () => {
1358+const typingSignals = createMockTypingSignaler();
1359+const onAgentRunStart = vi.fn();
1360+state.runEmbeddedAgentMock.mockImplementationOnce(async (params: EmbeddedAgentParams) => {
1361+params.onExecutionPhase?.({
1362+phase: "model_call_started",
1363+provider: "openai",
1364+model: "gpt-5.4",
1365+firstModelCallStarted: true,
1366+});
1367+return { payloads: [{ text: "final" }], meta: {} };
1368+});
1369+1370+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
1371+const result = await runAgentTurnWithFallback({
1372+ ...createMinimalRunAgentTurnParams({
1373+opts: {
1374+ onAgentRunStart,
1375+} satisfies GetReplyOptions,
1376+}),
1377+ typingSignals,
1378+});
1379+1380+expect(result.kind).toBe("success");
1381+expect(typingSignals.signalExecutionActivity).toHaveBeenCalledOnce();
1382+expect(typingSignals.signalRunStart).not.toHaveBeenCalled();
1383+expect(onAgentRunStart).toHaveBeenCalledOnce();
1384+});
1385+1386+it("forwards CLI harness execution phases into typing signals", async () => {
1387+state.isCliProviderMock.mockReturnValue(true);
1388+state.runWithModelFallbackMock.mockImplementationOnce(async (params: FallbackRunnerParams) => ({
1389+result: await params.run("codex-cli", "gpt-5.4"),
1390+provider: "codex-cli",
1391+model: "gpt-5.4",
1392+attempts: [],
1393+}));
1394+state.runCliAgentMock.mockImplementationOnce(async (params: EmbeddedAgentParams) => {
1395+params.onExecutionPhase?.({
1396+phase: "process_spawned",
1397+provider: "codex-cli",
1398+model: "gpt-5.4",
1399+backend: "codex",
1400+});
1401+return { payloads: [{ text: "final" }], meta: {} };
1402+});
1403+const followupRun = createFollowupRun();
1404+followupRun.run.provider = "codex-cli";
1405+followupRun.run.model = "gpt-5.4";
1406+const typingSignals = createMockTypingSignaler();
1407+1408+const runAgentTurnWithFallback = await getRunAgentTurnWithFallback();
1409+const result = await runAgentTurnWithFallback(
1410+createMinimalRunAgentTurnParams({
1411+ followupRun,
1412+ typingSignals,
1413+}),
1414+);
1415+1416+expect(result.kind).toBe("success");
1417+expect(typingSignals.signalExecutionActivity).toHaveBeenCalledOnce();
1418+expectMockCallArgFields(state.runCliAgentMock, 0, "CLI run params", {
1419+provider: "codex-cli",
1420+model: "gpt-5.4",
1421+});
1422+});
1423+13301424it("registers run ownership before asynchronous image preflight", async () => {
13311425const agentEvents = await import("../../infra/agent-events.js");
13321426const registerAgentRunContext = vi.mocked(agentEvents.registerAgentRunContext);
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。