import { describe, expect, it, vi } from "vitest";
import { TaskExecutor } from "../executor";
import { DurableContextService } from "../../memory/DurableContextService";

vi.mock("electron", () => ({
  app: {
    getPath: vi.fn().mockReturnValue("/tmp"),
  },
}));

vi.mock("../custom-skill-loader", () => ({
  getCustomSkillLoader: () => ({
    getEnabledGuidelinesPrompt: () => "",
    rankModelInvocableSkillsForQuery: () => [],
  }),
}));

vi.mock("../../settings/memory-features-manager", () => ({
  MemoryFeaturesManager: {
    loadSettings: vi.fn().mockReturnValue({ contextPackInjectionEnabled: false }),
  },
}));

vi.mock("../../memory/DurableContextService", () => ({
  DurableContextService: {
    recordHistory: vi.fn(),
  },
}));

vi.mock("../../settings/personality-manager", () => ({
  PersonalityManager: {
    getPersonalityPrompt: vi.fn().mockReturnValue(""),
    getPersonalityPromptById: vi.fn().mockReturnValue(""),
    getIdentityPrompt: vi.fn().mockReturnValue(""),
  },
}));

describe("TaskExecutor chat mode", () => {
  const createInferredChatExecutor = (prompt: string, agentConfig: Record<string, unknown> = {}) => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    executor.task = {
      id: "task-inferred-chat",
      title: prompt,
      prompt,
      userPrompt: prompt,
      rawPrompt: prompt,
      createdAt: Date.now(),
      agentConfig: {
        executionMode: "execute",
        executionModeSource: "strategy",
        conversationMode: "chat",
        taskIntent: "chat",
        ...agentConfig,
      },
    };
    return executor;
  };

  const createExecuteUnlockedRoutingExecutor = (
    prompt: string,
    agentConfig: Record<string, unknown> = {},
  ) => {
    const executor = createInferredChatExecutor(prompt, agentConfig);
    executor.workspace = {
      id: "ws-routing",
      path: "/tmp",
      isTemp: true,
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    executor.daemon = {
      updateTaskStatus: vi.fn(),
      updateTask: vi.fn(),
      getTransientRetryCount: vi.fn().mockReturnValue(0),
    };
    executor.toolRegistry = {
      cleanup: vi.fn().mockResolvedValue(undefined),
    };
    executor.emitEvent = vi.fn();
    executor.handleCompanionPrompt = vi.fn().mockResolvedValue(undefined);
    executor.maybeHandleExplicitClaudeCodeDelegation = vi.fn().mockResolvedValue(false);
    executor.maybeHandleOnboardingSlashCommand = vi.fn().mockResolvedValue(false);
    executor.maybePrepareInitialGoalSlashCommand = vi.fn().mockResolvedValue(false);
    executor.maybeHandleScheduleSlashCommand = vi.fn().mockResolvedValue(false);
    executor.maybeHandleSkillSlashCommandOrInlineChain = vi.fn().mockResolvedValue(false);
    executor.maybeHandleNaturalLlmWikiPrompt = vi.fn().mockResolvedValue(undefined);
    executor.maybeAutoApplyExplicitSkillInvocation = vi.fn().mockResolvedValue(undefined);
    executor.maybeHandleHighConfidenceSkillRouting = vi.fn().mockResolvedValue(undefined);
    executor.analyzeTask = vi.fn().mockResolvedValue({ complexity: "simple" });
    executor.ensureVerificationOutcomeSets = vi.fn();
    executor.getBudgetConstrainedFailureStepIdSet = vi.fn().mockReturnValue(new Set());
    executor.nonBlockingVerificationFailedStepIds = new Set();
    executor.blockingVerificationFailedStepIds = new Set();
    executor.stepStopReasons = new Map();
    executor.taskFailureDomains = new Set();
    executor.completionVerificationMetadata = null;
    executor.terminalStatus = "ok";
    executor.failureClass = undefined;
    executor.cancelled = false;
    executor.lastUserMessage = prompt;
    executor.cancelReason = undefined;
    return executor;
  };

  it("records executor conversation history into durable context", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    executor.task = { id: "task-durable-history" };
    executor.workspace = {
      id: "ws-durable-history",
      path: "/tmp",
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    vi.mocked(DurableContextService.recordHistory).mockClear();

    (TaskExecutor as Any).prototype.updateConversationHistory.call(executor, [
      { role: "user", content: "Project codename: Lantern Harbor" },
      { role: "assistant", content: [{ type: "text", text: "Rollback phrase: blue anchor" }] },
    ]);

    expect(DurableContextService.recordHistory).toHaveBeenCalledWith({
      workspaceId: "ws-durable-history",
      taskId: "task-durable-history",
      source: "executor_history",
      messages: [
        { role: "user", content: "Project codename: Lantern Harbor" },
        { role: "assistant", content: [{ type: "text", text: "Rollback phrase: blue anchor" }] },
      ],
    });
    expect(executor.conversationHistory).toHaveLength(2);
  });

  it("promotes explicit chat PDF attachment turns to read-only analysis mode", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    executor.task = {
      id: "task-chat-pdf",
      title: "PDF chat",
      prompt: [
        "Summarize this PDF",
        "",
        "Attached files (relative to workspace):",
        "- report.pdf (.cowork/uploads/123/report.pdf)",
        "  Extracted content:",
        "    PDF attachment: report.pdf",
        "    Path: .cowork/uploads/123/report.pdf",
      ].join("\n"),
      userPrompt: "Summarize this PDF",
      rawPrompt: "Summarize this PDF",
      createdAt: Date.now(),
      agentConfig: {
        executionMode: "chat",
        executionModeSource: "user",
        conversationMode: "hybrid",
      },
    };

    expect((TaskExecutor as Any).prototype.getEffectiveExecutionMode.call(executor)).toBe(
      "analyze",
    );
    expect((TaskExecutor as Any).prototype.getEffectiveExecutionModeSource.call(executor)).toBe(
      "auto_promote",
    );
    expect((TaskExecutor as Any).prototype.isExplicitChatExecutionMode.call(executor)).toBe(false);
  });

  it("injects live parent status as a turn-scoped sidechat system block", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    executor.task = {
      id: "side-task",
      source: "side_chat",
      branchLabel: "side-chat",
      agentConfig: {
        conversationMode: "chat",
        executionMode: "chat",
        sideChatTurnContext: "LIVE_PARENT_STATUS\nParent task status: executing",
      },
    };
    executor.workspace = { path: "/tmp" };

    const blocks = (TaskExecutor as Any).prototype.buildChatOrThinkSystemBlocks.call(
      executor,
      false,
      {
        identityPrompt: "",
        roleContext: "",
        profileContext: "",
        personalityPrompt: "",
        extraChatRules: [],
      },
    );

    expect(blocks.some((block: Any) => block.text.includes("LIVE_PARENT_STATUS"))).toBe(true);
    expect(blocks.some((block: Any) => block.text.includes("authoritative for progress"))).toBe(
      true,
    );
  });

  it("returns a single chat response without entering the task pipeline", async () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    const companionPrompt = vi.fn().mockResolvedValue(undefined);
    const schedule = vi.fn().mockResolvedValue(false);
    const skillRouting = vi.fn().mockResolvedValue(false);
    const highConfidenceRouting = vi.fn().mockResolvedValue(false);

    executor.task = {
      id: "task-chat",
      title: "Who are you?",
      prompt: "Who are you?",
      userPrompt: "Who are you?",
      rawPrompt: "Who are you?",
      createdAt: Date.now(),
      agentConfig: {
        executionMode: "chat",
        conversationMode: "hybrid",
      },
    };
    executor.workspace = {
      id: "ws-chat",
      path: "/tmp",
      isTemp: true,
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    executor.daemon = {
      updateTaskStatus: vi.fn(),
      updateTask: vi.fn(),
    };
    executor.toolRegistry = {
      cleanup: vi.fn().mockResolvedValue(undefined),
    };
    executor.emitEvent = vi.fn();
    executor.handleCompanionPrompt = companionPrompt;
    executor.maybeHandleScheduleSlashCommand = schedule;
    executor.maybeHandleSkillSlashCommandOrInlineChain = skillRouting;
    executor.maybeHandleHighConfidenceSkillRouting = highConfidenceRouting;
    executor.getEffectiveExecutionMode = vi.fn().mockReturnValue("chat");
    executor.ensureVerificationOutcomeSets = vi.fn();
    executor.getBudgetConstrainedFailureStepIdSet = vi.fn().mockReturnValue(new Set());
    executor.nonBlockingVerificationFailedStepIds = new Set();
    executor.blockingVerificationFailedStepIds = new Set();
    executor.stepStopReasons = new Map();
    executor.taskFailureDomains = new Set();
    executor.completionVerificationMetadata = null;
    executor.terminalStatus = "ok";
    executor.failureClass = undefined;
    executor.cancelled = false;
    executor.lastUserMessage = "Who are you?";
    executor.cancelReason = undefined;
    executor.daemon.updateTaskStatus.mockClear();

    await (TaskExecutor as Any).prototype.executeUnlocked.call(executor);

    expect(companionPrompt).toHaveBeenCalledTimes(1);
    expect(schedule).not.toHaveBeenCalled();
    expect(skillRouting).not.toHaveBeenCalled();
    expect(highConfidenceRouting).not.toHaveBeenCalled();
    expect(executor.emitEvent).toHaveBeenCalledWith(
      "log",
      expect.objectContaining({
        reason: "initial_companion_prompt",
        explicitChat: true,
      }),
    );
  });

  it("does not treat inferred chat intent as explicit chat mode", async () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;

    executor.task = {
      id: "task-inferred-chat",
      title: "hello",
      prompt: "hello",
      userPrompt: "hello",
      rawPrompt: "hello",
      createdAt: Date.now(),
      agentConfig: {
        executionMode: "execute",
        executionModeSource: "strategy",
        conversationMode: "chat",
        taskIntent: "chat",
      },
    };

    expect((TaskExecutor as Any).prototype.isExplicitChatExecutionMode.call(executor)).toBe(false);
    expect(
      (TaskExecutor as Any).prototype.shouldHandleInitialPromptAsCompanion.call(executor, "hello"),
    ).toBe(true);

    executor.shouldEmitAnswerFirst = vi.fn().mockReturnValue(true);
    executor.hasDirectAnswerReady = vi.fn().mockReturnValue(true);
    executor.promptRequestsArtifactOutput = vi.fn().mockReturnValue(false);
    executor.isLikelyTaskRequest = vi.fn().mockReturnValue(false);

    expect((TaskExecutor as Any).prototype.shouldShortCircuitSimpleNonExecuteAnswer.call(executor)).toBe(false);
  });

  it("does not route local walking errand prompts through companion mode", () => {
    const prompt =
      "My kid just fell into the duck pond and the wedding starts in 30 minutes. Where can I walk and buy her a new dress?";
    const executor = createInferredChatExecutor(prompt, {
      conversationMode: "chat",
      taskIntent: "chat",
    });

    expect(
      (TaskExecutor as Any).prototype.shouldHandleInitialPromptAsCompanion.call(executor, prompt),
    ).toBe(false);
  });

  it("prefers the latest follow-up assistant text over stale prior summaries", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;

    executor.task = {
      id: "task-follow-up-summary",
      title: "Research Analyst run",
      prompt: "Research prompt",
      resultSummary: "Research Analyst - Awaiting Input",
    };
    executor.bestKnownOutcome = {
      resultSummary: "Yo! What's up? How can I help you today?",
    };
    executor.lastNonVerificationOutput = "Research Analyst - Awaiting Input";
    executor.lastAssistantOutput = "Research Analyst - Awaiting Input";
    executor.lastAssistantText =
      "Premier League fixtures: Liverpool vs Chelsea; Brentford vs Manchester City.";
    executor.getContentFallback = vi.fn().mockReturnValue("");

    expect((TaskExecutor as Any).prototype.buildFollowUpResultSummary.call(executor)).toBe(
      "Premier League fixtures: Liverpool vs Chelsea; Brentford vs Manchester City.",
    );
  });

  it("prefers the latest persisted follow-up assistant message over stale assistant text", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;

    executor.task = {
      id: "task-follow-up-history-summary",
      title: "Persistent goal",
      prompt: "Track release blockers",
      resultSummary: "Release blocker analysis from the prior run.",
    };
    executor.bestKnownOutcome = {
      resultSummary: "Older best-known release blocker summary.",
    };
    executor.conversationHistory = [
      { role: "user", content: [{ type: "text", text: "/goal status" }] },
      {
        role: "assistant",
        content: [{ type: "text", text: "Goal active.\n\nObjective: Track release blockers" }],
      },
    ];
    executor.lastAssistantText = "A stale assistant reply from before the follow-up.";
    executor.lastNonVerificationOutput = "Goal active.\n\nObjective: Track release blockers";
    executor.lastAssistantOutput = "Goal active.\n\nObjective: Track release blockers";
    executor.getContentFallback = vi.fn().mockReturnValue("");

    expect((TaskExecutor as Any).prototype.buildFollowUpResultSummary.call(executor)).toBe(
      "Goal active.\n\nObjective: Track release blockers",
    );
  });

  it("keeps local goal follow-up messages aligned with last assistant text", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;

    executor.task = {
      id: "task-goal-follow-up",
      title: "Persistent goal",
      prompt: "Track release blockers",
    };
    executor.workspace = {
      id: "ws-goal-follow-up",
      path: "/tmp",
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    executor.emitEvent = vi.fn();

    (TaskExecutor as Any).prototype.emitGoalAssistantMessage.call(
      executor,
      "/goal status",
      "Goal active.\n\nObjective: Track release blockers",
    );

    expect(executor.lastAssistantText).toBe("Goal active.\n\nObjective: Track release blockers");
    expect((TaskExecutor as Any).prototype.buildFollowUpResultSummary.call(executor)).toBe(
      "Goal active.\n\nObjective: Track release blockers",
    );
  });

  it("does not route inferred chat live-lookup prompts through companion mode", () => {
    const executor = createInferredChatExecutor(
      "please tell me which football clubs have games tomorrow in premier league",
    );

    expect(
      (TaskExecutor as Any).prototype.shouldHandleInitialPromptAsCompanion.call(
        executor,
        "please tell me which football clubs have games tomorrow in premier league",
      ),
    ).toBe(false);
  });

  it("keeps ambiguous inferred chat prompts in the normal executor path", () => {
    const prompts = [
      "are there premier league games tomorrow",
      "weather in paris today",
      "is apple stock up today",
      "/schedule tomorrow remind me to send the report",
      "/goal keep an eye on deploy health",
      "/skill pdf summarize report.pdf",
      "Use the Codex CLI Agent skill to review this change",
      "answer_first=true explain the tradeoffs before planning",
      "summarize report.pdf",
      "describe this image",
      "Attached files:\n- photo.png\nWhat is in this image?",
      "PDF attachment: report.pdf\nPath: .cowork/uploads/123/report.pdf\nSummarize it",
    ];

    for (const prompt of prompts) {
      const executor = createInferredChatExecutor(prompt);

      expect(
        (TaskExecutor as Any).prototype.shouldHandleInitialPromptAsCompanion.call(executor, prompt),
      ).toBe(false);
    }
  });

  it("keeps external runtime tasks out of inferred companion routing", () => {
    const executor = createInferredChatExecutor("hello", {
      externalRuntime: {
        kind: "acpx",
        agent: "claude",
        sessionMode: "persistent",
        outputMode: "json",
        permissionMode: "approve-reads",
      },
    });

    expect(
      (TaskExecutor as Any).prototype.shouldHandleInitialPromptAsCompanion.call(executor, "hello"),
    ).toBe(false);
  });

  it("keeps explicit chat ACP tasks on the external runtime path", async () => {
    const executor = createExecuteUnlockedRoutingExecutor("hello", {
      executionMode: "chat",
      executionModeSource: "user",
      conversationMode: "hybrid",
      externalRuntime: {
        kind: "acpx",
        agent: "claude",
        sessionMode: "persistent",
        outputMode: "json",
        permissionMode: "approve-reads",
      },
    });
    executor.executeWithAcpxRuntime = vi.fn().mockResolvedValue(undefined);

    await (TaskExecutor as Any).prototype.executeUnlocked.call(executor);

    expect(executor.executeWithAcpxRuntime).toHaveBeenCalledWith("hello");
    expect(executor.handleCompanionPrompt).not.toHaveBeenCalled();
    expect(executor.maybeHandleScheduleSlashCommand).not.toHaveBeenCalled();
  });

  it("keeps slash commands on the executor entrypoint path", async () => {
    const executor = createExecuteUnlockedRoutingExecutor(
      "/schedule tomorrow remind me to send the report",
    );
    executor.maybeHandleScheduleSlashCommand = vi.fn().mockResolvedValue(true);

    await (TaskExecutor as Any).prototype.executeUnlocked.call(executor);

    expect(executor.handleCompanionPrompt).not.toHaveBeenCalled();
    expect(executor.maybeHandleScheduleSlashCommand).toHaveBeenCalledTimes(1);
    expect(executor.analyzeTask).not.toHaveBeenCalled();
  });

  it("only exposes the last non-verification step as an assistant bubble", () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    executor.plan = {
      description: "Hello plan",
      steps: [
        { id: "1", description: "Interpret the task as a simple chat greeting.", kind: "primary" },
        { id: "2", description: "Draft a concise reply.", kind: "primary" },
        { id: "3", description: "Send the greeting response.", kind: "primary" },
        { id: "4", description: "Verify: confirm the reply includes a greeting and help offer.", kind: "verification" },
      ],
    };

    expect((TaskExecutor as Any).prototype.isLastVisibleAssistantStep.call(executor, executor.plan.steps[0])).toBe(false);
    expect((TaskExecutor as Any).prototype.isLastVisibleAssistantStep.call(executor, executor.plan.steps[1])).toBe(false);
    expect((TaskExecutor as Any).prototype.isLastVisibleAssistantStep.call(executor, executor.plan.steps[2])).toBe(true);
    expect((TaskExecutor as Any).prototype.isLastVisibleAssistantStep.call(executor, executor.plan.steps[3])).toBe(false);
  });

  it("uses the 48K cap for explicit chat sessions", async () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    const createMessageWithTimeout = vi.fn().mockResolvedValue({
      content: [{ type: "text", text: "reply" }],
      stopReason: "end_turn",
      usage: { inputTokens: 1, outputTokens: 1 },
    });

    executor.task = {
      id: "task-chat-cap",
      title: "Chat session",
      prompt: "Say hello",
      userPrompt: "Say hello",
      rawPrompt: "Say hello",
      createdAt: Date.now(),
      agentConfig: {
        executionMode: "chat",
        conversationMode: "hybrid",
      },
    };
    executor.workspace = {
      id: "ws-chat-cap",
      path: "/tmp",
      isTemp: true,
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    executor.daemon = {
      updateTaskStatus: vi.fn(),
      updateTask: vi.fn(),
    };
    executor.emitEvent = vi.fn();
    executor.buildChatOrThinkSystemPrompt = vi.fn().mockReturnValue("system prompt");
    executor.getRoleContextPrompt = vi.fn().mockReturnValue("");
    executor.buildUserProfileBlock = vi.fn().mockReturnValue("");
    executor.buildUserContent = vi.fn().mockResolvedValue("Say hello");
    executor.callLLMWithRetry = vi.fn(async (fn: Any) => fn());
    executor.createMessageWithTimeout = createMessageWithTimeout;
    executor.updateTracking = vi.fn();
    executor.extractTextFromLLMContent = vi.fn().mockReturnValue("reply");
    executor.updateConversationHistory = vi.fn();
    executor.saveConversationSnapshot = vi.fn();
    executor.finalizeTaskBestEffort = vi.fn();
    executor.capturePlaybookOutcome = vi.fn();
    executor.generateCompanionFallbackResponse = vi.fn().mockReturnValue("fallback");
    executor.getCumulativeInputTokens = vi.fn().mockReturnValue(0);
    executor.getCumulativeOutputTokens = vi.fn().mockReturnValue(0);
    executor.taskCompleted = false;
    executor.cancelled = false;

    await (TaskExecutor as Any).prototype.handleCompanionPrompt.call(executor);

    expect(createMessageWithTimeout).toHaveBeenCalled();
    expect(createMessageWithTimeout.mock.calls[0][0].maxTokens).toBe(48_000);
  });

  it("reuses a cached explicit chat summary instead of regenerating it every turn", async () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    const buildCompactionSummaryBlock = vi.fn().mockResolvedValue("<cowork_compaction_summary>\nsummary\n</cowork_compaction_summary>");

    executor.conversationHistory = Array.from({ length: 30 }, (_, index) => ({
      role: index % 2 === 0 ? "user" : "assistant",
      content: [{ type: "text", text: `${index % 2 === 0 ? "User" : "Assistant"} turn ${index}` }],
    }));
    executor.buildCompactionSummaryBlock = buildCompactionSummaryBlock;
    executor.explicitChatSummaryBlock = null;
    executor.explicitChatSummaryCreatedAt = 0;
    executor.explicitChatSummarySourceMessageCount = 0;

    const first = await (TaskExecutor as Any).prototype.buildExplicitChatMessages.call(
      executor,
      "Follow up question",
      "system prompt",
    );
    const second = await (TaskExecutor as Any).prototype.buildExplicitChatMessages.call(
      executor,
      "Another follow up",
      "system prompt",
    );

    expect(buildCompactionSummaryBlock).toHaveBeenCalledTimes(1);
    expect(executor.explicitChatSummaryBlock).toContain("summary");
    expect(
      typeof first[0].content === "string"
        ? first[0].content
        : JSON.stringify(first[0].content),
    ).toContain("<cowork_compaction_summary>");
    expect(
      typeof second[0].content === "string"
        ? second[0].content
        : JSON.stringify(second[0].content),
    ).toContain("<cowork_compaction_summary>");
  });

  it("routes long sub-agent chat synthesis through the shared text turn kernel flow", async () => {
    const executor = Object.create(TaskExecutor.prototype) as Any;
    const runTextTurnKernel = vi.fn().mockResolvedValue({
      assistantText: "Part one. Part two.",
      messages: [
        { role: "user", content: [{ type: "text", text: "Synthesis prompt" }] },
        { role: "assistant", content: [{ type: "text", text: "Part one. Part two." }] },
      ],
    });

    executor.task = {
      id: "task-sub-chat",
      title: "Synthesis child",
      prompt: "x".repeat(2200),
      userPrompt: "x".repeat(2200),
      rawPrompt: "x".repeat(2200),
      parentTaskId: "parent-1",
      createdAt: Date.now(),
      agentType: "sub",
      agentConfig: {
        executionMode: "chat",
        conversationMode: "chat",
        maxTokens: 16000,
      },
    };
    executor.workspace = {
      id: "ws-sub-chat",
      path: "/tmp",
      isTemp: true,
      permissions: { read: true, write: true, delete: true, network: true, shell: true },
    };
    executor.daemon = {
      updateTaskStatus: vi.fn(),
      updateTask: vi.fn(),
    };
    executor.emitEvent = vi.fn();
    executor.getRoleContextPrompt = vi.fn().mockReturnValue("");
    executor.buildUserContent = vi.fn().mockResolvedValue("Synthesis prompt");
    executor.runTextTurnKernel = runTextTurnKernel;
    executor.updateTracking = vi.fn();
    executor.updateConversationHistory = vi.fn();
    executor.buildResultSummary = vi.fn().mockReturnValue("summary");
    executor.finalizeTaskBestEffort = vi.fn();

    await (TaskExecutor as Any).prototype.handleSubAgentChatMode.call(executor, "x".repeat(2200));

    expect(runTextTurnKernel).toHaveBeenCalledWith(
      expect.objectContaining({
        messages: [{ role: "user", content: [{ type: "text", text: "Synthesis prompt" }] }],
        systemPrompt: expect.stringContaining("Respond thoroughly and completely"),
        initialMaxTokens: 16000,
        continuationMaxTokens: 1200,
        mode: "follow_up",
        operationLabel: "Sub-agent chat response",
        allowContinuation: true,
      }),
    );
    expect(executor.updateConversationHistory).toHaveBeenCalledWith([
      { role: "user", content: [{ type: "text", text: "Synthesis prompt" }] },
      { role: "assistant", content: [{ type: "text", text: "Part one. Part two." }] },
    ]);
    expect(executor.finalizeTaskBestEffort).toHaveBeenCalledWith("summary");
  });
});
