// Verifies OpenAI-compatible streaming payloads, failures, and transport wrapping.
import { createServer } from "node:http";
import OpenAI from "openai";
import type { Api, Model } from "openclaw/plugin-sdk/llm";
import { describe, expect, it, vi } from "vitest";
import {
  classifyAssistantFailoverReason,
  formatUserFacingAssistantErrorText,
} from "./embedded-agent-helpers.js";
import {
  buildOpenAIResponsesParams,
  buildOpenAICompletionsParams,
  createOpenAICompletionsTransportStreamFn,
  parseTransportChunkUsage,
  resolveAzureOpenAIApiVersion,
  sanitizeTransportPayloadText,
  testing,
} from "./openai-transport-stream.js";
import { attachModelProviderRequestTransport } from "./provider-request-config.js";
import {
  buildTransportAwareSimpleStreamFn,
  createBoundaryAwareStreamFnForModel,
  createOpenClawTransportStreamFnForModel,
  isTransportAwareApiSupported,
  prepareTransportAwareSimpleModel,
  resolveTransportAwareSimpleApi,
} from "./provider-transport-stream.js";
import { SYSTEM_PROMPT_CACHE_BOUNDARY } from "./system-prompt-cache-boundary.js";

type OpenAICompletionsOutput = Parameters<typeof testing.processOpenAICompletionsStream>[1];
type OpenAIResponsesOutput = Parameters<typeof testing.processResponsesStream>[1];

type CapturedStreamEvent = {
  type?: string;
  delta?: string;
  content?: string;
  partial?: unknown;
};

function createDeepSeekCompletionsModel(): Model<"openai-completions"> {
  return {
    id: "deepseek-v4-pro",
    name: "DeepSeek V4 Pro",
    api: "openai-completions",
    provider: "deepseek",
    baseUrl: "https://api.deepseek.com",
    compat: { thinkingFormat: "deepseek" },
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 1_000_000,
    maxTokens: 384_000,
  };
}

function createAssistantOutput(model: Model<"openai-completions">): OpenAICompletionsOutput {
  return {
    role: "assistant" as const,
    content: [],
    api: model.api,
    provider: model.provider,
    model: model.id,
    usage: {
      input: 0,
      output: 0,
      cacheRead: 0,
      cacheWrite: 0,
      totalTokens: 0,
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
    },
    stopReason: "stop",
    timestamp: Date.now(),
  };
}

function createResponsesAssistantOutput(
  model: Model<"azure-openai-responses">,
): OpenAIResponsesOutput {
  return {
    role: "assistant" as const,
    content: [],
    api: model.api,
    provider: model.provider,
    model: model.id,
    usage: {
      input: 0,
      output: 0,
      cacheRead: 0,
      cacheWrite: 0,
      totalTokens: 0,
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
    },
    stopReason: "stop",
    timestamp: Date.now(),
  };
}

function createAzureResponsesModel(): Model<"azure-openai-responses"> {
  return {
    id: "gpt-5.4-pro",
    name: "GPT-5.4 Pro",
    api: "azure-openai-responses",
    provider: "azure-openai-responses-devdiv",
    baseUrl: "https://example.openai.azure.com/openai/responses",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 200_000,
    maxTokens: 8192,
  };
}

function neverYieldsStream(): AsyncIterable<unknown> {
  // Simulates an HTTP stream that opened but never delivered the first SSE event.
  return {
    [Symbol.asyncIterator]() {
      return {
        next: async () => await new Promise<IteratorResult<unknown>>(() => {}),
        return: async () => ({ done: true, value: undefined }),
      };
    },
  };
}

async function* streamChunks(chunks: readonly unknown[]): AsyncGenerator<never> {
  for (const chunk of chunks) {
    yield chunk as never;
  }
}

function expectRecordFields(record: unknown, expected: Record<string, unknown>) {
  // Shared assertion helper for parsed transport payload/event records.
  if (!record || typeof record !== "object") {
    throw new Error("Expected record");
  }
  const actual = record as Record<string, unknown>;
  for (const [key, value] of Object.entries(expected)) {
    expect(actual[key]).toEqual(value);
  }
  return actual;
}

