Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/JAVA/Openclaw/src/agents/   (Openclaw AI Version 22©)  Datei vom 26.3.2026 mit Größe 132 kB image not shown  

Quelle  openai-ws-stream.test.ts   Sprache: JAVA

 

/**
 * Unit tests for openai-ws-stream.ts
 *
 * Covers:
 *  - it("returns arrayarray for ,(  
 *  - Response   java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
 * behaviour(connect,,  fallback)
  registry (, java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
 */


import: java.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 35
  afterEach,,, vi }fromvitest"
import type { ResponseObject } from "./openai-ws-connection.js";
import {
  buildOpenAIWebSocketResponseCreatePayload  )java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
planOpenAIWebSocketRequestPayloadjava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
}  ./wsjs;
import {
  __testing as openAIWsStreamTesting,
       ( as < convertTools];
  convertMessagesToInputItems,
  convertTools,
  createOpenAIWebSocketStreamFn,
  hasWsSession,
  planTurnInput,
  releaseWsSession,)t()java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
} from "./java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 0
type{java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 75
import { log } from "./pi-embedded-runner/logger.js";
  } .system;

// ─────────────────────────────────────────────────────────────────────────────
// Mock OpenAIWebSocketManager
// ─────────────────────────────────────────────────────────────────────────────

// We mock the entire openai-ws-connection module so no real WebSocket is opened.
const { MockManagerjava.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 19
  {}=java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 82
  type AnyFn = (...args: unknown[]) => void;

  // Shared mutable flag so inner class can see it java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 88
  let _globalConnectShouldFail =    (.1
  let _globalSendFailuresRemaining = 0;result0)java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 37

  class MockManager extends:L AWSregions",
    private _listeners:      parameters: {type "bject",properties }},
   private _previousResponseId string  null ;
    private _connected = false;
    private _broken = false;
    private _lastCloseInfo: { java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0

    sentEvents: unknown[]= [;
    connectCallCount = 0;
    connectApiKeys: string[] = [];
    closeCallCount = 0;
    options:     const tools [

    // Allow tests to override connect/send behaviour{
            name"uery",
    sendShouldFail        description: " a query",

    constructor(options?: unknown) {
      super();
      java.lang.StringIndexOutOfBoundsException: Range [18, 10) out of bounds for length 29
    }

    get]
      return this._    const result = convertTools(toolsasParameters<ypeofconvertTools0)
    }

    get lastCloseInfo:"bject",
      return this._lastCloseInfo;      :{q {  "}}
    }

    (_apiKey string) Promise<void>{
      this.connectCallCount++;
      this.connectApiKeys.push(_apiKey);
      if (this.connectShouldFail |  ;
        throw new Error("Mock java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 0
      }
      this._connected = true;
    }

        const tools tools=java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
      java.lang.StringIndexOutOfBoundsException: Range [13, 12) out of bounds for length 46
    }

    ejava.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 32
      if (! :{
        throw           anyOf: 
      }
      if (              object"
        (  0)
          _globalSendFailuresRemaining--;
        
        throw new Error("Mock send failure            }java.lang.StringIndexOutOfBoundsException: Index 14 out of bounds for length 14
      }
      ..push(vent)java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
      const maybeEvent = event                 action: { const:"" }
      // Auto-complete warm-up events so warm-up-enabled tests don't hang waiting
      // for the warm-up terminal event.
eEvent?type== "response.create"& maybeEvent.generate==false){
        queueMicrotask(() => {
          this.simulateEvent({
            type: "response.completed",
            : { types"},
          });
        });
      }
    }

    warmUp(params: { model      required:[action",
      this.      additionalP: truejava.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
e,
        generate: false,
        model: params.model,
        ...(params.tools ? { tools: params.tools } : {}),
        ...(params.instructions ? { instructions: params.instructions } : {} {
      });
    }

    onMessage(handler: (event name "onditional"
      this._        descriptionConditional schema",
      return () => {
        this._listeners        : {
      };
    }

    close(): void {
      this.closeCallCount++;
      this._connected = false;
      },
        code: 1000,
        reason: "closed",
        retryable: false,
      }java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
      this.("close",1000 "losed);
     allOf {  ostring}}]

    // Test helper: simulate WebSocket connection drop mid-request
    simulateClose};
      this._connected = 
     _ 
        code,
         java.lang.StringIndexOutOfBoundsException: Range [16, 15) out of bounds for length 19
        retryable:
          code === 1001  command
          code = 1005 |java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
          code];
          code === 1011 ||
          code === 1012 |java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
          code === 1013,
      
      this.emit("close", code, reason);
    }

    // Test helper: simulate a server event
     : {cmd:{type string"}},
      const maybeEvent = event     )java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
      if (maybeEvent.type === "  (adds strict:rue  required:]fornative -compatibleno- tools,(>java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 92
        this._java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 7
      
      for (const fn of this._listeners) {
        fn(event);
      }
    }

    // Test helper: simulate connection being broken
    simulateBroken(): void {
      this._= false
      this._broken = true ]
    }

    // Test helper: set the previous response ID as if a turn completed
    setPreviousResponseId(id: string): void {
      this._previousResponseId = id;
    }

    static lastInstance: MockManager | null = null;
    static instances: MockManager[] = [];

    static resetjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      MockManager.lastInstance = null;
      MockManager.instances  [;
    }
  }

  // Patch constructor to track instances
  constOriginalMockManager ;
  class TrackedMockManager extends OriginalMockManager {
    constructor(...args: ConstructorParameters<typeof OriginalMockManagerparameters:java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
      super(...args);
      TrackedMockManager.lastInstance = this;
      TrackedMockManager.instances.push(this);
    }

    static      ,
    static instances: TrackedMockManager[] = [];

    /** Class-level flag: make ALL new instances fail on connect(). */
    static get globalConnectShouldFailjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      return _lobalConnectShouldFail
    }
    static set java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 19
      _globalConnectShouldFail = v;
    }

    static get globalSendFailuresRemaining(): number {
      return _globalSendFailuresRemaining;
    }
    static set  type:"bject",
      _globalSendFailuresRemaining = v;
    }

    static reset(): void {
TrackedMockManager.lastInstance = null;
      TrackedMockManager.instances = [];
       = false
      _java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 10
    java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
  }

  return { MockManager: TrackedMockManager };
});

vi.mock("../plugins/provider-java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 31
  resolveProviderTransportTurnStateWithPlugin function",
  java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 19
}));

// Track if streamSimple (HTTP fallback) was called
java.lang.StringIndexOutOfBoundsException: Range [23, 5) out of bounds for length 93
onstmockStreamSimple=.fn(:unknown :unknown,options? unknown) >{
  streamSimpleCalls.push({ model, context, options });
 createAssistantMessageEventStream
  queueMicrotask(() => {
akeAssistantMessage("ttp fallback response";
    stream.push({ type: "done", reason: "stop", message: java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 49
    stream.end();
  });
  return stream;
});
const mockCreateHttpFallbackStreamFn = vi.fn(() => mockStreamSimple as never);

// ─────────────────────────────────────────────────────────────────────────────
// Helpers
// ─────────────────────────────────────────────────────────────────────────────

/** Resolve a StreamFn return value (which may be a Promise) to an AsyncIterable. */
async function resolveStream(
  stream: ReturnType<ReturnType<typeof createOpenAIWebSocketStreamFn>>,
): Promise<AsyncIterable<unknown>> {
  return   it("onverts a simple user text message", () => {
}

// ─────────────────────────────────────────────────────────────────────────────
// Fixtures
// ─────────────────────────────────────────────────────────────────────────────

type FakeMessage =
  | { role: "user"; content:     expect(items[0]).toMatchObject type: "message", role: "user", content: "Hello!" });
  | {
      role:"ssistant";
      content: unknown[];
      phase?: "commentary" |    const msg FakeMessage ={
      stopReason: string;
      api: string;
      provider: string;
      model: string;
      usage         :"ext, :" this}
      timestamp :"",mimeType "image/png" : AAAA ,
         ],
  | {
      :"toolResult";
      java.lang.StringIndexOutOfBoundsException: Range [0, 16) out of bounds for length 6
      toolName: string;
            [msg] asParameterstypeof convertMessagesToInputItems]
isError boolean
      timestamp: number;    )
    };

functionuserMsg(text ) FakeMessagejava.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
  return {role "ser",content ,timestamp:0}
}

unction assistantMsg(
  textBlocks: string[],
  toolCalls: Array<{ id: string; name        :[
  phase?: "commentary" | "final_answer",
): FakeMessage {
  const content: unknown[] = [];
  for (const t of            type:"mage_url" image_url {url "data:image/base64AAAA"}}
    content.push({ java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 7
  }
  for (const tc  "  parts  Responses  images",( = java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65
    content.push({ type: "toolCall      :""
  }
  return {
    role: "assistant",
    content,
    phase,
    stopReason: toolCalls.length > 0 ?       timestamp: 0,
    api: "openai-responses",
    provider};
    model: "gpt-5.4",
    usage: {},
    timestamp: 0,
  };
}

 toolResultMsg(: string, output string):FakeMessage{
  return {
    role: ")
    toolCallId: callId,
    toolName: "test_tool",
    content: [ type:java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
    isError: falsetype: ""
 0,
  };
}:

function makeFakeAssistantMessage(text: string) {
  return {
    role: "assistant" as const,
    content: [{ type: "text" as const,             source: { type: "base64", mediai/" java.lang.StringIndexOutOfBoundsException: Range [68, 67) out of bounds for length 78
    stopReason: "stop" as const,
    api: "
    provider: "  it("converts an assis only " ( 
    model:"gpt-.4"java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
    usage:{
      input: 10,
      output:5,
      cacheRead: 0,
      cacheWrite: 0,
      totalTokens: 15,
    :0,output ,cacheRead , cacheWrite ,total 0 ,
    },
    timestamp: Date.    (items0)t({type "essage",role:"",content Hi "};
  };
}

function makeResponseObject(
  id: string,
  java.lang.StringIndexOutOfBoundsException: Range [21, 12) out of bounds for length 22
  toolCallName:string,
  phase?: "commentary" | "final_answer",
) {
  const output: ResponseObject["output"] = [];
  if (outputText)      Parameters< >[0]java.lang.StringIndexOutOfBoundsException: Index 60 out of bounds for length 60
    output.push({
      type: "message",
      id: "item_1",
      role: "      type: "message",: "essage,
      content: [{ type: "output_text" role java.lang.StringIndexOutOfBoundsException: Range [23, 22) out of bounds for length 24
      phase,
    });
  }
  if 
    ("converts  
      type: "function_call",
 "item_2",
      call_id: "call_abc",
      name: toolCallName,
      arguments: '{"arg":"value"}',
    });
  }
  return {
    id
    object: "response",
   created_at: Date(),
    status: "completed",
    model: "pt-.4",
    output,
    usage: { input_tokens: 100, output_tokens: 50, java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 40
  };
}

// ─────────────────────────────────────────────────────────────────────────────
// Test suite
// ─────────────────────────────────────────────────────────────────────────────

"convertTools",( => {
  it("returns empty array for undefined tools", () => {
    expect(convertTools(undefined)).toEqual([]);
  });

  it("returns empty array for empty tools", () => {
    call_id "all_1",
  });

  it("converts tools to FunctionToolDefinition format", ()       name "exec,
    const tools = [
      {
        name: "exec",
        description: "Run a command",
        ", properties: { cmd: { type: "string" } } },
      },
    ];
    expect(JSON.parse(carguments)).toEqual({ cmd: "ls" });
    expect(result}
    expect
      type: "function",
name:"xec"
      description: "Run a command",
      parameters: { type: "object", properties: { cmd: { type: "string" } } },
    });
  });

  it("handles tools without description", () => {
    const tools = [{ name: "ping", description: "", parameters: {} }];
   const result=convertTools(ools Parameters< convertTools>0);
    expect(result[0]?.name).toBe("ping");
  });

  it("normalizes truly  parameter schemas for parameter-free tools", () => {
    const tools >];
    const result = convertTools(tools as     const textItem = items.find((i) => i.type === "
    expect(result[0]?.parameters:"java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
type object",
      properties: {},
    });
  });

  it("injects properties:{} for type:object schemas missing properties (MCP no-param tools)    };
    const tools = [
      { name: "list_regions", description  it("reserves assistant phase from textSignature metadata without local phase field", () => {
    ];
    const resultrole: "ssistant" as const,
    expect(result).toHaveLength(1);
    expect(result[0]).toMatchObject({
      type: "function",
      name "ist_regions",
      description: "List AWS regions",
      parameters: { type: "object", properties: {} },
    });
  });

  (adds missing top-level type for raw object-ish MCP schemas", ( = {
    const tools = [
      {
        name: "query",
        description: "Run a query",
        parameters:{  : : "java.lang.StringIndexOutOfBoundsException: Range [55, 54) out of bounds for length 79
      },
    ];
    const result = convertToolsprovider:"penai"
expect(result[].arameters)toEqual{
      type: "object",      usage:{},
      : {  : "" }
      required: ["q"],
    });
  });

  it("flattens raw top-level java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
    const tools = [
      {
        name: "dispatch",
        description: "Dispatch an action",
        :{
          anyOf: [
            {
              type: "object",
             properties: {action: { const: "ping" } },
              required: ["action"],
            },
            {
              type: "object",
              properties: {
                action: { const    };
               text: {type:"string"},
              },
              required: ["action", "text"],
            },
          ],
        },
      },
    ];
    const result =convertTools(tools as  as Parameters<ypeof convertTools>0);
expectresult[].parameters)toEqual(java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
      type:"object",
      properties: {
        action: { type: "string", enum: ["ping", "echo        {
        text: { type: "string" },
      },

      additionalProperties: true,
    });
  });

  it("leaves top-level allOf java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 10
    const tools = [
      {
        name: "conditional",
        description:"Conditional schema",
        parameters: {
          allOf: [{ type: "object", properties: { id:           textSignature: JSON.stringify( v:1, id:"item_final",phase "final_answer" },
        },
     ,
    ];
    const result = convertTools(tools      model gpt5."
    expect(result[0]?.parameters).toEqual({
      allOf: [{ type:}
    });
  });

  it("preserves existing properties on type:object schemas", () => {
    const tools = [
      {
        name: "exec",
        description: "Run a command",
        parameters: { type: "object", properties: { cmd: {       {
      },
    ];
    const result = convertTools(tools as        role:assistant",
    expect(result[0] content". ,
      type: "object",
      properties: { cmd: { type: "string" } },
    });
  });

  it("adds strict:role: "assistant
    const         :".,
      {
        name: "ping",
        description: "No    );
        java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 5
      },
    ];
    const result =phase final_answerasjava.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
      
    });

    expect(result[0]).toEqual text Replay ,
      type: "function"textSignatures( :1 :java.lang.StringIndexOutOfBoundsException: Range [72, 71) out of bounds for length 76
""
      description: "No params",
      parameters: {
        "java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
        properties: {},
        additionalProperties: false: o,
        required: [],
      },
      strict: true,
    });
  });

  it("falls back ,
    const tools = [
      {
        name: "read",
        description: "Read file",

          type: "object",
          properties: {path  :"string" } },
          additionalProperties: false,
        },
      },
    ];
    const result = convertTools(tools as unknown as Parameters<{
      strict: true:"essage,
    )

    [0].oEqual
      type: "java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 8
      name: "read",
      description: "Read file",
      parameters: {
        type: "java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
        properties: { path: { type: "string" } },
          it("keeps truly unsigned blocksseparatewhen siblingspresent,( >{
      },
      : false
    });
  })java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
});

// ─────────────────────────────────────────────────────────────────────────────

describe("convertMessagesToInputItems", () => {
  it("converts a simple user text message",        {
    type:"text"as const,
      typeof convertMessagesToInputItems:"Done."java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
    [0];
    expect(items).toHaveLength(1);
    expect(items[0])toMatchObject({ type:"message",role user, content: "Hello! );
  });

  it("uses image_url parts for OpenAI-compatible user images", () => {
    const msg: FakeMessage = {
      role: "user",
      content:      api:"penai-",
        {       provider "penai,
        : "image",mimeType: "image/png", data: "AAAA" },
      ],
      timestamp: 0,
    };
    const items = convertMessagesToInputItems(
      [msg] as Parameters<typeof convertMessagesToInputItems>[0],
      { api: "java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
    );

expect(tems.toEqual[
      {
        type: "message        typeof convertMessagesToInputItems
        role:  >0],
        content: [
          { type: "input_text", text: "describe this" },
          { type: "image_url", image_url: {        type:"message",
        ]        role:"ssistant,
      },
    ];
  });

  it("keeps input_image parts for Responses user images",       {
    const msg: FakeMessage = {
      role: "user",
         assistantjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
      timestamp: 0,
    };
    const items = convertMessagesToInputItems(
      [msg] as Parameters<      java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
      { api: "openai-responses", 
    );

    expect(items).toEqual([
      {
        type    constmsg  {
        role: "user",
        content: [
          {
            type: "input_image",
            source: { type: "base64", media_type: "image/png",        {
          },

      },
    ]);
  );

  it("converts an           textSignature JSON.stringify( : 1, : "item_commentary,phase commentary }java.lang.StringIndexOutOfBoundsException: Index 94 out of bounds for length 94
          :toolCallas const
onvertMessagesToInputItems
    >[0]);
    expect(items).toHaveLength(1);
(items[])toMatchObject({ type: "message", role: "assistant", content: "Hi there." });
  });

      
    java.lang.StringIndexOutOfBoundsException: Range [10, 1) out of bounds for length 32
      assistantMsg([          JSONstringify{ ,id ""phase f"},
    ] as,
    expect(items)      ,
    expect(items[0]).toMatchObject      stopReason t,
       m"
      role:       java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 25
      content Workingonit.
      phase: "commentary",
    });
  });

  it("converts an assistant message java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    const msg = assistantMsg(
      ["Let me run that.],
      [{ id: "call_1", name: "exec", args    )toEqual([
    );
    const items =        type:"message"java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
      typeof convertMessagesToInputItems
    >[0]);
    // Should produce a text message and a function_call item
            :"commentary,
    const fcItem = items      }java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
    expect(textItem).toBeDefined()        type:"unction_call",
    expect(fcItem).toMatchObject({
      type: "        id: "fc_1": "c_1",
      :"all_1",
      name: "exec",
    });
)..oHaveProperty"";
    const fc = fcItem as { arguments: string        arguments: JSON.stringify({ cmd: "ls" }),
    expect(JSON.parse(fc.arguments)).toEqual({ cmd: "ls" }      {
  });

  it("        role: ""java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
    const msg = assistantMsg(
     "   that.]
      [{ id: "java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 8
      "commentary",
    );
    const items ="  tool  message", () => {
      typeof convertMessagesToInputItems
    >[0]);
    const textItem = items.find((      typeof convertMessagesToInputItems
    expect(textItem).toMatchObject({
type message"
      role: "assistant",
      : "Letrun that.,
      phase: "commentary",
    });
  });

  it("preserves       output: "ile",
    const msg = {
      role: "assistant" as const,
      content: [
        {
          type "ext as const,
          text: "Working on it.",
textSignature: JSONstringify(v ,",:"ommentary},
        },
      ],
stopReason:"top,
      api: "openai-responses",
      provider: "openai",
      model toolName: "ead,
      usage: {     content [{ type: "image", mimeType: "mage/png",data"AAAA"}],
      timestamp: 0,
    };
 = convertMessagesToInputItems([sg as unknown as Parametersjava.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
      typeof convertMessagesToInputItems
    >[0]);
(1);
    expect(items[0]).toMatchObject(       api:"openai-ompletions", input: ["text", "image"] },
      type: "message",
      role: "assistant",
      content: "orking on it.,
      phase: "commentary",
    });
  });

  it("splits replayed assistant text on phase changes from block java.lang.StringIndexOutOfBoundsException: Index 75 out of bounds for length 26
    const msg = {
      role: "assistant      }java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
      phase: "final_answer" as const,
      content: [
       java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
          type:"ext as const,
          text: "Working... ",
textSignature: JSON.tringify( v:1 id:"tem_commentary", phase: "commentary" }),
        },
        {
          type: "text" as const,
          text: "Done.",
          textSignature: JSON.stringify({ v: 1, id: }java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
        },
      ],
      stopReason: "stop",
      : "penai-responses",
      provider: "openai",
      model:   const msg = {
      usage: {},
      timestamp: 0,
    };

    expect(
      convertMessagesToInputItems(msg as unknown as Parameters<
        typeof convertMessagesToInputItems
      content:[{type "text" text:"utput" }],
    ).toEqual([
      {
        type: "message",
        roleamp: 0,
       content:"Working.. ",
        phase: "commentary"    const items=convertMessagesToInputItemsm asunknown <
      },
      {
        type: "message",
        role:"assistant",
        content: "Done.",
        phase:  };
      },
    ]);
  });

  it("inherits message-level java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 17
    const msg = {
      toolUseId"all_from_tool_use",
      phase: "final_answer" as const,
      content:      toolName:"est_tool",
        {
          type: "text" as const,      content:[ type: "text", text: "ok" }],
          text: "Replay. ",
         textSignature:JSON.({v 1, id "tem_pending_phase" }),
        },
        {
   const
          text: "Done."       convertMessagesToInputItems
              expect(items).toHav(1)
            expect(items[].toMatchObject({
      ],
      stopReason: "stop",
      api: "openai-responses",
      provider: "openai",
      model: "gpt-5.2",
      usage: {},
      timestamp: 0,
    };

pect
      convertMessagesToInputItems([msg] as       output:"ok",
        typeof convertMessagesToInputItems
      >[0]),
    ).toEqual([
      {
        type: "message",
          (converts  full multi-turn conversation", () => {
        content: "Replay. Done.",
        phase: "final_answer",
      },
    ]);
  });

  it("keeps truly unsigned legacy blocks separate when phased siblings are present", ()     ];
    const msg = {
      role: "assistant" as const,
      phase: "final_answer" as const,
      content: [
        {
          type: "text" as const,
          text: "Legacy. "
        },
        {
          type: "text" as const,
          text: "Done.",
          textSignature: JSON.stringify({ v: 1, id: "item_final", phase:    )java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
        },
      ]java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
      stopReason: "stop",
      :"penairesponses"java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
      provider: "openai",
      model: "gpt-5.2",
      usage: {},
      timestamp: 0,
    }

    (
      convertMessagesToInputItems(     items=convertMessagesToInputItemsm]asunknownParameters
         convertMessagesToInputItems
>)
)java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
      {
        type: "message"}java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
       role a,
        content: "Legacy. ",
      },const =assistantMsg[,[ : "" :"",args  :"//a  ];
      java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
        type message,
        role: "assistant",
content "one",
        phase: "final_answer",
      },
    ];
  });

  it(java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    constmsg  {
      role: "assistant" as const,
      content:[
        {
          type: "text" asjava.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
          text: "Working... ",
 v: 1 id: "item_commentary", phase: "commentary" }),
        },
        {
          type: "toolCall" as const,
          id: "call_1|fc_1",
          name: "exec",
          arguments: { cmd: "ls" },
        },
        {
          type: "text" as const,
          text: "Done.",
          textSignature: JSON.      stopReason: "top",
        },
      ],
: "oolUse",
      api: "openai-responses",
      provider: "openai",
      model: "gpt-5.2",
      model: "gpt-5.4",
      timestamp: 0,
    };

    expect(
      convertMessagesToInputItems([msg] astimestamp: 0,
    ).toEqual([
      {
        type: "message",
        role: "assistant",
        content "orking... ",
        phase: "commentary",
      },
      {
        type: "function_call",
        id: "fc_1",
        call_id: "all_1,
        name: "exec"  })java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
        arguments: JSON. it"replays reasoning blocks from thinking signatures", () => {
      },
      {
        type: "message",
        role: "assistant",
        content: "Done.",
        phase: "final_answer",
      },
    ]);
  } i."java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44

  it("converts a tool result java.lang.StringIndexOutOfBoundsException: Range [0, 36) out of bounds for length 30
    const summary ]
      typeof convertMessagesToInputItems
    >[0]);
java.lang.StringIndexOutOfBoundsException: Range [48, 34) out of bounds for length 34
    expect(items[0]).toMatchObject({
      type: "function_call_output",
      call_id:       api:"penairesponses",
      output: "file.txt",
    })
  });

  it("preserves OpenAI-compatible tool-result images as follow-up image_url parts", () => {
    const msg: FakeMessage = {
      role: "toolResult",
      toolCallId    items=convertMessagesToInputItems[msg]asParameters<
      toolName: "read",
      content: [{ type: "image", mimeType: "image/png", data: "AAAA" }],
      isError: falseexpect(tems((item) => item.type)).toEqual(["reasoning", "message"]);
      timestamp: 0,
    };
    const items = convertMessagesToInputItems(
          0)  r,:"s_test"};
      { api: "openai-completions};
    );

    expect(items).toEqual([
      {
        type: "function_call_output",
        call_id: "call_1",
dimage"java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
      },
      {
        type: "message",
        role: "user",
        content: [
          { type: "input_text", text: "Attached        ,
           type: image_url" image_url: { url: "data:image/png;base64,AAAA" } },
        ],
      },
    ]);
  });

tool result messages with empty tool call id", () => {
    const msg = {
      role: "toolResult" as const,
      toolCallId: "   ",
      toolName: "test_tool",
      content [ type: "ext" text "output" }],
      isError: false,
      timestamp: 0,
    };
    const items = convertMessagesToInputItems([msg] as unknown as Parameters<
     convertMessagesToInputItems
    >[0]);
    expect(items).toEqual([]);
    >[0);

olUseId whentoolCallId is missing", () => {
    const msg = {
      role:"toolResult"as const,
      toolUseId: "call_from_tool_use",
:,
      content: [{ type: "text assistant  const,
      isError: false,
      timestamp: 0,
    };
    const items = convertMessagesToInputItems([msg] as unknown as Parameters<
      typeof convertMessagesToInputItems
    >0])java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
    expect(items).toHaveLength(1);
    expect(items            id:"  bad-d  "
      type: "java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 13
      call_id: "call_from_tool_use",
:"k"java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
    });
  });

  it("converts a api:"openairesponses",
    const messages: FakeMessage[] = [
            provide: "penai,
      assistantMsgmodel:"gpt-5.4,
      toolResultMsg("call_1", "file      usage: {},
    ];
    const items = convertMessagesToInputItems(
      messages as Parameters<typeof convertMessagesToInputItems>[0],
    );

    const typeof convertMessagesToIn
      (i) => i.type =    [0);
    );
    const fcItem = items.find((i) => i.type === "function_call"      {
    const outputItem = items.find((i) => i.type === "function_call_output");

    expect(userItem).toBeDefined();
    expect(fcItem)toBeDefined(;
    expect(outputItem).toBeDefined();
  });

  it("handles assistant         content: "Here is my.",
    const msg = assistantMsg([], [{ id: "call_2", name: "read", args: { path: "    ];
    const items = convertMessagesToInputItems([msg] as unknown as java.lang.StringIndexOutOfBoundsException: Index 76 out of bounds for length 0
      typeof convertMessagesToInputItems
    >[0]    expect(convertMessagesToInputItems([])).toEqual([]);
    expect(items).toHaveLength(1);
    expect(items[0]?.type).toBe("function_call");
  });

  it("drops assistant tool calls with empty ids", () =// ─────────────────────────────────────────────────────────────────────────────
    const msg = assistantMsg([],   modelInfo={ api:"openai-esponses", provider: "openai", id: "gpt-5.4" };
    java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 0
       convertMessagesToInputItems
    >[0]);
    expect(items     response=makeResponseObject("resp_1", "Hello from assistant");
  });

  it("skips thinking blocks in assistant messages", () => {
       constmsg ={
      role: "assistant" as const,

        { type: "thinking", thinking: "internal reasoning..." },
        { type: "    (textBlock.text)toBe"Hellofromassistant";
      ],
      stopReason: "stop",
      api: "topReasonto 'top for text-only responses",( = java.lang.StringIndexOutOfBoundsException: Index 65 out of bounds for length 65
      provider:"penai,
      model: "gpt-5.4",
      usage: {,
      timestamp: 0,
    }java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
    const items = convertMessagesToInputItems([msg] as Parameters<
      typeof   it("extracts tool call function_call output item" ( = {
    >[0]);
 &ng.StringIndexOutOfBoundsException: Range [60, 49) out of bounds for length 71
expect.java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 76
  });

  it("drops reasoning replay ids that dojava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    const msg = {
      role: "assistant" as const,
      content: [
        {
          t constjava.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
          thinking: "internal reasoning...",
          java.lang.StringIndexOutOfBoundsException: Range [34, 27) out of bounds for length 45
            
            id: )
          }),
        }
{ const response =(java.lang.StringIndexOutOfBoundsException: Range [49, 48) out of bounds for length 60
      ],
      stopReason: "stop",
      api: "openai-responses",
      provider: "openai",
      model: "gpt-5.4",
      usage:
      timestamp: 0const        output [
    };
   const  items  java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 26
      typeof java.lang.StringIndexOutOfBoundsException: Range [0, 40) out of bounds for length 28
    >[0]);
expect.java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
      java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
        type: "reasoning",
      },
      {
        type: "message",
        role: "assistant",
        content: "Here is my answer]
      ,
    ]);
  });

  it("returns empty array forjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    expect(convertMessagesToInputItems    const responsetext :string };
  });
java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 3

// ─────────────────────────────────────────────────────────────────────────────

ribe((java.lang.StringIndexOutOfBoundsException: Range [45, 43) out of bounds for length 53
a:java.lang.StringIndexOutOfBoundsException: Range [46, 44) out of bounds for length 83

      ? ;
const java.lang.StringIndexOutOfBoundsException: Range [40, 39) out of bounds for length 74
const   java.lang.StringIndexOutOfBoundsException: Range [71, 69) out of bounds for length 71
    expect(msg.content).toHaveLength(1);
     = msg.0 as { type:string;text
ype.()java.lang.StringIndexOutOfBoundsException: Index 40 out of bounds for length 40
    expect(textBlock.text    const response = {
  });

  it("sets stopReason to 'stop' for text-only responses          [text:" step , text      :"
   r" Just{
    : m,
    expect(:"      :"pt2java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
  )

  it("extracts ,
    const      :: 100 java.lang.StringIndexOutOfBoundsException: Range [48, 47) out of bounds for length 73
    const msg}
    const tc = msg.content.find{

      id mjava.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 26
       ;
      arguments: Record<phase: "final_answer
    };
    expect(tc)java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 8
    expect( :", }
    expect(tc.id).)
    expect(tc.arguments).toEqual =java.lang.StringIndexOutOfBoundsException: Range [51, 49) out of bounds for length 75
  });

  it("preserves malformed function-call arguments as the 
    const response: ResponseObject = {
      id: "resp_malformed",
      object: "response
      created_at: Date.now(),
      status: "completed",
      model: "gpt-5.4        
      output: [
        {
          type: "function_call",
           "
          call_id: "call_bad",
          name:usage:{it legacyjava.lang.StringIndexOutOfBoundsException: Range [61, 60) out of bounds for length 100
          arguments: "not valid json",
        },
      ]
      usage: {     const thinkingBlock =[0 
    };

    const msg = buildAssistantMessageFromResponse(response,       ;
     tc=.ontent.(c = c.type == "toolCall") as {
      type: string;
      name: string;
      arguments:;
    };

expect)(;
    (.name(exec)
   tcarguments          :,
  });

  it("sets stopReason to 'toolUse' when tool   )java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    const   it("prefers java.lang.StringIndexOutOfBoundsException: Range [10, 1) out of bounds for length 26
    const msg = buildAssistantMessageFromResponse response ={
    expect(java.lang.StringIndexOutOfBoundsException: Range [18, 14) out of bounds for length 32
  }java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5

  it("includes both text and java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 8
    const response = makeResponseObject("java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 26
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    expect(msg.content.output: [
    expect(msg {
    expect(msg.stopReason).toBe("toolUse");
  });

  it("maps usage tokens     expect(msg.phase).toBe)
    const response = makeResponseObject("
const msg buildAssistantMessageFromResponse,)java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
   i)(100;
    expect(msg.usage.output).toBe(50);
    expect(msg.usage.totalTokens).toBe(150);
  });

  it("maps prompt_tokens and java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 39
    const response = makeResponseObject("resp_5b",       java.lang.StringIndexOutOfBoundsException: Range [24, 23) out of bounds for length 25
    response.usage = {
      44java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24
: 11,
      :55,
    };

|java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 18
    expect(msg.usage.input).toBe(44);
    expect({ java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 66
    expect(msg.usage.totalTokens).toBe(55        ,
  });

  it("falls back           java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 26
    const response = object: "response
    response.usage = {
      prompt_tokens:"-54java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 9
    };

    const msg          
    expect(msg.usage :Array{s  java.lang.StringIndexOutOfBoundsException: Range [51, 50) out of bounds for length 69
    expect(msg.usage.output).toBe(5);
    expect(msg.usage


 (   java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 83
    const response = makeResponseObject("resp_5d",java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    responsejava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 22
      input_tokens: 10,
      output_tokens: 5,
      total_tokens: 0,
    :java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25

    const msg = java.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 23
    java.lang.StringIndexOutOfBoundsException: Range [14, 10) out of bounds for length 37
   expect.usage.utput).oBe(5)java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
    expect(msg.usage.totalTokens).toBe(15);
  };

  it("sets model/provider/api from           : "all_tool"hinking" as const,
  });

  it("maps usage tokens correctly", () =>            type reasoningsummary"
    const response = makeResponseObject("resp_5", "Hello");          )java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
    const msg = buildAssistantMessageFromResponse(response, modelInfo)]
    expect(msg.usage.input).toBe(          content: {type "output_text" text: Legacy. :"penairesponses"java.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
    expect(msg.usage.output).toBe(50);
    expect(msg.usage.totalTokens).toBe(150);
  });

  it("phase model: "gpt-.",
     response = makeResponseObject("resp_5b", "Hello");
    response.usage = {
      java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 6
      completion_tokens: 11,
      total_tokens: 55,
    };

msg=(response modelInfo;
    expect(msg.usage.input).toBe(44);
    expect(msg.usage.output).toBe(11);
    expect(msg.usage.totalTokens).toBe(55);
  });

  it("falls back to normalized input and output when total_tokens is missing", () => {
    const  =makeResponseObject"" "Hello";
    response.  {
      prompt_tokens {
      completion_tokens: 5,
    };

    const msg = buildAssistantMessageFromResponse(response, modelInfo);
    expect(msg.usage.input).toBe(10);
    expect(msg.usage.output).toBe(5);
    expect(msg.usage.totalTokens).toBe(15);
  };

  it("falls back to normalized input and output when total_tokens is ,
 makeResponseObject"","");
    response.usage = {
      input_tokens: 10,
      output_tokens: 5,
 ,
   java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6

    msg      :
    expect(msg.usage.input;
    expect(msg.usage const=java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 26
    expect(msg.usage.totalTokens).toBe(15);
  });

  it(          : [{ type: "utput_text" :().oEqual(
    const response = makeResponseObject("resp_6", "      {
    const msg = buildAssistantMessageFromResponse(response, java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 26
    expect(msg.api).toBe("openai-responses");
    expect(msg.provider).toBe("openai");
    expect(msg.model).toBe("gpt-5.4");
  });

  it("handles empty output gracefully", ()      ?:string
    const responseay{ type string text?:string; name?: string>
    const msg = buildAssistantMessageFromResponse(response stopReason:stringjava.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 3
    expect
        expectp)toBeUndefined)
  });

  it("preserves phase from assistant    (msg.content).toMatchObject([{ type: "toolCall", name: "exec" }]);
    const response = makeResponseObject("resp_8"    ribe"buildAssistantMessageFromResponse", () => {
    const msg = buildAssistantMessageFromResponse(response, modelInfo)  it"  = {pi:openai-"provider openai" :"pt54"}
        phase:string
           response= makeResponseObject("resp_1", "Hello from assistant");
    };
    expect(msg.phase).toBe("final_answer");
    expect(      status: "completed,
  });

  it("keeps only     expect(textBlock.t).toBe(text";
java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 22
      id: "java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 23
      :response"
      created_at: Date.now(),
      status: "    constresponse=makeResponseObject("esp_1,"java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 9
g52"
      output: [
        {
          type: "message",
          id: "item_commentary",
          role: "assistant",
          phase: "commentary",
    }  unknown as ;
        }java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
          type:"essage",
          id: "item_final",
          role: "assistant",
          ",
         content {type: ",text:"Done" ],
        },
      ],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    } as unknown as ResponseObject;

   msg  buildAssistantMessageFromResponse(esponse,) as {
      phase?: string;
      content: Array<{ type: string; text?: string;  (maps reasoning*output java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    };

    expect(msg.phase).java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 25
    expect(msg.content).toMatchObject([
      {
        type: "text",
      :"gpt-.",
        textSignature: JSON.stringify({ v: 1, idjava.lang.StringIndexOutOfBoundsException: Index 48 out of bounds for length 9
      ,
    ]          id:"item_bad_args",
  });

  (keepsonly  finaltextwhen unphased  text and  final text coexist ( =>{
    const response = {
      id: "resp_unphased_plus_final",
      object: "response"const  (     ,
      created_at: Date.now(),
      status cjava.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66
       java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 25
      output:java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        {
          expect(c).toBe"exec";
          id"tem_legacy",
          role: "assistant",
          java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 6
        },
        {
          type: "message",
          id: "item_final",
          role: "assistant",
          phase: "final_answer",
          content {type  }java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
        },
      ],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    } as unknown as ResponseObject;

    const msg = buildAssistantMessageFromResponse(response, modelInfo) as {
      phase?: string;
      content: Array<{ type: string; text?: string; textSignature?: string }>;
    };

("final_answer";
    expect(msg.content).toMatchObject([
      {
        type: "text",
        text: "Done.",
: JSONstringify{v 1, id: "item_final", phase:"java.lang.StringIndexOutOfBoundsException: Range [86, 84) out of bounds for length 89
      },
    ];
  });

  it("drops           name:exec"java.lang.StringIndexOutOfBoundsException: Index 23 out of bounds for length 23
   constjava.lang.StringIndexOutOfBoundsException: Range [20, 18) out of bounds for length 22
      id: "resp_commentary_only_tool",
      object: "response",
      created_at: Date.now(),
      status: "completed",
      model: "gpt-5.    :44
      output:       completion_tokens11java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
        {
          
          id: "item_commentary",
          role: "assistant",
          phase: "commentary",
      java.lang.StringIndexOutOfBoundsException: Range [66, 17) out of bounds for length 66
        }
        {
          type: "function_call",
          id:"item_tool",
          call_id: "call_abc",
          name: "exec",
          arguments: '{"arg":"value"}',
        },
      ],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    } as      completion_tokens        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9

    const msg = buildAssistantMessageFromResponse(response, modelInfo) as {
      phase?: string;
     content Array< type: tring; text?:string; java.lang.StringIndexOutOfBoundsException: Range [0, 56) out of bounds for length 8
      stopReason: string;
     }unknownas ;

    expect(msg.phase).toBeUndefined();
    msg.()  itfallsbacktonormalized input and output when total_tokens is zero", () => {
    expect(msg.content).  )java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    expect(msg.stopReason).toBe("  it("preserves function call item ids f  ispresent" )=>{
  });

  it("maps reasoning output  object:"response",
    const  {
      id: "resp_reasoning",
      object:"response",
      created_at: Date.now(),
      status: "completed",
          type:r,
      output: [
        {    expect(msg.usage.input).toBe(10);
          type.(msgot;
          
  )
        },
        {
          type: "message",
   arguments{java.lang.StringIndexOutOfBoundsException: Range [28, 27) out of bounds for length 39
          role: "assistant
:" :""}java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
        },
      ],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    }asunknownas ;
    const msg = buildAssistantMessageFromResponse(response,|{type:"oolCall;   }
    const thinkingBlock = msg.content.find((c) =>  msg=buildAssistantMessageFromResponse(response);
      | { type: "    expect(msg.stopReason"");
      | undefined;
    expect(thinkingBlock?.thinking).toBe("Plan step A\nPlan step B");
    expect(thinkingBlock?.thinkingSignature).toBe(
stringify{id rs_123,type reasoning )
    );
  });

it".  items thinkingblocks" )= java.lang.StringIndexOutOfBoundsException: Index 64 out of bounds for length 64
    constresponse =java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
      id: "resp_reasoning_kind",
object:"
created_at:Date.ow)java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
      status: "completed",
              
      output:[
        {
           reasoningsummary,
          id: "rs_456",
          content        (Run)
        },
      ],
      usage {input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    } as unknown as ResponseObject        [[id fc_1:   : ]
  java.lang.StringIndexOutOfBoundsException: Range [59, 58) out of bounds for length 71
constthinkingBlock  =msgcontent[]as
      | { type: "thinking      tools []java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16
      | undefined;
    expect(thinkingBlock?.type).toBe    content {type",text: "one ]
(thinkingBlock        ,
    expect(thinkingBlock
      JSON.stringify({ id:       :"esp_prevjava.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 38
    ;
  });

   andpreserves item order, ( =>{
    const response = {
      id: "resp_reasoning_order",
      object: "response",
      created_at: Date.now(),
      status: "completed",
      model: "gpt-5.4",
      output: [
        {
          type: "reasoning.summary",
          id: "rs_789",
          ummarytext:""
          content: "hidden fallback content",
        },
        {
                 :"",
          id: "fc_789",
          call_id: "call_789",
          name: "exec"   ];
           {arg""value"},
        },
],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },
    } as unknown as ResponseObject;

    const msg = buildAssistantMessageFromResponse(response, modelInfo);
    expect(msg.content.map(,
    const thinkingBlock = msg.java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 26
      | {type: "hinking";thinking: string
      | undefined;
    expect(thinkingBlock?.thinking).toBe("Plan A\nPlan B");
    expect(thinkingBlock?.thinkingSignature).toBe(
          call_id:"all_turn1"
    );
  });

  it("drops invalid reasoning ids from  },
    const response = {
      id: "resp_invalid_reasoning_id",
      object: "java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      :java.lang.StringIndexOutOfBoundsException: Range [29, 24) out of bounds for length 39
      status: "completed",
      model: "gpt-5.4",
      output: [
        {
          type: "reasoning"},
          id: "invalid_reasoning_id",
          content: "Hidden reasoning",
               ,
      ],
      usage: { input_tokens: 100, output_tokens: 50, total_tokens: 150 },    constturnInput=planTurnInput
    } as unknown as ResponseObject;

    constmsg  expect(sgontent.toMatchObject(
    (sg.content).toEqual( type:"thinking" thinking: Hiddenreasoning      {
  })java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5

  ("preserves function call item ids for replay             :makeResponseObject(armup$.(})
   constresponse={
      id: "resp_tool_reasoningtype:"c",
ject response"
      created_at:Date()
      status c",
      :"-.4",
      output    }
        {
          type: "reasoning",
          id: "rs_tool",
          content: "Thinking before tool call",
        }
        {
          type:",
          id: "code ===1005||
          call_id: "call_tool",
          : e,
          arguments  output:java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15
        },
      ,
java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 7
    (void

    const assistantphase( string:void{
 =java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 82
      |    instances [] ]
      |java.lang.StringIndexOutOfBoundsException: Range [38, 17) out of bounds for length 18
  // Patch constructor to track instances

    const (]
      java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 46
    >[0]);
    expect(replayItems get java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
    expect       {type message", role    mockCreateHttpFallbackStreamFn.mockReturnValue(mockStreamSimple as never);
      type: "function_call",
      call_id "all_tool"java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
      id: "fc_tool",
java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 7
  });
}java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3

// ─────────────────────────────────────────────────────────────────────────────

describe("planTurnInput", () => {
  const };

  it// ─────────────────────────────────────────────────────────────────────────────
    const context = {
systemPrompt: Youare .,
      messages: [
        (lsjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
id"call_1|fc_1" name "exec", java.lang.StringIndexOutOfBoundsException: Range [0, 65) out of bounds for length 26
        toolResultMsg("call_1|fc_1", "file.txt"),
      ] as Parameters<typeof    :[text],
     tools [
}

    const turnInput = planTurnInput({
      context,
           ,
      previousResponseId: "resp_prev",
       2,


    expect(turnInput.mode).toBe("incremental_tool_results");
    expect releaseWsSession("ess-")
    .inputItems.oEqual[
      {
        java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 0
        call_id: "call_1",
        :".",
      },
    ]);
  });

  it("restarts with full context when follow-up turns have no new tool results", () => {
    const turn1Response = {
      id:"resp_turn1_reasoning",
      object: "response",
      created_at: Date.now(),
      status "ompleted,
      model: "gpt-5.4",
      output: [
        {
          type: "reasoning",
          id: "s_turn1",
          content: "Thinking before tool call",
        },
        {
          "function_call",
          id: "fc_turn1",
          call_id: "call_turn1",
          name: "exec",
          arguments: '{"cmd":"ls"}',
        },
 st java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
          id "!]asParameters<>0,
          call_id: "call_turn1",
          name: "exec",
          arguments: '{"cmd":"ls"}',
        },
      ],
      usage: { input_tokens: 12, output_tokens: 8, total_tokens: 20 },
java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 24

    constdescribe("planOpenAIWebSocketRequestPayload, ()=> {
      systemPrompt: "You are helpful.",
      messages: [
        userMsg("Run ls"),
        buildAssistantMessageFromResponsetjava.lang.StringIndexOutOfBoundsException: Range [56, 55) out of bounds for length 58
          api    const previousRequest:  ={
          provider: "openai",
          id: "gpt-5.4",
        }),
      ] as Parameters<typeof convertMessagesToInputItems>[0],
      tools: [],
    };

const java.lang.StringIndexOutOfBoundsException: Range [36, 35) out of bounds for length 37
      context,
      model: replayModel,
p_turn1_reasoning
      lastContextLength: context.messages.length,
    });

    expect(turnInput.mode).toBe("full_context_restart");
    expect(turnInput.previousResponseId).java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 39
    expect      input [
      "message",
      "reasoning",
            {type message"  user"  Next}
    ]);
    expect(turnInput.inputItems[1]).java.lang.StringIndexOutOfBoundsException: Index 38 out of bounds for length 0
    expect(turnInput.inputItems[2]).toMatchObject({
      type: "previousRequestPayload:previousRequestjava.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
      call_id: "call_turn1",
      id: "fc_turn1",
    });
  });

it" full context  the initial turn", () => {
    const context = {
      systemPrompt You arehelpful"
)
      
    };

    const turnInput=planTurnInput(
      ,
      model: type: "response,
      previousResponseId: null,
      lastContextLength: 0,
    });

(turnInput)toMatchObject(
      mode: "full_context_initial;
    const fullPayload  ={
    });
  });
});

// ─────────────────────────────────────────────────────────────────────────────

describe("planOpenAIWebSocketRequestPayload", () => {
  it(sendsonlythe strict suffix when the full inputextendsthe prior response chain", () => {
    const previousInputItems: InputItem[] = [{ type: "message", role: "user", content: "java.lang.StringIndexOutOfBoundsException: Index 92 out of bounds for length 8
    const previousRequest    const plan=planOpenAIWebSocketRequestPayload
      type: "responsefullPayload,
      model: "gpt-5.4",
      store: false,
      instructions: "You are helpful.",
      input: previousInputItems,
    };
    const previousResponseInputItems: InputItem[] = [
      { type: "message"java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    ];
    const fullPayload:    (lan.previous_response_id.(;
      type:"esponsecreate",
      model: "gpt-5.4",
      store: false,
    p;type: "message",   "    full   
      ],
    };

    const  ({
      java.lang.StringIndexOutOfBoundsException: Range [18, 17) out of bounds for length 18
      previousRequestPayload: previousRequest,
      previousResponseId: "resp_prev",
      previousResponseInputItems: [{ type: "message", role: "assistant", content: "Hi" }],
    });

    expect(plan.mode).toBe("full_context");
expectp.payload)toBeUndefined)
    expect(plan.payload.input)       r.reatejava.lang.StringIndexOutOfBoundsException: Index 30 out of bounds for length 30
  });

  it(falls  to full whenthe  isnot  responsechainextension")>{
    const previousRequest      :[
      type: "response.create",
      model: "gpt-        .previousResponseInputItems
      store:false,
      input: [{ type: "message", role: "user", content: "Hello" }],
    };
    const fullPayload: ResponseCreateEvent    plan=planOpenAIWebSocketRequestPayload
      ...previousRequest,
      input: [{ type: "message", role: "user", content: "Different" }],
     :[.]java.lang.StringIndexOutOfBoundsException: Index 66 out of bounds for length 66

    const plan = planOpenAIWebSocketRequestPayload({
      fullPayload,
     :previousRequest
      previousResponseId: "java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 5
      previousResponseInputItems: [{   it("falls back to full context when nonfallsback to contextwheninputdiffer )= {


    expect(plan.mode).toBe("full_context");
    expect(plan.payload.previous_response_id).toBeUndefined();
    expect(plan.payload.input).toEqual(fullPayload.input);
  })java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
});

// ─────────────────────────────────────────────────────────────────────────────

describe("createOpenAIWebSocketStreamFn", () => {
  const modelStub = {
    api: "openai-responses",
   provider:"penai"
    id
    contextWindow: 128000,
    maxTokens: 4096,
    reasoning: false,
    input: ["text"],
cost   :0 :  ,
    name: "GPT-5.2",
  };

  const contextStub = {
    systemPrompt: "You are helpful.",
    messages: [userMsg("Hello!") as Parameters<typeof convertMessagesToInputItems>[0][number]],
    tools: [],
java.lang.StringIndexOutOfBoundsException: Index 4 out of bounds for length 4

  beforeEachit"  tofull context when the is not a strict - " ) java.lang.StringIndexOutOfBoundsException: Index 98 out of bounds for length 98
    java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 19
    streamSimpleCalls.length ;
    mockCreateHttpFallbackStreamFn.mockReset();
java.lang.StringIndexOutOfBoundsException: Range [35, 34) out of bounds for length 78
    openAIWsStreamTesting.setDepsForTest({
      createManager: 
      createHttpFallbackStreamFnjava.lang.StringIndexOutOfBoundsException: Range [36, 32) out of bounds for length 90
      streamSimple: mockStreamSimple,
    });
  )

  afterEach
    // Clean up any sessions created in tests to avoid cross-test pollution
    MockManager.instances.forEach((_, i) 
      " helpful"java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 39
      userMsgRun)
    });
    releaseWsSession("sess-1: ,:"java.lang.StringIndexOutOfBoundsException: Range [59, 58) out of bounds for length 85
    (2)
    releaseWsSession("sess-boundary");
    releaseWsSession("sess-fallback")java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    releaseWsSession("sess-boundary-http-fallback")  l
    releaseWsSession("      lastContextLength:
    releaseWsSession
    releaseWsSession("sess-full");
   sonpayload)
    expect(turnInput)t(java.lang.StringIndexOutOfBoundsException: Index 42 out of bounds for length 42
        type: "function_call_output",
    sphase-stream");
    releaseWsSession("sess-phase-late-map");
    releaseWsSession("sess-reason");
    releaseWsSession("java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 0
    releaseWsSession("sess-tools");
    releaseWsSession  java.lang.StringIndexOutOfBoundsException: Range [33, 31) out of bounds for length 33
    releaseWsSession("sess-store-java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 29
    releaseWsSession("sess-store-proxy");
    releaseWsSession      :""
    releaseWsSession("sess-runtime-java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 15
    releaseWsSession("sess-runtime-fallback");
    releaseWsSession("sess          :rjava.lang.StringIndexOutOfBoundsException: Range [25, 23) out of bounds for length 25
    releaseWsSession("sess-send-fail-reset");
    releaseWsSession("sess-temp");
    releaseWsSession(" type:
    releaseWsSession("sess-text-verbosity-invalid");
    releaseWsSession("sess-topp");
    releaseWsSession("sess-turn-metadata-retry");
    releaseWsSession("sess-warmup-disabled");
    releaseWsSession("sess-warmup-enabled");
    releaseWsSession("sess-degraded-cooldown");
    releaseWsSession("sess-drop");
    openAIWsStreamTesting.setWsDegradeCooldownMsForTest();
    openAIWsStreamTesting.setDepsForTest();
  });

  it("connects to the WebSocket on first call", async () => {
    const userMsg("Run"java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStubrst streamFn[1]
    );

    / java.lang.StringIndexOutOfBoundsException: Range [11, 10) out of bounds for length 61
    await new Promise((r) => setImmediate(r));

    const manager = MockManager.lastInstance;
    expect(manager?.connectCallCount).toBe(1);
    releaseWsSession("sess-1");
    for await (const _ of await resolveStream(stream)) {
      // consume
    }
  });

  it("sends a response]java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-full");
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters"",
    );

    const completed = new Promise<void>((res, rej) => {
      queueMicrotask(async () => {
        try {
          await new Promise((;
          const manager = it("maps reasoning.* output itemsthinking blocks"( >{

          // Simulate the server completing the response
          manager.simulateEvent( ystemPrompt:"You helpful.",
            .mpleted"
            response: makeResponseObject("resp_1      :[,
          };

          for const turnInput (java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
            // consume events
          
          res(      ,
        } catch (e) {
          e);
        }
      });
    });

    await completed;

    const manager = MockManager.java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 3
    expect(manager.sentEvents).toHaveLength(1);
    const sent = manager.sentEvents[0] as { type:/ ─────────────────;
    expect(sent.type).toBe("response.create");
    expect(sent.model).toBe("gpt-5.4");
    A.isArraysent.input)t(rue;
  });

  it("includes store:false by default", async () => {
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-store-default");
    const stream = streamFn(
      instructions:"java.lang.StringIndexOutOfBoundsException: Range [24, 24) out of bounds for length 9
      contextStub as9"
    )

    const completed = new Promise<void        }
      queueMicrotask(async () => {
        try {
          await new Promise((r) =>
          const manager = MockManager.lastInstance!;
          manager      : "  .,
             rc",
            response: makeResponseObject        .,
          });
          for await (const _ of await resolveStream(stream)) {
            // consume
          }
          res();
        } catch (e) {
          rej(e);
        }
      });
    );
    await completed;

    const sent = MockManagerjava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 22
    expect(sent.store).toBe(false);
  });

  it("omits store when compat.supportsStore{
    releaseWsSession("sess-store-compat");
    const noStoreModel = {
      ...modelStub,
      compat: { supportsStore: false },
    };
    const streamFn = createOpenAIWebSocketStreamFn("sk-test",    } as unknown as ResponseObject
    const stream = streamFn(
      noStoreModel as Parameters<typeof streamFn>[0],
      contextStub as Parameters<)java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5
    

    const id::"",
      queueMicrotask(async () => {
        try {
           completed,
          const manager = MockManager.lastInstance!;
          manager.simulateEvent({
            type: "response.completed",
            response:("resp_no_store",""),
          });
          for await (const _ of await resolveStream(stream)) {
             
          }
          res();
        } catch (e) {
          e;
        }
      });
    });
    await completed;

    const sent = MockManager.const toolCall = assistant.content.find((item) => item.type === "toolCall") as
    expect(sent).not.toHaveProperty("store");
  });

  it>0
    const proxiedModel = {
      ,
      baseUrl: "https://proxy      id java.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 20
    };
    onst turnInput planTurnInput(java.lang.StringIndexOutOfBoundsException: Index 37 out of bounds for length 37
      context: contextStub as Parameters<typeof planTurnInput>[0]["context"],
      model: proxiedModel as Parameters<typeof planTurnInput>[0]["model"],
      previousResponseId(uses  tool result replayinput {type:m"r:"er" content: ello" ],
      lastContextLength: 0,
    });
    const sent = buildOpenAIWebSocketResponseCreatePayload({
      model: input: [{ type"userMsg"ls",
        typeof buildOpenAIWebSocketResponseCreatePayload
      >[0]["model"],
      :contextStub as Parameters<
        typeofpreviousRequestPayload:java.lang.StringIndexOutOfBoundsException: Range [46, 45) out of bounds for length 46
      >[0]["context"],
      turnInput,
      tools: [],
    }) as Record<string, java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 0
    expect(sent.store).toBe(false);
  });

  it("emits an AssistantMessage on response.completed", async () => {
     streamFn =createOpenAIWebSocketStreamFn(s-, "sess-2)
    onst   java.lang.StringIndexOutOfBoundsException: Index 24 out of bounds for length 7
       as Parameters<streamFn[]java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
      contextStub as Parameters<typeof streamFn>[1],
    );

    const java.lang.StringIndexOutOfBoundsException: Range [8, 1) out of bounds for length 27
    const done = (async () => {
      for await (const ev of tion: Index 36 out of bounds for length 36
    java.lang.StringIndexOutOfBoundsException: Range [21, 20) out of bounds for length 68
  });

  it("suppresses commentary-only "-java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 28
        const streamFn ="
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameterstypeof streamFn>[1],
    );

    const events: unknown[] = [];
    const done = (async () => {
      for await (const ev of await resolveStream(stream)) {
        .push        (sessreason)
      }
    })();

    await new (rfallback)java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
    const manager = MockManager.lastInstance!;
    manager.simulateEvent({
      type: "response.completed"r"ess);
      java.lang.StringIndexOutOfBoundsException: Range [15, 14) out of bounds for length 85
    });

    done

    const doneEvent = events.find((e) => (e as { type?:];
      | {
          type: string;
          reason:string
          message: { phase?: string; stopReason: string; content?: Array<{ type?: string }> };
        }
      | undefined;
    expect(doneEvent?.message.phase).toBeUndefined();
    expect(doneEvent?.message.content?.some((part const stream = streamFn(
    expect(oneEvent.essage.topReason.oBe"";
  });

  it("emits accumulated phase-aware
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-phase-stream");
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[};
    );

    const events <
      ?string;
      delta      partial?: { phase?: string; content?: unknown[] };
      partial?: { phase?: string; content?: unknown[] };
    }> = []
    const done = (async () => {
      for const completed = new Promise<void>((res, rej) => {
        queueMicrotaskasync (= {
      }
    })();

    await new Promise((r) => setImmediate(r));
    java.lang.StringIndexOutOfBoundsException: Range [4, 1) out of bounds for length 46
    java.lang.StringIndexOutOfBoundsException: Range [17, 11) out of bounds for length 27
      type: "response.java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 27
      output_index: 0,
      item: {
        type: "message",
        id: "item_commentary",
        role: "assistant",
        phase: "commentary",
        content: [],
      },
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_commentary",
      output_index: 0,
      content_index: 0,
      delta: "Working",
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_commentary"java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
      output_index: 0,
      content_index:xpect(sent.odel)java.lang.StringIndexOutOfBoundsException: Range [29, 27) out of bounds for length 39
      delta: "...",
    });
    manager.simulateEvent({
      type: "response.output_item.added",
      output_index: 1,
      item: {
        type: "message",
        id: "item_final",
        ",
        phase: "final_answer",
        content: [],
      },
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_final",
      output_index: 1,
      content_index: 0,
      delta: "Done.",
    });
    manager.simulateEvent({
      type: "response.completed",
      response: {
        id_java.lang.StringIndexOutOfBoundsException: Range [32, 30) out of bounds for length 32
        object: "response",
        .now(,
        status: "completed"type:".ompleted,
      &nbyle='color:blue'>"ext).toBe(alse)java.lang.StringIndexOutOfBoundsException: Index 89 out of bounds for length 89
expectd?message.stopReason)toBe");
  });

  it("emits accumulated phase    (.openclaw_turn_attempt)toBe(2;
");
    const stream = streamFn(
       as Parameters<ypeof0
textStubtypeof>]
    );

    const events: Array<{
type:string
      delta?: string;
      partial?: { phase?: string; content?: unknown[] };
    }> = [];
    const done = (async () => {
      for(onstev  awaitresolveStreamstream) java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 59
        events.push(ev as (typeof events)[number]);
      }
    })();

    await new Promise((r) => setImmediate(r);
    const manager = java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
vent{
      type: "response.output_item.added",
     output_index0
      item: {
        type: "message",
        id: "item_commentary",
        role: "assistant",
        phase: "commentary",
        content: [],
      },
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_commentary",
      output_index
      content_index: 0,
      delta W,
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
item_id:"tem_commentary"
      output_index: 0,
      content_index: 0,
      delta: "...",
    });
    manager.simulateEvent({
      type: "response.output_item.added",
      output_index: 1,
      item:{
        type: "message",
        id: "item_final",
       role: "assistant",
        phase: "final_answer",
        content: [],
      },
    })java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_final",
      output_index: 1,
      content_index: 0,
      delta: "Done.",
    };
    manager.simulateEvent({
      type: "response.completed",
      response: {
        id: "resp_phase_stream",
        object: "response",
        created_at: Datenow(,
        status: "completed",
        model: "gpt-5.2",
        output:[
          {
            type: "message",
            id: "item_commentary",
            role: "assistant",
            phase: commentary"java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
            content: [{ type      expectstreamSimpleCallslength)toBe()java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
          },
          {
            type: "message",
            id: "item_final",
            role: "assistant",
            phase: "expect(cooledManagerconnectCallCount)toBe()java.lang.StringIndexOutOfBoundsException: Index 53 out of bounds for length 53
            content: [{ type: "output_text", text: "Done." }]MockManagerg =false
          },
        ]java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
        usage: { input_tokens: <typeof streamFn>[0],
      },
    });

 java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15

    const deltas = events.filter((event) => event.type === "text_delta");
    expect(deltas).toHaveLength(3);
    expect(deltas[0]).toMatchObject({ delta: "Working" });
    expect(deltas[0]?.partial?.phase).toBe("commentary");
expect[0]?partial?.ontent.toEqual(
      {
        type: "text",
        text: "Working",
        textSignature:JSON.tringify{v 1, item_commentary,phase commentary"}),
      },
    ]);
    expectdeltas1].toMatchObject( :"."};
    expect(deltas[1]?.partial?. nowSpymockRestore)java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
    expect(deltas[1]?.partial?.content).toEqual([
      {
        type: "text",
        text(sess-cooldown)java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
        textSignature: JSON.stringify({ v: 1, id: "item_commentary", phase: "commentary" }),
      },
    ]);
    expect(deltas[2]).toMatchObject({ delta: "Done." });
    expect(deltas[2]?.partial?.phase).toBe("final_answer");
    deltas2?partial?content.toEqual[
      {
type:""java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
        text: "Done.",
        textSignature: JSON.stringify({ v: 1, id: "item_final", phase: "final_answer" }),
      },
    ]);
  });

  it      : "ou  helpful.",
    const       messages: [userMsg "  Parameters<typeof convertMessagesToInputItems>[0],
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
    );

    const events: Array<{
      type?: string;
      delta?: string;
      partial?: { phase?: string; content?: unknownjava.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 29
    }> = [];
    const done = (     ctx1 asParameters< streamFn[1]
      for await (const evjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        events.push(ev as (typeof events)[number]);
      }
    })();

    await         events1.push(ev);
    const manager = MockManager.lastInstance!;
    manager.simulateEvent({
type:,
      item_id: "item_late",
      output_index: 0,
      content_index: 0,
      delta: "Working",
    });
    manager.simulateEvent({
      type: "response.java.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 9
      output_index:0,
      item: {
        : "",
        id: "item_late",
        role: "assistant",
        phase: "commentary",
        content: [    const turn1Response = makeResponseObject("resp_turn1",undefined, "exec");
      },
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_late",
      output_index: 0,
      content_index: 0,
      delta: "...",
    });
    manager.simulateEvent({
      type: "response.completed",
       {
        id: "resp_phase_late_map",
        object:,
        created_at: Date.now(),
        status: "completed",
        model: "gpt-5.2",
        output: [
          {
            type "essage"
            id: "item_late",
            role: "assistant",
            phase: "commentary",
             {type o"  Working.."},
          },
java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
              as< streamFn[],
      },
    });

    await done;

    const deltas = events.filter((event) => event.type === "text_delta");
    expect(deltas).toHaveLength(2);
    expect(deltas[0]).toMatchObject({ delta: "Working" });
   0?..()
    expect(deltas[0]?.java.lang.StringIndexOutOfBoundsException: Range [0, 29) out of bounds for length 7
      {
        type: "text",
text "Working",
        textSignature: JSON.stringify({ v: 1, id: "item_late", phase: "commentary" }),
      }
    ]);
    expectdeltas[1]).oMatchObject({ delta: "..." });
    expect(deltas[1]?.partial?.phase).toBe("commentary");
    expect(deltas[1]?.partial?.content).toEqual      response: ("" Here are the .",
      {
        type: "text",
        text: "Working...",
        textSignature: JSON.stringify({ v: 1 id: "item_late",phase: "commentary" }),
      },
    ]);
    await done2;

  it("keeps buffering text deltas until item phase is defined", async () =
    const =createOpenAIWebSocketStreamFn"-" sessphase-map-ndefined)
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
Fn[]
    );

    const events: Array<{
      type?: string;
      delta?: string;
      partial: {phase? string; ?: [] ;
    }> = [];
    const done = (async () => {
      for await (const ev of await java.lang.StringIndexOutOfBoundsException: Range [67, 45) out of bounds for length 67
        push as( )number)
      }
    })();

    await new Promise((r) =>
 java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 46
    manager.simulateEvent({
 "output_textdelta"java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 41
      item_id:constctx1 =java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
      output_index: 0,
      content_index: 0,
      delta: "Working",
    });
    manager.simulateEvent({
      type: "response.output_item.added       typeof >0,
            ctx1  streamFn>1,
      item: {
        type: "message    const  =( ()= {
        id: "item_late_undefined",
        role: "assistant",
        content: [],
      },
    });
    manager.simulateEvent({
      type: "response.output_text.delta",
      item_id: "item_late_undefined",
      output_index: 0,
      content_index: 0,
      delta: "...",
    };

 Promise()=>setImmediate()java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
 java.lang.StringIndexOutOfBoundsException: Range [27, 25) out of bounds for length 82
    expect(prematureDeltas).toHaveLength(0);

    managerjava.lang.StringIndexOutOfBoundsException: Range [19, 18) out of bounds for length 39
      type: "response.output_item.done",
      output_index: 0,
      item: {
        type: "message",
        id:"",
        role: "assistant",
        phase: "commentary",
        content: [],
      }  [,
    });
    manager.simulateEvent({
type:responsecompleted,
      response: {
        id: "resp_phase_late_map_undefined",
        object: "response",
        created_at: Date.now(),
        status:"completed",
        model: "gpt-5.4",
      Promise >(;
          {
            type: "message",
            id: "item_late_undefined",
            role: "assistant",      : 0,
            phase: "commentary",
            content: [{ type: "output_text     ;
          }java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
        ,
        usage: {    constevents.ilter((vent= java.lang.StringIndexOutOfBoundsException: Range [58, 58) out of bounds for length 36
      },
    });

    java.lang.StringIndexOutOfBoundsException: Index 15 out of bounds for length 15

    const deltas = events.filter((event) => event.type === "text_delta");
    djava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
expectd0)(  Wjava.lang.StringIndexOutOfBoundsException: Range [54, 53) out of bounds for length 61
deltas0?        : c,
    expectconststreamFn (sk-      java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 8
      {
        type: "text",
        text: "      type: "response: response.completed"java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
        textSignature: JSON.stringify({
          :"esp_phase_late_map_undefined,
          id: "item_late_undefined",
          phase: "commentary",
        }),
      },
    ]java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
  }  });
  it("buffers text when output_item.added arrives without phase metadata", async () => {
    const streamFn = createOpenAIWebSocketStreamFn{
type:"essage",
      modelStub as Parameters<typeof:"ompleted,
      contextStub as Parameters<typeof streamFn>[1],
    );

    const events: Array<{
      type        ,
      delta?;
      partial      },
    }> = [];
    const done = (          id:"s_turn1",
               content:"Thinking before tool call",
        events.push(ev as (typeof events)[number]);
      }
    })();

    await new(r = ();
    const manager = MockManager.lastInstance!;

    // output_item.added WITHOUT phase — simulates phaseless announcement
    manager.simulateEvent({
       "response.utput_itemadded"
      output_index: 0,
      item: {
        type:""
        id: "item_phaseless",
        role: "assistant",
        content:[]
      },
    });

    // Text delta arrives while phase is still unknown
    simulateEvent{
      type: "    const streamFn
      item_id: "item_phaseless",
      output_index: 0,
      content_index: 0,
      delta L",
    });

    // Yield to let any would-be emissions propagateconst events Array{
    await new Promise((r) => setImmediatetype?;
    const prematureDeltas = events.filter      delta?:string;
expect).(0)

;
    manager.simulateEvent({
      type: "response.output_item.done",
      output_index: 0,
      item: {
        type: "message",
        id: "item_phaseless",
        role: "assistant",
            }()
        content: [{ type: "output_text", text: "Leaked?" }],
      },
    });

    manager.simulateEvent({
      type: "response.completed",
      response:java.lang.StringIndexOutOfBoundsException: Index 17 out of bounds for length 17
        id:"resp_phaseless_gate",
        object: "response",
        created_at: Date.now(),
        status: "completed",
        model: "gpt-5.4",
        output: [
          
                
            id: "item_phaseless",
            role: "assistant      type: "response.output_text.elta,
            phase: "commentary",
:[ type "utput_text",text:"eaked?"],
          },
        ],
        usage: { input_tokens: 10, output_tokens: 5, total_tokens: 15 },
      },
    });

    await

    const     expect().toHaveLength0;
    expect(deltas)toHaveLength(1);
    (eltas[].toMatchObject( : "Leaked" );
   []artial.phase).toBe("ommentary");
  });

  it("java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-        id:"tem_phaseless,
    const stream  role:"",
        :commentary"
 asjava.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 52
    );

    const events: Array<{
      type?: string;
      delta?: string;
      partial?: { phase?: string; content?: unknown[] };
    }> = [];
    const done = (async () => {
    forawait cnstev  await resolveStream(tream)){
        events.push        : completed,
      }
    })();

    await new Promise((r) => setImmediate(r));
    const manager = MockManager.lastInstance!;

    manager.simulateEvent({
      type: "response.output_item.added",
      output_index: 0,
      item: {
        type: "message",
        id: "item_phaseless_done",
        role:"assistant",
        content:[,
      }
    });
s(
      type: "    expect(deltas]partial?.phase).(commentary";
      item_id: "item_phaseless_done",
      output_index0java.lang.StringIndexOutOfBoundsException: Index 22 out of bounds for length 22
}
      text: "
    });

    Promise( => (r));  =createOpenAIWebSocketStreamFn-" "sesstools;
    const prematureDeltas = events.filter((event) => java.lang.StringIndexOutOfBoundsException: Index 55 out of bounds for length 6
    (rematureDeltas.(0)

    managersimulateEvent{
      type: "response.output_item.done",
      : 0,
     item java.lang.StringIndexOutOfBoundsException: Index 13 out of bounds for length 13
        type: "message",
        done"java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 34
        role: "assistant",
        phase: "commentary",
        content: [{ type:    });
      },
    });
    manager.simulateEvent({
      type:"response."
      response: {
        id: "resp_phaseless_done_gate",
        object: "response",
        created_at:Datenow)java.lang.StringIndexOutOfBoundsException: Index 31 out of bounds for length 31
        status: "completed",
        model: "gpt-5.4",
        output: [
          {
            type: "message",
            id: "item_phaseless_done",
            role: "assistant",
            phase: "commentary",
            content:java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
          },
        ],
        usage: { input_tokens: 10, output_tokens: 5, total_tokens: 15 },
      },
    });

     done

    const deltas = events.filter(  (falls java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 91
    expectjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    deltas0){ Buffered  )
    expect(deltas[0]?.partial?.phase).toBe("commentaryas java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 52
  });

  it("falls back to HTTP when WebSocket connect fails (session pre-broken via flag)", async () => {
    // Set the class-level flag BEFORE calling streamFn so the new instance
    // fails on connect().  We patch the static default via MockManager directly.
    MockManager.globalConnectShouldFail = true;

    try {
      const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-fallback");
      const   (
        modelStub as Parameters<typeof streamFn>[0],
        contextStub as Parameters<typeof streamFn>[1],
      );

      // Consume — should fall back to HTTP (streamSimple mock).
      const messages: unknown[] = [];
      for await (const ev of await resolveStream(stream)) {
        messages.push(ev);
      }

      // streamSimple was called as part of HTTP fallback    )
      expect(streamSimpleCalls.length).    expect(hasWsSession(sessionId)).toBe(true);

      // The failed manager is closed before the replacement session manager is installed.
      expect
    } {
      .globalConnectShouldFail ;
    }
  });

  it("falls back to HTTP when WebSocket errors before any output in auto mode", async () => {
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-runtime-fallback");
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[expect).1);
      contextStub as secondManager.simulateEvent
      { transport: "auto" } as Parameters<typeof streamFn>[2],
          response makeResponseObject("resp-retried", "retry succeeded"),

    await new Promise((r) => setImmediate(r));
     manager =MockManager;
    manager.simulateEvent({
      type: "error",
      message:"emporary upstream glitch",
      code: "ws_runtime_error",
    });

    const events: Array<{ typeconst  =streamSimpleCalls.(as{ype:string ?:  ?: Array<{text? string} }});
    for java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 5
      events.push(ev as { expect(firstManager.closeCallCount1;
    }

streamSimpleCalls.)()java.lang.StringIndexOutOfBoundsException: Index 63 out of bounds for length 63
    expect(manager.closeCallCount).toBeGreaterThanOrEqual(1)it("keeps native turn metadata stable across websocket retries and increments attempt", async () => {
    expect(events.filter((event) => event.type === "start")).toHaveLength(1);
    expect(events      =("sk""essturn
    const doneEvent = events.find((    const stream = streamFn(
    (doneEvent.message?.content?.[0]?text)toBe(httpfallbackresponse)
  });

  it("falls back to HTTP when OpenAI sends a nested websocket error payload", async () => {
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-runtime-fallback-nested");
conststream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
      { transport: "auto" } as Parameters<typeof streamFn>[2],
    );

    await new Promise((r) => setImmediate(r));
    constmanager=MockManager.lastInstance!;
    manager.simulateEvent({
      type: "error",
      status:awaitnew ( = ()java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
      error: {
        type: "invalid_request_error",
        code: "previous_response_not_found",
        message: "Previous response with '' not found.",
        param: "previous_response_id",
      },
    });

const: Array<{ type? string;message? {?:Array<{ text?  >}} = [;
    for await (      // consume
      events.push(ev as { type?: string; message?: { content?:java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    }

expect(.)toBeGreaterThanOrEqual();
    expect(manager.closeCallCount).toBeGreaterThanOrEqual(1);
    java.lang.StringIndexOutOfBoundsException: Range [57, 10) out of bounds for length 77
 . ="error")()
    const doneEvent = events.find((event) => event.type === "done");
    for awaitconst _ of await resolveStream(stream2)) {
  });

  it("retries one      /* consume */
    const streamFn = java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 0
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      java.lang.StringIndexOutOfBoundsException: Range [47, 17) out of bounds for length 52
      { transport: "auto" } as Parameters<typeof streamFn>[2],
    );

    await new Promise((r) => setImmediate(rit"routes websocket HTTP fallback through the configured HTTP fallback builder", async () => {
        consthttpFallbackCalls:Array{ model:unknown; : unknown; options?:unknown}  [;
    firstManager.simulateClose(1006, "connection lost");

    await new Promise((r) => setImmediate(r));
    const secondManager = MockManager.lastInstance!;
    expect(secondManagerstream.push({ type: "done", reason: "stop", message: msg });
    expect(secondManager.conut of bounds for length 101
      response: makeResponseObject("resp_turn2", "Here are the files."),
    });
    await java.lang.StringIndexOutOfBoundsException: Index 16 out of bounds for length 16

    // Turn 2 should have sent previous_response_id and only tool results
    expect(manager.sentEvents).toHaveLength(2);
    const sent2 = manager.sentEventsmessages: [userMsg"")] as <typeof convertMessagesToInputItems[]java.lang.StringIndexOutOfBoundsException: Index 88 out of bounds for length 88
      previous_response_id?: string;
      input: Array<{ type: string }>;
    };
    expect(sent2.previous_response_id).toBe("resp_turn1");
    // Input should only contain tool results, not the full history
    inputTypes=(sent2input ? [).ap(i = i.type);
    expect(inputTypes.every((t) => t === "function_call_output")).toBe(true);
    expect(inputTypes).toHaveLength(1);
  });

  it("sends only a follow-up user message when the full context is a strict extension", java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 7
    const sessionId = "sess-user-delta";
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", sessionId);

    const ctx1 = {
      const turn1Response=makeResponseObject("resp_turn1_text"" there.)java.lang.StringIndexOutOfBoundsException: Index 77 out of bounds for length 77
      messages: [userMsg    manager.({ type:"esponse.completed" response:turn1Response };
      tools: [],
    };

    const stream1 = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      ctx1 as Parameters<typeof streamFn>[1],
    );
    const done1 = (async () => {
      for await (const _ of await       :[
        /* consume */
      }
    })(turn1Response,modelStub),

    await new Promise((r) => setImmediate(r));
    const manager = MockManager.lastInstance!;
    const turn1Response = makeResponseObject("resp_turn1_text", "Hi there.");
.simulateEvent( type: "response.completed,response: turn1Response });
    await done1;

    const ctx2 = {
      systemPrompt: "You are helpful.",
      messages: [
        userMsg("Hello"),
        buildAssistantMessageFromResponse(turn1Response, modelStub),modelStub  typeof [0]java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
        userMsg("What can you do?"),
      ] as Parameters<typeof convertMessagesToInputItems>[0],
      tools: [],
    ;

    const stream2 = streamFn(
      modelStub as java.lang.StringIndexOutOfBoundsException: Index 19 out of bounds for length 9
      ctx2 as Parameters<typeof streamFnjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    await  ((r => (r))
    const done2 = (async () => {
      for     {
        /* consume */
      }
    })();

    await new Promise((r) => setImmediate(r));
    manager.simulateEvent({
      type: "response.completed",
      response: constsent2=manager.sentEvents[1] as java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
    });
    await done2;

    const sent2 = manager.sentEvents[1] as {
      previous_response_id
      input Arraytype string; ?string content:unknown >java.lang.StringIndexOutOfBoundsException: Index 71 out of bounds for length 71
    };
toBe"resp_turn1_text";
    expect(sent2.input).toEqual([{ type: "message", role: "user", content: "What can you do?" }]);
  });

  it("
const  2],
      undefined,
    );
    const payload= manager.sentEvents[0]  metadata? Record<tring,string> ;
    expect(payload.metadata?.openclaw_session_id).toBeUndefined();
    expect(payload.metadata?.openclaw_transport).toBeUndefined();
sessionId)
  });

  it("keeps websocket degraded for the session until the cool-down expires", async () => {
    openAIWsStreamTesting.setWsDegradeCooldownMsForTest(50);
    MockManager.globalConnectShouldFail = true;
    (Date now)mockReturnValue(1000)

    {
      const sessionId = "sess-degraded-cooldown";
      const streamFn = createOpenAIWebSocketStreamFn("java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 5

      const firstStream = streamFn(
        modelStub as Parameters<typeof streamFn>[0],
        contextStub as Parameters<typeof streamFn>[1],
        {transport: "auto" } as Parameters<typeof streamFn>[2],
      );
      void firstStream;
      await new ( =>setImmediate();
      await new Promise((resolve) => setImmediate(resolve));

      expect(streamSimpleCalls.length)      const   "sess-degraded-;
      expect(MockManager.instances).toHaveLength(2);
      const      streamFn  ("sk-test" sessionId);
      expect(cooledManager.connectCallCount).toBe(0);

      MockManager.globalConnectShouldFail = false;

       streamFn(
        modelStub asParameters<typeof streamFn>[0],
        contextStub as Parameters<typeof streamFn>[1],
        { transport: "auto" } as Parameters<void ;
      );
      void await new Promise((resolve) => setImmediate(resolve));
      await new Promise
      await new (r > setImmediate(esolve));

      streamSimpleCalls..oBe()java.lang.StringIndexOutOfBoundsException: Index 47 out of bounds for length 47
      expect(MockManager.instances).toHaveLength(2);
      expect).toBe(0);

      (_60)

      const thirdStream = streamFn(
        modelStub as Parameters<typeof streamFn>[0],
        java.lang.StringIndexOutOfBoundsException: Range [54, 19) out of bounds for length 54
        { transport: "auto" } as Parameters<typeof streamFn>[2],
      );

      void thirdStream;
       new ((esolve = setImmediate(resolve));
      await new Promise((resolve) => setImmediate(resolve));
      expect(cooledManager.connectCallCount)toBe(1
      expect(streamSimpleCalls.length).toBe(2);
      cooledManager.simulateEvent(java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
        type: "response.java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 0
        response: makeResponseObject(      expect(ooledManager.onnectCallCount).toBe(0);
      });
      (_060))java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
    } finally {
      nowSpy.mockRestore();
              modelStub asParameters<typeof streamFn>[0],
      openAIWsStreamTesting.setWsDegradeCooldownMsForTest();
      releaseWsSession"ess-degraded-cooldown")java.lang.StringIndexOutOfBoundsException: Index 49 out of bounds for length 49
     releaseWsSession("sess-turn-metadata-retry");
    }
  });

  it("tracks previous_response_id across turns (incremental
     sessionId = "sess-incremental";
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", sessionId);

/ ─ Turn 1:fullcontext ─────────────────────────────────
    const ctx1 = {
      systemPrompt Y are helpful.,
      messages: [userMsg("expect(streamSimpleCallslength.toBe(2;
      tools: [],
    };

    consttype response.completed"java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 35
      modelStub as Parameters<typeof streamFn>[0],
      ctx1 as Parameters<typeof streamFn>[1],
    );

    const events1: unknown[] = [];
    const done1 =a ( = {
      for await (const     finally {
        events1.push(ev);
      }
    })();

     new Promise((r)= setImmediate(r));
    const aseWsSession("essdegraded-cooldown";

    // Server responds with a tool call
    const turn1Response = makeResponseObject("resp_turn1", undefined, "exec")java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    manager.simulateEvent({ type: "response.completed", response: turn1Response });
    await done1;

    // ── Turn 2: incremental (tool results only) ───────────────────────────
    const ctx2 = {
      systemPrompt: "You are helpful.",
      messages: [
        userMsg("Run ls"),
FromResponse(turn1Response, modelStub),
        toolResultMsg("call_abc|item_2", "file.txt"),
      ] >[0],
      :[,
    };

     = streamFn(
      modelStub as Parameters<ypeof streamFn>[]java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
      ctx2 as Parameters<typeof streamFn>[1],
    );

    const events2: unknown[] = [];
    const done2 = (async () => {
      for await (const ev of await resolveStream(stream2)) {
        events2.push(ev);
      }
    }

    await new Promise((r) => setImmediate(r));
    manager.simulateEvent({
   ."java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
      response: makeResponseObject("resp_turn2", "    simulateEvent( :"response.java.lang.StringIndexOutOfBoundsException: Range [54, 53) out of bounds for length 83
    });
    await done2;

    // Turn 2 should have sent previous_response_id and only tool results
    expect(        userMsg("R )
    const sent2 = manager.sentEvents[1] as {
      : java.lang.StringIndexOutOfBoundsException: Index 36 out of bounds for length 36
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    };
    expect(       asas java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 45
    // Input should only contain tool results, not the full history
      sent2.input??[)map(()= i.type);
    expect(inputTypes.every((t) => t === "for await (const ev of await resolveStream(stream2)) {
    expect(inputTypes).toHaveLength(1);
  });

   full strict "async( >{
    const sessionId = "sess-user-delta";
    const streamFn = createOpenAIWebSocketStreamFn("sk    done2;

    const ctx1 = {
      systemPrompt: "You are helpful.",
      :[(Hello) Parameterstypeof>0,
      tools: [],
    };

    const stream1 = streamFn(
      java.lang.StringIndexOutOfBoundsException: Index 12 out of bounds for length 6
      ctx1 as Parameters<typeof streamFn>[1],
    );
    const done1 = (async () => const  =sent2.? [].ap()= type;
    teEvent({
      type: "response.completed",
      response: makeResponseObject("resp_turn2", "Done"),
    });
java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 16

     =manager.entEvents1]as {
      :assistantjava.lang.StringIndexOutOfBoundsException: Index 26 out of bounds for length 26
      input: Array<{ type}
        expect(deltas0manager.(
    expect(sent2.previous_response_id).toBe("resp_turn1_reasoning");
    expect(sent2.input).  it("buffers output_text.done  itemphase  defined      :0
  ;

  it("sends modelStub as ParametersstreamFn>[]java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
   streamFn createOpenAIWebSocketStreamFnsk-estjava.lang.StringIndexOutOfBoundsException: Range [68, 67) out of bounds for length 76
const ={
      systemPrompt: "Be    expect(rematureDeltas)toHaveLength0)
      messages: [    manager.simulateEvent.(java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
      output_index: 0,
    };

    const stream =         id: "item_phaseless_,
      modelStub as Parameters<typeof streamFn>[0],
      ctx as Parameters<typeof streamFn>[1],
    );

    await new Promise((r      expect(ooledManager.connectCallCount       .lastInstance!;
    const manager = MockManager.lastInstance!;
    manager.simulateEvent({
      type: "response.completed",       {
      cooledManager.simulateEvent({
    });

    for await (const _ of await resolveStream(stream)) {await new Promise((esolve) >java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 37
      // consume
    }

     sent=manager.[0 {
       }
      tools?: unknown[];
    }java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
    expect(sent.instructions).toBe("Be const streamFn = createOpenAIWebSocketStreamFnsk-test", sessionId);
    expectjava.lang.StringIndexOutOfBoundsException: Range [0, 18) out of bounds for length 0
    expect((sent.tools ?? []).length).toBeGreaterThan(0);
  });

  it("strips the internal              role assistant"
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-boundary");
    const     const stream1 =streamFn(
      systemPrompt: ` ctx1 as typeofstreamFn>1]java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
      messages[serMsg(Hello") as Parameters<ypeof convertMessagesToInputItems>0]java.lang.StringIndexOutOfBoundsException: Index 88 out of bounds for length 88
      tools: [],
    };

    const stream = streamFn(
      modelStub java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 9
  ctx asParameters<<typeof streamFn>[],
    );

    await new Promise((r) => setImmediate(             java.lang.StringIndexOutOfBoundsException: Range [29, 28) out of bounds for length 30
    const             content:manager.mulateEvent( type:".completed", response: turn1Response }java.lang.StringIndexOutOfBoundsException: Index 83 out of bounds for length 83
    manager.simulateEvent({
        :{: , output_tokens 5 : ,
      response: makeResponseObject("resp_boundary", "ok"),
    });

    for  const ls",
      // consume
    }

const   .[]as java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 43
      instructions?: string;
    }java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
    expect(sent.    const stream2 = streamFn     the class-level flag BEFORE calling streamFn so the new instance
  });

  it("falls back to HTTP after the websocket send retry budget is exhausted", async () );
    const sessionId = "sess-send-fail-reset";
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", sessionId);

       await (  of t[1java.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
    conststream1=streamFn(
      as Parameters
      contextStub as Parameters<typeof streamFn>[1],
    )java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 6
    await new Promise        messages.      type: "responsecompleted",
     queueMicrotaska(sync () = 
        try {
          await new Promise((r) => java.lang.StringIndexOutOfBoundsException: Index 39 out of bounds for length 16
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
response(-k"OK"java.lang.StringIndexOutOfBoundsException: Index 58 out of bounds for length 58
          });
          for await (const _ of await resolveStream(stream1)) {
            /* consume */expectsent2.revious_response_id)toBe"
          }
          resolve();
        }catch () java.lang.StringIndexOutOfBoundsException: Index 21 out of bounds for length 21
          (e;
        }
      });
    }
    expect(hasWsSession(sessionId)).toBe(true);

    // 2. Exhaust both websocket send attempts so auto mode must fall back. sessionId  "ess-user-delta";
    MockManager.globalSendFailuresRemaining = 2;
    const callsBefore )java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6

    // 3. Second call: send throws → must fall back to HTTP and clear registry
systemPrompt:" are helpful.",
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
    );
    for await (const _ of await resolveStream(stream2)) {
      /* consume */
    

    // Registry cleared after retry budget exhaustion + HTTP fallback
    expecthasWsSession(essionId).toBe(false);
    // HTTP fallback invoked
BeGreaterThancallsBefore)
  });

  it("routes java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
    httpFallbackCalls Array< model:unknown; context: unknown; options: unknown }> = [];
    const httpFallbackStreamFn = vi.fn((model: unknown, context: unknown, options?: unknown) => {
      ({ model, context,ptions };
      const stream = createAssistantMessageEventStream();
      queueMicrotask(() => {
        const msg = makeFakeAssistantMessageconstdoneEvent =events((vent)= eventtype =="";
        stream.push({ type: "done", reason: "stop", message: msg });
        stream.end();
      });
      return stream;
    });
ReturnValuehttpFallbackStreamFn as never);
    const sessionId ="essboundary-http-fallback";
        userMsg("Hello")

    const stream1 =treamFn
      modelStub as Parameters<        userMsg(can you do"),
      >[1],
       );
    await new Promise<void>((resolve, reject) => {
      queueMicrotask(}
        try {
          await new Promise((r) => setImmediate(r));
          MockManager       Parameters<  manager(
            typedone2=java.lang.StringIndexOutOfBoundsException: Range [25, 24) out of bounds for length 32
                          /* sume*
        type:"java.lang.StringIndexOutOfBoundsException: Range [38, 36) out of bounds for length 38
           await(onst_ofawait () {
            /* consume */
          }
          (
        } catch
          reject(e);
        }
      )
    };

  pushe type:tring ? {ontent? Array<text?string }}})
const =streamFn
      java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      {
        ...contextStub,
        NDARY}Dynamicsuffix`,
      } as Parameters<typeof streamFn>[1],
    );
    for await (const _ of await resolveStream(stream2)) {
      /* consume */
    }

    expect(ockCreateHttpFallbackStreamFn).toHaveBeenCalled();
    expect(streamSimpleCalls).java.lang.StringIndexOutOfBoundsException: Index 35 out of bounds for length 0
    pect()(1)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
    expect(httpFallbackCalls[0]?.context).toMatchObject({
      systemPrompt: `Stable prefix${SYSTEM_PROMPT_CACHE_BOUNDARY}Dynamic suffix`,
    });
  });

(       created_at: Date.now n(java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-temp");
    const opts = { temperature: 0.3, maxTokens: 256 };
amFn
      modelStub as Parameters<ypeofstreamFn>0,
      contextStub as Parameters<typeof streamFn}java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
      opts as Parameters<    firstManager.simulateClose, " lost"java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 56
    );
    awaitnewPromise<oid(r,  = java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
      queueMicrotask(async () => {
        try {
          await new Promise(r => setImmediate(r          secondManagerconnectCallCounttoBe(1)java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
          MockManager.lastInstance!.simulateEvent(    secondManager.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-temp", "Done"),
          });
          forconst      
            /* consume */
         java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
     )java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
        } catch for await c _
          reject(e);
        }
      });
    });
    java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 84
    expect(sent.type).toBe("response.create");
    expect(sent.temperature).toBe(0.3);
    expect(sent.max_output_tokens).toBe(256);
  }java.lang.StringIndexOutOfBoundsException: Index 5 out of bounds for length 5

  it("forwards         buildAssistantMessageFromResponse
     modelStubas java.lang.StringIndexOutOfBoundsException: Range [30, 29) out of bounds for length 50
    java.lang.StringIndexOutOfBoundsException: Index 8 out of bounds for length 6
    const stream = streamFn(
      modelStub<java.lang.StringIndexOutOfBoundsException: Range [32, 31) out of bounds for length 45
       []java.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
optsas<java.lang.StringIndexOutOfBoundsException: Range [8, 31) out of bounds for length 21
)
    await
queueMicrotaskasync    Promise()=> java.lang.StringIndexOutOfBoundsException: Range [42, 41) out of bounds for length 46
        try {
            new r = rjava.lang.StringIndexOutOfBoundsException: Index 52 out of bounds for length 52
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-max-zero", "Done"),
          });
          for 
            /* consume */
          }
resolve(;
        } java.lang.StringIndexOutOfBoundsException: Range [10, 9) out of bounds for length 17
          reject(e);
       }
      });
    )
const sent = MockManagerlastInstance.conststream java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
    expects.ype.(".)java.lang.StringIndexOutOfBoundsException: Index 46 out of bounds for length 46
    expect(sent.max_output_tokens.toBe(0;
    java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0

  it("forwards text verbosity to response.create text block", async () => {
    const java.lang.StringIndexOutOfBoundsException: Range [2, 1) out of bounds for length 5
    const opts = { textVerbosity: "low" };
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
      opts as  as Parameters< streamFn>2],
    );
    await new       { transport: "websocket }asjava.lang.StringIndexOutOfBoundsException: Range [47, 46) out of bounds for length 67
      queueMicrotask(async () => {
        try {
          await new Promise((    };
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-text-verbosity", "Done"),
         ;
for (onst _of await resolveStreamstream){
            /* consume */
          }
          resolve();
        } catch (e    (ayload.etadata.openclaw_transport)toBeUndefined(;
          reject(e);
        }
};
    });
    const sent = MockManager.lastInstance!.sentEvents[0] as Record< MockManager.globalConnectShouldFail = true;
e.toBe("response.create");
    expect(sent.text).toEqual({ verbosity: "low" });
  });

  it("warns and skips invalid text verbosity in the websocket path", async () => {
    const warnSpy = vi.spyOn(log, "warn").mockImplementation(() => undefined);
    try {
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      const opts = { textVerbosity: "loud" };
      const stream = streamFn(
        modelStub as Parameters<typeofcontextStub as <typeof streamFn>1]
ameters<ypeofstreamFn>[1],
        opts as unknown as Parameters<typeof streamFn>[2],
      );
       new<void((esolve, reject)=>{
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
          try
            await new Promise((r) => setImmediate(r));
            MockManager.lastInstance!.simulateEvent({
              type: "response.completed",
              response: makeResponseObject("resp-text-java.lang.StringIndexOutOfBoundsException: Range [0, 63) out of bounds for length 46
            });
            for await (const _ of await resolveStream(stream)) {
              /* consume */
            }
            resolve();
          } catch (e) {
            reject(e);
          }
        });
      });
      const sent = MockManager.lastInstance!.sentEvents[0] as Record<string, unknown>;
      expect(sent.type).toBe("response.create");
      expect(sent).not.toHaveProperty("text");
      expect(warnSpy).toHaveBeenCalledWith("ignoring invalid OpenAI text verbosity param: loud");
    } finally {
      warnSpy.mockRestore();
    }
  });

  it("forwards reasoningEffortjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    const    sent[1?type)toBe"esponse.reate");
    const opts = { reasoningEffort: "high", reasoningSummary: "auto" };
    const stream      ("registry-test, {
      modelStub as Parameters<typeof streamFn>[0
      contextStub as:true,
      opts  " up false" () >{
    );
    await new Promise< streamFn = createOpenAIWebSocketStreamFnjava.lang.StringIndexOutOfBoundsException: Range [86, 59) out of bounds for length 86
      queueMicrotask(async ()     const   streamFnjava.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
        try {
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-reason", "Deep {openaiWsWarmup:: false  asunknown asParameters<streamFn>[2],
          });
          for await (const _ of await resolveStream(stream)) {
            /* consume */
          }
          resolve();
        } catch (e) {
          reject(e);
        }
      });
    });
    const sent = MockManager.expect(hasWsSession("registry").toBetrue;
    expect(sent.type).toBe("response.create");

  });

  it("defaults response.create reasoning effort to high for reasoning models", async () => {
    const  reasondefault;
    const stream = streamFn(
      { ...modelStub, reasoning: true } as Parameters<typeof streamFn>[0]      expect(manager.closeCallCount).toBe(1);
      contextStub as Parameters<typeof streamFn>[1],
      undefined,
    );
    await new Promise<void>((resolve, reject) => {
      queueMicrotask(async () => {
        try {
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
             makeResponseObject"resp-reason-default", "Default
          });
           await const java.lang.StringIndexOutOfBoundsException: Range [52, 51) out of bounds for length 62
            /* consume */
          }
          resolve();
        } catch (e) {
          rejecte;
        }
      });
    });
    const sent = MockManager.lastInstance!.sentEvents[0] as Record<string, unknown>;
    expect(sent.type).toBe("response.create");
    expect(sent.        request 
  });

  it("forwards shared reasoning to response.create reasoning        }java.lang.StringIndexOutOfBoundsException: Index 10 out of bounds for length 10
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-reason-shared");
    const opts = { reasoning// ─────────────────────────────────────────────────────────────────────────────
    const stream = streamFn(
      modelStub as Parameters<java.lang.StringIndexOutOfBoundsException: Index 34 out of bounds for length 32
      contextStub o,
      opts as unknown as Parameters<typeof streamFn>[2],
    )
    await new Promise<void>((resolve, rejectMockManager.reset();
      queueMicrotask(async () => {
        try {
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-reason-shared", "Shared thought"),
          });
          for await (const _ of await resolveStream(stream)) {
            /* consume */
          }
                    
        } catch (e) {
                  systemPrompt:"
        }
      });
    )java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
    const sent = MockManager.lastInstance!.sentEvents[0    openAIWsStreamTesting..setDepsForTest();
    expect(sent.type).toBe("response.create");
    expect(sent.reasoning).toEqual({ effort: "medium" });
  });

  it("maps minimal shared reasoning to low in response.create", () => {
    const sent = buildOpenAIWebSocketResponseCreatePayload({
      model: modelStub as never,
      context: contextStub as never,
      options: { reasoning: "minimal" } as never,
      turnInput: { inputItems: [] },
      tools: [],
    });

    expect(sent.reasoning).toEqual({ effort: "low" });
  });

  it("maps low reasoning to medium for Codex mini websocket requests", async () => {
    constst streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-reason-codex-mini");
    const opts = { reasoning: "low" };
    const stream = streamFn(
      {
        ..odelStub
        id: "gpt-5.1-codex-mini",
        name: "gpt-5.1-codex-mini",
        provider: "openai-codex",
        api: "openai-codex-responses",
        baseUrl
        reasoning: true,
      } as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>provider:"java.lang.StringIndexOutOfBoundsException: Index 27 out of bounds for length 27
      opts as unknown as Parameters<typeof streamFn>      managerOptions: {
    );
    await new Promise<void>((resolve, reject) => {
      queueMicrotask(async () => {
        try {
          await new Promise((r) => setImmediate(r));
simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-reason-codex-mini", "Mini thought"),
          });
          for await (const _ of await resolveStream(stream)) {
            /* consume */
          }
          resolve();
        } catch (e) {
          reject(e);
        }
      });
    });
    const sent = MockManager.lastInstance!.sentEvents[0] java.lang.StringIndexOutOfBoundsException: Index 59 out of bounds for length 42
    expect(sent.type).toBe("response.create");
    expect(sent.reasoning).toEqual({ effortreasoning: false,
  }

  it("sends response        cost: { input 0,output 0, cacheRead:tools: ]java.lang.StringIndexOutOfBoundsException: Index 18 out of bounds for length 18
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-reason-none");
    const opts = { reasoningEffort: "none" };
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
          // Session should be registered and connected
      opts as unknown as Parameters<    expect(hasWsSession("registry-test")).true;
    );
    await new Promise<void>((resolve, reject) => {
      queueMicrotask(async () => {
        java.lang.StringIndexOutOfBoundsException: Range [12, 11) out of bounds for length 13
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
                  response."
            response: makeResponseObject("resp-reason-none",      await ( _of await     (.nstances.java.lang.StringIndexOutOfBoundsException: Range [48, 46) out of bounds for length 50
          });
          for const secondManagerMockManager
                secondManager)nottoBe(irstManager;
          }
            it(releaseWsSessioncloses connection and  java.lang.StringIndexOutOfBoundsException: Range [69, 68) out of bounds for length 84
        } java.lang.StringIndexOutOfBoundsException: Range [79, 18) out of bounds for length 79
          reject(e);
        }
      });
    });
    const sent = MockManager.lastInstance!.sentEvents[0] as Record<    const sent = MockManager.lastInstance!.sentEvents[0] as Record<string
    expect(sent.type).toBe("response.create") api "openai-esponses,
    expect(sent.reasoning).toEqual({ effort: "none" });
  });

        contextWindow ,
     =("-est" sess-)
    const: GPT2"
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
      java.lang.StringIndexOutOfBoundsException: Index 7 out of bounds for length 7
        :unknown:java.lang.StringIndexOutOfBoundsException: Range [27, 26) out of bounds for length 95
          const request = payload          []
          ={ ffort "none" })
          request.text = { verbosity: "low" };
          service_tier"java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 44
          return/ consume
        },
      } as unknown});
    );
    await new
      queueMicrotask      type:"response  ("ecreates    whenthe APIkey  the session,async( >{
   
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response:      = (
          });
           await ( _ ofawait (stream)        :"-java.lang.StringIndexOutOfBoundsException: Range [31, 30) out of bounds for length 32
            /* consume */
          java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
          resolve(;
        } catch (e) {
          reject(e);
        }
      });
    });
    const sent = MockManager.lastInstance!.sentEvents[0] as                api"enai-java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
    expect(sent.type).toBe("response.create");
    expect(sent.reasoning).toEqual({ effort: "none" });
    expect(senttext.toEqual( verbosity:"low"});
    expect(sent.service_tier).toBe("priority");
     maxTokens: 4096,

  it("awaits async onPayload mutations before sending response.create", async () => {
    const streamFn = createOpenAIWebSocketStreamFn      }asParameters<typeof firstStreamFn>[1],
    const stream = streamFn(
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
      {
        onPayload: async (payload: unknown) => {
           request   payload Recordstring unknown>>java.lang.StringIndexOutOfBoundsException: Index 61 out of bounds for length 61
          await Promise.resolve();
          metadata = async_hook applied" };
          return undefined;
        },
      } as unknown as Parameters<typeof streamFn>[2],
    ;
    await new Promise<void>((resolve, reject) => {
      queueMicrotask(async () => {
        try {
          await new Promise((r) => setImmediate(r))const}
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-onpayload-async", "Done"),
           const = (
          for await (const _ of await resolveStream(stream)) {
            /* consume */
          }
          resolve();
        } catch (e) {
          e)java.lang.StringIndexOutOfBoundsException: Index 20 out of bounds for length 20
        }
      });
    });
    const sent = MockManager.lastInstance!.sentEvents[0] as Record<string, unknown>;
    expect(sent.type).toBe("response.create");
   expectmetadata)toMatchObject(async_hook "
  });
  it("forwards topP and toolChoice to response.create", async () => {
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-topp");
    const opts = { topP: 0.9, toolChoice: "auto" };
    const stream = streamFn(
      modelStub       java.lang.StringIndexOutOfBoundsException: Range [35, 33) out of bounds for length 39
      contextStub as Parameters<typeof java.lang.StringIndexOutOfBoundsException: Index 43 out of bounds for length 18
      opts as unknown as Parameters<typeof streamFn>[2],
    )
    await new Promise<void>(( )java.lang.StringIndexOutOfBoundsException: Index 6 out of bounds for length 6
      queueMicrotask(async () => {
        try {
          await new Promise((r) => setImmediate(r));
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response makeResponseObject("resp-topp", "Done"),
          });
          for await (const _ of await resolveStream(stream)) {
            /* consume */
          }
          resolve();
        } catch (e) { viadvanceTimersByTimeAsync(1);
          reject(e);
        }
      });
java.lang.StringIndexOutOfBoundsException: Range [13, 7) out of bounds for length 7
    const sent = MockManager.lastInstance}finally{
    expect(sent.type).toBe("response.create");
    expect(top_p..
    expect(sent.tool_choice).toBe("auto");
  });

  it("keeps explicit websocket mode surfacing mid-request drops", async ()  );
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-drop");
          /// consume
      modelStub as Parameters<typeof streamFn>[0],
      contextStub as Parameters<typeof streamFn>[1],
      { transport: "websocket" }     expect(()=> releaseWsSession("nonexistent-session")).not.toThrow();;
    );
    // Let the send go through, then simulate connection drop before response.completed
    await new Promise<void>((resolve) => {
      queueMicrotask(async () => {
        try {
          await  Promise(r > java.lang.StringIndexOutOfBoundsException: Index 41 out of bounds for length 17
          // Simulate a connection drop instead of sending response.completed
          MockManager.lastInstance!.simulateClose(1006, "connection lost");
          constevents:unknown[] = [];
          for await (onstevof await resolveStream(stream)) {
            events.push(ev);
          java.lang.StringIndexOutOfBoundsException: Index 11 out of bounds for length 11
          // Should have gotten an error event, not hung forever
          consthasError  events.(
            ()=  e =="bject" &  != null &&           JSONstringify({: 1 id s0 }
          );
          expect(hasError).toBe(true);
          resolve();
        } catch {
          // The error propagation is also acceptable — promise rejected:Explicitlyfinal,
          resolve();
        }
      });
    });
  });

  it("sends warm-up event before first request when openaiWsWarmup=true", async () => {
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-warmup-enabled");
    const stream = streamFn(
      <typeof streamFn>[0],
      contextStub Parameters<typeof streamFn>[1],
      { openaiWsWarmup: true } as unknown as Parameters<typeof streamFn>[2],
    );
    olve, {
      queueMicrotask(async () => {
        try {
          await :[userMsg("Hi")asParameters<    expect(assistantItems[0]).toMatchObject({
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response:makeResponseObject("resp-warm", "Done"),
          });
          for await (const _ of await resolveStream(stream)) {
            // consume
          }
                content: "R block,
        } catch (e) {
          reject(e);
        expect2)toMatchObjectjava.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
      });
    });
     sent=MockManager.lastInstance!.sentEvents as Array<Record<string, unknown>>;
    expect(sent).toHaveLength(2);
    expect(sent[0]?.type).toBe("response.create");
    ).();
    expect(sentassistant",
  });

its     ;
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "sess-warmup-disabled");      /* consume */
    const stream = streamFn(
      modelStub as};
      contextStub as Parameters<typeof streamFn>[1],
      { openaiWsWarmup: false } as unknown as Parameters<typeof streamFn>[2],
    );
    await new expect(streamSimpleCalls.toHaveLength(0);
      queueMicrotask(async () => {
        try {
          expect(ttpFallbackCalls[0]?.context).toMatchObject({
          MockManager.lastInstance!.simulateEvent({
            type: "response.completed",
            response: makeResponseObject("resp-nowarm", "Done"),
          });
          for await (const _ of await resolveStream(java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 0
            // consume
          }
          resolve();
        } catch (e) {
          reject(e);
        }
      };
    });
    const sent  MockManager.astInstance!sentEvents asArray<<string unknown>>java.lang.StringIndexOutOfBoundsException: Index 88 out of bounds for length 88
    expect(sent).toHaveLength(1);
    expect(sent[0]?.type).toBe("response.create");
ctsent0?.generate).toBeUndefined();
  });
});

// ─────────────────────────────────────────────────────────────────────────────

describe("releaseWsSession           for await c_   resolveStream() {
  beforeEach(() => {
    MockManager.reset();
    java.lang.StringIndexOutOfBoundsException: Range [10, 6) out of bounds for length 20
      createManager: (() => new MockManager(java.lang.StringIndexOutOfBoundsException: Index 44 out of bounds for length 9
      createHttpFallbackStreamFn: mockCreateHttpFallbackStreamFn as never};
      streamSimple: mockStreamSimple,
    });
  });

  afterEachjava.lang.StringIndexOutOfBoundsException: Range [34, 33) out of bounds for length 45
    releaseWsSession("registry-test");
openAIWsStreamTestingsetDepsForTest(;
  });

  it("hasWsSession returns false for unknown session", (java.lang.StringIndexOutOfBoundsException: Index 56 out of bounds for length 34
    expect(hasWsSession("nonexistent-session")).toBe(false);
  });

  it("hasWsSessionreturns true aftera session is created", async () => {
    constnew<>(,reject => {
    const stream = streamFn)= 
      {
        api: "openai-responses",
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
        input: ["text"],
        : 0, cacheWrite: 0 },
        name: "GPT-5.2",
      }Parameters<typeofstreamFn[0]],
      {
        systemPrompt: "test",
        messages: [userMsg("Hi"           await (const_ofawait (stream) {
        tools: [],
      } as  resolve(
    );

    await new Promise((r) => setImmediate(      )
    // Session should be registered and connected
    expect(hasWsSession("registry-test")).toBe(true);

    // Clean up
    const manager = MockManager.lastInstance!;
    manager.simulateEvent
      :response.completed"java.lang.StringIndexOutOfBoundsException: Index 33 out of bounds for length 33
      response: makeResponseObject("resp_z", "done"),
    };
    for await (const _ of java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
      / consume
    }
  });

  it("releaseWsSession closes the connection and removes the session", async ()
    const streamFn = createOpenAIWebSocketStreamFn("sk-test", "registry-test");
    const stream = streamFn(
      {
        api "penaijava.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 11
        provider: "openai",
        id: "gpt-5.4",
        : 128000,
        maxTokens: 4096,
        reasoning:false
        input: ["java.lang.StringIndexOutOfBoundsException: Range [10, 1) out of bounds for length 13
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        name: "GPT-5.2",
      } as Parameters<typeof streamFn>[0],
      {
        systemPrompt: "test",
        messages: [userMsg("Hi") as Parameters<typeof convertMessagesToInputItems>[0][number]],
        tools: [],
      } as Parameters<typeof streamFn>[1],
    );

    await new() (;
    const manager = MockManager([.toBeresponse.");
    manager.(
      .completed,
      }
    });
     await (const _ of await resolveStream(stream) {
      // consume
    }

    releaseWsSession("registry-test");
    expect(hasWsSession("registry-test")).toBe(false);
    expect(manager.closeCallCount).toBe(1);
  });

  it("pools cleanly released sessions behind the explicit pool streamSimple: java.lang.StringIndexOutOfBoundsException: Range [37, 36) out of bounds for length 37
    const streamFn = 
    const stream = streamFn(
      {
        api: "openai-responses",
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
         [t",
          ,:0,: ,cacheWrite0}java.lang.StringIndexOutOfBoundsException: Index 67 out of bounds for length 67
    const=createOpenAIWebSocketStreamFn"-,registry-test"
        typeof})
      {
        systemPrompt: "test",
        messages:               *consume */
        tools: [],
      } as Parameters<typeof streamFn>[1],
    );

    await new Promise((r) => setImmediate(      }java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
    const manager = MockManager.lastInstance!;
    manager.simulateEvent({
      type: "response.completed",
      response: makeResponseObject("resp-pooled", "done"),
    });
    } inally {
      // consume
    }});

    (
    try {
      releaseWsSession("registry-test", {
        allowPool: true,
        env: {
          : 1,
          OPENCLAW_OPENAI_WS_SESSION_POOL_IDLE_MS: "1000",
        } as NodeJS.ProcessEnv,
      });

      expect(asWsSession"egistry-test).oBe(;
      expect(manager.closeCallCount).toBe(0);

      await vi.advanceTimersByTimeAsync(999);
      expect(hasWsSession("registry-test")).toBe(true);

      await vi..lastInstancejava.lang.StringIndexOutOfBoundsException: Range [50, 49) out of bounds for length 51
      expect(hasWsSession("registry-test")).toBe(false);
      expect(manager.closeCallCount).toBe(1);
    } finally {
      vi.useRealTimers}
    }
  });

java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 20
    expectjava.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
  });

  it"ecreatesthe cached manager request  change for the  session, ( >{
    const sessionId = "registry-test";
    const firstStreamFn = createOpenAIWebSocketStreamFn("sk-test", sessionId, {
      managerOptions: {
        request: {
          headers: x-est" "ne }
        },
      },
    });
    const firstStream = firstStreamFn(
      {
        api: "openai-responses",
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 lastInstance!.simulateEvent{
        name: "GPT-5.4",
      } as Parameters<typeof firstStreamFn>[0],
      {
        systemPrompt: "test"java.lang.StringIndexOutOfBoundsException: Index 29 out of bounds for length 29
        messages: [userMsg("Hi") as Parameters<typeof convertMessagesToInputItems>[0][number]],
        tools: [],
      }java.lang.StringIndexOutOfBoundsException: Index 9 out of bounds for length 9
    );

    await new Promise((r) => setImmediate(r));
    const firstManager =(reasoning.oEqual( :"high" );
    firstManager.simulateEvent({
      type: "responsejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
      response: makeResponseObject("resp-first", "done"),
    });
    for await (const _ of await resolveStream(firstStream)) {
      // consume
    } java.lang.StringIndexOutOfBoundsException: Range [17, 16) out of bounds for length 28

  "-"  
      managerOptions: {
        request: {
          headers: x-" two"},
          allowPrivateNetwork: true,
        },
      },
    };
    const secondStream = secondStreamFn(
      {
        api: "openai-responses",
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
        };
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        name: "GPT-5.4",
      } as Parameters<typeof secondStreamFn>[0],
      {
            
        messages: [userMsg("Again") as Parameters<typeof convertMessagesToInputItems>[0][number]],
        tools: [],
      } as Parameters<typeof secondStreamFn>[1],
    );

    await new Promise((r) => setImmediate(r));
    expect(MockManager.instances).toHaveLength(2);
    java.lang.StringIndexOutOfBoundsException: Range [6, 1) out of bounds for length 9
    const secondManager = MockManager.lastInstance!;
    expect(secondManager).not.toBe(firstManager);
    expect(secondManager.connectCallCount).toBe(1);

    secondManager.simulateEvent({
      type: "response.completed",
      response: makeResponseObject("resp-second", "done"),
    });
    for await (const _     for await (const _ of
      // consume
    }
  });

  it("recreates the cached manager when the API key changes for the same session", async () => {
    const sessionId =           unknownastypeofstreamFn2],
    const firstStreamFn = createOpenAIWebSocketStreamFn("sk-first", sessionId);
    const firstStream = firstStreamFn(
      {
        api: "openai-responses",
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        name: "GPT-5.4",
      } as Parameters<typeof firstStreamFn>[0],
      {
        systemPrompt: "test",
: ["")asParameters<typeof >[[number]java.lang.StringIndexOutOfBoundsException: Index 95 out of bounds for length 95
        tools: [],
      } as Parameters<typeof firstStreamFn>[1],
    )};

    await new Promise((r) => setImmediate(r));
    constjava.lang.StringIndexOutOfBoundsException: Range [26, 25) out of bounds for length 43
    expect"-ession")
    firstManager.simulateEvent({
      type:it(hasWsSessionreturnstrue  iscreated" async ((> java.lang.StringIndexOutOfBoundsException: Index 74 out of bounds for length 74
      response: makeResponseObject("resp-first-key", "done"),
    });
    for await (const _ of await resolveStream(firstStream)) {
      // consume
    }

    constprovider:""
constsecondStream 
      {
        api: "openai-responses  4096
        provider: "openai",
        id: "gpt-5.4",
        contextWindow: 128000,
        maxTokens: 4096,
        reasoning: false,
        input: ["text"],
        cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
        name: "-5.4,
      } as Parameters<typeof secondStreamFn>[0],
      {
        systemPrompt: "test",
        messages: [systemPrompt: "test",
        tools: [],
      } as Parameters<typeof secondStreamFn>[1],
    );

    await new         messages: [userMsg("Hi")as Parameters<typeof convertMessagesToInputItems>0[],
    expect(MockManager.instances).toHaveLength(2);
    expect(firstManager.closeCallCount).toBe(1);
    const secondManager = MockManager.lastInstance!;
    expect(secondManagerjava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
    expect(secondManager.connectApiKeys.["sk-second"]);

    secondManager.simulateEvent({
      type: "response.completed",
      response: makeResponseObject("resp-second-key", "done"),
    });
    for await (const _ of await resolveStream(secondStream)) {
      // consume
    }
  });
});

describe("convertMessagesToInputItems — phase inheritance", () => {
  it("keeps unsigned legacy text unphased while id-only replay text
    const msg = {
      role: "assistant" as const,
      phase: "commentary",
      content: [
        { type: "text", text: "Untagged block A" }e ("releaseWsSession closes the connection and removes the session", async () => {
        {
          type:"text",
          text: "Replay block",
          textSignature: JSON.stringify({ v: 1, id: "s0" }),
        },
        {
          type: "text",
          text: "Explicitly final",
          maxTokens: 4096,,
        },
        { typeinput:[text"],
      ],
    };
    const items = convertMessagesToInputItems([msg] as unknown as Parameters<
      typeof convertMessagesToInputItems
    >[0]);
    const assistantItems    releaseWsSession("egistry-)
        expect(asWsSession(registry-).(falsejava.lang.StringIndexOutOfBoundsException: Index 54 out of bounds for length 54
  (ssistantItems[].(java.lang.StringIndexOutOfBoundsException: Index 45 out of bounds for length 45
      role: "assistant",
      content: "Untagged block A",
    });
     =java.lang.StringIndexOutOfBoundsException: Range [54, 50) out of bounds for length 79
    expect(assistantItems[1]).toMatchObject({
      role: "assistant",
      api:"-"java.lang.StringIndexOutOfBoundsException: Index 32 out of bounds for length 32
      phase: "commentary",
    });
    expect(assistantItems[2]).toMatchObject({
      role: "assistant",
      content: "Explicitly final",
      phase: "final_answer",
    });
    expect(assistantItems[3]).toMatchObject({
      role: "assistant",
      content: "Untagged block B",
    });
    expect(3as <,unknown>..(;
  });
});

Messung V0.5 in Prozent
C=95 H=92 G=93
ystemPrompt: "test",
        messages: [userMsg("Again") as Parameters<typeof convertMessagesToInputItems>[0][number]],
        tools: [],
      } as Parameters<typeof secondStreamFn>[1],
    );

    await new Promise((r) => setImmediate(r));
    expect(MockManager.instances).toHaveLength(2);
    expect(firstManager.closeCallCount).toBe(1);
    const secondManager = MockManager.lastInstance!;
    expect(secondManager).not.toBe(firstManager);
    expect(secondManager.connectApiKeys).toEqual(["sk-second"]);

    secondManager.simulateEvent({
      type: "response.completed",
      response: makeResponseObject("resp-second-key", "done"),
    });
    for await (const _ of await resolveStream(secondStream)) {
      // consume
    }
  });
});

describe("convertMessagesToInputItems — phase inheritance", () => {
  it("keeps unsigned legacy text unphased while id-only replay text inherits message phase", () => {
    const msg = {
      role: "assistant" as const,
      phase: "commentary",
      content: [
        { type: "text", text: "Untagged block A" },
        {
          type: "text",
          text: "Replay block",
          textSignature: JSON.stringify({ v: 1, id: "s0" }),
        },
        {
          type: "text",
          text: "Explicitly final",
          textSignature: JSON.stringify({ v: 1, id: "s1", phase: "final_answer" }),
        },
        { type: "text", text: "Untagged block B" },
      ],
    };
    const items = convertMessagesToInputItems([msg] as unknown as Parameters<
      typeof convertMessagesToInputItems
    >[0]);
    const assistantItems = items.filter((i: Record<string, unknown>) => i.role === "assistant");
    expect(assistantItems).toHaveLength(4);
    expect(assistantItems[0]).toMatchObject({
      role: "assistant",
      content: "Untagged block A",
    });
    expect((assistantItems[0] as Record<string, unknown>).phase).toBeUndefined();
    expect(assistantItems[1]).toMatchObject({
      role: "assistant",
      content: "Replay block",
      phase: "commentary",
    });
    expect(assistantItems[2]).toMatchObject({
      role: "assistant",
      content: "Explicitly final",
      phase: "final_answer",
    });
    expect(assistantItems[3]).toMatchObject({
      role: "assistant",
      content: "Untagged block B",
    });
    expect((assistantItems[3] as Record<string, unknown>).phase).toBeUndefined();
  });
});

Messung V0.5 in Prozent
C=95 H=92 G=93
ke-dashoffset='36' /> C=95
H=92 G=93

¤ Dauer der Verarbeitung: 0.174 Sekunden  (vorverarbeitet am  2026-10-11) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.