describe("openai transport stream", () => {
  it("fails Azure Responses streams when headers arrive but no first event follows", async () => {
    const model = createAzureResponsesModel();
    await expect(
      testing.processResponsesStream(
        neverYieldsStream(),
        createResponsesAssistantOutput(model),
        { push: vi.fn() },
        model,
        { firstEventTimeoutMs: 1 },
      ),
    ).rejects.toThrow(/did not deliver a first event within 1ms after HTTP streaming headers/);
  });

  it("observes detail-less Responses failures without leaking request ids", async () => {
    // Observation should preserve hashes/metadata shape while dropping raw request ids.
    const model = createAzureResponsesModel();
    const event = {
      type: "response.failed",
      response: {
        id: "resp_failed_123",
        status: "failed",
        model: "gpt-5.4-pro",
        metadata: {
          litellm_request_id: "litellm_req_plaintext_123",
          api_key: "sk-observation-secret",
        },
        provider_request_id: "provider_req_plaintext_456",
        status_details: {
          provider_request_id: "provider_req_nested_789",
        },
        provider_error: {
          request_id: "provider_error_req_nested_012",
          headers: {
            "x-request-id": ["header_req_plaintext_345", "header_req_plaintext_678"],
          },
        },
      },
    };

    const observation = testing.buildResponsesFailedNoDetailsObservation(event, model);
    const summary = testing.summarizeResponsesFailedNoDetailsObservation(observation);

    expect(observation.providerRuntimeFailureKind).toBe("no_error_details");
    expect(observation.responseId).toBe("resp_failed_123");
    expect(observation.responseStatus).toBe("failed");
    expect(observation.responseModel).toBe("gpt-5.4-pro");
    expect(observation.metadataKeys).toEqual(["api_key", "litellm_request_id"]);
    expect(observation.requestIdHashes).toHaveLength(6);
    expect(observation.requestIdHashes.join(",")).toContain("sha256:");
    expect(summary).toContain("responseId=resp_failed_123");
    expect(summary).toContain("requestIds=");
    expect(JSON.stringify(observation)).not.toContain("litellm_req_plaintext_123");
    expect(JSON.stringify(observation)).not.toContain("provider_req_plaintext_456");
    expect(JSON.stringify(observation)).not.toContain("provider_req_nested_789");
    expect(JSON.stringify(observation)).not.toContain("provider_error_req_nested_012");
    expect(JSON.stringify(observation)).not.toContain("header_req_plaintext_345");
    expect(JSON.stringify(observation)).not.toContain("header_req_plaintext_678");
    expect(JSON.stringify(observation)).not.toContain("sk-observation-secret");
  });

  it("normalizes Responses failed events before transport errors are thrown", () => {
    const model = createAzureResponsesModel();

    expect(
      testing.normalizeResponsesFailedEvent(
        {
          type: "response.failed",
          response: {
            id: "resp_failed_rate_limit",
            error: {
              code: "rate_limit_exceeded",
              message: "Too many requests",
            },
          },
        },
        model,
      ),
    ).toMatchObject({
      message: "rate_limit_exceeded: Too many requests",
      responseId: "resp_failed_rate_limit",
    });

    expect(
      testing.normalizeResponsesFailedEvent(
        {
          type: "response.failed",
          response: {
            id: "resp_failed_incomplete",
            incomplete_details: { reason: "max_output_tokens" },
          },
        },
        model,
      ),
    ).toMatchObject({
      message: "incomplete: max_output_tokens",
      responseId: "resp_failed_incomplete",
    });
  });

  it("preserves the failed response id before throwing detail-less Responses failures", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await expect(
      testing.processResponsesStream(
        streamChunks([
          {
            type: "response.failed",
            response: {
              id: "resp_failed_runtime",
              status: "failed",
              model: "gpt-5.4-pro",
            },
          },
        ]),
        output,
        { push: vi.fn() },
        model,
      ),
    ).rejects.toThrow("Unknown error (no error details in response)");

    expect(output.responseId).toBe("resp_failed_runtime");
  });

  it("treats empty Responses error objects as detail-less failures", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await expect(
      testing.processResponsesStream(
        streamChunks([
          {
            type: "response.failed",
            response: {
              id: "resp_failed_empty_error",
              status: "failed",
              model: "gpt-5.4-pro",
              error: { code: null, message: null },
              provider_request_id: "provider_req_empty_error",
            },
          },
        ]),
        output,
        { push: vi.fn() },
        model,
      ),
    ).rejects.toThrow("Unknown error (no error details in response)");

    expect(output.responseId).toBe("resp_failed_empty_error");
  });

  it("tags Responses encrypted reasoning with replay provenance while streaming", async () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-chatgpt-responses">;
    const output: OpenAIResponsesOutput = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    await testing.processResponsesStream(
      streamChunks([
        { type: "response.output_item.added", item: { type: "reasoning" } },
        {
          type: "response.output_item.done",
          item: {
            type: "reasoning",
            id: "rs_123",
            encrypted_content: "ciphertext",
            summary: [{ type: "summary_text", text: "Need a tool." }],
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
      { authProfileId: "openai:oauth", sessionId: "session-123" },
    );

    const expectedReplayMetadata = testing.buildOpenAIResponsesReasoningReplayMetadata(model, {
      authProfileId: "openai:oauth",
      sessionId: "session-123",
    });
    const thinkingBlock = output.content[0] as {
      thinkingSignature?: string;
      openclawReasoningReplay?: unknown;
    };
    const replayItem = JSON.parse(thinkingBlock.thinkingSignature ?? "{}") as Record<
      string,
      unknown
    >;
    expect(replayItem).toMatchObject({
      type: "reasoning",
      id: "rs_123",
      encrypted_content: "ciphertext",
    });
    expect(replayItem).not.toHaveProperty("__openclaw_replay");
    expect(thinkingBlock.openclawReasoningReplay).toEqual(expectedReplayMetadata);
  });

  it("clamps Responses cached prompt usage at zero", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.completed",
          response: {
            id: "resp-cache-overflow",
            status: "completed",
            usage: {
              input_tokens: 2,
              output_tokens: 5,
              total_tokens: 7,
              input_tokens_details: { cached_tokens: 4 },
              output_tokens_details: { reasoning_tokens: 3 },
            },
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    expectRecordFields(output.usage, {
      input: 0,
      output: 5,
      cacheRead: 4,
      reasoningTokens: 3,
      totalTokens: 9,
    });
  });

  it("backfills Azure Responses completed message output when item events are absent", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.completed",
          response: {
            id: "resp-azure-completed-message",
            status: "completed",
            output: [
              { type: "reasoning", id: "rs_123", summary: [] },
              {
                type: "message",
                id: "msg_123",
                role: "assistant",
                content: [{ type: "text", text: "AZURE_RESPONSES_CANARY_OK" }],
              },
            ],
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    expect(output.stopReason).toBe("stop");
    expect(output.content).toEqual([
      {
        type: "text",
        text: "AZURE_RESPONSES_CANARY_OK",
        textSignature: '{"v":1,"id":"msg_123"}',
      },
    ]);
  });

  it("collapses cumulative message snapshot items into one text block (#91959)", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);
    const pushSpy = vi.fn();
    const snapshot1 = "Scaled dot-product attention";
    const snapshot2 = "Scaled dot-product attention divides by sqrt(d_k)";
    const snapshot3 = "Scaled dot-product attention divides by sqrt(d_k) before softmax.";
    const messageItem = (id: string, text: string) => ({
      type: "message",
      id,
      phase: "final_answer",
      content: [{ type: "output_text", text }],
    });

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.output_item.added",
          item: { type: "message", id: "msg_1", phase: "final_answer" },
        },
        { type: "response.output_text.delta", delta: snapshot1 },
        { type: "response.output_item.done", item: messageItem("msg_1", snapshot1) },
        {
          type: "response.output_item.added",
          item: { type: "message", id: "msg_2", phase: "final_answer" },
        },
        { type: "response.output_item.done", item: messageItem("msg_2", snapshot2) },
        {
          type: "response.output_item.added",
          item: { type: "message", id: "msg_3", phase: "final_answer" },
        },
        { type: "response.output_item.done", item: messageItem("msg_3", snapshot3) },
        {
          type: "response.completed",
          response: { id: "resp-snapshots", status: "completed" },
        },
      ]),
      output,
      { push: pushSpy },
      model,
    );

    expect(output.content).toEqual([
      {
        type: "text",
        text: snapshot3,
        textSignature: '{"v":1,"id":"msg_3","phase":"final_answer"}',
      },
    ]);
    // Balanced lifecycle: one text_start, all events on index 0, and each
    // collapsed snapshot re-ends the same block.
    const textEvents = pushSpy.mock.calls
      .map(([event]) => event as { type: string; contentIndex?: number })
      .filter((event) => event.type.startsWith("text_"));
    expect(textEvents.map((event) => [event.type, event.contentIndex])).toEqual([
      ["text_start", 0],
      ["text_delta", 0],
      ["text_end", 0],
      ["text_end", 0],
      ["text_end", 0],
    ]);
  });

  it("keeps prefix-nested message items separated by a tool call as separate blocks", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);
    const messageEvents = (id: string, text: string) => [
      { type: "response.output_item.added", item: { type: "message", id } },
      {
        type: "response.output_item.done",
        item: { type: "message", id, content: [{ type: "output_text", text }] },
      },
    ];

    await testing.processResponsesStream(
      streamChunks([
        ...messageEvents("msg_1", "Done."),
        {
          type: "response.output_item.added",
          item: {
            type: "function_call",
            id: "fc_1",
            call_id: "call_1",
            name: "write",
            arguments: "{}",
          },
        },
        {
          type: "response.output_item.done",
          item: {
            type: "function_call",
            id: "fc_1",
            call_id: "call_1",
            name: "write",
            arguments: "{}",
          },
        },
        ...messageEvents("msg_2", "Done."),
        {
          type: "response.completed",
          response: { id: "resp-tool-boundary", status: "completed" },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    // The post-tool message is a real reply, not a snapshot of the pre-tool one.
    expect(output.content.map((block) => block.type)).toEqual(["text", "toolCall", "text"]);
    expect(output.content[2]).toMatchObject({ type: "text", text: "Done." });
  });

  it("collapses cumulative message snapshots in completed-response backfill (#91959)", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.completed",
          response: {
            id: "resp-backfill-snapshots",
            status: "completed",
            output: [
              {
                type: "message",
                id: "msg_1",
                role: "assistant",
                content: [{ type: "output_text", text: "The answer" }],
              },
              {
                type: "message",
                id: "msg_2",
                role: "assistant",
                content: [{ type: "output_text", text: "The answer is 42." }],
              },
              {
                type: "message",
                id: "msg_3",
                role: "assistant",
                content: [{ type: "output_text", text: "The answer" }],
              },
            ],
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    // msg_2 strictly extends msg_1 and collapses into it; msg_3 shrinks back
    // and is an independently identified message, so it stays a real block.
    expect(output.content).toEqual([
      {
        type: "text",
        text: "The answer is 42.",
        textSignature: '{"v":1,"id":"msg_2"}',
      },
      {
        type: "text",
        text: "The answer",
        textSignature: '{"v":1,"id":"msg_3"}',
      },
    ]);
  });

  it("keeps backfill message items separated by a reasoning item as distinct blocks", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.completed",
          response: {
            id: "resp-backfill-reasoning-boundary",
            status: "completed",
            output: [
              {
                type: "message",
                id: "msg_1",
                role: "assistant",
                content: [{ type: "output_text", text: "Step one." }],
              },
              { type: "reasoning", id: "rs_1", summary: [] },
              {
                type: "message",
                id: "msg_2",
                role: "assistant",
                content: [{ type: "output_text", text: "Step one. Step two." }],
              },
            ],
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    // A reasoning item is a real boundary even in backfill: msg_2 must not
    // collapse into msg_1 despite being a strict extension (mirrors streaming).
    expect(output.content).toEqual([
      { type: "text", text: "Step one.", textSignature: '{"v":1,"id":"msg_1"}' },
      { type: "text", text: "Step one. Step two.", textSignature: '{"v":1,"id":"msg_2"}' },
    ]);
  });

  it("backfills Azure Responses completed function calls when item events are absent", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.completed",
          response: {
            id: "resp-azure-completed-tool",
            status: "completed",
            output: [
              {
                type: "function_call",
                id: "fc_123",
                call_id: "call_123",
                name: "session_status",
                arguments: '{"sessionKey":"current"}',
              },
            ],
          },
        },
      ]),
      output,
      { push: vi.fn() },
      model,
    );

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toEqual([
      {
        type: "toolCall",
        id: "call_123|fc_123",
        name: "session_status",
        arguments: { sessionKey: "current" },
        partialJson: '{"sessionKey":"current"}',
      },
    ]);
  });

  it("summarizes model payload tools with full names when requested", () => {
    const previous = process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
    process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = "tools";
    try {
      expect(
        testing.summarizeResponsesTools([
          { type: "function", name: "exec" },
          { type: "function", function: { name: "wait" } },
        ]),
      ).toBe("count=2 names=exec,wait");
    } finally {
      if (previous === undefined) {
        delete process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
      } else {
        process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = previous;
      }
    }
  });

  it("skips unreadable model payload tool names in debug summaries", () => {
    const previous = process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
    process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = "tools";
    try {
      expect(
        testing.summarizeResponsesTools([
          {
            type: "function",
            get function(): { name: string } {
              throw new Error("responses debug tool function getter exploded");
            },
          },
          {
            type: "function",
            function: {
              get name(): string {
                throw new Error("responses debug nested name getter exploded");
              },
            },
          },
          { type: "function", function: { name: "wait" } },
        ]),
      ).toBe("count=3 names=wait");
    } finally {
      if (previous === undefined) {
        delete process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
      } else {
        process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = previous;
      }
    }
  });

  it("redacts full model payload debug summaries", () => {
    const previous = process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
    process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = "full-redacted";
    try {
      const summary = testing.summarizeResponsesPayload({
        model: "gpt-5.5",
        stream: true,
        input: [],
        tools: [{ type: "function", name: "exec" }],
        apiKey: "sk-abcdefghijklmnopqrstuvwxyz",
      });
      expect(summary).toContain("payload=");
      expect(summary).toContain("sk-abc");
      expect(summary).not.toContain("sk-abcdefghijklmnopqrstuvwxyz");
    } finally {
      if (previous === undefined) {
        delete process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD;
      } else {
        process.env.OPENCLAW_DEBUG_MODEL_PAYLOAD = previous;
      }
    }
  });

  it("enforces the code mode responses tool surface before requests leave OpenClaw", () => {
    const payload = {
      tools: [
        { type: "function", name: "exec" },
        { type: "web_search_preview" },
        { type: "function", function: { name: "wait" } },
      ],
    };

    testing.enforceCodeModeResponsesToolSurface(payload);
    testing.assertCodeModeResponsesToolSurface(payload);
    expect(payload.tools).toHaveLength(2);
  });

  it("skips unreadable code mode response payload tool names", () => {
    const payload = {
      tools: [
        { type: "function", name: "exec" },
        {
          type: "function",
          get function(): { name: string } {
            throw new Error("responses code mode function getter exploded");
          },
        },
        {
          type: "function",
          function: {
            get name(): string {
              throw new Error("responses code mode nested name getter exploded");
            },
          },
        },
        { type: "function", function: { name: "wait" } },
      ],
    };

    testing.enforceCodeModeResponsesToolSurface(payload);
    testing.assertCodeModeResponsesToolSurface(payload);
    expect(payload.tools).toEqual([
      { type: "function", name: "exec" },
      { type: "function", function: { name: "wait" } },
    ]);
  });

  it("fails closed when the code mode final payload tool surface is not exec/wait", () => {
    expect(() =>
      testing.assertCodeModeResponsesToolSurface({
        tools: [{ type: "function", name: "exec" }, { type: "web_search_preview" }],
      }),
    ).toThrow(/Code mode payload tool surface violation/);
  });

  it("adds OpenClaw attribution to native OpenAI transport headers and protects it from provider overrides", () => {
    vi.stubEnv("OPENCLAW_VERSION", "2026.3.22");
    const headers = testing.buildOpenAIClientHeaders(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        headers: {
          originator: "openclaw",
          "User-Agent": "openclaw",
          "X-Provider": "model",
        },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      { systemPrompt: "", messages: [] } as never,
      {
        originator: "openclaw",
        "User-Agent": "openclaw",
        "X-Caller": "request",
      },
    );

    expectRecordFields(headers, {
      originator: "openclaw",
      version: "2026.3.22",
      "User-Agent": "openclaw/2026.3.22",
      "X-Provider": "model",
      "X-Caller": "request",
    });
  });

  it("adds OpenClaw attribution to native OpenAI Codex transport headers", () => {
    vi.stubEnv("OPENCLAW_VERSION", "2026.3.22");
    const headers = testing.buildOpenAIClientHeaders(
      {
        id: "gpt-5.4-codex",
        name: "GPT-5.4 Codex",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        headers: {
          originator: "openclaw",
          "User-Agent": "openclaw",
        },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      { systemPrompt: "", messages: [] } as never,
    );

    expectRecordFields(headers, {
      originator: "openclaw",
      version: "2026.3.22",
      "User-Agent": "openclaw/2026.3.22",
    });
    expect(headers.Accept).toBeUndefined();
    expect(headers.accept).toBeUndefined();
  });

  it("adds SSE Accept only to native ChatGPT/Codex Responses stream requests", () => {
    const codexModel = {
      id: "gpt-5.5",
      name: "GPT-5.5",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://chatgpt.com/backend-api/codex",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 400000,
      maxTokens: 128000,
    } satisfies Model<"openai-chatgpt-responses">;
    const transportAliasModel = {
      ...codexModel,
      api: "openclaw-openai-responses-transport" as Api,
    } satisfies Model;
    const nonNativeChatGPTModel = {
      ...codexModel,
      baseUrl: "https://api.openai.com/v1",
    } satisfies Model<"openai-chatgpt-responses">;
    const openAIModel = {
      ...codexModel,
      api: "openai-responses",
      baseUrl: "https://api.openai.com/v1",
    } satisfies Model<"openai-responses">;

    expect(testing.buildOpenAISdkRequestOptions(codexModel, undefined, { stream: true })).toEqual({
      headers: { Accept: "text/event-stream" },
    });
    expect(
      testing.buildOpenAISdkRequestOptions(transportAliasModel, undefined, { stream: true }),
    ).toEqual({ headers: { Accept: "text/event-stream" } });
    expect(testing.buildOpenAISdkRequestOptions(codexModel)).toBeUndefined();
    expect(
      testing.buildOpenAISdkRequestOptions(nonNativeChatGPTModel, undefined, { stream: true }),
    ).toBeUndefined();
    expect(
      testing.buildOpenAISdkRequestOptions(openAIModel, undefined, { stream: true }),
    ).toBeUndefined();
  });

  it("moves Azure OpenAI completions api-version headers into default query params", () => {
    const config = testing.buildOpenAICompletionsClientConfig(
      {
        id: "gpt-4o-mini",
        name: "GPT-4o Mini",
        api: "openai-completions",
        provider: "azure-custom",
        baseUrl: "https://example.openai.azure.com/openai/deployments/gpt-4o-mini?existing=1",
        headers: {
          "api-key": "azure-key",
          "api-version": "2024-10-21",
          "X-Tenant": "acme",
        },
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 4096,
      } as unknown as Model<"openai-completions">,
      { systemPrompt: "", messages: [] } as never,
    );

    expect(config).toEqual({
      baseURL: "https://example.openai.azure.com/openai/deployments/gpt-4o-mini",
      defaultHeaders: {
        "api-key": "azure-key",
        "X-Tenant": "acme",
      },
      defaultQuery: {
        existing: "1",
        "api-version": "2024-10-21",
      },
    });
  });

  it("preserves configured base URL query params without moving non-Azure headers", () => {
    const config = testing.buildOpenAICompletionsClientConfig(
      {
        id: "proxy-model",
        name: "Proxy Model",
        api: "openai-completions",
        provider: "custom-proxy",
        baseUrl: "https://proxy.example.com/v1?tenant=acme",
        headers: {
          "api-version": "proxy-header",
          "X-Tenant": "acme",
        },
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 4096,
      } satisfies Model<"openai-completions">,
      { systemPrompt: "", messages: [] } as never,
    );

    expect(config).toEqual({
      baseURL: "https://proxy.example.com/v1",
      defaultHeaders: {
        "api-version": "proxy-header",
        "X-Tenant": "acme",
      },
      defaultQuery: {
        tenant: "acme",
      },
    });
  });

  it("reports the supported transport-aware APIs", () => {
    expect(isTransportAwareApiSupported("openai-responses")).toBe(true);
    expect(isTransportAwareApiSupported("openai-chatgpt-responses")).toBe(true);
    expect(isTransportAwareApiSupported("openai-completions")).toBe(true);
    expect(isTransportAwareApiSupported("azure-openai-responses")).toBe(true);
    expect(isTransportAwareApiSupported("anthropic-messages")).toBe(true);
    expect(isTransportAwareApiSupported("google-generative-ai")).toBe(true);
  });

  it("builds boundary-aware stream shapers for supported default agent transports", () => {
    expect(
      createBoundaryAwareStreamFnForModel({
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">),
    ).toBeTypeOf("function");
    expect(
      createOpenClawTransportStreamFnForModel({
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">),
    ).toBeTypeOf("function");
    expect(
      createBoundaryAwareStreamFnForModel({
        id: "codex-mini-latest",
        name: "Codex Mini Latest",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">),
    ).toBeTypeOf("function");
    expect(
      createBoundaryAwareStreamFnForModel({
        id: "claude-sonnet-4-6",
        name: "Claude Sonnet 4.6",
        api: "anthropic-messages",
        provider: "anthropic",
        baseUrl: "https://api.anthropic.com",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"anthropic-messages">),
    ).toBeTypeOf("function");
  });

  it("prepares a custom simple-completion api alias when transport overrides are attached", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    const prepared = prepareTransportAwareSimpleModel(model);

    expect(resolveTransportAwareSimpleApi(model.api)).toBe("openclaw-openai-responses-transport");
    expectRecordFields(prepared, {
      api: "openclaw-openai-responses-transport",
      provider: "openai",
      id: "gpt-5.4",
    });
    expect(buildTransportAwareSimpleStreamFn(model)).toBeTypeOf("function");
  });

  it("prepares a Codex Responses simple-completion api alias when transport overrides are attached", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "codex-mini-latest",
        name: "Codex Mini Latest",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    const prepared = prepareTransportAwareSimpleModel(model);

    expect(resolveTransportAwareSimpleApi(model.api)).toBe("openclaw-openai-responses-transport");
    expectRecordFields(prepared, {
      api: "openclaw-openai-responses-transport",
      provider: "openai",
      id: "codex-mini-latest",
    });
    expect(buildTransportAwareSimpleStreamFn(model)).toBeTypeOf("function");
  });

  it("prepares an Anthropic simple-completion api alias when transport overrides are attached", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "claude-sonnet-4-6",
        name: "Claude Sonnet 4.6",
        api: "anthropic-messages",
        provider: "anthropic",
        baseUrl: "https://api.anthropic.com",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"anthropic-messages">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    const prepared = prepareTransportAwareSimpleModel(model);

    expect(resolveTransportAwareSimpleApi(model.api)).toBe("openclaw-anthropic-messages-transport");
    expectRecordFields(prepared, {
      api: "openclaw-anthropic-messages-transport",
      provider: "anthropic",
      id: "claude-sonnet-4-6",
    });
    expect(buildTransportAwareSimpleStreamFn(model)).toBeTypeOf("function");
  });

  it("reports the Google simple-completion api alias without loading provider runtime", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "gemini-3.1-pro-preview",
        name: "Gemini 3.1 Pro Preview",
        api: "google-generative-ai",
        provider: "google",
        baseUrl: "https://generativelanguage.googleapis.com/v1beta",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"google-generative-ai">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    expect(resolveTransportAwareSimpleApi(model.api)).toBe(
      "openclaw-google-generative-ai-transport",
    );
  });

  it("keeps github-copilot OpenAI-family models on the shared transport seam", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "github-copilot",
        baseUrl: "https://api.githubcopilot.com/v1",
        reasoning: true,
        input: ["text", "image"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    expect(resolveTransportAwareSimpleApi(model.api)).toBe("openclaw-openai-responses-transport");
    expectRecordFields(prepareTransportAwareSimpleModel(model), {
      api: "openclaw-openai-responses-transport",
      provider: "github-copilot",
      id: "gpt-5.4",
    });
    expect(buildTransportAwareSimpleStreamFn(model)).toBeTypeOf("function");
  });

  it("keeps github-copilot Claude models on the shared Anthropic transport seam", () => {
    const model = attachModelProviderRequestTransport(
      {
        id: "claude-sonnet-4.6",
        name: "Claude Sonnet 4.6",
        api: "anthropic-messages",
        provider: "github-copilot",
        baseUrl: "https://api.githubcopilot.com/anthropic",
        reasoning: true,
        input: ["text", "image"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"anthropic-messages">,
      {
        proxy: {
          mode: "explicit-proxy",
          url: "http://proxy.internal:8443",
        },
      },
    );

    expect(resolveTransportAwareSimpleApi(model.api)).toBe("openclaw-anthropic-messages-transport");
    expectRecordFields(prepareTransportAwareSimpleModel(model), {
      api: "openclaw-anthropic-messages-transport",
      provider: "github-copilot",
      id: "claude-sonnet-4.6",
    });
    expect(buildTransportAwareSimpleStreamFn(model)).toBeTypeOf("function");
  });

  it("removes unpaired surrogate code units but preserves valid surrogate pairs", () => {
    const high = String.fromCharCode(0xd83d);
    const low = String.fromCharCode(0xdc00);

    expect(sanitizeTransportPayloadText(`left${high}right`)).toBe("leftright");
    expect(sanitizeTransportPayloadText(`left${low}right`)).toBe("leftright");
    expect(sanitizeTransportPayloadText("emoji 🙈 ok")).toBe("emoji 🙈 ok");
  });

  it("uses a valid Azure API version default when the environment is unset", () => {
    expect(resolveAzureOpenAIApiVersion({})).toBe("preview");
    expect(resolveAzureOpenAIApiVersion({ AZURE_OPENAI_API_VERSION: "2025-01-01-preview" })).toBe(
      "2025-01-01-preview",
    );
  });

  it("uses an OpenAI-compatible client for Foundry Azure Responses base URLs", () => {
    const model = {
      ...createAzureResponsesModel(),
      baseUrl: "https://project.services.ai.azure.com/api/projects/demo/openai/v1",
    };
    const client = testing.createAzureOpenAIClient(
      model,
      { systemPrompt: "system", messages: [], tools: [] } as never,
      "test-key",
    );

    expect(client.constructor.name).toBe("OpenAI");
  });

  it("keeps traditional Azure Responses hosts on the AzureOpenAI client", () => {
    const client = testing.createAzureOpenAIClient(
      createAzureResponsesModel(),
      { systemPrompt: "system", messages: [], tools: [] } as never,
      "test-key",
    );

    expect(client.constructor.name).toBe("AzureOpenAI");
  });

  it("passes provider request timeouts to OpenAI SDK clients", () => {
    const requestTimeoutMs = 900_000;

    const responsesModel = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-responses",
      provider: "custom-openai",
      baseUrl: "https://api.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
      requestTimeoutMs,
    } satisfies Model<"openai-responses"> & { requestTimeoutMs: number };
    const azureModel = {
      ...responsesModel,
      api: "azure-openai-responses",
      provider: "azure-openai",
      baseUrl: "https://example.openai.azure.com/openai/deployments/gpt-5.4",
    } satisfies Model<"azure-openai-responses"> & { requestTimeoutMs: number };
    const completionsModel = {
      ...responsesModel,
      api: "openai-completions",
      reasoning: false,
    } satisfies Model<"openai-completions"> & { requestTimeoutMs: number };

    expect(testing.buildOpenAISdkClientOptions(responsesModel).timeout).toBe(requestTimeoutMs);
    expect(testing.buildOpenAISdkClientOptions(azureModel).timeout).toBe(requestTimeoutMs);
    expect(testing.buildOpenAISdkClientOptions(completionsModel).timeout).toBe(requestTimeoutMs);
  });

  it("passes provider request timeouts to OpenAI SDK per-request options", () => {
    const signal = new AbortController().signal;
    const model = {
      id: "glm-5",
      name: "GLM-5",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 4096,
      requestTimeoutMs: 900_000.7,
    } satisfies Model<"openai-completions"> & { requestTimeoutMs: number };

    expect(testing.buildOpenAISdkRequestOptions(model, signal)).toEqual({
      signal,
      timeout: 900_000,
    });
    expect(
      testing.buildOpenAISdkRequestOptions(
        { ...model, requestTimeoutMs: -1 } as Model<"openai-completions">,
        undefined,
      ),
    ).toBeUndefined();
  });

  it("streams OpenAI-compatible loopback requests with the configured SDK timeout", async () => {
    let captured: { path?: string; timeout?: string; model?: string; roles?: string[] } = {};
    const server = createServer((req, res) => {
      let body = "";
      req.setEncoding("utf8");
      req.on("data", (chunk) => {
        body += chunk;
      });
      req.on("end", () => {
        const parsed = JSON.parse(body) as {
          model?: string;
          messages?: Array<{ role?: string }>;
        };
        captured = {
          path: req.url,
          timeout: Array.isArray(req.headers["x-stainless-timeout"])
            ? req.headers["x-stainless-timeout"][0]
            : req.headers["x-stainless-timeout"],
          model: parsed.model,
          roles: parsed.messages?.map((message) => message.role ?? ""),
        };
        res.writeHead(200, {
          "content-type": "text/event-stream; charset=utf-8",
          "cache-control": "no-cache",
          connection: "keep-alive",
        });
        const created = Math.floor(Date.now() / 1000);
        res.write(
          `data: ${JSON.stringify({
            id: "chatcmpl-timeout-proof",
            object: "chat.completion.chunk",
            created,
            model: "mlx-community/Qwen3-30B-A3B-6bit",
            choices: [
              {
                index: 0,
                delta: { role: "assistant", content: "OK" },
                finish_reason: null,
              },
            ],
          })}\n\n`,
        );
        res.write(
          `data: ${JSON.stringify({
            id: "chatcmpl-timeout-proof",
            object: "chat.completion.chunk",
            created,
            model: "mlx-community/Qwen3-30B-A3B-6bit",
            choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
            usage: { prompt_tokens: 1, completion_tokens: 1, total_tokens: 2 },
          })}\n\n`,
        );
        res.write("data: [DONE]\n\n");
        res.end();
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const baseModel = {
        id: "mlx-community/Qwen3-30B-A3B-6bit",
        name: "Qwen3 MLX",
        api: "openai-completions",
        provider: "mlx",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 256,
        requestTimeoutMs: 900_000,
      } satisfies Model<"openai-completions"> & { requestTimeoutMs: number };
      const stream = createOpenAICompletionsTransportStreamFn()(
        baseModel,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Reply OK", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key" } as never,
      );

      let doneReason: string | undefined;
      let text = "";
      for await (const event of stream as AsyncIterable<{
        type: string;
        delta?: string;
        reason?: string;
      }>) {
        if (event.type === "text_delta") {
          text += event.delta ?? "";
        }
        if (event.type === "done") {
          doneReason = event.reason;
        }
      }

      expect(captured.path).toBe("/v1/chat/completions");
      expect(captured.timeout).toBe("900");
      expect(captured.model).toBe("mlx-community/Qwen3-30B-A3B-6bit");
      expect(captured.roles).toEqual(["system", "user"]);
      expect(doneReason).toBe("stop");
      expect(text).toBe("OK");
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("refuses ModelStudio chat streams with no user or assistant payload turns", async () => {
    const model = {
      id: "qwen-coder-plus",
      name: "qwen-coder-plus",
      api: "openai-completions",
      provider: "qwen",
      baseUrl: "",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 4096,
      maxTokens: 256,
    } satisfies Model<"openai-completions">;
    const stream = createOpenAICompletionsTransportStreamFn()(
      model,
      {
        systemPrompt: "runtime-only system prompt",
        messages: [],
        tools: [],
      } as never,
      { apiKey: "test-key" } as never,
    );

    let errorPayload: Record<string, unknown> | undefined;
    for await (const event of stream as AsyncIterable<{
      type: string;
      error?: Record<string, unknown>;
    }>) {
      if (event.type === "error") {
        errorPayload = event.error;
      }
    }

    expect(errorPayload).toMatchObject({ stopReason: "error" });
    expect(String(errorPayload?.errorMessage)).toContain(
      "contains no non-empty user or assistant messages",
    );
    expect(String(errorPayload?.errorMessage)).toContain("system/tool-only request");
  });

  it("allows generic OpenAI-compatible chat streams without the ModelStudio turn guard", async () => {
    let capturedRoles: string[] | undefined;
    const server = createServer((req, res) => {
      let body = "";
      req.setEncoding("utf8");
      req.on("data", (chunk) => {
        body += chunk;
      });
      req.on("end", () => {
        const parsed = JSON.parse(body) as { messages?: Array<{ role?: string }> };
        capturedRoles = parsed.messages?.map((message) => message.role ?? "");
        res.writeHead(200, {
          "content-type": "text/event-stream; charset=utf-8",
          "cache-control": "no-cache",
          connection: "keep-alive",
        });
        const created = Math.floor(Date.now() / 1000);
        res.write(
          `data: ${JSON.stringify({
            id: "chatcmpl-system-only",
            object: "chat.completion.chunk",
            created,
            model: "generic-openai-compatible",
            choices: [
              {
                index: 0,
                delta: { role: "assistant", content: "OK" },
                finish_reason: null,
              },
            ],
          })}\n\n`,
        );
        res.write(
          `data: ${JSON.stringify({
            id: "chatcmpl-system-only",
            object: "chat.completion.chunk",
            created,
            model: "generic-openai-compatible",
            choices: [{ index: 0, delta: {}, finish_reason: "stop" }],
          })}\n\n`,
        );
        res.write("data: [DONE]\n\n");
        res.end();
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        id: "generic-openai-compatible",
        name: "Generic OpenAI Compatible",
        api: "openai-completions",
        provider: "custom-openai-compatible",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 256,
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "runtime-only system prompt",
          messages: [],
          tools: [],
        } as never,
        { apiKey: "test-key" } as never,
      );

      let doneReason: string | undefined;
      for await (const event of stream as AsyncIterable<{ type: string; reason?: string }>) {
        if (event.type === "done") {
          doneReason = event.reason;
        }
      }

      expect(capturedRoles).toEqual(["system"]);
      expect(doneReason).toBe("stop");
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("parses JSON chat completions returned to streaming requests", async () => {
    let capturedStreamFlag: unknown;
    const server = createServer((req, res) => {
      let body = "";
      req.setEncoding("utf8");
      req.on("data", (chunk) => {
        body += chunk;
      });
      req.on("end", () => {
        capturedStreamFlag = (JSON.parse(body) as { stream?: unknown }).stream;
        res.writeHead(200, {
          "content-type": "application/json; charset=utf-8",
        });
        res.end(
          JSON.stringify({
            id: "chatcmpl-json-fallback",
            object: "chat.completion",
            model: "moonshotai/kimi-k2.6",
            choices: [
              {
                index: 0,
                message: {
                  role: "assistant",
                  reasoning_content: "Need a direct answer.",
                  content: "live-ok",
                },
                finish_reason: "stop",
              },
            ],
            usage: { prompt_tokens: 2, completion_tokens: 3, total_tokens: 5 },
          }),
        );
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        id: "moonshotai/kimi-k2.6",
        name: "Kimi K2.6",
        api: "openai-completions",
        provider: "openrouter",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 256_000,
        maxTokens: 16_384,
        compat: {
          supportsReasoningEffort: true,
        },
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Reply live-ok", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key", reasoningEffort: "high" } as never,
      );

      let doneReason: string | undefined;
      let thinking = "";
      let text = "";
      for await (const event of stream as AsyncIterable<{
        type: string;
        delta?: string;
        reason?: string;
      }>) {
        if (event.type === "thinking_delta") {
          thinking += event.delta ?? "";
        }
        if (event.type === "text_delta") {
          text += event.delta ?? "";
        }
        if (event.type === "done") {
          doneReason = event.reason;
        }
      }

      expect(capturedStreamFlag).toBe(true);
      expect(thinking).toBe("Need a direct answer.");
      expect(text).toBe("live-ok");
      expect(doneReason).toBe("stop");
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("emits Qwen thinking streams when enabled without reasoning_effort support", async () => {
    let capturedPayload: Record<string, unknown> | undefined;
    const server = createServer((req, res) => {
      let body = "";
      req.setEncoding("utf8");
      req.on("data", (chunk) => {
        body += chunk;
      });
      req.on("end", () => {
        capturedPayload = JSON.parse(body) as Record<string, unknown>;
        res.writeHead(200, {
          "content-type": "application/json; charset=utf-8",
        });
        res.end(
          JSON.stringify({
            id: "chatcmpl-qwen-thinking",
            object: "chat.completion",
            model: "qwen3.5-32b",
            choices: [
              {
                index: 0,
                message: {
                  role: "assistant",
                  reasoning_content: "Need a Qwen answer.",
                  content: "qwen-ok",
                },
                finish_reason: "stop",
              },
            ],
          }),
        );
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        id: "qwen3.5-32b",
        name: "Qwen 3.5 32B",
        api: "openai-completions",
        provider: "qwen",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131072,
        maxTokens: 8192,
        compat: {
          thinkingFormat: "qwen",
          supportsReasoningEffort: false,
        },
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Reply qwen-ok", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key", reasoning: "medium" } as never,
      );

      let thinking = "";
      let text = "";
      for await (const event of stream as AsyncIterable<{ type: string; delta?: string }>) {
        if (event.type === "thinking_delta") {
          thinking += event.delta ?? "";
        }
        if (event.type === "text_delta") {
          text += event.delta ?? "";
        }
      }

      expect(capturedPayload?.enable_thinking).toBe(true);
      expect(capturedPayload).not.toHaveProperty("reasoning_effort");
      expect(thinking).toBe("Need a Qwen answer.");
      expect(text).toBe("qwen-ok");
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("does not emit thinking streams when reasoning is disabled", () => {
    const model = {
      id: "grok-4.20-beta-latest-reasoning",
      name: "Grok 4.20 Beta Latest (Reasoning)",
      api: "openai-completions",
      provider: "xai",
      baseUrl: "https://api.x.ai/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 2_000_000,
      maxTokens: 30_000,
    } satisfies Model<"openai-completions">;

    expect(
      testing.shouldEmitOpenAICompletionsReasoningForModel(model, {
        apiKey: "test-key",
        reasoning: "off",
      } as never),
    ).toBe(false);
  });

  it("emits Z.ai thinking streams when enabled without reasoning_effort support", () => {
    const model = {
      id: "glm-4.7",
      name: "GLM 4.7",
      api: "openai-completions",
      provider: "zai",
      baseUrl: "",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128_000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    expect(
      testing.shouldEmitOpenAICompletionsReasoningForModel(model, {
        apiKey: "test-key",
        reasoning: "medium",
      } as never),
    ).toBe(true);
  });

  it("preserves OpenAI-compatible error metadata on failed chat requests", async () => {
    const server = createServer((req, res) => {
      req.resume();
      req.on("end", () => {
        res.writeHead(429, {
          "content-type": "application/json; charset=utf-8",
          "x-request-id": "req_error_metadata",
        });
        res.end(
          JSON.stringify({
            error: {
              message: "Quota exceeded for api_key=sk-secret1234567890abcd",
              type: "rate_limit_error",
              code: "insufficient_quota",
            },
          }),
        );
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        id: "gpt-5.4-mini",
        name: "GPT-5.4 Mini",
        api: "openai-completions",
        provider: "openai",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200_000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Reply OK", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key" } as never,
      );

      let errorPayload: Record<string, unknown> | undefined;
      for await (const event of stream as AsyncIterable<{
        type: string;
        error?: Record<string, unknown>;
      }>) {
        if (event.type === "error") {
          errorPayload = event.error;
        }
      }

      expect(errorPayload).toMatchObject({
        stopReason: "error",
        errorCode: "insufficient_quota",
        errorType: "rate_limit_error",
      });
      expect(String(errorPayload?.errorBody)).toContain("Quota exceeded");
      expect(String(errorPayload?.errorBody)).not.toContain("sk-secret1234567890abcd");
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("classifies OpenAI-compatible unsupported-model detail from failed chat requests", async () => {
    const server = createServer((req, res) => {
      req.resume();
      req.on("end", () => {
        res.writeHead(400, {
          "content-type": "application/json; charset=utf-8",
          "x-request-id": "req_not_supported_model",
        });
        res.end(
          JSON.stringify({
            error: {
              code: "400",
              message: "Param Incorrect",
              param: "Not supported model some-model-id",
            },
          }),
        );
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        id: "some-model-id",
        name: "Some Model",
        api: "openai-completions",
        provider: "openai",
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200_000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Reply OK", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key" } as never,
      );

      let errorPayload: Record<string, unknown> | undefined;
      for await (const event of stream as AsyncIterable<{
        type: string;
        error?: Record<string, unknown>;
      }>) {
        if (event.type === "error") {
          errorPayload = event.error;
        }
      }

      expect(errorPayload).toMatchObject({
        stopReason: "error",
        errorMessage: "400 Param Incorrect",
        errorCode: "400",
      });
      expect(String(errorPayload?.errorBody)).toContain("Not supported model some-model-id");
      expect(classifyAssistantFailoverReason(errorPayload as never)).toBe("model_not_found");
      expect(formatUserFacingAssistantErrorText(errorPayload as never)).toBe(
        "The selected model was not found by the provider. Check the model id or choose a different model.",
      );
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("preserves reasoning tokens without double-counting them", () => {
    const model = {
      id: "gpt-5",
      name: "GPT-5",
      api: "openai-completions",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 1, output: 2, cacheRead: 0.5, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    expectRecordFields(
      parseTransportChunkUsage(
        {
          prompt_tokens: 10,
          completion_tokens: 20,
          total_tokens: 30,
          prompt_tokens_details: { cached_tokens: 3 },
          completion_tokens_details: { reasoning_tokens: 7 },
        },
        model,
      ),
      {
        input: 7,
        output: 20,
        cacheRead: 3,
        reasoningTokens: 7,
        totalTokens: 30,
      },
    );
  });

  it("clamps uncached prompt usage at zero", () => {
    const model = {
      id: "gpt-5",
      name: "GPT-5",
      api: "openai-completions",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 1, output: 2, cacheRead: 0.5, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    expectRecordFields(
      parseTransportChunkUsage(
        {
          prompt_tokens: 2,
          completion_tokens: 5,
          total_tokens: 7,
          prompt_tokens_details: { cached_tokens: 4 },
        },
        model,
      ),
      {
        input: 0,
        output: 5,
        cacheRead: 4,
        totalTokens: 9,
      },
    );
  });

  it("records usage from OpenAI-compatible streaming usage chunks", async () => {
    const model = {
      id: "glm-5",
      name: "GLM-5",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 4096,
    } satisfies Model<"openai-completions">;
    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };
    const stream: { push(event: unknown): void } = { push() {} };

    async function* mockStream() {
      yield {
        id: "chatcmpl-vllm",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "glm-5",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "ok" },
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      };
      yield {
        id: "chatcmpl-vllm",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "glm-5",
        choices: [],
        usage: {
          prompt_tokens: 8,
          completion_tokens: 10,
          total_tokens: 18,
        },
      };
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expectRecordFields(output.usage, {
      input: 8,
      output: 10,
      cacheRead: 0,
      totalTokens: 18,
    });
  });

  it("emits reasoning activity for OpenAI-compatible usage-only reasoning chunks", async () => {
    const model = {
      id: "google/gemini-2.5-flash",
      name: "Gemini 2.5 Flash",
      api: "openai-completions",
      provider: "vertex-ai",
      baseUrl: "http://127.0.0.1:8787/v1beta1/projects/test/locations/us/endpoints/openapi",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 1_000_000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-vertex",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [],
          usage: {
            prompt_tokens: 8,
            completion_tokens: 23,
            total_tokens: 31,
            completion_tokens_details: { reasoning_tokens: 23 },
          },
        },
        {
          id: "chatcmpl-vertex",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { role: "assistant" as const, content: "Hi" },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(events.map((event) => event.type)).toEqual([
      "thinking_start",
      "thinking_delta",
      "text_start",
      "text_delta",
    ]);
    expect(events[1]).toHaveProperty("delta", "");
    expect(output.content).toEqual([
      { type: "thinking", thinking: "" },
      { type: "text", text: "Hi" },
    ]);
  });

  it("does not add trailing reasoning activity after visible OpenAI-compatible text", async () => {
    const model = {
      id: "google/gemini-2.5-flash",
      name: "Gemini 2.5 Flash",
      api: "openai-completions",
      provider: "vertex-ai",
      baseUrl: "http://127.0.0.1:8787/v1beta1/projects/test/locations/us/endpoints/openapi",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 1_000_000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-vertex",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { role: "assistant" as const, content: "Hi" },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-vertex",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [],
          usage: {
            prompt_tokens: 8,
            completion_tokens: 25,
            total_tokens: 33,
            completion_tokens_details: { reasoning_tokens: 23 },
          },
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(events.map((event) => event.type)).toEqual(["text_start", "text_delta"]);
    expect(output.content).toEqual([{ type: "text", text: "Hi" }]);
  });

  it("yields to aborts during bursty OpenAI-compatible streams", async () => {
    const model = {
      id: "deepseek-v4-flash",
      name: "DeepSeek V4 Flash",
      api: "openai-completions",
      provider: "opencode-go",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 4096,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const abort = new AbortController();
    const stream = { push: vi.fn() };
    let yieldedToTimer = false;

    async function* mockStream() {
      for (let index = 0; index < 512; index += 1) {
        yield {
          id: "chatcmpl-bursty",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { role: "assistant" as const, content: "x" },
              logprobs: null,
              finish_reason: null,
            },
          ],
        };
      }
    }

    setTimeout(() => {
      yieldedToTimer = true;
      abort.abort();
    }, 0);

    await expect(
      testing.processOpenAICompletionsStream(mockStream(), output, model, stream, {
        signal: abort.signal,
      }),
    ).rejects.toThrow("Request was aborted");
    expect(yieldedToTimer).toBe(true);
    expect(stream.push.mock.calls.length).toBeLessThan(512);
  });

  it("omits accumulated partial snapshots from OpenAI-compatible text deltas", async () => {
    const model = {
      id: "dense-local",
      name: "Dense Local",
      api: "openai-completions",
      provider: "local",
      baseUrl: "http://127.0.0.1:18065/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 4096,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-dense",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { role: "assistant" as const, content: "a" },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-dense",
          object: "chat.completion.chunk" as const,
          created: 1775425651,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { content: "b" },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    const textDeltas = events.filter((event) => event.type === "text_delta");
    expect(textDeltas).toHaveLength(2);
    expect(textDeltas.every((event) => !("partial" in event))).toBe(true);
    expect(output.content).toEqual([{ type: "text", text: "ab" }]);
  });

  it("yields to aborts during bursty Responses streams", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);
    const abort = new AbortController();
    const stream = { push: vi.fn() };
    let yieldedToTimer = false;

    async function* mockStream() {
      yield { type: "response.output_item.added", item: { type: "message" } };
      for (let index = 0; index < 512; index += 1) {
        yield { type: "response.output_text.delta", delta: "x" };
      }
    }

    setTimeout(() => {
      yieldedToTimer = true;
      abort.abort();
    }, 0);

    await expect(
      testing.processResponsesStream(mockStream(), output, stream, model, {
        signal: abort.signal,
      }),
    ).rejects.toThrow("Request was aborted");
    expect(yieldedToTimer).toBe(true);
    expect(stream.push.mock.calls.length).toBeLessThan(512);
  });

  it("omits accumulated partial snapshots from Responses text deltas", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processResponsesStream(
      streamChunks([
        { type: "response.output_item.added", item: { type: "message" } },
        { type: "response.output_text.delta", delta: "a" },
        { type: "response.output_text.delta", delta: "b" },
      ]),
      output,
      { push: (event) => events.push(event as CapturedStreamEvent) },
      model,
    );

    const textDeltas = events.filter((event) => event.type === "text_delta");
    expect(textDeltas).toHaveLength(2);
    expect(textDeltas.every((event) => !("partial" in event))).toBe(true);
    expect(output.content).toEqual([{ type: "text", text: "ab" }]);
  });

  it("handles Azure Responses text content and text delta events", async () => {
    const model = createAzureResponsesModel();
    const output = createResponsesAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processResponsesStream(
      streamChunks([
        {
          type: "response.output_item.added",
          item: {
            type: "message",
            role: "assistant",
            id: "msg_azure_text",
            content: [],
            status: "in_progress",
          },
        },
        { type: "response.text.delta", delta: "Hello" },
        { type: "response.text.delta", delta: " from Azure!" },
        {
          type: "response.output_item.done",
          item: {
            type: "message",
            role: "assistant",
            id: "msg_azure_text",
            content: [{ type: "text", text: "Hello from Azure!" }],
            status: "completed",
          },
        },
        {
          type: "response.completed",
          response: {
            id: "resp_azure_text",
            status: "completed",
            usage: {
              input_tokens: 4,
              output_tokens: 3,
              total_tokens: 7,
            },
          },
        },
      ]),
      output,
      { push: (event) => events.push(event as CapturedStreamEvent) },
      model,
    );

    expect(events).toMatchObject([
      { type: "text_start" },
      { type: "text_delta", delta: "Hello" },
      { type: "text_delta", delta: " from Azure!" },
      { type: "text_end", content: "Hello from Azure!" },
    ]);
    expect(output.content).toMatchObject([{ type: "text", text: "Hello from Azure!" }]);
    expectRecordFields(output.usage, {
      input: 4,
      output: 3,
      totalTokens: 7,
    });
    expect(output.responseId).toBe("resp_azure_text");
  });

  it("skips null and non-object OpenAI-compatible stream chunks", async () => {
    const model = {
      id: "glm-5",
      name: "GLM-5",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 4096,
    } satisfies Model<"openai-completions">;
    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };
    const stream: { push(event: unknown): void } = { push() {} };

    async function* mockStream() {
      yield null as never;
      yield "not-a-chunk" as never;
      yield {
        id: "chatcmpl-vllm",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "glm-5",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "ok" },
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      };
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toStrictEqual([{ type: "text", text: "ok" }]);
    expect(output.stopReason).toBe("stop");
  });

  it("filters DeepSeek DSML content without disturbing native tool calls", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "before <｜DSML｜tool_use_error>body</｜DSML｜tool_use_error> after",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-deepseek-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "<|DSML|tool_calls>shadow</|DSML|tool_calls>",
                tool_calls: [
                  {
                    index: 0,
                    id: "call_native_1",
                    type: "function",
                    function: { name: "read", arguments: '{"path":"/tmp/native.md"}' },
                  },
                ],
              },
              logprobs: null,
              finish_reason: "tool_calls",
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(output.content).toEqual([
      { type: "text", text: "before  after" },
      {
        type: "toolCall",
        id: "call_native_1",
        name: "read",
        arguments: { path: "/tmp/native.md" },
        partialArgs: '{"path":"/tmp/native.md"}',
      },
    ]);
    expect(JSON.stringify(events)).not.toContain("DSML");
  });

  it("preserves DeepSeek visible content before same-chunk native tool calls", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-native-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "I'll check",
                tool_calls: [
                  {
                    index: 0,
                    id: "call_native_1",
                    type: "function",
                    function: { name: "read", arguments: '{"path":"/tmp/native.md"}' },
                  },
                ],
              },
              logprobs: null,
              finish_reason: "tool_calls",
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toEqual([
      { type: "text", text: "I'll check" },
      {
        type: "toolCall",
        id: "call_native_1",
        name: "read",
        arguments: { path: "/tmp/native.md" },
        partialArgs: '{"path":"/tmp/native.md"}',
      },
    ]);
  });

  it("filters DeepSeek DSML text queued after native tool calls", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-post-tool-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                tool_calls: [
                  {
                    index: 0,
                    id: "call_native_1",
                    type: "function",
                    function: { name: "read", arguments: '{"path":"/tmp/native.md"}' },
                  },
                ],
              },
              logprobs: null,
              finish_reason: "tool_calls",
            },
          ],
        },
        {
          id: "chatcmpl-deepseek-post-tool-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "<|DSML|tool_calls>shadow</|DSML|tool_calls> visible",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(output.content).toEqual([
      {
        type: "toolCall",
        id: "call_native_1",
        name: "read",
        arguments: { path: "/tmp/native.md" },
        partialArgs: '{"path":"/tmp/native.md"}',
      },
      { type: "text", text: " visible" },
    ]);
    expect(JSON.stringify(events)).not.toContain("DSML");
  });

  it("keeps DeepSeek DSML state across native tool-call chunks", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-split-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "before <|DSML|tool",
                tool_calls: [
                  {
                    index: 0,
                    id: "call_native_1",
                    type: "function",
                    function: { name: "read", arguments: '{"path":"/tmp/native.md"}' },
                  },
                ],
              },
              logprobs: null,
              finish_reason: "tool_calls",
            },
          ],
        },
        {
          id: "chatcmpl-deepseek-split-dsml",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "_calls>shadow</|DSML|tool_calls> after",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(output.content).toEqual([
      { type: "text", text: "before " },
      {
        type: "toolCall",
        id: "call_native_1",
        name: "read",
        arguments: { path: "/tmp/native.md" },
        partialArgs: '{"path":"/tmp/native.md"}',
      },
      { type: "text", text: " after" },
    ]);
    expect(JSON.stringify(events)).not.toContain("DSML");
  });

  it("recovers DeepSeek DSML parameter tool calls emitted as text", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-dsml-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content:
                  '<｜DSML｜tool_calls>\n<｜DSML｜invoke name="session_status">\n<｜DSML｜parameter name="sessionKey" string="true">current</｜DSML｜parameter>\n</｜DSML｜invoke>\n</｜DSML｜tool_calls>',
              },
              logprobs: null,
              finish_reason: "stop",
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toEqual([
      {
        type: "toolCall",
        id: "call_deepseek_dsml_1",
        name: "session_status",
        arguments: { sessionKey: "current" },
        partialArgs: '{"sessionKey":"current"}',
      },
    ]);
    expect(JSON.stringify(events)).not.toContain("DSML");
  });

  it.each([
    { finishReason: "length", stopReason: "length" },
    { finishReason: "content_filter", stopReason: "error" },
  ])(
    "does not authorize recovered DeepSeek DSML calls after $finishReason",
    async ({ finishReason, stopReason }) => {
      const model = createDeepSeekCompletionsModel();
      const output = createAssistantOutput(model);
      expect(testing.getCompat(model).thinkingFormat).toBe("deepseek");

      await testing.processOpenAICompletionsStream(
        streamChunks([
          {
            id: "chatcmpl-deepseek-dsml-terminal",
            object: "chat.completion.chunk",
            created: 1,
            model: model.id,
            choices: [
              {
                index: 0,
                delta: {
                  content:
                    '<|DSML|tool_calls><|DSML|invoke name="read">{"path":"/tmp/partial.md"}</|DSML|invoke></|DSML|tool_calls>',
                },
                logprobs: null,
                finish_reason: finishReason,
              },
            ],
          },
        ]),
        output,
        model,
        { push() {} },
      );

      expect(output.stopReason).toBe(stopReason);
      expect(output.content).toEqual([]);
    },
  );

  it("does not authorize recovered DeepSeek DSML calls when the stream omits a terminal", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-dsml-no-terminal",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content:
                  '<|DSML|tool_calls><|DSML|invoke name="read">{"path":"/tmp/partial.md"}</|DSML|invoke></|DSML|tool_calls>',
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.stopReason).toBe("stop");
    expect(output.content).toEqual([]);
  });

  it("emits recovered DeepSeek content-filter terminals as errors", async () => {
    const server = createServer((req, res) => {
      req.resume();
      req.on("end", () => {
        res.writeHead(200, {
          "content-type": "text/event-stream; charset=utf-8",
          "cache-control": "no-cache",
          connection: "keep-alive",
        });
        res.write(
          `data: ${JSON.stringify({
            id: "chatcmpl-deepseek-dsml-content-filter",
            object: "chat.completion.chunk",
            created: 1,
            model: "deepseek-v4-pro",
            choices: [
              {
                index: 0,
                delta: {
                  content:
                    '<|DSML|tool_calls><|DSML|invoke name="read">{"path":"/tmp/partial.md"}</|DSML|invoke></|DSML|tool_calls>',
                },
                finish_reason: "content_filter",
              },
            ],
          })}\n\n`,
        );
        res.end("data: [DONE]\n\n");
      });
    });

    await new Promise<void>((resolve) => {
      server.listen(0, "127.0.0.1", resolve);
    });
    try {
      const address = server.address();
      if (!address || typeof address === "string") {
        throw new Error("Missing loopback server address");
      }
      const model = {
        ...createDeepSeekCompletionsModel(),
        baseUrl: `http://127.0.0.1:${address.port}/v1`,
      } satisfies Model<"openai-completions">;
      const stream = createOpenAICompletionsTransportStreamFn()(
        model,
        {
          systemPrompt: "system",
          messages: [{ role: "user", content: "Read the file", timestamp: Date.now() }],
          tools: [],
        } as never,
        { apiKey: "test-key" } as never,
      );

      const terminalEvents: Array<{
        type: string;
        reason?: string;
        error?: Record<string, unknown>;
      }> = [];
      for await (const event of stream as AsyncIterable<{
        type: string;
        reason?: string;
        error?: Record<string, unknown>;
      }>) {
        if (event.type === "done" || event.type === "error") {
          terminalEvents.push(event);
        }
      }

      expect(terminalEvents).toEqual([
        expect.objectContaining({
          type: "error",
          reason: "error",
          error: expect.objectContaining({
            stopReason: "error",
            errorMessage: "Provider finish_reason: content_filter",
            content: [],
          }),
        }),
      ]);
    } finally {
      await new Promise<void>((resolve, reject) => {
        server.close((error) => (error ? reject(error) : resolve()));
      });
    }
  });

  it("parses repeated DeepSeek DSML name attributes consistently", async () => {
    // Guards the cached attribute matchers: repeated parses must stay identical
    // (no stale RegExp lastIndex) across separate stream invocations.
    const model = createDeepSeekCompletionsModel();
    const content =
      '<｜DSML｜tool_calls>\n<｜DSML｜invoke name="session_status">\n<｜DSML｜parameter name="sessionKey" string="true">current</｜DSML｜parameter>\n</｜DSML｜invoke>\n</｜DSML｜tool_calls>';

    const runOnce = async () => {
      const output = createAssistantOutput(model);
      await testing.processOpenAICompletionsStream(
        streamChunks([
          {
            id: "chatcmpl-deepseek-dsml-repeat",
            object: "chat.completion.chunk",
            created: 1,
            model: model.id,
            choices: [
              {
                index: 0,
                delta: { content },
                logprobs: null,
                finish_reason: "stop",
              },
            ],
          },
        ]),
        output,
        model,
        { push() {} },
      );
      return output.content;
    };

    const first = await runOnce();
    const second = await runOnce();
    expect(second).toEqual(first);
    expect(first).toEqual([
      {
        type: "toolCall",
        id: "call_deepseek_dsml_1",
        name: "session_status",
        arguments: { sessionKey: "current" },
        partialArgs: '{"sessionKey":"current"}',
      },
    ]);
  });

  it("recovers split DeepSeek DSML JSON tool calls emitted as text", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-split-dsml-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { content: '<|DSML|tool_calls><|DSML|invoke name="read">' },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-deepseek-split-dsml-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { content: '{"path":"/tmp/native.md"}</|DSML|invoke>' },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-deepseek-split-dsml-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { content: "</|DSML|tool_calls>" },
              logprobs: null,
              finish_reason: "stop",
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toEqual([
      {
        type: "toolCall",
        id: "call_deepseek_dsml_1",
        name: "read",
        arguments: { path: "/tmp/native.md" },
        partialArgs: '{"path":"/tmp/native.md"}',
      },
    ]);
  });

  it("does not recover malformed DeepSeek DSML tool calls", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-deepseek-malformed-dsml-tool",
          object: "chat.completion.chunk",
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content:
                  '<｜DSML｜tool_calls>\n<｜DSML｜invoke name="session_status">\n</｜DSML｜invoke>\n</｜DSML｜tool_calls>',
              },
              logprobs: null,
              finish_reason: "stop",
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.stopReason).toBe("stop");
    expect(output.content).toEqual([]);
  });

  it("keeps OpenRouter thinking format for declared OpenRouter providers on custom proxy URLs", () => {
    const params = buildOpenAICompletionsParams(
      attachModelProviderRequestTransport(
        {
          id: "anthropic/claude-sonnet-4",
          name: "Claude Sonnet 4",
          api: "openai-completions",
          provider: "openrouter",
          baseUrl: "https://proxy.example.com/v1",
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 200000,
          maxTokens: 8192,
        } satisfies Model<"openai-completions">,
        {
          proxy: {
            mode: "explicit-proxy",
            url: "http://proxy.internal:8443",
          },
        },
      ),
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoningEffort: "high",
      } as never,
    );

    expect(params.reasoning).toEqual({ effort: "high" });
  });

  it("keeps OpenRouter thinking format for native OpenRouter hosts behind custom provider ids", () => {
    const params = buildOpenAICompletionsParams(
      attachModelProviderRequestTransport(
        {
          id: "anthropic/claude-sonnet-4",
          name: "Claude Sonnet 4",
          api: "openai-completions",
          provider: "custom-openrouter",
          baseUrl: "https://openrouter.ai/api/v1",
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 200000,
          maxTokens: 8192,
        } satisfies Model<"openai-completions">,
        {
          proxy: {
            mode: "explicit-proxy",
            url: "http://proxy.internal:8443",
          },
        },
      ),
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoningEffort: "high",
      } as never,
    );

    expect(params.reasoning).toEqual({ effort: "high" });
  });

  it("forwards temperature and top_p to chat completions request params", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [{ role: "user", content: "hi", timestamp: 1 }],
        tools: [],
      } as never,
      {
        temperature: 0.4,
        topP: 0.9,
      },
    );

    expect(params.temperature).toBe(0.4);
    expect(params.top_p).toBe(0.9);
  });

  it("forwards penalty params and seed to chat completions request params", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [{ role: "user", content: "hi", timestamp: 1 }],
        tools: [],
      } as never,
      {
        frequencyPenalty: -0.5,
        presencePenalty: 1.25,
        seed: 12345,
      },
    );

    expect(params.frequency_penalty).toBe(-0.5);
    expect(params.presence_penalty).toBe(1.25);
    expect(params.seed).toBe(12345);
  });

  it("forwards stop sequences to chat completions request params", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [{ role: "user", content: "hi", timestamp: 1 }],
        tools: [],
      } as never,
      {
        stop: ["User:", "Assistant:"],
      },
    );

    expect(params.stop).toEqual(["User:", "Assistant:"]);
  });

  it("forwards response_format to chat completions request params", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-completions",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const context = {
      systemPrompt: "system",
      messages: [{ role: "user", content: "hi", timestamp: 1 }],
      tools: [],
    } as never;

    {
      const params = buildOpenAICompletionsParams(model, context, {
        responseFormat: { type: "json_object" },
      });
      expect(params.response_format).toEqual({ type: "json_object" });
    }

    {
      const params = buildOpenAICompletionsParams(model, context, {
        responseFormat: { type: "json_schema", json_schema: {} },
      });
      expect(params.response_format).toEqual({ type: "json_schema", json_schema: {} });
    }

    {
      const params = buildOpenAICompletionsParams(model, context, {});
      expect(params).not.toHaveProperty("response_format");
    }
  });

  it("does not build OpenRouter reasoning params for Hunter Alpha when reasoning is disabled", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "openrouter/hunter-alpha",
        name: "Hunter Alpha",
        api: "openai-completions",
        provider: "openrouter",
        baseUrl: "https://openrouter.ai/api/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1_048_576,
        maxTokens: 65_536,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoningEffort: "high",
      } as never,
    ) as { reasoning?: unknown; reasoning_effort?: unknown };

    expect(params).not.toHaveProperty("reasoning");
    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it("uses system role instead of developer for responses providers that disable developer role", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "grok-4.1-fast",
        name: "Grok 4.1 Fast",
        api: "openai-responses",
        provider: "xai",
        baseUrl: "https://api.x.ai/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { input?: Array<{ role?: string }> };

    expect(params.input?.[0]?.role).toBe("system");
  });

  it("adds explicit message item types for Responses system and user input items", () => {
    const params = buildOpenAIResponsesParams(
      createAzureResponsesModel(),
      {
        systemPrompt: "system",
        messages: [{ role: "user", content: "hello" }],
        tools: [],
      } as never,
      undefined,
    ) as { input?: Array<{ type?: string; role?: string; content?: unknown }> };

    expect(params.input?.[0]).toMatchObject({
      type: "message",
      role: "system",
      content: [{ type: "input_text", text: "system" }],
    });
    expect(params.input?.[1]).toMatchObject({
      type: "message",
      role: "user",
      content: [{ type: "input_text", text: "hello" }],
    });
  });

  it("omits Responses reasoning params when model compat disables reasoning effort", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "grok-4.20-beta-latest-reasoning",
        name: "Grok 4.20 Beta Latest (Reasoning)",
        api: "openai-responses",
        provider: "xai",
        baseUrl: "https://api.x.ai/v1",
        reasoning: true,
        input: ["text", "image"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 2_000_000,
        maxTokens: 30_000,
        compat: { supportsReasoningEffort: false },
      } as unknown as Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "high",
      } as never,
    ) as { reasoning?: unknown; include?: string[] };

    expect(params).not.toHaveProperty("reasoning");
    expect(params).not.toHaveProperty("include");
  });

  it("preserves xAI Grok 4.3 default reasoning by omitting default none", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "grok-4.3",
        name: "Grok 4.3",
        api: "openai-responses",
        provider: "xai",
        baseUrl: "https://api.x.ai/v1",
        reasoning: true,
        input: ["text", "image"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1_000_000,
        maxTokens: 128_000,
        compat: {
          supportsReasoningEffort: true,
          supportedReasoningEfforts: ["low", "medium", "high"],
        },
      } as unknown as Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { reasoning?: unknown; include?: string[] };

    expect(params).not.toHaveProperty("reasoning");
    expect(params).not.toHaveProperty("include");
  });

  it("passes explicit xAI Grok 4.3 reasoning effort through", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "grok-4.3",
        name: "Grok 4.3",
        api: "openai-responses",
        provider: "xai",
        baseUrl: "https://api.x.ai/v1",
        reasoning: true,
        input: ["text", "image"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1_000_000,
        maxTokens: 128_000,
        compat: {
          supportsReasoningEffort: true,
          supportedReasoningEfforts: ["low", "medium", "high"],
        },
      } as unknown as Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "high",
      } as never,
    ) as { reasoning?: unknown; include?: string[] };

    expect(params.reasoning).toEqual({ effort: "high", summary: "auto" });
    expect(params.include).toEqual(["reasoning.encrypted_content"]);
  });

  it("keeps developer role for native OpenAI reasoning responses models", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { input?: Array<{ role?: string }> };

    expect(params.input?.[0]?.role).toBe("developer");
  });

  it("serializes Responses input messages with explicit message type and content parts", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "microsoft-foundry",
        baseUrl: "https://example.services.ai.azure.com/api/projects/demo/openai/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [{ role: "user", content: "hello", timestamp: 1 }],
        tools: [],
      } as never,
      undefined,
    ) as { input?: unknown };

    expect(params.input).toEqual([
      {
        type: "message",
        role: "system",
        content: [{ type: "input_text", text: "system" }],
      },
      {
        type: "message",
        role: "user",
        content: [{ type: "input_text", text: "hello" }],
      },
    ]);
  });

  it("uses model maxTokens for Responses params when runtime maxTokens is omitted", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 65_536,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { max_output_tokens?: unknown };

    expect(params.max_output_tokens).toBe(65_536);
  });

  it("prefers promptCacheKey over sessionId for Responses prompt-cache affinity", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        sessionId: "run-session",
        promptCacheKey: "cron-cache-key",
      },
    ) as { prompt_cache_key?: string };

    expect(params.prompt_cache_key).toBe("cron-cache-key");
  });

  it("clamps Responses promptCacheKey before sending it upstream", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        promptCacheKey: "x".repeat(80),
        sessionId: "session-123",
      },
    ) as { prompt_cache_key?: string };

    expect(params.prompt_cache_key).toBe("x".repeat(64));
  });

  it("omits Responses prompt_cache_key when caching is disabled", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        sessionId: "run-session",
        promptCacheKey: "cron-cache-key",
        cacheRetention: "none",
      },
    ) as { prompt_cache_key?: string };

    expect(params.prompt_cache_key).toBeUndefined();
  });

  it("adds fallback instructions for raw native Codex responses probes", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api/codex",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 400000,
        maxTokens: 128000,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: "",
        messages: [{ role: "user", content: "Reply OK", timestamp: 1 }],
        tools: [],
      } as never,
      {
        maxTokens: 16,
        sessionId: "session-123",
      },
    ) as Record<string, unknown>;

    expect(params.instructions).toBe("Follow the user request.");
    expect(params.max_output_tokens).toBeUndefined();
    expect(params.prompt_cache_retention).toBeUndefined();
  });

  it("treats canonical OpenAI Codex responses models as native Codex responses", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api/codex",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 400000,
        maxTokens: 128000,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: "",
        messages: [{ role: "user", content: "Reply OK", timestamp: 1 }],
        tools: [],
      } as never,
      {
        maxTokens: 16,
        sessionId: "session-123",
      },
    ) as Record<string, unknown>;

    expect(params.instructions).toBe("Follow the user request.");
    expect(params.max_output_tokens).toBeUndefined();
    expect(params.prompt_cache_retention).toBeUndefined();
  });

  it("does not add fallback instructions for custom Codex-compatible responses backends", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 400000,
        maxTokens: 128000,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: "",
        messages: [{ role: "user", content: "Reply OK", timestamp: 1 }],
        tools: [],
      } as never,
      {
        maxTokens: 16,
        sessionId: "session-123",
      },
    ) as Record<string, unknown>;

    expect(params.instructions).toBeUndefined();
    expect(params.max_output_tokens).toBe(16);
  });

  it("uses top-level instructions for Codex responses and preserves prompt cache identity", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [{ role: "user", content: "Hello", timestamp: 1 }],
        tools: [],
      } as never,
      {
        cacheRetention: "long",
        maxTokens: 1024,
        serviceTier: "auto",
        sessionId: "session-123",
        temperature: 0.2,
        topP: 0.85,
      },
      {
        openclaw_session_id: "session-123",
        openclaw_turn_id: "turn-123",
      },
    ) as Record<string, unknown> & {
      input?: Array<{ role?: string }>;
      instructions?: string;
    };

    expect(params.instructions).toBe("Stable prefix\nDynamic suffix");
    expect(Array.isArray(params.input)).toBe(true);
    expect(params.input?.map((item) => item.role)).toEqual(["user"]);
    expect(
      params.input?.filter((item) => item.role === "system" || item.role === "developer"),
    ).toStrictEqual([]);
    expect(params.prompt_cache_key).toBe("session-123");
    expect(params.store).toBe(false);
    expect(params).not.toHaveProperty("metadata");
    expect(params).not.toHaveProperty("max_output_tokens");
    expect(params).not.toHaveProperty("prompt_cache_retention");
    expect(params).not.toHaveProperty("service_tier");
    expect(params).not.toHaveProperty("temperature");
    expect(params).not.toHaveProperty("top_p");
  });

  it("keeps Codex response shaping when simple completions use the OpenClaw transport alias", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openclaw-openai-responses-transport" as Api,
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api/codex",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [{ role: "user", content: "Hello", timestamp: 1 }],
        tools: [],
      } as never,
      {
        cacheRetention: "long",
        maxTokens: 1024,
        serviceTier: "auto",
        sessionId: "session-123",
        temperature: 0.2,
        topP: 0.85,
      },
      {
        openclaw_session_id: "session-123",
        openclaw_turn_id: "turn-123",
      },
    ) as Record<string, unknown> & {
      input?: Array<{ role?: string }>;
      instructions?: string;
    };

    expect(params.instructions).toBe("Stable prefix\nDynamic suffix");
    expect(params.input?.map((item) => item.role)).toEqual(["user"]);
    expect(params.prompt_cache_key).toBe("session-123");
    expect(params.store).toBe(false);
    expect(params).not.toHaveProperty("metadata");
    expect(params).not.toHaveProperty("max_output_tokens");
    expect(params).not.toHaveProperty("prompt_cache_retention");
    expect(params).not.toHaveProperty("service_tier");
    expect(params).not.toHaveProperty("temperature");
    expect(params).not.toHaveProperty("top_p");
  });

  it("sanitizes Codex responses params after payload hooks mutate them without stripping cache identity", () => {
    const payload = {
      model: "gpt-5.4",
      input: [],
      stream: true,
      max_output_tokens: 1024,
      metadata: { openclaw_session_id: "session-123" },
      prompt_cache_key: "session-123",
      prompt_cache_retention: "24h",
      service_tier: "auto",
      temperature: 0.2,
      text: { format: { type: "json_object" }, verbosity: "low" },
      top_p: 0.85,
    };

    const sanitized = testing.sanitizeOpenAICodexResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      payload,
    );

    expect(sanitized.prompt_cache_key).toBe("session-123");
    expect(sanitized).not.toHaveProperty("metadata");
    expect(sanitized).not.toHaveProperty("max_output_tokens");
    expect(sanitized).not.toHaveProperty("prompt_cache_retention");
    expect(sanitized).not.toHaveProperty("service_tier");
    expect(sanitized).not.toHaveProperty("temperature");
    expect(sanitized.text).toEqual({ verbosity: "low" });
    expect(sanitized).not.toHaveProperty("top_p");
  });

  it("preserves custom Codex-compatible responses params", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [{ role: "user", content: "Hello", timestamp: 1 }],
        tools: [],
      } as never,
      {
        cacheRetention: "long",
        maxTokens: 1024,
        sessionId: "session-123",
        temperature: 0.2,
        topP: 0.85,
      },
      {
        openclaw_session_id: "session-123",
        openclaw_turn_id: "turn-123",
      },
    ) as Record<string, unknown>;

    expect(params.instructions).toBe("Stable prefix\nDynamic suffix");
    expect(params.prompt_cache_key).toBe("session-123");
    expect(params.metadata).toEqual({
      openclaw_session_id: "session-123",
      openclaw_turn_id: "turn-123",
    });
    expect(params.max_output_tokens).toBe(1024);
    expect(params.temperature).toBe(0.2);
    expect(params.top_p).toBe(0.85);
  });

  it("forwards response_format to responses text format request params", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-responses",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 65_536,
    } satisfies Model<"openai-responses">;

    const context = {
      systemPrompt: "system",
      messages: [{ role: "user", content: "hi", timestamp: 1 }],
      tools: [],
    } as never;

    {
      const params = buildOpenAIResponsesParams(model, context, {
        responseFormat: { type: "json_object" },
      }) as Record<string, unknown>;
      expect(params.text).toEqual({ format: { type: "json_object" } });
    }

    {
      const params = buildOpenAIResponsesParams(model, context, {
        responseFormat: {
          type: "json_schema",
          json_schema: { name: "test", schema: { type: "object" } },
        },
      }) as Record<string, unknown>;
      expect(params.text).toEqual({
        format: { type: "json_schema", name: "test", schema: { type: "object" } },
      });
    }

    {
      const params = buildOpenAIResponsesParams(model, context, {}) as Record<string, unknown>;
      expect(params).not.toHaveProperty("text");
    }
  });

  it("preserves custom Codex-compatible responses params after payload hooks mutate them", () => {
    const payload = {
      model: "gpt-5.4",
      input: [],
      stream: true,
      max_output_tokens: 1024,
      metadata: { openclaw_session_id: "session-123" },
      prompt_cache_key: "session-123",
      prompt_cache_retention: "24h",
      service_tier: "auto",
      temperature: 0.2,
    };

    const sanitized = testing.sanitizeOpenAICodexResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      payload,
    );

    expect(sanitized).toEqual(payload);
  });

  it("omits native Codex replay item ids and unproven encrypted reasoning", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-chatgpt-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
              },
              {
                type: "text",
                text: "Checking the price.",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_prior",
                  phase: "commentary",
                }),
              },
              {
                type: "toolCall",
                id: "call_abc|fc_prior",
                name: "price_lookup",
                arguments: { symbol: "SOL" },
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: "call_abc|fc_prior",
            toolName: "price_lookup",
            content: [{ type: "text", text: "$83.95" }],
            isError: false,
            timestamp: 2,
          },
          { role: "user", content: "what is the capital of the philippines", timestamp: 3 },
        ],
        tools: [],
      } as never,
      { sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        role?: string;
        id?: string;
        call_id?: string;
        phase?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("encrypted_content");
    const assistantMessage = params.input?.find(
      (item) => item.type === "message" && item.role === "assistant",
    );
    expectRecordFields(assistantMessage, {
      type: "message",
      role: "assistant",
      phase: "commentary",
    });
    expect(assistantMessage?.id).toBeUndefined();
    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      call_id: "call_abc",
    });
    expect(functionCall?.id).toBeUndefined();
  });

  it("omits Responses replay item ids when OpenAI Responses requests disable store", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "mycodex",
        baseUrl: "http://127.0.0.1:8317/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1_000_000,
        maxTokens: 128_000,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "mycodex",
            model: "gpt-5.5",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
              },
              {
                type: "text",
                text: "Checking the price.",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_prior",
                  phase: "commentary",
                }),
              },
              {
                type: "toolCall",
                id: "call_abc|fc_prior",
                name: "price_lookup",
                arguments: { symbol: "SOL" },
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: "call_abc|fc_prior",
            toolName: "price_lookup",
            content: [{ type: "text", text: "$83.95" }],
            isError: false,
            timestamp: 2,
          },
        ],
        tools: [],
      } as never,
      { sessionId: "session-123" },
    ) as {
      store?: boolean;
      input?: Array<{
        type?: string;
        role?: string;
        id?: string;
        call_id?: string;
        phase?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    expect(params.store).toBe(false);
    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("encrypted_content");
    const assistantMessage = params.input?.find(
      (item) => item.type === "message" && item.role === "assistant",
    );
    expectRecordFields(assistantMessage, {
      type: "message",
      role: "assistant",
      phase: "commentary",
    });
    expect(assistantMessage?.id).toBeUndefined();
    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      call_id: "call_abc",
    });
    expect(functionCall?.id).toBeUndefined();
  });

  it("preserves Responses replay item ids when a store-enabled wrapper requests replay", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
              },
              {
                type: "text",
                text: "Checking the price.",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_prior",
                  phase: "commentary",
                }),
              },
              {
                type: "toolCall",
                id: "call_abc|fc_prior",
                name: "price_lookup",
                arguments: { symbol: "SOL" },
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: "call_abc|fc_prior",
            toolName: "price_lookup",
            content: [{ type: "text", text: "$83.95" }],
            isError: false,
            timestamp: 2,
          },
        ],
        tools: [],
      } as never,
      { replayResponsesItemIds: true, sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        role?: string;
        id?: string;
        call_id?: string;
        phase?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      id: "rs_prior",
      summary: [],
    });
    const assistantMessage = params.input?.find(
      (item) => item.type === "message" && item.role === "assistant",
    );
    expectRecordFields(assistantMessage, {
      type: "message",
      role: "assistant",
      id: "msg_prior",
      phase: "commentary",
    });
    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      id: "fc_prior",
      call_id: "call_abc",
    });
  });

  it("preserves Responses replay item ids for store-capable third-party opt-in routes", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "store-capable-model",
        name: "Store-capable model",
        api: "openai-responses",
        provider: "custom-openai-responses",
        baseUrl: "https://custom.example.com/v1",
        compat: { supportsStore: true } as never,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "custom-openai-responses",
            model: "store-capable-model",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  summary: [],
                }),
              },
              {
                type: "text",
                text: "Checking the price.",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_prior",
                  phase: "commentary",
                }),
              },
              {
                type: "toolCall",
                id: "call_abc|fc_prior",
                name: "price_lookup",
                arguments: { symbol: "SOL" },
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { replayResponsesItemIds: true, sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        role?: string;
        id?: string;
        call_id?: string;
        phase?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      id: "rs_prior",
      summary: [],
    });
    const assistantMessage = params.input?.find(
      (item) => item.type === "message" && item.role === "assistant",
    );
    expectRecordFields(assistantMessage, {
      type: "message",
      role: "assistant",
      id: "msg_prior",
      phase: "commentary",
    });
    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      id: "fc_prior",
      call_id: "call_abc",
    });
  });

  it("omits prior Responses replay item ids when store is disabled for custom Codex-compatible responses", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-chatgpt-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-chatgpt-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
                openclawReasoningReplay: testing.buildOpenAIResponsesReasoningReplayMetadata(
                  model,
                  {
                    authProfileId: "openai:oauth",
                    sessionId: "session-123",
                  },
                ),
              },
              {
                type: "text",
                text: "Checking the price.",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_prior",
                  phase: "commentary",
                }),
              },
              {
                type: "toolCall",
                id: "call_abc|fc_prior",
                name: "price_lookup",
                arguments: { symbol: "SOL" },
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { authProfileId: "openai:oauth", sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        role?: string;
        id?: string;
        call_id?: string;
        phase?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      encrypted_content: "ciphertext",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("__openclaw_replay");
    const assistantMessage = params.input?.find(
      (item) => item.type === "message" && item.role === "assistant",
    );
    expectRecordFields(assistantMessage, {
      type: "message",
      role: "assistant",
      phase: "commentary",
    });
    expect(assistantMessage?.id).toBeUndefined();
    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      call_id: "call_abc",
    });
    expect(functionCall?.id).toBeUndefined();
  });

  it("keeps GitHub Copilot Responses reasoning replay when store-disabled ids are omitted", () => {
    const model = {
      id: "gpt-5.5",
      name: "GPT-5.5",
      api: "openai-responses",
      provider: "github-copilot",
      baseUrl: "https://api.githubcopilot.com",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 400000,
      maxTokens: 8192,
    } satisfies Model<"openai-responses">;
    const longReasoningId = `rs_${"x".repeat(380)}`;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "github-copilot",
            model: "gpt-5.5",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: longReasoningId,
                  summary: [],
                }),
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        id?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
  });

  it("drops oversized GitHub Copilot Responses reasoning replay ids before send", () => {
    const model = {
      id: "gpt-5.5",
      name: "GPT-5.5",
      api: "openai-responses",
      provider: "github-copilot",
      baseUrl: "https://api.githubcopilot.com",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 400000,
      maxTokens: 8192,
    } satisfies Model<"openai-responses">;
    const longReasoningId = `rs_${"x".repeat(380)}`;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "github-copilot",
            model: "gpt-5.5",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: longReasoningId,
                  summary: [],
                }),
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { replayResponsesItemIds: true, sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        id?: string;
      }>;
    };

    expect(params.input?.some((item) => item.type === "reasoning")).toBe(false);
  });

  it("strips encrypted reasoning replay when provenance does not match", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-chatgpt-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-chatgpt-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
                openclawReasoningReplay: testing.buildOpenAIResponsesReasoningReplayMetadata(
                  model,
                  {
                    authProfileId: "openai:oauth",
                    sessionId: "different-session",
                  },
                ),
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { authProfileId: "openai:oauth", sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        id?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("encrypted_content");
  });

  it("strips encrypted reasoning replay when the auth profile provenance changes", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-chatgpt-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-chatgpt-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify({
                  type: "reasoning",
                  id: "rs_prior",
                  encrypted_content: "ciphertext",
                }),
                openclawReasoningReplay: testing.buildOpenAIResponsesReasoningReplayMetadata(
                  model,
                  {
                    authProfileId: "openai:old-oauth",
                    sessionId: "session-123",
                  },
                ),
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { authProfileId: "openai:new-oauth", sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        id?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("encrypted_content");
  });

  it("keeps embedded replay provenance as a compatibility fallback", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-chatgpt-responses",
      provider: "openai",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-chatgpt-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-chatgpt-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "thinking",
                thinking: "Need a tool.",
                thinkingSignature: JSON.stringify(
                  testing.tagOpenAIResponsesReasoningReplayItem(
                    {
                      type: "reasoning",
                      id: "rs_prior",
                      encrypted_content: "ciphertext",
                    },
                    model,
                    {
                      authProfileId: "openai:oauth",
                      sessionId: "session-123",
                    },
                  ),
                ),
              },
            ],
          },
        ],
        tools: [],
      } as never,
      { authProfileId: "openai:oauth", sessionId: "session-123" },
    ) as {
      input?: Array<{
        type?: string;
        id?: string;
        encrypted_content?: string;
        summary?: unknown;
      }>;
    };

    const reasoningItem = params.input?.find((item) => item.type === "reasoning");
    expectRecordFields(reasoningItem, {
      type: "reasoning",
      encrypted_content: "ciphertext",
      summary: [],
    });
    expect(reasoningItem?.id).toBeUndefined();
    expect(reasoningItem).not.toHaveProperty("__openclaw_replay");
  });

  it("strips nested encrypted reasoning content from retry payloads without changing ids", () => {
    const params = {
      model: "gpt-5.5",
      stream: true,
      input: [
        {
          type: "reasoning",
          id: "rs_prior",
          encrypted_content: "ciphertext",
          summary: [{ type: "summary_text", text: "checked" }],
          nested: { encrypted_content: "nested-ciphertext", keep: "value" },
        },
        {
          type: "function_call",
          id: "fc_prior",
          call_id: "call_abc",
          name: "price_lookup",
          arguments: "{}",
        },
      ],
    };

    const stripped = testing.stripResponsesRequestEncryptedContent(
      params as never,
    ) as typeof params;

    expect(stripped).not.toBe(params);
    expect(stripped.input[0]).toMatchObject({
      type: "reasoning",
      id: "rs_prior",
      summary: [{ type: "summary_text", text: "checked" }],
      nested: { keep: "value" },
    });
    expect(stripped.input[0]).not.toHaveProperty("encrypted_content");
    expect(stripped.input[0].nested).not.toHaveProperty("encrypted_content");
    expect(stripped.input[1]).toEqual(params.input[1]);
  });

  it("retries thinking_signature_invalid once without encrypted reasoning content", async () => {
    const request = {
      model: "gpt-5.5",
      stream: true,
      input: [
        {
          type: "reasoning",
          id: "rs_prior",
          encrypted_content: "ciphertext",
          summary: [],
        },
        {
          type: "message",
          id: "msg_prior",
          role: "assistant",
          content: [{ type: "output_text", text: "visible answer" }],
        },
        {
          type: "function_call",
          id: "fc_prior",
          call_id: "call_abc",
          name: "price_lookup",
          arguments: "{}",
        },
      ],
    };
    const recoveredStream = streamChunks([]);
    const create = vi
      .fn()
      .mockRejectedValueOnce(
        new OpenAI.BadRequestError(
          400,
          {
            code: "thinking_signature_invalid",
            message:
              "The encrypted content for item rs_prior could not be verified. Reason: Encrypted content could not be decrypted or parsed.",
            type: "invalid_request_error",
          },
          undefined,
          new Headers(),
        ),
      )
      .mockResolvedValueOnce(recoveredStream);

    await expect(
      testing.createResponsesStreamWithEncryptedContentRetry({
        client: { responses: { create } } as never,
        request: request as never,
        requestOptions: undefined,
        model: {
          id: "gpt-5.5",
          name: "GPT-5.5",
          api: "openai-responses",
          provider: "openai",
          baseUrl: "https://api.openai.com/v1",
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 200_000,
          maxTokens: 8192,
        },
      }),
    ).resolves.toBe(recoveredStream);

    expect(create).toHaveBeenCalledTimes(2);
    expect(create.mock.calls[0]?.[0]).toBe(request);
    expect(create.mock.calls[1]?.[0]).toEqual({
      ...request,
      input: [
        {
          type: "reasoning",
          id: "rs_prior",
          summary: [],
        },
        request.input[1],
        request.input[2],
      ],
    });
  });

  it("normalizes overlong Copilot Responses replay tool ids before dispatch", () => {
    const longToolItemId = "iVec" + "A".repeat(360);
    const longToolCallId = `call_ug6lFGKwZDjHfzW8H0PDQRwN|${longToolItemId}`;
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "github-copilot",
        baseUrl: "https://api.githubcopilot.com",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          { role: "user", content: "read the queue", timestamp: 0 },
          {
            role: "assistant",
            api: "openai-responses",
            provider: "github-copilot",
            model: "gpt-5.5",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              {
                type: "toolCall",
                id: longToolCallId,
                name: "exec",
                arguments: { command: "gh pr list --limit 1" },
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: longToolCallId,
            toolName: "exec",
            content: [{ type: "text", text: "[]" }],
            isError: false,
            timestamp: 2,
          },
          { role: "user", content: "continue", timestamp: 3 },
        ],
        tools: [],
      } as never,
      { sessionId: "session-123" },
    ) as {
      input?: Array<{ type?: string; id?: string; call_id?: string }>;
    };

    const functionCall = params.input?.find((item) => item.type === "function_call");
    const functionOutput = params.input?.find((item) => item.type === "function_call_output");
    expect(functionCall).toBeDefined();
    expect(functionOutput).toBeDefined();
    expect(functionCall?.id).toBeUndefined();
    expect(functionCall?.call_id).toBe("call_ug6lFGKwZDjHfzW8H0PDQRwN");
    expect(functionOutput?.call_id).toBe(functionCall?.call_id);
    for (const item of params.input ?? []) {
      if (item.id !== undefined) {
        expect(item.id.length).toBeLessThanOrEqual(64);
      }
      if (item.call_id !== undefined) {
        expect(item.call_id.length).toBeLessThanOrEqual(64);
      }
    }
  });

  it("omits distinct overlong Copilot Responses replay item ids when store is disabled", () => {
    const sharedToolItemPrefix = "iVec" + "A".repeat(160);
    const firstToolCallId = `call_first|${sharedToolItemPrefix}Aa`;
    const secondToolCallId = `call_second|${sharedToolItemPrefix}BB`;
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "github-copilot",
        baseUrl: "https://api.githubcopilot.com",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "github-copilot",
            model: "gpt-5.5",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "toolUse",
            timestamp: 1,
            content: [
              { type: "toolCall", id: firstToolCallId, name: "read", arguments: { path: "a" } },
              { type: "toolCall", id: secondToolCallId, name: "read", arguments: { path: "b" } },
            ],
          },
          {
            role: "toolResult",
            toolCallId: firstToolCallId,
            toolName: "read",
            content: [{ type: "text", text: "a" }],
            isError: false,
            timestamp: 2,
          },
          {
            role: "toolResult",
            toolCallId: secondToolCallId,
            toolName: "read",
            content: [{ type: "text", text: "b" }],
            isError: false,
            timestamp: 3,
          },
          { role: "user", content: "continue", timestamp: 4 },
        ],
        tools: [],
      } as never,
      { sessionId: "session-123" },
    ) as {
      input?: Array<{ type?: string; id?: string; call_id?: string }>;
    };

    const functionCalls = params.input?.filter((item) => item.type === "function_call") ?? [];
    const functionOutputs =
      params.input?.filter((item) => item.type === "function_call_output") ?? [];
    expect(functionCalls).toHaveLength(2);
    expect(functionOutputs).toHaveLength(2);
    expect(functionCalls.map((item) => item.id)).toEqual([undefined, undefined]);
    expect(functionOutputs.map((item) => item.call_id)).toEqual(["call_first", "call_second"]);
  });

  it("adds minimal user input for Codex responses when only the system prompt is present", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      input?: Array<{ role?: string; content?: Array<{ type?: string; text?: string }> }>;
      instructions?: string;
    };

    expect(params.instructions).toBe("Stable prefix\nDynamic suffix");
    expect(params.input).toEqual([
      {
        type: "message",
        role: "user",
        content: [{ type: "input_text", text: " " }],
      },
    ]);
  });

  it("does not infer high reasoning when the runtime passes thinking off", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { reasoning?: unknown; include?: string[] };

    expect(params.reasoning).toEqual({ effort: "none" });
    expect(params).not.toHaveProperty("include");
  });

  it("uses shared stream reasoning as OpenAI Responses effort", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "high",
      } as never,
    ) as { reasoning?: unknown };

    expect(params.reasoning).toEqual({ effort: "high", summary: "auto" });
  });

  it("uses disabled OpenAI Responses reasoning when the model supports none", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoningEffort: "none",
      } as never,
    ) as { reasoning?: unknown; include?: unknown };

    expect(params.reasoning).toEqual({ effort: "none" });
    expect(params).not.toHaveProperty("include");
  });

  it("omits disabled OpenAI Responses reasoning when the model does not support none", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5",
        name: "GPT-5",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoningEffort: "none",
      } as never,
    ) as { reasoning?: unknown; include?: unknown };

    expect(params).not.toHaveProperty("reasoning");
    expect(params).not.toHaveProperty("include");
  });

  it("maps minimal shared reasoning to low for OpenAI Responses", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "minimal",
      } as never,
    ) as { reasoning?: unknown };

    expect(params.reasoning).toEqual({ effort: "low", summary: "auto" });
  });

  it("raises minimal OpenAI Responses reasoning when web_search is available", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-responses",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
      compat: {
        supportedReasoningEfforts: ["minimal", "low", "medium", "high"],
      },
    } as unknown as Model<"openai-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "web_search",
            description: "Search the web",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      {
        reasoning: "minimal",
      } as never,
    ) as { reasoning?: unknown };

    expect(params.reasoning).toEqual({ effort: "low", summary: "auto" });
  });

  it("keeps minimal OpenAI Responses reasoning without web_search", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-responses",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
      compat: {
        supportedReasoningEfforts: ["minimal", "low", "medium", "high"],
      },
    } as unknown as Model<"openai-responses">;

    const params = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      {
        reasoning: "minimal",
      } as never,
    ) as { reasoning?: unknown };

    expect(params.reasoning).toEqual({ effort: "minimal", summary: "auto" });
  });

  it("maps low reasoning to medium for Codex mini responses models", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.1-codex-mini",
        name: "gpt-5.1-codex-mini",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-chatgpt-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "low",
      } as never,
    ) as { reasoning?: unknown };

    expect(params.reasoning).toEqual({ effort: "medium", summary: "auto" });
  });

  it.each([
    {
      label: "openai-platform",
      model: {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
      },
    },
    {
      label: "openai-chatgpt",
      model: {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-chatgpt-responses",
        provider: "openai",
        baseUrl: "https://chatgpt.com/backend-api",
      },
    },
    {
      label: "azure-openai-responses",
      model: {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "azure-openai-responses",
        provider: "azure-openai-responses",
        baseUrl: "https://azure.example.openai.azure.com/openai/v1",
      },
    },
    {
      label: "custom-openai-responses",
      model: {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "custom-openai-responses",
        baseUrl: "https://proxy.example.com/v1",
      },
    },
  ])("omits orphan phase-tagged ids for $label responses payloads", ({ label: _label, model }) => {
    const params = buildOpenAIResponsesParams(
      {
        ...model,
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: model.api,
            provider: model.provider,
            model: model.id,
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "stop",
            timestamp: 1,
            content: [
              {
                type: "text",
                text: "Working...",
                textSignature: JSON.stringify({
                  v: 1,
                  id: "msg_commentary",
                  phase: "commentary",
                }),
              },
            ],
          },
          {
            role: "user",
            content: "Continue",
            timestamp: 2,
          },
        ],
        tools: [],
      } as never,
      undefined,
    ) as {
      input?: Array<{ role?: string; id?: string; phase?: string }>;
    };

    const assistantItem = params.input?.find((item) => item.role === "assistant");
    expectRecordFields(assistantItem, {
      role: "assistant",
      phase: "commentary",
    });
    expect(assistantItem?.id).toBeUndefined();
  });

  it("strips the internal cache boundary from OpenAI system prompts", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { input?: Array<{ content?: Array<{ type?: string; text?: string }> }> };

    expect(params.input?.[0]?.content).toEqual([
      { type: "input_text", text: "Stable prefix\nDynamic suffix" },
    ]);
  });

  it("defaults responses tool schemas to strict on native OpenAI routes", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ strict?: boolean }> };

    expect(params.tools?.[0]?.strict).toBe(true);
    expectRecordFields(params.tools?.[0], {
      parameters: {
        type: "object",
        properties: {},
        additionalProperties: false,
        required: [],
      },
    });
  });

  it("passes explicit Responses tool_choice when tools are present", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      { toolChoice: "required" } as never,
    ) as { tool_choice?: string };

    expect(params.tool_choice).toBe("required");
  });

  it("keeps healthy Responses tools when a sibling schema is unreadable", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "broken",
            description: "Broken",
            get parameters(): never {
              throw new Error("parameters exploded");
            },
          },
          {
            name: "lookup",
            description: "Lookup",
            parameters: {},
          },
        ],
      } as never,
      { toolChoice: { type: "function", name: "lookup" } },
    ) as {
      tools?: Array<{ name?: string; strict?: boolean }>;
      tool_choice?: unknown;
    };

    expect(params.tools).toEqual([expect.objectContaining({ name: "lookup", strict: true })]);
    expect(params.tool_choice).toEqual({ type: "function", name: "lookup" });
  });

  it("fails locally when a pinned Responses tool is unreadable", () => {
    expect(() =>
      buildOpenAIResponsesParams(
        {
          id: "gpt-5.5",
          name: "GPT-5.5",
          api: "openai-responses",
          provider: "openai",
          baseUrl: "https://api.openai.com/v1",
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 200000,
          maxTokens: 8192,
        } satisfies Model<"openai-responses">,
        {
          systemPrompt: "system",
          messages: [],
          tools: [
            {
              name: "broken",
              get parameters(): never {
                throw new Error("parameters exploded");
              },
            },
          ],
        } as never,
        { toolChoice: { type: "function", name: "broken" } },
      ),
    ).toThrow('requested unavailable tool "broken"');
  });

  it("filters official Responses allowed_tools against projected functions", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup",
            description: "Lookup",
            parameters: {},
          },
        ],
      } as never,
      {
        toolChoice: {
          type: "allowed_tools",
          mode: "required",
          tools: [
            { type: "function", name: "broken" },
            { type: "function", name: "lookup" },
          ],
        },
      },
    ) as { tool_choice?: unknown };

    expect(params.tool_choice).toEqual({
      type: "allowed_tools",
      mode: "required",
      tools: [{ type: "function", name: "lookup" }],
    });
  });

  it("fails locally when required Chat Completions has no usable tools", () => {
    expect(() =>
      buildOpenAICompletionsParams(
        {
          id: "gpt-5.5",
          name: "GPT-5.5",
          api: "openai-completions",
          provider: "openai",
          baseUrl: "https://api.openai.com/v1",
          reasoning: false,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 200000,
          maxTokens: 8192,
        } satisfies Model<"openai-completions">,
        {
          systemPrompt: "system",
          messages: [],
          tools: [
            {
              name: "broken",
              get parameters(): never {
                throw new Error("parameters exploded");
              },
            },
          ],
        } as never,
        { toolChoice: "required" },
      ),
    ).toThrow("no tools survived schema conversion");
  });

  it("preserves the native empty tools marker for tool history after quarantining every schema", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            content: [
              {
                type: "toolCall",
                id: "call_abc",
                name: "lookup",
                arguments: {},
              },
            ],
          },
          {
            role: "toolResult",
            content: [{ type: "text", text: "done" }],
            toolCallId: "call_abc",
          },
          { role: "user", content: "continue", timestamp: 1 },
        ],
        tools: [
          {
            name: "broken",
            description: "Broken tool.",
            get parameters(): never {
              throw new Error("parameters exploded");
            },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: unknown[] };

    expect(params.tools).toEqual([]);
  });

  it("does not reread an unreadable tool inventory length", () => {
    const tools = new Proxy([], {
      get(target, property, receiver) {
        if (property === "length") {
          throw new Error("length exploded");
        }
        return Reflect.get(target, property, receiver);
      },
    });
    const responsesModel = {
      id: "gpt-5.5",
      name: "GPT-5.5",
      api: "openai-responses",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-responses">;
    const completionsModel = {
      ...responsesModel,
      api: "openai-completions",
      reasoning: false,
    } satisfies Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [{ role: "user", content: "hello", timestamp: 1 }],
      tools,
    } as never;

    expect(buildOpenAIResponsesParams(responsesModel, context, undefined)).not.toHaveProperty(
      "tools",
    );
    expect(buildOpenAICompletionsParams(completionsModel, context, undefined)).not.toHaveProperty(
      "tools",
    );
  });

  it("sorts Responses tools by name for stable prompt-cache payloads", () => {
    const model = {
      id: "gpt-5.4",
      name: "GPT-5.4",
      api: "openai-responses",
      provider: "openai",
      baseUrl: "https://api.openai.com/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-responses">;
    const zetaTool = {
      name: "zeta",
      description: "Z",
      parameters: { type: "object", properties: {}, additionalProperties: false },
    };
    const alphaTool = {
      name: "alpha",
      description: "A",
      parameters: { type: "object", properties: {}, additionalProperties: false },
    };

    const first = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [zetaTool, alphaTool],
      } as never,
      { sessionId: "session-123" } as never,
    ) as { tools?: Array<{ name?: string }> };
    const second = buildOpenAIResponsesParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [alphaTool, zetaTool],
      } as never,
      { sessionId: "session-123" } as never,
    ) as { tools?: Array<{ name?: string }> };

    expect(first.tools?.map((tool) => tool.name)).toEqual(["alpha", "zeta"]);
    expect(first.tools).toEqual(second.tools);
  });

  it("falls back to strict:false when a native OpenAI tool schema is not strict-compatible", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "read",
            description: "Read file",
            parameters: {
              type: "object",
              additionalProperties: false,
              properties: { path: { type: "string" } },
              required: [],
            },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ strict?: boolean }> };

    expect(params.tools?.[0]?.strict).toBe(false);
  });

  it("deduplicates repeated OpenAI strict schema downgrade diagnostics", async () => {
    const debug = vi.fn();
    const logger = {
      subsystem: "openai-transport",
      isEnabled: vi.fn((level: string, target?: string) => level === "debug" && target === "any"),
      trace: vi.fn(),
      debug,
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
      fatal: vi.fn(),
      raw: vi.fn(),
      child: vi.fn(),
    };
    logger.child.mockReturnValue(logger);

    vi.resetModules();
    vi.doMock("../logging/subsystem.js", async (importOriginal) => ({
      ...(await importOriginal<typeof import("../logging/subsystem.js")>()),
      createSubsystemLogger: vi.fn(() => logger),
    }));

    try {
      const { buildOpenAIResponsesParams: isolatedBuildOpenAIResponsesParams } =
        await import("./openai-transport-stream.js");
      const model = {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">;
      const context = {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "read",
            description: "Read file",
            parameters: {
              type: "object",
              additionalProperties: false,
              properties: { path: { type: "string" } },
              required: [],
            },
          },
        ],
      } as never;

      const first = isolatedBuildOpenAIResponsesParams(model, context, undefined) as {
        tools?: Array<{ strict?: boolean }>;
      };
      const second = isolatedBuildOpenAIResponsesParams(model, context, undefined) as {
        tools?: Array<{ strict?: boolean }>;
      };

      expect(first.tools?.[0]?.strict).toBe(false);
      expect(second.tools?.[0]?.strict).toBe(false);
      expect(
        debug.mock.calls.filter(
          ([message]) =>
            typeof message === "string" &&
            message.includes("tool schema strict mode downgraded to strict=false"),
        ),
      ).toHaveLength(1);
    } finally {
      vi.doUnmock("../logging/subsystem.js");
      vi.resetModules();
    }
  });

  it("omits responses strict tool shaping for proxy-like OpenAI routes", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ strict?: boolean }> };

    expect(params.tools?.[0]).not.toHaveProperty("strict");
  });

  it("keeps native responses strict mode for projected tools after dropping bad schemas", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "broken",
            description: "Broken",
            parameters: {
              type: "object",
              get properties(): never {
                throw new Error("properties exploded");
              },
            },
          },
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: {},
          },
        ],
      } as never,
      undefined,
    ) as {
      tools?: Array<{
        name?: string;
        strict?: boolean;
        parameters?: Record<string, unknown>;
      }>;
    };

    expect(params.tools).toEqual([
      {
        type: "function",
        name: "lookup_weather",
        description: "Get forecast",
        strict: true,
        parameters: {
          type: "object",
          properties: {},
          required: [],
          additionalProperties: false,
        },
      },
    ]);
  });

  it("still normalizes responses tool parameters when strict is omitted", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: {},
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ strict?: boolean; parameters?: Record<string, unknown> }> };

    expect(params.tools?.[0]).not.toHaveProperty("strict");
    expectRecordFields(params.tools?.[0]?.parameters, {
      type: "object",
      properties: {},
    });
  });

  it("normalizes responses tool parameters while downgrading native strict:false", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "read",
            description: "Read file",
            parameters: {
              properties: { path: { type: "string" } },
              required: [],
            },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ strict?: boolean; parameters?: Record<string, unknown> }> };

    expect(params.tools?.[0]?.strict).toBe(false);
    expectRecordFields(params.tools?.[0]?.parameters, {
      type: "object",
      properties: { path: { type: "string" } },
      required: [],
    });
  });

  it("adds native OpenAI turn metadata on direct Responses routes", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { sessionId: "session-123" } as never,
      {
        openclaw_session_id: "session-123",
        openclaw_turn_id: "turn-123",
        openclaw_turn_attempt: "1",
        openclaw_transport: "stream",
      },
    ) as { metadata?: Record<string, string> };

    expectRecordFields(params.metadata, {
      openclaw_session_id: "session-123",
      openclaw_turn_id: "turn-123",
      openclaw_turn_attempt: "1",
      openclaw_transport: "stream",
    });
  });

  it("leaves proxy-like OpenAI Responses routes without native turn metadata by default", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { sessionId: "session-123" } as never,
      undefined,
    ) as { metadata?: Record<string, string> };

    expect(params).not.toHaveProperty("metadata");
  });

  it("gates responses service_tier to native OpenAI endpoints", () => {
    const nativeParams = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        serviceTier: "priority",
      },
    ) as { service_tier?: unknown };
    const proxyParams = buildOpenAIResponsesParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        serviceTier: "priority",
      },
    ) as { service_tier?: unknown };

    expect(nativeParams.service_tier).toBe("priority");
    expect(proxyParams).not.toHaveProperty("service_tier");
  });

  it("strips store when responses compat disables it", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-responses",
        provider: "custom-provider",
        baseUrl: "https://proxy.example.com/v1",
        compat: { supportsStore: false },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { store?: unknown };

    expect(params).not.toHaveProperty("store");
  });

  it("uses system role for xAI default-route responses providers without relying on baseUrl host sniffing", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "grok-4.1-fast",
        name: "Grok 4.1 Fast",
        api: "openai-responses",
        provider: "xai",
        baseUrl: "https://api.x.ai/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { input?: Array<{ role?: string }> };

    expect(params.input?.[0]?.role).toBe("system");
  });

  it("uses system role for Moonshot default-route completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "kimi-k2.5",
        name: "Kimi K2.5",
        api: "openai-completions",
        provider: "moonshot",
        baseUrl: "",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { messages?: Array<{ role?: string }> };

    expect(params.messages?.[0]?.role).toBe("system");
  });

  it("strips the internal cache boundary from OpenAI completions system prompts", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-4.1",
        name: "GPT-4.1",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { messages?: Array<{ content?: string }> };

    expect(params.messages?.[0]?.content).toBe("Stable prefix\nDynamic suffix");
  });

  it("uses shared stream reasoning as OpenAI completions effort", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "medium",
      } as never,
    ) as { reasoning_effort?: unknown };

    expect(params.reasoning_effort).toBe("medium");
  });

  it("maps minimal shared reasoning to low for OpenAI completions", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "minimal",
      } as never,
    ) as { reasoning_effort?: unknown };

    expect(params.reasoning_effort).toBe("low");
  });

  it("defaults OpenAI completions reasoning effort to high when unset", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as { reasoning_effort?: unknown };

    expect(params.reasoning_effort).toBe("high");
  });

  it("omits reasoning_effort for gpt-5.4-mini Chat Completions tool payloads", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4-mini",
        name: "GPT-5.4 mini",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 400000,
        maxTokens: 128000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      {
        reasoning: "medium",
      } as never,
    ) as { reasoning_effort?: unknown; tools?: unknown };

    expect(params.tools).toHaveLength(1);
    const tool = (params.tools as Array<Record<string, unknown>>)[0];
    expectRecordFields(tool, { type: "function" });
    expectRecordFields(tool.function, { name: "lookup_weather" });
    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it.each([
    ["implicit default", ""],
    ["default", "https://api.openai.com/v1"],
  ])(
    "omits reasoning_effort for OpenAI %s gpt-5.5 Chat Completions tool payloads",
    (_label, baseUrl) => {
      const params = buildOpenAICompletionsParams(
        {
          id: "gpt-5.5",
          name: "GPT-5.5",
          api: "openai-completions",
          provider: "openai",
          baseUrl,
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 1000000,
          maxTokens: 128000,
        } satisfies Model<"openai-completions">,
        {
          systemPrompt: "system",
          messages: [],
          tools: [
            {
              name: "lookup_weather",
              description: "Get forecast",
              parameters: { type: "object", properties: {}, additionalProperties: false },
            },
          ],
        } as never,
        {
          reasoning: "medium",
        } as never,
      ) as { reasoning_effort?: unknown; tools?: unknown };

      expect(params.tools).toHaveLength(1);
      expect(params).not.toHaveProperty("reasoning_effort");
    },
  );

  it.each([
    ["Azure OpenAI", "https://example.openai.azure.com/openai/v1"],
    ["Foundry", "https://example.services.ai.azure.com/openai/v1"],
    ["Cognitive Services", "https://example.cognitiveservices.azure.com/openai/v1"],
  ])(
    "omits reasoning_effort for %s gpt-5.5 deployment aliases with tool payloads",
    (_label, baseUrl) => {
      const params = buildOpenAICompletionsParams(
        {
          id: "prod-spud",
          name: "GPT-5.5 (Azure)",
          api: "openai-completions",
          provider: "azure-openai",
          baseUrl,
          reasoning: true,
          input: ["text"],
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
          contextWindow: 1000000,
          maxTokens: 128000,
        } satisfies Model<"openai-completions">,
        {
          systemPrompt: "system",
          messages: [],
          tools: [
            {
              name: "lookup_weather",
              description: "Get forecast",
              parameters: { type: "object", properties: {}, additionalProperties: false },
            },
          ],
        } as never,
        {
          reasoning: "medium",
        } as never,
      ) as { reasoning_effort?: unknown; tools?: unknown };

      expect(params.tools).toHaveLength(1);
      expect(params).not.toHaveProperty("reasoning_effort");
    },
  );

  it("keeps reasoning_effort for custom gpt-5.5 Chat Completions tool payloads", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-completions",
        provider: "custom-openai",
        baseUrl: "https://models.example.com/v1",
        compat: { supportsReasoningEffort: true },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1000000,
        maxTokens: 128000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      {
        reasoning: "medium",
      } as never,
    ) as { reasoning_effort?: unknown; tools?: unknown };

    expect(params.tools).toHaveLength(1);
    expect(params.reasoning_effort).toBe("medium");
  });

  it("keeps reasoning_effort for gpt-5.5 Chat Completions payloads without tools", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.5",
        name: "GPT-5.5",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 1000000,
        maxTokens: 128000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "medium",
      } as never,
    ) as { reasoning_effort?: unknown; tools?: unknown };

    expect(params.tools).toHaveLength(0);
    expect(params.reasoning_effort).toBe("medium");
  });

  it("keeps reasoning_effort for gpt-5.4-mini Chat Completions payloads without tools", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4-mini",
        name: "GPT-5.4 mini",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 400000,
        maxTokens: 128000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "medium",
      } as never,
    ) as { reasoning_effort?: unknown; tools?: unknown };

    expect(params.tools).toStrictEqual([]);
    expect(params.reasoning_effort).toBe("medium");
  });

  it("uses provider-native reasoning effort values declared by model compat", () => {
    const baseModel = {
      id: "qwen/qwen3-32b",
      name: "Qwen 3 32B",
      api: "openai-completions",
      provider: "groq",
      baseUrl: "https://api.groq.com/openai/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
      compat: {
        supportsReasoningEffort: true,
        supportedReasoningEfforts: ["none", "default"],
        reasoningEffortMap: {
          off: "none",
          low: "default",
          medium: "default",
          high: "default",
        },
      },
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const enabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "medium",
    } as never) as { reasoning_effort?: unknown };
    const disabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "off",
    } as never) as { reasoning_effort?: unknown };

    expect(enabled.reasoning_effort).toBe("default");
    expect(disabled.reasoning_effort).toBe("none");
  });

  it("maps qwen thinking format to top-level enable_thinking", () => {
    const baseModel = {
      id: "qwen3.5-32b",
      name: "Qwen 3.5 32B",
      api: "openai-completions",
      provider: "llama-cpp",
      baseUrl: "http://127.0.0.1:8080/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
      compat: {
        thinkingFormat: "qwen",
      },
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const enabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "medium",
    } as never) as { enable_thinking?: unknown; reasoning_effort?: unknown };
    const disabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "off",
    } as never) as { enable_thinking?: unknown; reasoning_effort?: unknown };

    expect(enabled.enable_thinking).toBe(true);
    expect(disabled.enable_thinking).toBe(false);
    expect(enabled).not.toHaveProperty("reasoning_effort");
    expect(disabled).not.toHaveProperty("reasoning_effort");
  });

  it("maps qwen-chat-template thinking format to chat_template_kwargs", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3.5-32b",
        name: "Qwen 3.5 32B",
        api: "openai-completions",
        provider: "llama-cpp",
        baseUrl: "http://127.0.0.1:8080/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131072,
        maxTokens: 8192,
        compat: {
          thinkingFormat: "qwen-chat-template",
        },
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "off",
      } as never,
    ) as { chat_template_kwargs?: Record<string, unknown>; reasoning_effort?: unknown };

    expect(params.chat_template_kwargs).toEqual({ enable_thinking: false });
    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it("maps together thinking format to reasoning enabled", () => {
    const baseModel = {
      id: "moonshotai/Kimi-K2.5",
      name: "Kimi K2.5",
      api: "openai-completions",
      provider: "together",
      baseUrl: "https://api.together.xyz/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 262144,
      maxTokens: 32768,
      compat: {
        thinkingFormat: "together",
        supportsReasoningEffort: true,
      },
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const enabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "medium",
    } as never) as {
      max_completion_tokens?: unknown;
      max_tokens?: unknown;
      reasoning?: unknown;
      reasoning_effort?: unknown;
    };
    const disabled = buildOpenAICompletionsParams(baseModel, context, {
      reasoning: "off",
    } as never) as { reasoning?: unknown; reasoning_effort?: unknown };

    expect(enabled.max_tokens).toBe(32768);
    expect(enabled).not.toHaveProperty("max_completion_tokens");
    expect(enabled.reasoning).toEqual({ enabled: true });
    expect(enabled.reasoning_effort).toBe("medium");
    expect(disabled.reasoning).toEqual({ enabled: false });
    expect(disabled).not.toHaveProperty("reasoning_effort");
  });

  it("omits unsupported disabled reasoning for completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "openai/gpt-oss-120b",
        name: "GPT OSS 120B",
        api: "openai-completions",
        provider: "groq",
        baseUrl: "https://api.groq.com/openai/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131072,
        maxTokens: 8192,
        compat: {
          supportsReasoningEffort: true,
          supportedReasoningEfforts: ["low", "medium", "high"],
        },
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        reasoning: "off",
      } as never,
    ) as { reasoning_effort?: unknown };

    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it("uses system role and streaming usage compat for native Qwen completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3.6-plus",
        name: "Qwen 3.6 Plus",
        api: "openai-completions",
        provider: "qwen",
        baseUrl: "https://dashscope-intl.aliyuncs.com/compatible-mode/v1",
        compat: { supportsUsageInStreaming: true },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      messages?: Array<{ role?: string }>;
      stream_options?: { include_usage?: boolean };
    };

    expect(params.messages?.[0]?.role).toBe("system");
    expect(params.stream_options?.include_usage).toBe(true);
  });

  it("enables streaming usage compat for generic providers on native DashScope endpoints", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "glm-5",
        name: "GLM-5",
        api: "openai-completions",
        provider: "generic",
        baseUrl: "https://coding.dashscope.aliyuncs.com/v1",
        compat: { supportsUsageInStreaming: true },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      stream_options?: { include_usage?: boolean };
    };

    expect(params.stream_options?.include_usage).toBe(true);
  });

  it("honors explicit streaming usage compat for configured custom providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-completions",
        provider: "custom-cpa",
        baseUrl: "https://proxy.example.com/v1",
        compat: { supportsUsageInStreaming: true },
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 32768,
        maxTokens: 8192,
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      stream_options?: { include_usage?: boolean };
    };

    expect(params.stream_options?.include_usage).toBe(true);
  });

  it("includes stream_options.include_usage for Volcengine CodingPlan", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "ark-code-latest",
        name: "Ark Coding Plan",
        api: "openai-completions",
        provider: "volcengine-plan",
        baseUrl: "https://ark.cn-beijing.volces.com/api/coding/v3",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 256000,
        maxTokens: 4096,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      stream_options?: { include_usage?: boolean };
    };

    expect(params.stream_options).toEqual({ include_usage: true });
  });

  it("includes stream_options.include_usage for known local backends like llama-cpp", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "llama-3",
        name: "Llama 3",
        api: "openai-completions",
        provider: "llama-cpp",
        baseUrl: "http://localhost:8080/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 8192,
        maxTokens: 4096,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    ) as {
      stream_options?: { include_usage?: boolean };
    };

    expect(params.stream_options).toEqual({ include_usage: true });
  });

  it("forwards prompt_cache_key for opted-in OpenAI-compatible completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-completions",
        provider: "custom-cpa",
        baseUrl: "https://proxy.example.com/v1",
        compat: { supportsPromptCacheKey: true },
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 32768,
        maxTokens: 8192,
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { sessionId: "session-123", promptCacheKey: "cron-cache-key" },
    ) as { prompt_cache_key?: string };

    expect(params.prompt_cache_key).toBe("cron-cache-key");
  });

  it("omits prompt_cache_key for completions when caching is disabled or not opted in", () => {
    const baseModel = {
      id: "custom-model",
      name: "Custom Model",
      api: "openai-completions",
      provider: "custom-cpa",
      baseUrl: "https://proxy.example.com/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 32768,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const disabled = buildOpenAICompletionsParams(
      {
        ...baseModel,
        compat: { supportsPromptCacheKey: true },
      } as unknown as Model<"openai-completions">,
      context,
      { sessionId: "session-123", promptCacheKey: "cron-cache-key", cacheRetention: "none" },
    ) as { prompt_cache_key?: string };
    const notOptedIn = buildOpenAICompletionsParams(baseModel, context, {
      sessionId: "session-123",
    }) as { prompt_cache_key?: string };

    expect(disabled.prompt_cache_key).toBeUndefined();
    expect(notOptedIn.prompt_cache_key).toBeUndefined();
  });

  it("emits prompt_cache_retention=24h for completions when cacheRetention is long", () => {
    const model = {
      id: "custom-model",
      name: "Custom Model",
      api: "openai-completions",
      provider: "custom-cpa",
      baseUrl: "https://proxy.example.com/v1",
      compat: { supportsPromptCacheKey: true },
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 32768,
      maxTokens: 8192,
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const longRetention = buildOpenAICompletionsParams(model, context, {
      sessionId: "session-123",
      cacheRetention: "long",
    }) as { prompt_cache_key?: string; prompt_cache_retention?: string };

    expect(longRetention.prompt_cache_key).toBe("session-123");
    expect(longRetention.prompt_cache_retention).toBe("24h");
  });

  it("omits prompt_cache_retention for completions when cacheRetention is short or unset", () => {
    const model = {
      id: "custom-model",
      name: "Custom Model",
      api: "openai-completions",
      provider: "custom-cpa",
      baseUrl: "https://proxy.example.com/v1",
      compat: { supportsPromptCacheKey: true },
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 32768,
      maxTokens: 8192,
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const shortRetention = buildOpenAICompletionsParams(model, context, {
      sessionId: "session-123",
      cacheRetention: "short",
    });
    const defaultRetention = buildOpenAICompletionsParams(model, context, {
      sessionId: "session-123",
    });

    expect(shortRetention).not.toHaveProperty("prompt_cache_retention");
    expect(defaultRetention).not.toHaveProperty("prompt_cache_retention");
  });

  it("keeps Mistral prompt cache keys without unsupported long retention", () => {
    const model = {
      id: "mistral-large-latest",
      name: "Mistral Large",
      api: "openai-completions",
      provider: "mistral",
      baseUrl: "https://api.mistral.ai/v1",
      compat: {
        supportsPromptCacheKey: true,
        supportsLongCacheRetention: false,
        supportsStore: false,
        supportsReasoningEffort: false,
        maxTokensField: "max_tokens",
      },
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 32768,
      maxTokens: 8192,
    } as unknown as Model<"openai-completions">;
    const context = {
      systemPrompt: "system",
      messages: [],
      tools: [],
    } as never;

    const params = buildOpenAICompletionsParams(model, context, {
      sessionId: "session-123",
      cacheRetention: "long",
    }) as { prompt_cache_key?: string; prompt_cache_retention?: string };

    expect(params.prompt_cache_key).toBe("session-123");
    expect(params).not.toHaveProperty("prompt_cache_retention");
  });

  it("sorts Chat Completions tools by function name for stable prompt-cache payloads", () => {
    const model = {
      id: "custom-model",
      name: "Custom Model",
      api: "openai-completions",
      provider: "custom-cpa",
      baseUrl: "https://proxy.example.com/v1",
      compat: { supportsPromptCacheKey: true },
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 32768,
      maxTokens: 8192,
    } as unknown as Model<"openai-completions">;
    const zetaTool = {
      name: "zeta",
      description: "Z",
      parameters: { type: "object", properties: {} },
    };
    const alphaTool = {
      name: "alpha",
      description: "A",
      parameters: { type: "object", properties: {} },
    };

    const first = buildOpenAICompletionsParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [zetaTool, alphaTool],
      } as never,
      { sessionId: "session-123" },
    ) as { tools?: Array<{ function?: { name?: string } }> };
    const second = buildOpenAICompletionsParams(
      model,
      {
        systemPrompt: "system",
        messages: [],
        tools: [alphaTool, zetaTool],
      } as never,
      { sessionId: "session-123" },
    ) as { tools?: Array<{ function?: { name?: string } }> };

    expect(first.tools?.map((tool) => tool.function?.name)).toEqual(["alpha", "zeta"]);
    expect(first.tools).toEqual(second.tools);
  });

  it("disables developer-role-only compat defaults for configured custom proxy completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "custom-model",
        name: "Custom Model",
        api: "openai-completions",
        provider: "custom-cpa",
        baseUrl: "https://proxy.example.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      {
        reasoningEffort: "high",
      } as never,
    ) as {
      messages?: Array<{ role?: string }>;
      reasoning_effort?: unknown;
      stream_options?: unknown;
      store?: unknown;
      tools?: Array<{ function?: { strict?: boolean } }>;
    };

    expect(params.messages?.[0]?.role).toBe("system");
    expect(params).not.toHaveProperty("reasoning_effort");
    expect(params).not.toHaveProperty("stream_options");
    expect(params).not.toHaveProperty("store");
    expect(params.tools?.[0]?.function).not.toHaveProperty("strict");
  });

  it("flattens pure text content arrays for string-only completions backends when opted in", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "google/gemma-4-E2B-it",
        name: "Gemma 4 E2B",
        api: "openai-completions",
        provider: "inferrs",
        baseUrl: "http://127.0.0.1:8080/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131072,
        maxTokens: 4096,
        compat: {
          requiresStringContent: true,
        } as Record<string, unknown>,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "user",
            content: [{ type: "text", text: "What is 2 + 2?" }],
            timestamp: Date.now(),
          },
        ],
        tools: [],
      } as never,
      undefined,
    ) as { messages?: Array<{ role?: string; content?: unknown }> };

    expect(params.messages?.[0]).toEqual({ role: "system", content: "system" });
    expect(params.messages?.[1]).toEqual({ role: "user", content: "What is 2 + 2?" });
  });

  it("strips extra message keys for strict-key completions backends when opted in", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "mistral3",
        name: "mistral3",
        api: "openai-completions",
        provider: "infomaniak",
        baseUrl: "https://api.infomaniak.com/1/ai/example/openai",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 32768,
        maxTokens: 4096,
        compat: {
          strictMessageKeys: true,
        } as Record<string, unknown>,
      } satisfies Model<"openai-completions">,
      {
        messages: [
          {
            role: "assistant",
            content: [
              {
                type: "toolCall",
                id: "call_1",
                name: "noop",
                arguments: {},
              },
            ],
            timestamp: Date.now(),
          },
          {
            role: "toolResult",
            toolCallId: "call_1",
            content: [{ type: "text", text: "tool result" }],
            timestamp: Date.now(),
          },
        ],
        tools: [],
      } as never,
      undefined,
    ) as { messages?: Array<Record<string, unknown>> };

    expect(params.messages?.[0]).toEqual({ role: "assistant", content: null });
    expect(params.messages?.[1]).toEqual({ role: "tool", content: "tool result" });
  });

  it("uses max_tokens for Chutes default-route completions providers without relying on baseUrl host sniffing", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "zai-org/GLM-4.7-TEE",
        name: "GLM 4.7 TEE",
        api: "openai-completions",
        provider: "chutes",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        maxTokens: 2048,
      } as never,
    );

    expect(params.max_tokens).toBe(2048);
    expect(params).not.toHaveProperty("max_completion_tokens");
  });

  it("uses model maxTokens for OpenAI completions params when runtime maxTokens is omitted", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 65_536,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(65_536);
    expect(params).not.toHaveProperty("max_tokens");
  });

  it("uses model params max_completion_tokens for OpenAI completions before model maxTokens", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "kimi-k2.6",
        name: "Kimi K2.6",
        api: "openai-completions",
        provider: "dashscope",
        baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 262_144,
        maxTokens: 32_000,
        params: {
          max_completion_tokens: 64_000,
        },
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(64_000);
    expect(params).not.toHaveProperty("max_tokens");
  });

  it("keeps runtime maxTokens ahead of model params max_completion_tokens for OpenAI completions", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "kimi-k2.6",
        name: "Kimi K2.6",
        api: "openai-completions",
        provider: "dashscope",
        baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 262_144,
        maxTokens: 32_000,
        params: {
          max_completion_tokens: 64_000,
        },
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { maxTokens: 16_000 } as never,
    );

    expect(params.max_completion_tokens).toBe(16_000);
    expect(params).not.toHaveProperty("max_tokens");
  });

  it("clamps runtime maxTokens to the OpenAI completions model output cap", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "mimo-v2.5-pro",
        name: "MiMo V2.5 Pro",
        api: "openai-completions",
        provider: "xiaomi-token-plan",
        baseUrl: "https://token-plan-sgp.xiaomimimo.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200_000,
        maxTokens: 32_000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { maxTokens: 200_000 } as never,
    );

    expect(params.max_completion_tokens).toBe(32_000);
    expect(params).not.toHaveProperty("max_tokens");
  });

  it("keeps zero runtime maxTokens falling back to model params for OpenAI completions", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "kimi-k2.6",
        name: "Kimi K2.6",
        api: "openai-completions",
        provider: "dashscope",
        baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 262_144,
        maxTokens: 32_000,
        params: {
          max_completion_tokens: 64_000,
        },
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      { maxTokens: 0 } as never,
    );

    expect(params.max_completion_tokens).toBe(64_000);
    expect(params).not.toHaveProperty("max_tokens");
  });

  it("uses model maxTokens with max_tokens completions compat when runtime maxTokens is omitted", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "zai-org/GLM-4.7-TEE",
        name: "GLM 4.7 TEE",
        api: "openai-completions",
        provider: "chutes",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 65_536,
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_tokens).toBe(65_536);
    expect(params).not.toHaveProperty("max_completion_tokens");
  });

  it("clamps max_completion_tokens to the remaining context budget for proxy-like endpoints when prompt + output would exceed contextWindow (covers #83086)", () => {
    // StepFun-style shape: large context window, max_tokens equal to context,
    // and a substantial prompt that should leave well under the context budget.
    // 200_000 ASCII chars -> estimated 62_500 input tokens (chars/4 * 1.25).
    // That leaves remaining budget of 262_144 - 62_500 - 1 = 199_643 tokens.
    const systemPrompt = "x".repeat(200_000);
    const params = buildOpenAICompletionsParams(
      {
        id: "step-router-v1",
        name: "StepFun step-router-v1",
        api: "openai-completions",
        provider: "stepfun-plan",
        baseUrl: "https://api.stepfun.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 262_144,
        maxTokens: 262_144,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt,
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(typeof params.max_completion_tokens).toBe("number");
    const cap = params.max_completion_tokens as number;
    const estimatedInputTokens = Math.ceil((systemPrompt.length / 4) * 1.25);
    expect(cap).toBe(262_144 - estimatedInputTokens - 1);
    expect(cap).toBeLessThan(262_144);
  });

  it("uses CJK-aware input estimates when clamping proxy-like completions output budgets", () => {
    const cjkPrompt = "你好世界".repeat(1_000);
    const params = buildOpenAICompletionsParams(
      {
        id: "kimi-k2.6",
        name: "Kimi K2.6",
        api: "openai-completions",
        provider: "dashscope",
        baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 10_000,
        maxTokens: 10_000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: cjkPrompt,
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    // 4,000 CJK chars count as 16,000 adjusted chars, then chars/4 * 1.25.
    expect(params.max_completion_tokens).toBe(10_000 - 5_000 - 1);
  });

  it("rounds proxy-like completions input estimates after summing message content", () => {
    const messages = Array.from({ length: 4_000 }, () => ({
      role: "user",
      content: "x",
    }));
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3-5-122b-a10b-nvfp4",
        name: "qwen3-5-122b-a10b-nvfp4",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 10_000,
        maxTokens: 10_000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: undefined,
        messages,
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(10_000 - 1_250 - 1);
  });

  it("estimates proxy-like completions input from the final outbound messages after compat transforms", () => {
    const userText = "ok";
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3-5-122b-a10b-nvfp4",
        name: "qwen3-5-122b-a10b-nvfp4",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 10_000,
        maxTokens: 10_000,
      } satisfies Model<"openai-completions">,
      {
        messages: [
          { role: "user", content: userText, timestamp: 1 },
          {
            role: "assistant",
            content: [{ type: "text", text: "x".repeat(20_000) }],
            api: "openai-completions",
            provider: "vllm",
            model: "qwen3-5-122b-a10b-nvfp4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "aborted",
            timestamp: 2,
          },
        ],
        tools: [],
      } as never,
      undefined,
    );

    const estimatedInputTokens = Math.ceil((userText.length / 4) * 1.25);
    expect(params.max_completion_tokens).toBe(10_000 - estimatedInputTokens - 1);
  });

  it("clamps proxy-like completions output budgets against contextTokens before contextWindow", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3-5-122b-a10b-nvfp4",
        name: "qwen3-5-122b-a10b-nvfp4",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131_072,
        contextTokens: 4_096,
        maxTokens: 200_000,
      } as unknown as Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(4_096 - 2 - 1);
  });

  it("clamps max_completion_tokens for proxy-like endpoints when configured maxTokens >= contextWindow and prompt is small", () => {
    // Misconfig case: tiny prompt, but configured maxTokens still exceeds the
    // model's contextWindow. Clamp should land just under the window.
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3-5-122b-a10b-nvfp4",
        name: "qwen3-5-122b-a10b-nvfp4",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131_072,
        maxTokens: 200_000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(typeof params.max_completion_tokens).toBe("number");
    const cap = params.max_completion_tokens as number;
    expect(cap).toBeLessThan(131_072);
    // Small prompt → cap is essentially contextWindow - 1 - tiny_input_estimate.
    expect(cap).toBeGreaterThanOrEqual(131_000);
  });

  it("does not clamp max_completion_tokens for proxy-like endpoints when maxTokens fits the context window", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "qwen3-5-122b-a10b-nvfp4",
        name: "qwen3-5-122b-a10b-nvfp4",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 131_072,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(8192);
  });

  it("preserves the configured maxTokens for native openai-completions endpoints even when it equals or exceeds contextWindow", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 100_000,
        maxTokens: 200_000,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params.max_completion_tokens).toBe(200_000);
  });

  it("omits strict tool shaping for Z.ai default-route completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "glm-5",
        name: "GLM 5",
        api: "openai-completions",
        provider: "zai",
        baseUrl: "",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ function?: { strict?: boolean } }> };

    expect(params.tools?.[0]?.function).not.toHaveProperty("strict");
  });

  it("defaults completions tool schemas to strict on native OpenAI routes", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5",
        name: "GPT-5",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: { type: "object", properties: {}, additionalProperties: false },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ function?: { strict?: boolean } }> };

    expect(params.tools?.[0]?.function?.strict).toBe(true);
  });

  it("keeps native completions strict mode for projected tools after dropping bad schemas", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5",
        name: "GPT-5",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "broken",
            description: "Broken",
            parameters: {
              type: "object",
              get properties(): never {
                throw new Error("properties exploded");
              },
            },
          },
          {
            name: "lookup_weather",
            description: "Get forecast",
            parameters: {},
          },
        ],
      } as never,
      undefined,
    ) as {
      tools?: Array<{
        function?: {
          name?: string;
          strict?: boolean;
          parameters?: Record<string, unknown>;
        };
      }>;
    };

    expect(params.tools?.map((tool) => tool.function)).toEqual([
      {
        name: "lookup_weather",
        description: "Get forecast",
        strict: true,
        parameters: {
          type: "object",
          properties: {},
          required: [],
          additionalProperties: false,
        },
      },
    ]);
  });

  it("falls back to completions strict:false when a native OpenAI tool schema is not strict-compatible", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5",
        name: "GPT-5",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "read",
            description: "Read file",
            parameters: {
              type: "object",
              additionalProperties: false,
              properties: { path: { type: "string" } },
              required: [],
            },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: Array<{ function?: { strict?: boolean } }> };

    expect(params.tools?.[0]?.function?.strict).toBe(false);
  });

  it("applies model compat unsupported schema keywords to completions tools", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "accounts/fireworks/routers/kimi-k2p5-turbo",
        name: "Kimi K2.5 Turbo",
        api: "openai-completions",
        provider: "fireworks",
        baseUrl: "https://api.fireworks.ai/inference/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 256000,
        maxTokens: 256000,
        compat: {
          unsupportedToolSchemaKeywords: ["not"],
        } as never,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "lookup",
            description: "Lookup",
            parameters: {
              type: "object",
              properties: {
                forbidden: { not: {} },
              },
            },
          },
        ],
      } as never,
      undefined,
    ) as {
      tools?: Array<{ function?: { parameters?: { properties?: Record<string, unknown> } } }>;
    };

    expect(params.tools?.[0]?.function?.parameters?.properties?.forbidden).toStrictEqual({});
  });

  it("applies model compat empty array items omission after completions normalization", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "mimo-v2.5",
        name: "MiMo V2.5",
        api: "openai-completions",
        provider: "xiaomi",
        baseUrl: "https://api.xiaomimimo.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 256000,
        maxTokens: 256000,
        compat: {
          omitEmptyArrayItems: true,
        } as never,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "collect",
            description: "Collect hints",
            parameters: {
              type: "object",
              properties: {
                hints: { type: "array" },
                typedHints: { type: "array", items: { type: "string" } },
              },
            },
          },
        ],
      } as never,
      undefined,
    ) as {
      tools?: Array<{ function?: { parameters?: { properties?: Record<string, unknown> } } }>;
    };

    expect(params.tools?.[0]?.function?.parameters?.properties?.hints).toStrictEqual({
      type: "array",
    });
    expect(params.tools?.[0]?.function?.parameters?.properties?.typedHints).toStrictEqual({
      type: "array",
      items: { type: "string" },
    });
  });

  it("omits tools from completions payload when model compat sets supportsTools to false", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "chat-only-model",
        name: "Chat Only Model",
        api: "openai-completions",
        provider: "venice",
        baseUrl: "https://api.venice.ai/api/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 4096,
        compat: {
          supportsTools: false,
        } as Record<string, unknown>,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [],
        tools: [
          {
            name: "noop",
            description: "noop tool",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      undefined,
    ) as { tools?: unknown; tool_choice?: unknown };

    expect(params).not.toHaveProperty("tools");
    expect(params).not.toHaveProperty("tool_choice");
  });

  it("omits tool-history tools:[] fallback when model compat sets supportsTools to false", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "chat-only-model",
        name: "Chat Only Model",
        api: "openai-completions",
        provider: "venice",
        baseUrl: "https://api.venice.ai/api/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 128000,
        maxTokens: 4096,
        compat: {
          supportsTools: false,
        } as Record<string, unknown>,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            content: [
              {
                type: "toolCall",
                id: "call_abc",
                name: "noop",
                arguments: {},
              },
            ],
            timestamp: Date.now(),
          },
          {
            role: "toolResult",
            toolCallId: "call_abc",
            toolName: "noop",
            content: [{ type: "text", text: "ok" }],
            isError: false,
            timestamp: Date.now(),
          },
        ],
      } as never,
      undefined,
    ) as { tools?: unknown };

    expect(params).not.toHaveProperty("tools");
  });

  describe("Gemini thought_signature round-trip on OpenAI-compatible completions", () => {
    const geminiModel = {
      id: "gemini-3-flash-preview",
      name: "Gemini 3 Flash Preview",
      api: "openai-completions",
      provider: "google",
      baseUrl: "https://generativelanguage.googleapis.com/v1beta/openai",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 1_000_000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    function makeAssistantOutput(model: Model<"openai-completions">) {
      return {
        role: "assistant" as const,
        content: [] as Array<Record<string, unknown>>,
        api: model.api,
        provider: model.provider,
        model: model.id,
        usage: {
          input: 0,
          output: 0,
          cacheRead: 0,
          cacheWrite: 0,
          totalTokens: 0,
          cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
        },
        stopReason: "stop",
        timestamp: Date.now(),
      };
    }

    it("captures thought_signature from streamed Google tool_calls", async () => {
      const output = makeAssistantOutput(geminiModel);
      const chunks = [
        {
          id: "chatcmpl-gemini",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: geminiModel.id,
          choices: [
            {
              index: 0,
              delta: {
                tool_calls: [
                  {
                    index: 0,
                    id: "call_abc",
                    type: "function",
                    function: { name: "echo_value", arguments: "" },
                    extra_content: { google: { thought_signature: "SIG-OPAQUE-ABC==" } },
                  },
                ],
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-gemini",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: geminiModel.id,
          choices: [
            {
              index: 0,
              delta: {
                tool_calls: [{ index: 0, function: { arguments: '{"value":"repro"}' } }],
              },
              logprobs: null,
              finish_reason: "tool_calls" as const,
            },
          ],
        },
      ] as const;
      async function* mockStream() {
        for (const chunk of chunks) {
          yield chunk as never;
        }
      }

      await testing.processOpenAICompletionsStream(mockStream(), output, geminiModel, {
        push() {},
      });

      expectRecordFields(output.content[0], {
        type: "toolCall",
        id: "call_abc",
        name: "echo_value",
        arguments: { value: "repro" },
        thoughtSignature: "SIG-OPAQUE-ABC==",
      });
    });

    it("re-emits captured thought_signature for same Google route tool-call replay", () => {
      const params = buildOpenAICompletionsParams(
        geminiModel,
        {
          messages: [
            { role: "user", content: "echo" },
            {
              role: "assistant",
              api: geminiModel.api,
              provider: geminiModel.provider,
              model: geminiModel.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [
                {
                  type: "toolCall",
                  id: "call_abc",
                  name: "echo_value",
                  arguments: { value: "repro" },
                  thoughtSignature: "SIG-OPAQUE-ABC==",
                },
              ],
            },
            {
              role: "toolResult",
              toolCallId: "call_abc",
              toolName: "echo_value",
              content: [{ type: "text", text: "ok" }],
              isError: false,
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBe(
        "SIG-OPAQUE-ABC==",
      );
    });

    it("uses the Gemini skip-validator signature across a different API surface", () => {
      const params = buildOpenAICompletionsParams(
        geminiModel,
        {
          messages: [
            {
              role: "assistant",
              api: "google-generative-ai",
              provider: geminiModel.provider,
              model: geminiModel.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [
                {
                  type: "toolCall",
                  id: "call_abc",
                  name: "echo_value",
                  arguments: { value: "repro" },
                  thoughtSignature: "SIG-OPAQUE-ABC==",
                },
              ],
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBe(
        "skip_thought_signature_validator",
      );
    });

    it("uses the Gemini skip-validator signature when no thought_signature was captured", () => {
      const params = buildOpenAICompletionsParams(
        geminiModel,
        {
          messages: [
            {
              role: "assistant",
              api: geminiModel.api,
              provider: geminiModel.provider,
              model: geminiModel.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [{ type: "toolCall", id: "call_abc", name: "echo_value", arguments: {} }],
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBe(
        "skip_thought_signature_validator",
      );
    });

    it("falls back to skip_thought_signature_validator when a captured same-route Gemini 3 signature is truncated", () => {
      // Compaction-truncated sig: 109 chars, length mod 4 == 1.
      // Same-route assistant tool-call whose captured thoughtSignature is truncated.
      // The guard should fall back to the sentinel instead of dropping the field.
      const params = buildOpenAICompletionsParams(
        geminiModel,
        {
          messages: [
            {
              role: "assistant",
              api: geminiModel.api,
              provider: geminiModel.provider,
              model: geminiModel.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [
                {
                  type: "toolCall",
                  id: "call_abc",
                  name: "echo_value",
                  arguments: { value: "repro" },
                  thoughtSignature:
                    "CmcBjz1rX55U6JcpC2oZVTk40Kx6nVK8LKzbl61rOFztcvSdL7pdIvBEDyJLRqWrPVpdD+rj3GsJ3f9PG6b2Ry2UnK38+dInfGIlJbXHt++EC",
                },
              ],
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBe(
        "skip_thought_signature_validator",
      );
    });

    it("drops the field when the model is not Gemini 3 and the captured same-route signature is truncated", () => {
      // gemini-2.5-pro: requiresGoogleCompatToolCallThoughtSignature returns false,
      // so fallbackSig is undefined and there is no sentinel to fall back to.
      // A truncated same-route sig should cause the field to be dropped entirely.
      const nonGemini3Model = {
        ...geminiModel,
        id: "gemini-2.5-pro",
        name: "Gemini 2.5 Pro",
      };
      const params = buildOpenAICompletionsParams(
        nonGemini3Model,
        {
          messages: [
            {
              role: "assistant",
              api: nonGemini3Model.api,
              provider: nonGemini3Model.provider,
              model: nonGemini3Model.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [
                {
                  type: "toolCall",
                  id: "call_abc",
                  name: "echo_value",
                  arguments: { value: "repro" },
                  thoughtSignature:
                    "CmcBjz1rX55U6JcpC2oZVTk40Kx6nVK8LKzbl61rOFztcvSdL7pdIvBEDyJLRqWrPVpdD+rj3GsJ3f9PG6b2Ry2UnK38+dInfGIlJbXHt++EC",
                },
              ],
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: { google?: { thought_signature?: string } } }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content?.google?.thought_signature).toBeUndefined();
    });

    it("does not trust cross-route thought_signature for non-Gemini-3 Google compat models", () => {
      const nonGemini3Model = {
        ...geminiModel,
        id: "gemini-2.5-pro",
        name: "Gemini 2.5 Pro",
      };
      const params = buildOpenAICompletionsParams(
        nonGemini3Model,
        {
          messages: [
            {
              role: "assistant",
              api: "google-generative-ai",
              provider: nonGemini3Model.provider,
              model: nonGemini3Model.id,
              usage: {
                input: 0,
                output: 0,
                cacheRead: 0,
                cacheWrite: 0,
                totalTokens: 0,
                cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
              },
              stopReason: "toolUse",
              timestamp: 1,
              content: [
                {
                  type: "toolCall",
                  id: "call_abc",
                  name: "echo_value",
                  arguments: { value: "repro" },
                  thoughtSignature: "SIG-OPAQUE-ABC==",
                },
              ],
            },
          ],
          tools: [],
        } as never,
        undefined,
      ) as { messages: Array<Record<string, unknown>> };

      const assistant = params.messages.find((message) => message.role === "assistant") as
        | { tool_calls?: Array<{ extra_content?: unknown }> }
        | undefined;
      expect(assistant?.tool_calls?.[0]?.extra_content).toBeUndefined();
    });
  });

  it("uses Mistral compat defaults for direct Mistral completions providers", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "mistral-large-latest",
        name: "Mistral Large",
        api: "openai-completions",
        provider: "mistral",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        maxTokens: 2048,
        reasoningEffort: "high",
      } as never,
    );

    expect(params.max_tokens).toBe(2048);
    expect(params).not.toHaveProperty("max_completion_tokens");
    expect(params).not.toHaveProperty("store");
    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it("uses Mistral compat defaults for custom providers on native Mistral hosts", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "mistral-small-latest",
        name: "Mistral Small",
        api: "openai-completions",
        provider: "custom-mistral-host",
        baseUrl: "https://api.mistral.ai/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } as never,
      {
        systemPrompt: "system",
        messages: [],
        tools: [],
      } as never,
      {
        maxTokens: 2048,
        reasoningEffort: "high",
      } as never,
    );

    expect(params.max_tokens).toBe(2048);
    expect(params).not.toHaveProperty("max_completion_tokens");
    expect(params).not.toHaveProperty("store");
    expect(params).not.toHaveProperty("reasoning_effort");
  });

  it("serializes raw string tool-call arguments without double-encoding them", () => {
    const params = buildOpenAIResponsesParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-responses",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: true,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 200000,
        maxTokens: 8192,
      } satisfies Model<"openai-responses">,
      {
        systemPrompt: "system",
        messages: [
          {
            role: "assistant",
            api: "openai-responses",
            provider: "openai",
            model: "gpt-5.4",
            usage: {
              input: 0,
              output: 0,
              cacheRead: 0,
              cacheWrite: 0,
              totalTokens: 0,
              cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
            },
            stopReason: "stop",
            timestamp: 1,
            content: [
              {
                type: "toolCall",
                id: "call_abc|fc_item1",
                name: "my_tool",
                arguments: "not valid json",
              },
            ],
          },
        ],
        tools: [],
      } as never,
      undefined,
    ) as {
      input?: Array<{ type?: string; arguments?: string }>;
    };

    const functionCall = params.input?.find((item) => item.type === "function_call");
    expectRecordFields(functionCall, {
      type: "function_call",
      arguments: "not valid json",
    });
  });

  it("defaults tool_choice to auto for proxy-like openai-completions endpoints", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "test-model",
        name: "Test Model",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [],
        tools: [
          {
            name: "get_weather",
            description: "Get weather information",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      undefined,
    );

    expect(params).toHaveProperty("tools");
    expect(params).toHaveProperty("tool_choice", "auto");
  });

  it("does not send tool_choice by default for native openai-completions endpoints", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [],
        tools: [
          {
            name: "get_weather",
            description: "Get weather information",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      undefined,
    );

    expect(params).toHaveProperty("tools");
    expect(params).not.toHaveProperty("tool_choice");
  });

  it("sends tool_choice when explicitly configured", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "test-model",
        name: "Test Model",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [],
        tools: [
          {
            name: "get_weather",
            description: "Get weather information",
            parameters: { type: "object", properties: {} },
          },
        ],
      } as never,
      {
        toolChoice: "required",
      },
    );

    expect(params).toHaveProperty("tools");
    expect(params).toHaveProperty("tool_choice", "required");
  });

  it("omits empty tools and tool_choice for proxy-like openai-completions endpoints when context.tools is []", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "test-model",
        name: "Test Model",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params).not.toHaveProperty("tools");
    expect(params).not.toHaveProperty("tool_choice");
  });

  it("omits tools for proxy-like openai-completions endpoints when only prior tool history is present", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "test-model",
        name: "Test Model",
        api: "openai-completions",
        provider: "vllm",
        baseUrl: "http://localhost:8000/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [
          {
            role: "assistant",
            content: [
              {
                type: "toolCall",
                id: "call_abc",
                name: "get_weather",
                arguments: "{}",
              },
            ],
          },
          {
            role: "toolResult",
            content: [{ type: "text", text: "sunny" }],
            toolCallId: "call_abc",
          },
        ],
      } as never,
      undefined,
    );

    expect(params).not.toHaveProperty("tools");
    expect(params).not.toHaveProperty("tool_choice");
  });

  it("preserves empty tools array for native openai-completions endpoints (existing behavior)", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [],
        tools: [],
      } as never,
      undefined,
    );

    expect(params).toHaveProperty("tools");
    expect((params as { tools: unknown[] }).tools).toEqual([]);
  });

  it("preserves tools: [] fallback for native openai-completions endpoints when only prior tool history is present (existing behavior)", () => {
    const params = buildOpenAICompletionsParams(
      {
        id: "gpt-5.4",
        name: "GPT-5.4",
        api: "openai-completions",
        provider: "openai",
        baseUrl: "https://api.openai.com/v1",
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 4096,
        maxTokens: 2048,
      } satisfies Model<"openai-completions">,
      {
        systemPrompt: "You are a helpful assistant",
        messages: [
          {
            role: "assistant",
            content: [
              {
                type: "toolCall",
                id: "call_abc",
                name: "get_weather",
                arguments: "{}",
              },
            ],
          },
          {
            role: "toolResult",
            content: [{ type: "text", text: "sunny" }],
            toolCallId: "call_abc",
          },
        ],
      } as never,
      undefined,
    );

    expect(params).toHaveProperty("tools");
    expect((params as { tools: unknown[] }).tools).toEqual([]);
  });

  it("resets stopReason to stop when finish_reason is tool_calls but tool_calls array is empty", async () => {
    const model = {
      id: "nemotron-3-super",
      name: "Nemotron 3 Super",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 1000000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream = {
      push: () => {},
    };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "nemotron-3-super",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "nemotron-3-super",
        choices: [
          {
            index: 0,
            delta: { content: "4" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "nemotron-3-super",
        choices: [
          {
            index: 0,
            delta: { tool_calls: [] as never[] },
            logprobs: null,
            finish_reason: "tool_calls" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("stop");
    expect(
      output.content.filter((block) => (block as { type?: string }).type === "toolCall"),
    ).toStrictEqual([]);
  });

  it("accumulates arguments for parallel tool calls with split indices", async () => {
    const model = {
      id: "kimi-for-coding",
      name: "Kimi for Coding",
      api: "openai-completions",
      provider: "kimi-code",
      baseUrl: "https://api.moonshot.cn",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);

    const mockChunks = [
      {
        id: "chatcmpl-parallel",
        object: "chat.completion.chunk" as const,
        created: 1,
        model: model.id,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  index: 0,
                  id: "call_0",
                  type: "function",
                  function: { name: "exec", arguments: "" },
                },
                {
                  index: 1,
                  id: "call_1",
                  type: "function",
                  function: { name: "read", arguments: "" },
                },
              ],
            },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-parallel",
        object: "chat.completion.chunk" as const,
        created: 1,
        model: model.id,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [{ index: 0, function: { arguments: '{"command":"ls"}' } }],
            },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-parallel",
        object: "chat.completion.chunk" as const,
        created: 1,
        model: model.id,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [{ index: 1, function: { arguments: '{"path":"/tmp"}' } }],
            },
            logprobs: null,
            finish_reason: "tool_calls" as const,
          },
        ],
      },
    ] as const;

    await testing.processOpenAICompletionsStream(streamChunks(mockChunks), output, model, {
      push() {},
    });

    expect(output.content).toHaveLength(2);
    expectRecordFields(output.content[0], {
      type: "toolCall",
      id: "call_0",
      name: "exec",
      arguments: { command: "ls" },
    });
    expectRecordFields(output.content[1], {
      type: "toolCall",
      id: "call_1",
      name: "read",
      arguments: { path: "/tmp" },
    });
  });

  it("keeps buffered visible text before following tool calls", async () => {
    const model = {
      id: "plain-openai-compatible",
      name: "Plain OpenAI Compatible",
      api: "openai-completions",
      provider: "plain-openai-compatible",
      baseUrl: "https://api.compat.test/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-buffered-text-tool",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: { content: "Use <" },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-buffered-text-tool",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                tool_calls: [
                  {
                    index: 0,
                    id: "call_0",
                    type: "function",
                    function: { name: "exec", arguments: '{"command":"ls"}' },
                  },
                ],
              },
              logprobs: null,
              finish_reason: "tool_calls" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content[0]).toEqual({ type: "text", text: "Use <" });
    expectRecordFields(output.content[1], {
      type: "toolCall",
      id: "call_0",
      name: "exec",
      arguments: { command: "ls" },
    });
  });

  it("partitions inline reasoning tags out of OpenAI-compatible visible text", async () => {
    const model = {
      id: "MiniMax-M2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "minimax",
      baseUrl: "https://api.minimax.test/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-reasoning-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "Before <thi",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-reasoning-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "nk>private reasoning</think> after",
                reasoning_content: "private reasoning",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-reasoning-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {},
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
    );

    const visibleText = output.content
      .filter((block): block is { type: "text"; text: string } => block.type === "text")
      .map((block) => block.text)
      .join("");
    const thinkingText = output.content
      .filter((block): block is { type: "thinking"; thinking: string } => block.type === "thinking")
      .map((block) => block.thinking)
      .join("");

    expect(visibleText).toBe("Before  after");
    expect(visibleText).not.toContain("private reasoning");
    expect(thinkingText).toBe("private reasoning");
    expect(events.filter((event) => event.type === "thinking_delta")).toHaveLength(1);
  });

  it("drops mirrored reasoning when disabled without recovering hidden reasoning tags", async () => {
    const model = {
      id: "MiniMax-M2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "minimax",
      baseUrl: "https://api.minimax.test/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;
    const output = createAssistantOutput(model);
    const events: CapturedStreamEvent[] = [];

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-reasoning-disabled",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "<think>private reasoning",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-reasoning-disabled",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                reasoning_content: "private reasoning",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push: (event) => events.push(event as CapturedStreamEvent) },
      { emitReasoning: false },
    );

    const visibleText = output.content
      .filter((block): block is { type: "text"; text: string } => block.type === "text")
      .map((block) => block.text)
      .join("");

    expect(visibleText).toBe("");
    expect(output.content.some((block) => block.type === "thinking")).toBe(false);
    expect(events.some((event) => event.type === "thinking_delta")).toBe(false);
  });

  it("keeps literal reasoning tag examples visible without mirrored reasoning", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-literal-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "Use `<think>private</think>` only as an example.",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "Use `<think>private</think>` only as an example.",
    });
    expect(output.content.some((block) => block.type === "thinking")).toBe(false);
  });

  it("keeps prose mentions of unclosed reasoning tags visible without mirrored reasoning", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-literal-unclosed-tag",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "The <reasoning> tag is deprecated in this example.",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "The <reasoning> tag is deprecated in this example.",
    });
    expect(output.content.some((block) => block.type === "thinking")).toBe(false);
  });

  it("keeps prose mentions of unmatched close tags visible without mirrored reasoning", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-literal-close-tag",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "Use </think> to close the tag.",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "Use </think> to close the tag.",
    });
    expect(output.content.some((block) => block.type === "thinking")).toBe(false);
  });

  it("strips content-only reasoning tags from OpenAI-compatible visible text", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-content-only-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "Before <think>private reasoning</think> after",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "Before  after",
    });
    expect(output.content.some((block) => block.type === "thinking")).toBe(false);
  });

  it("recovers fully wrapped unclosed OpenAI-compatible reasoning text", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-unclosed-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "<think>Visible answer from a malformed local model",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "Visible answer from a malformed local model",
    });
  });

  it("does not recover buffered reasoning tags after structured thinking content", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-structured-thinking",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "<think>private reasoning",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-structured-thinking",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: { type: "reasoning", text: "private reasoning" },
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    const visibleText = output.content
      .filter((block): block is { type: "text"; text: string } => block.type === "text")
      .map((block) => block.text)
      .join("");
    const thinkingText = output.content
      .filter((block): block is { type: "thinking"; thinking: string } => block.type === "thinking")
      .map((block) => block.thinking)
      .join("");

    expect(visibleText).toBe("");
    expect(thinkingText).toBe("private reasoning");
  });

  it("keeps literal reasoning tag examples visible with mirrored reasoning", async () => {
    const model = createDeepSeekCompletionsModel();
    const output = createAssistantOutput(model);

    await testing.processOpenAICompletionsStream(
      streamChunks([
        {
          id: "chatcmpl-literal-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "Use `<thi",
              },
              logprobs: null,
              finish_reason: null,
            },
          ],
        },
        {
          id: "chatcmpl-literal-tags",
          object: "chat.completion.chunk" as const,
          created: 1,
          model: model.id,
          choices: [
            {
              index: 0,
              delta: {
                content: "nk>private</think>` only as an example.",
                reasoning_content: "Actual hidden reasoning.",
              },
              logprobs: null,
              finish_reason: "stop" as const,
            },
          ],
        },
      ]),
      output,
      model,
      { push() {} },
    );

    expect(output.content).toContainEqual({
      type: "text",
      text: "Use `<think>private</think>` only as an example.",
    });
    expect(output.content).toContainEqual({
      type: "thinking",
      thinking: "Actual hidden reasoning.",
      thinkingSignature: "reasoning_content",
    });
  });

  it("promotes silent tool calls when provider signals finish_reason stop", async () => {
    const model = {
      id: "qwen3.6-27b",
      name: "Qwen 3.6 27B",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);
    const stream = { push: () => {} };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "qwen3.6-27b",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "qwen3.6-27b",
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  index: 0,
                  id: "call_legit",
                  function: { name: "bash", arguments: '{"cmd":"echo hi"}' },
                },
              ],
            },
            logprobs: null,
            finish_reason: "stop",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    const toolCalls = output.content.filter(
      (block) => (block as { type?: string }).type === "toolCall",
    );
    expect(toolCalls).toHaveLength(1);
  });

  it("does not promote tool calls when provider omits final finish_reason", async () => {
    const model = {
      id: "qwen3.6-27b",
      name: "Qwen 3.6 27B",
      api: "openai-completions",
      provider: "vllm",
      baseUrl: "http://localhost:8000/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);
    const stream = { push: () => {} };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "qwen3.6-27b",
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  index: 0,
                  id: "call_unfinished",
                  function: { name: "bash", arguments: '{"cmd":"echo hi"}' },
                },
              ],
            },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("stop");
    expect(
      output.content.filter((block) => (block as { type?: string }).type === "toolCall"),
    ).toStrictEqual([]);
  });

  it("strips tool call blocks when provider signals finish_reason stop after visible text", async () => {
    const model = {
      id: "llama-3.3-70b",
      name: "Llama 3.3 70B",
      api: "openai-completions",
      provider: "llamacpp",
      baseUrl: "http://localhost:8080/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);
    const stream = { push: () => {} };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: { content: "Here is the answer." },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  index: 0,
                  id: "call_spurious",
                  function: { name: "bash", arguments: '{"cmd":"rm -rf /"}' },
                },
              ],
            },
            logprobs: null,
            finish_reason: "stop",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("stop");
    expect(
      output.content.filter((block) => (block as { type?: string }).type === "toolCall"),
    ).toStrictEqual([]);
    expect(output.content.some((block) => (block as { type?: string }).type === "text")).toBe(true);
  });

  it("keeps tool call blocks when provider signals finish_reason tool_calls", async () => {
    const model = {
      id: "llama-3.3-70b",
      name: "Llama 3.3 70B",
      api: "openai-completions",
      provider: "llamacpp",
      baseUrl: "http://localhost:8080/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);
    const stream = { push: () => {} };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  index: 0,
                  id: "call_legit",
                  function: { name: "bash", arguments: '{"cmd":"echo hi"}' },
                },
              ],
            },
            logprobs: null,
            finish_reason: "tool_calls",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    const toolCalls = output.content.filter(
      (block) => (block as { type?: string }).type === "toolCall",
    );
    expect(toolCalls).toHaveLength(1);
  });

  it("leaves content unchanged when no tool calls and finish_reason is stop", async () => {
    const model = {
      id: "llama-3.3-70b",
      name: "Llama 3.3 70B",
      api: "openai-completions",
      provider: "llamacpp",
      baseUrl: "http://localhost:8080/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 131072,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = createAssistantOutput(model);
    const stream = { push: () => {} };

    const mockChunks = [
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: { role: "assistant" as const, content: "" },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-test",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: "llama-3.3-70b",
        choices: [
          {
            index: 0,
            delta: { content: "Just a text reply." },
            logprobs: null,
            finish_reason: "stop",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("stop");
    expect(output.content).toHaveLength(1);
    expect((output.content[0] as { type?: string }).type).toBe("text");
  });

  it("handles reasoning_details from OpenRouter/Qwen3 in completions stream", async () => {
    const model = {
      id: "openrouter/qwen/qwen3-235b-a22b",
      name: "Qwen3 235B A22B",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-reasoning",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [
                { type: "reasoning.text", text: "I need to think about this." },
                { type: "reasoning.text", text: " Let me analyze." },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-reasoning",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              content: " Hello! How can I help you?",
            },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-reasoning",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "stop",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    const thinkingBlock = output.content[0] as { type: string; thinking: string };
    const textBlock = output.content[1] as { type: string; text: string };

    expect(output.content.length).toBe(2);
    expect(thinkingBlock.type).toBe("thinking");
    expect(thinkingBlock.thinking).toBe("I need to think about this. Let me analyze.");
    expect(textBlock.type).toBe("text");
    expect(textBlock.text).toBe(" Hello! How can I help you?");
  });

  it("normalizes structured completions content blocks without stringifying objects (#78846)", async () => {
    const model = {
      id: "mistral-small-latest",
      name: "Mistral Small",
      api: "openai-completions",
      provider: "mistral",
      baseUrl: "https://api.mistral.ai/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };
    const mockChunks = [
      {
        id: "chatcmpl-structured-content",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              content: [
                { type: "thinking", thinking: [{ type: "text", text: "Need to think." }] },
                { type: "text", content: "Visible answer." },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-structured-content",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "stop",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toEqual([
      { type: "thinking", thinking: "Need to think.", thinkingSignature: "content" },
      { type: "text", text: "Visible answer." },
    ]);
  });

  it("keeps tool calls when reasoning_details and tool_calls share a chunk", async () => {
    const model = {
      id: "openrouter/qwen/qwen3-235b-a22b",
      name: "Qwen3 235B A22B",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-toolcall",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "reasoning.text", text: "Need a tool." }],
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":"qwen3"}' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-toolcall",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_calls",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toHaveLength(2);
    expectRecordFields(output.content[0], {
      type: "thinking",
      thinking: "Need a tool.",
      thinkingSignature: "reasoning_details",
    });
    expectRecordFields(output.content[1], {
      type: "toolCall",
      id: "call_1",
      name: "lookup",
      arguments: { query: "qwen3" },
    });
  });

  it("treats singular tool_call finish_reason as tool use", async () => {
    const model = {
      id: "minimax-m2.5-8bit",
      name: "MiniMax M2.5 8bit",
      api: "openai-completions",
      provider: "mlx-lm",
      baseUrl: "http://localhost:1234/v1",
      reasoning: false,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 128000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-mlx",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: model.id,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: "{}" },
                },
              ],
            },
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-mlx",
        object: "chat.completion.chunk" as const,
        created: 1775425651,
        model: model.id,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_call",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    const toolCall = (output.content as Array<{ type?: string }>).find(
      (item) => item.type === "toolCall",
    );
    expectRecordFields(toolCall, { type: "toolCall", id: "call_1", name: "lookup" });
  });

  it("keeps streamed tool call arguments intact when reasoning_details repeats", async () => {
    const model = {
      id: "openrouter/qwen/qwen3-235b-a22b",
      name: "Qwen3 235B A22B",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-toolcall-stream",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "reasoning.text", text: "Need a tool." }],
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-toolcall-stream",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "reasoning.text", text: " Still thinking." }],
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { arguments: '"qwen3"}' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-toolcall-stream",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_calls",
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toHaveLength(3);
    expectRecordFields(output.content[0], { type: "thinking", thinking: "Need a tool." });
    expectRecordFields(output.content[1], {
      type: "toolCall",
      id: "call_1",
      name: "lookup",
      arguments: { query: "qwen3" },
    });
    expectRecordFields(output.content[2], {
      type: "thinking",
      thinking: " Still thinking.",
      thinkingSignature: "reasoning_details",
    });
  });

  it("surfaces visible OpenRouter response text from reasoning_details without dropping tools", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-minimax",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [
                { type: "reasoning.text", text: "Need to look something up." },
                { type: "response.output_text", text: "Working on it." },
              ],
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":"weather"}' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-minimax",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_calls" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toHaveLength(3);
    expectRecordFields(output.content[0], {
      type: "thinking",
      thinking: "Need to look something up.",
      thinkingSignature: "reasoning_details",
    });
    expectRecordFields(output.content[1], { type: "text", text: "Working on it." });
    expectRecordFields(output.content[2], {
      type: "toolCall",
      id: "call_1",
      name: "lookup",
      arguments: { query: "weather" },
    });
  });

  it("does not surface ambiguous reasoning_details text without explicit compat opt-in", async () => {
    const model = {
      id: "openrouter/x-ai/grok-4",
      name: "Grok 4",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-grok",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [
                { type: "reasoning.text", text: "Internal thought." },
                { type: "text", text: "Do not leak this by default." },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-grok",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toHaveLength(1);
    expectRecordFields(output.content[0], {
      type: "thinking",
      thinking: "Internal thought.",
      thinkingSignature: "reasoning_details",
    });
  });

  it("preserves reasoning_details item order when visible text and thinking are interleaved", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-minimax-order",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [
                { type: "response.output_text", text: "Visible first." },
                { type: "reasoning.text", text: " Hidden second." },
                { type: "response.text", text: " Visible third." },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toHaveLength(3);
    expectRecordFields(output.content[0], { type: "text", text: "Visible first." });
    expectRecordFields(output.content[1], {
      type: "thinking",
      thinking: " Hidden second.",
      thinkingSignature: "reasoning_details",
    });
    expectRecordFields(output.content[2], { type: "text", text: " Visible third." });
  });

  it("does not duplicate fallback reasoning fields when reasoning_details already provided thinking", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-fallback-dup",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "reasoning.text", text: "Primary reasoning." }],
              reasoning: "Duplicate fallback reasoning.",
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toHaveLength(1);
    expectRecordFields(output.content[0], {
      type: "thinking",
      thinking: "Primary reasoning.",
      thinkingSignature: "reasoning_details",
    });
  });

  it("keeps fallback thinking when reasoning_details only carries visible text", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-visible-fallback",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "response.output_text", text: "Visible answer." }],
              reasoning: "Hidden fallback reasoning.",
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: "stop" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.content).toHaveLength(2);
    expectRecordFields(output.content[0], { type: "text", text: "Visible answer." });
    expectRecordFields(output.content[1], {
      type: "thinking",
      thinking: "Hidden fallback reasoning.",
      thinkingSignature: "reasoning",
    });
  });

  it("keeps a streaming tool call intact when visible reasoning text arrives mid-call", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-tool-split",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-split",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "response.output_text", text: "Working on it." }],
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { arguments: '"weather"}' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-split",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_calls" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toHaveLength(2);
    expectRecordFields(output.content[0], {
      type: "toolCall",
      id: "call_1",
      name: "lookup",
      arguments: { query: "weather" },
    });
    expectRecordFields(output.content[1], { type: "text", text: "Working on it." });
  });

  it("keeps a streaming tool call intact when visible reasoning text arrives between chunks", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };

    const mockChunks = [
      {
        id: "chatcmpl-tool-split-gap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-split-gap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              reasoning_details: [{ type: "response.output_text", text: "Working on it." }],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-split-gap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { arguments: '"weather"}' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-split-gap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {},
            logprobs: null,
            finish_reason: "tool_calls" as const,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await testing.processOpenAICompletionsStream(mockStream(), output, model, stream);

    expect(output.stopReason).toBe("toolUse");
    expect(output.content).toHaveLength(2);
    expectRecordFields(output.content[0], {
      type: "toolCall",
      id: "call_1",
      name: "lookup",
      arguments: { query: "weather" },
    });
    expectRecordFields(output.content[1], { type: "text", text: "Working on it." });
  });

  it("fails fast when post-tool-call buffering grows beyond the safety cap", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };
    const oversizedText = "x".repeat(300_000);

    const mockChunks = [
      {
        id: "chatcmpl-tool-buffer-cap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: '{"query":' },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
      {
        id: "chatcmpl-tool-buffer-cap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              content: oversizedText,
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await expect(
      testing.processOpenAICompletionsStream(mockStream(), output, model, stream),
    ).rejects.toThrow("Exceeded post-tool-call delta buffer limit");
  });

  it("fails fast when streaming tool-call arguments grow beyond the safety cap", async () => {
    const model = {
      id: "openrouter/minimax/minimax-m2.7",
      name: "MiniMax M2.7",
      api: "openai-completions",
      provider: "openrouter",
      baseUrl: "https://openrouter.ai/api/v1",
      reasoning: true,
      input: ["text"],
      cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
      contextWindow: 200000,
      maxTokens: 8192,
    } satisfies Model<"openai-completions">;

    const output = {
      role: "assistant" as const,
      content: [],
      api: model.api,
      provider: model.provider,
      model: model.id,
      usage: {
        input: 0,
        output: 0,
        cacheRead: 0,
        cacheWrite: 0,
        totalTokens: 0,
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
      },
      stopReason: "stop",
      timestamp: Date.now(),
    };

    const stream: { push(event: unknown): void } = { push() {} };
    const oversizedArgs = `"${"x".repeat(300_000)}"}`;

    const mockChunks = [
      {
        id: "chatcmpl-tool-arg-cap",
        object: "chat.completion.chunk" as const,
        choices: [
          {
            index: 0,
            delta: {
              tool_calls: [
                {
                  id: "call_1",
                  type: "function" as const,
                  function: { name: "lookup", arguments: `{${oversizedArgs}` },
                },
              ],
            } as Record<string, unknown>,
            logprobs: null,
            finish_reason: null,
          },
        ],
      },
    ] as const;

    async function* mockStream() {
      for (const chunk of mockChunks) {
        yield chunk as never;
      }
    }

    await expect(
      testing.processOpenAICompletionsStream(mockStream(), output, model, stream),
    ).rejects.toThrow("Exceeded tool-call argument buffer limit");
  });
});

describe("buildOpenAICompletionsParams sanitizes reasoning replay fields", () => {
  const openRouterModel = {
    id: "deepseek/deepseek-v4-flash",
    name: "DeepSeek v4 Flash",
    api: "openai-completions",
    provider: "openrouter",
    baseUrl: "https://openrouter.ai/api/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 128_000,
    maxTokens: 8192,
  } satisfies Model<"openai-completions">;

  const openRouterAnthropicModel = {
    ...openRouterModel,
    id: "anthropic/claude-sonnet-4.6",
    name: "Claude Sonnet 4.6",
  } satisfies Model<"openai-completions">;

  const openRouterXaiModel = {
    ...openRouterModel,
    id: "x-ai/grok-4.3",
    name: "Grok 4.3",
  } satisfies Model<"openai-completions">;

  const openAIModel = {
    id: "gpt-5.4-mini",
    name: "GPT-5.4 Mini",
    api: "openai-completions",
    provider: "openai",
    baseUrl: "https://api.openai.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 200_000,
    maxTokens: 8192,
  } satisfies Model<"openai-completions">;

  const nativeDeepSeekModel = {
    id: "deepseek-v4-flash",
    name: "DeepSeek V4 Flash",
    api: "openai-completions",
    provider: "deepseek",
    baseUrl: "https://api.deepseek.com",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 1_000_000,
    maxTokens: 384_000,
  } satisfies Model<"openai-completions">;

  const nativeZaiModel = {
    id: "glm-5.1",
    name: "GLM 5.1",
    api: "openai-completions",
    provider: "zai",
    baseUrl: "https://api.z.ai/api/paas/v4",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 200_000,
    maxTokens: 131_072,
  } satisfies Model<"openai-completions">;

  const xiaomiModel = {
    id: "mimo-v2.5-pro",
    name: "MiMo V2.5 Pro",
    api: "openai-completions",
    provider: "xiaomi",
    baseUrl: "https://api.xiaomimimo.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 1_048_576,
    maxTokens: 32_000,
  } satisfies Model<"openai-completions">;

  const customMiMoProxyModel = {
    ...xiaomiModel,
    provider: "xiaomi-orbit",
    baseUrl: "https://proxy.example.com/v1",
  } satisfies Model<"openai-completions">;

  const customKimiProxyModel = {
    id: "moonshotai/kimi-k2.6",
    name: "Kimi K2.6",
    api: "openai-completions",
    provider: "custom-openai-proxy",
    baseUrl: "https://proxy.example.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 262_144,
    maxTokens: 32_000,
  } satisfies Model<"openai-completions">;

  const staleKimiK27Model = {
    ...customKimiProxyModel,
    id: "kimi-k2.7-code",
    name: "Kimi K2.7 Code",
    provider: "moonshot",
    baseUrl: "https://api.moonshot.ai/v1",
    reasoning: false,
  } satisfies Model<"openai-completions">;

  const customQwenReasoningModel = {
    id: "Qwen3.6-35B-A3B",
    name: "Qwen3.6 35B",
    api: "openai-completions",
    provider: "custom-openai-proxy",
    baseUrl: "https://proxy.example.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 262_144,
    maxTokens: 32_000,
  } satisfies Model<"openai-completions">;

  const gemma4Model = {
    id: "google/gemma-4-12b",
    name: "Gemma 4 12B",
    api: "openai-completions",
    provider: "vllm",
    baseUrl: "https://proxy.example.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 262_144,
    maxTokens: 32_000,
  } satisfies Model<"openai-completions">;

  const kimiCodingProxyModel = {
    ...customKimiProxyModel,
    id: "kimi-for-coding",
    name: "Kimi for Coding",
    provider: "kimi",
    baseUrl: "https://api.kimi.com/coding/v1",
  } satisfies Model<"openai-completions">;

  function getAssistantMessage(params: { messages: unknown }) {
    expect(Array.isArray(params.messages)).toBe(true);
    const list = params.messages as Array<Record<string, unknown>>;
    const assistant = list.find((m) => m.role === "assistant");
    expect(assistant).toBeDefined();
    return assistant as Record<string, unknown>;
  }

  function buildReplayParams(model: Model<"openai-completions">, thinkingSignature: string) {
    return buildOpenAICompletionsParams(
      model,
      {
        systemPrompt: "system",
        messages: [
          { role: "user", content: "hello" },
          {
            role: "assistant",
            provider: model.provider,
            api: model.api,
            model: model.id,
            stopReason: "stop",
            timestamp: 0,
            content: [
              {
                type: "thinking",
                thinking: "Need to answer politely.",
                thinkingSignature,
              },
              { type: "text", text: "Hello!" },
            ],
          },
          { role: "user", content: "again" },
        ],
        tools: [],
      } as never,
      undefined,
    ) as { messages: unknown };
  }

  it.each(["reasoning_details", "reasoning_content", "reasoning", "reasoning_text"])(
    "strips %s from stock OpenAI Chat Completions assistant replay",
    (thinkingSignature) => {
      const assistant = getAssistantMessage(buildReplayParams(openAIModel, thinkingSignature));

      expect(assistant).not.toHaveProperty("reasoning_details");
      expect(assistant).not.toHaveProperty("reasoning_content");
      expect(assistant).not.toHaveProperty("reasoning");
      expect(assistant).not.toHaveProperty("reasoning_text");
    },
  );

  it("normalizes OpenRouter string reasoning_details to reasoning", () => {
    const assistant = getAssistantMessage(buildReplayParams(openRouterModel, "reasoning_details"));

    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant.reasoning).toBe("Need to answer politely.");
  });

  it.each([
    ["Anthropic", openRouterAnthropicModel],
    ["xAI", openRouterXaiModel],
  ] as const)("strips OpenRouter %s non-replayable reasoning fields", (_label, model) => {
    for (const thinkingSignature of [
      "reasoning_details",
      "reasoning_content",
      "reasoning",
      "reasoning_text",
    ]) {
      const assistant = getAssistantMessage(buildReplayParams(model, thinkingSignature));

      expect(assistant).not.toHaveProperty("reasoning_details");
      expect(assistant).not.toHaveProperty("reasoning_content");
      expect(assistant).not.toHaveProperty("reasoning");
      expect(assistant).not.toHaveProperty("reasoning_text");
    }
  });

  it.each(["reasoning", "reasoning_content"])(
    "preserves OpenRouter %s string reasoning replay",
    (thinkingSignature) => {
      const assistant = getAssistantMessage(buildReplayParams(openRouterModel, thinkingSignature));

      expect(assistant[thinkingSignature]).toBe("Need to answer politely.");
    },
  );

  it("strips empty-string reasoning_content from OpenRouter assistant replay", () => {
    const params = buildOpenAICompletionsParams(
      openRouterModel,
      {
        systemPrompt: "system",
        messages: [
          { role: "user", content: "read config" },
          {
            role: "assistant",
            provider: "openrouter",
            api: "openai-completions",
            model: "deepseek/deepseek-v4-pro",
            stopReason: "toolUse",
            timestamp: 0,
            content: [
              {
                type: "thinking",
                thinking: "",
                thinkingSignature: "reasoning_content",
              },
              {
                type: "toolCall",
                id: "call_1",
                name: "read_file",
                arguments: { path: "config.json" },
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: "call_1",
            toolName: "read_file",
            content: [{ type: "text", text: "{ }" }],
            isError: false,
            timestamp: 1,
          },
          { role: "user", content: "continue" },
        ],
        tools: [],
      } as never,
      undefined,
    ) as { messages: Array<Record<string, unknown>> };

    const assistantMessages = params.messages.filter((msg) => msg.role === "assistant");
    for (const msg of assistantMessages) {
      expect(msg).not.toHaveProperty("reasoning_content");
    }
  });

  it.each([
    ["DeepSeek", nativeDeepSeekModel],
    ["Z.AI", nativeZaiModel],
  ] as const)("preserves native %s reasoning_content replay", (_label, model) => {
    const assistant = getAssistantMessage(buildReplayParams(model, "reasoning_content"));

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
  });

  it.each([
    ["DeepSeek", nativeDeepSeekModel],
    ["Z.AI", nativeZaiModel],
  ] as const)("strips non-native %s reasoning replay fields", (_label, model) => {
    const assistant = getAssistantMessage(buildReplayParams(model, "reasoning_details"));

    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("normalizes OpenRouter reasoning_text to reasoning", () => {
    const assistant = getAssistantMessage(buildReplayParams(openRouterModel, "reasoning_text"));

    expect(assistant).not.toHaveProperty("reasoning_text");
    expect(assistant.reasoning).toBe("Need to answer politely.");
  });

  it("preserves reasoning_content replay for custom reasoning model metadata", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(customQwenReasoningModel, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for Gemma 4 openai-completions models", () => {
    const assistant = getAssistantMessage(buildReplayParams(gemma4Model, "reasoning_content"));

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves DeepSeek-style reasoning_content replay for Xiaomi MiMo", () => {
    const assistant = getAssistantMessage(buildReplayParams(xiaomiModel, "reasoning_content"));

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for custom MiMo proxy routes", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(customMiMoProxyModel, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for custom MiMo V2.6 proxy routes", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(
        {
          ...customMiMoProxyModel,
          id: "xiaomi/mimo-v2.6-pro",
        },
        "reasoning_content",
      ),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for custom Kimi K2 proxy routes", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(customKimiProxyModel, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves Kimi K2.7 reasoning_content replay with stale reasoning metadata", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(staleKimiK27Model, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for Kimi Coding OpenAI-compatible routes", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(kimiCodingProxyModel, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves reasoning_content replay for suffixed reasoning model ids", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(
        {
          ...customMiMoProxyModel,
          id: "xiaomi/mimo-v2.5-pro:cloud",
        },
        "reasoning_content",
      ),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
  });

  it("preserves reasoning_content replay for prefixed reasoning model ids", () => {
    const assistant = getAssistantMessage(
      buildReplayParams(
        {
          ...customKimiProxyModel,
          id: "hf:moonshotai/kimi-k2-thinking",
        },
        "reasoning_content",
      ),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
  });

  // Regression for #87575: OpenCode Zen exposes DeepSeek V4 with a `-free`
  // tier suffix that does not change the upstream replay contract. Without
  // matching the base id we stripped reasoning_content from the follow-up
  // request and DeepSeek rejected the assistant turn with HTTP 400.
  it.each([
    [
      "OpenCode Zen DeepSeek V4 Flash Free",
      {
        id: "deepseek-v4-flash-free",
        name: "DeepSeek V4 Flash Free",
        api: "openai-completions" as const,
        provider: "opencode",
        baseUrl: "https://opencode.ai/zen/v1",
        reasoning: true,
        input: ["text"] as ("text" | "image")[],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        contextWindow: 65_536,
        maxTokens: 8192,
      },
    ],
    [
      "OpenRouter MiMo V2 Pro Free",
      {
        ...customMiMoProxyModel,
        id: "xiaomi/mimo-v2-pro-free",
      },
    ],
    [
      "OpenRouter Kimi K2 Thinking Free",
      {
        ...customKimiProxyModel,
        id: "moonshotai/kimi-k2-thinking-free",
      },
    ],
  ] as const)("preserves reasoning_content replay despite the %s tier suffix", (_label, model) => {
    const assistant = getAssistantMessage(
      buildReplayParams(model as Model<"openai-completions">, "reasoning_content"),
    );

    expect(assistant.reasoning_content).toBe("Need to answer politely.");
    expect(assistant).not.toHaveProperty("reasoning_details");
    expect(assistant).not.toHaveProperty("reasoning");
    expect(assistant).not.toHaveProperty("reasoning_text");
  });

  it("preserves OpenRouter array reasoning_details from tool-call signatures", () => {
    const reasoningDetail = { type: "reasoning.encrypted", id: "rs_1", data: "ciphertext" };
    const params = buildOpenAICompletionsParams(
      openRouterModel,
      {
        systemPrompt: "system",
        messages: [
          { role: "user", content: "lookup" },
          {
            role: "assistant",
            provider: "openrouter",
            api: "openai-completions",
            model: "deepseek/deepseek-v4-flash",
            stopReason: "stop",
            timestamp: 0,
            content: [
              {
                type: "toolCall",
                id: "call_1",
                name: "lookup",
                arguments: { query: "weather" },
                thoughtSignature: JSON.stringify(reasoningDetail),
              },
            ],
          },
          {
            role: "toolResult",
            toolCallId: "call_1",
            toolName: "lookup",
            content: [{ type: "text", text: "sunny" }],
            isError: false,
            timestamp: 1,
          },
          { role: "user", content: "answer" },
        ],
        tools: [],
      } as never,
      undefined,
    ) as { messages: unknown };

    const assistant = getAssistantMessage(params);
    expect(assistant.reasoning_details).toEqual([reasoningDetail]);
  });

  // issue #89660: a custom OpenAI-compatible proxy (not auto-detected as DeepSeek/
  // Xiaomi/Kimi) can opt into the DeepSeek reasoning-content replay contract by
  // setting compat.requiresReasoningContentOnAssistantMessages in config. getCompat
  // must resolve `compat.X ?? detected.X` (matching every sibling field) instead of
  // using `detected.X` alone, so the explicit config flag is honored in this transport.
  const customReasoningProxyModel = {
    id: "my-proxy/r1-pro",
    name: "Custom Reasoning Proxy",
    api: "openai-completions",
    provider: "custom-openai-proxy",
    baseUrl: "https://my-proxy.example.com/v1",
    reasoning: true,
    input: ["text"],
    cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
    contextWindow: 200_000,
    maxTokens: 8_192,
  } satisfies Model<"openai-completions">;

  it("honors compat.requiresReasoningContentOnAssistantMessages from config on a custom provider (#89660)", () => {
    const resolved = testing.getCompat({
      ...customReasoningProxyModel,
      compat: { requiresReasoningContentOnAssistantMessages: true },
    } as never);

    expect(resolved.requiresReasoningContentOnAssistantMessages).toBe(true);
  });

  it("falls back to detection (false) for the same custom provider when the flag is absent", () => {
    const resolved = testing.getCompat(customReasoningProxyModel as never);

    expect(resolved.requiresReasoningContentOnAssistantMessages).toBe(false);
  });
});
