@strands-agents/sdk 0.6.0 → 1.0.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -7
- package/dist/src/__fixtures__/agent-helpers.d.ts +81 -4
- package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/agent-helpers.js +76 -4
- package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
- package/dist/src/__fixtures__/metrics-helpers.d.ts +30 -0
- package/dist/src/__fixtures__/metrics-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/metrics-helpers.js +29 -6
- package/dist/src/__fixtures__/metrics-helpers.js.map +1 -1
- package/dist/src/__fixtures__/mock-message-model.d.ts +8 -4
- package/dist/src/__fixtures__/mock-message-model.d.ts.map +1 -1
- package/dist/src/__fixtures__/mock-message-model.js +13 -7
- package/dist/src/__fixtures__/mock-message-model.js.map +1 -1
- package/dist/src/__fixtures__/mock-meter.d.ts +32 -0
- package/dist/src/__fixtures__/mock-meter.d.ts.map +1 -0
- package/dist/src/__fixtures__/mock-meter.js +47 -0
- package/dist/src/__fixtures__/mock-meter.js.map +1 -0
- package/dist/src/__fixtures__/mock-plugin.d.ts +13 -0
- package/dist/src/__fixtures__/mock-plugin.d.ts.map +1 -0
- package/dist/src/__fixtures__/{mock-hook-provider.js → mock-plugin.js} +11 -6
- package/dist/src/__fixtures__/mock-plugin.js.map +1 -0
- package/dist/src/__fixtures__/tool-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/tool-helpers.js +6 -2
- package/dist/src/__fixtures__/tool-helpers.js.map +1 -1
- package/dist/src/__tests__/index.test.js +21 -0
- package/dist/src/__tests__/index.test.js.map +1 -1
- package/dist/src/__tests__/mcp.test.js.map +1 -1
- package/dist/src/__tests__/mime.test.d.ts +2 -0
- package/dist/src/__tests__/mime.test.d.ts.map +1 -0
- package/dist/src/__tests__/mime.test.js +83 -0
- package/dist/src/__tests__/mime.test.js.map +1 -0
- package/dist/src/__tests__/state-store.test.d.ts +2 -0
- package/dist/src/__tests__/state-store.test.d.ts.map +1 -0
- package/dist/src/__tests__/{app-state.test.js → state-store.test.js} +86 -51
- package/dist/src/__tests__/state-store.test.js.map +1 -0
- package/dist/src/a2a/__tests__/a2a-agent.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/a2a-agent.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/a2a-agent.test.js +364 -0
- package/dist/src/a2a/__tests__/a2a-agent.test.js.map +1 -0
- package/dist/src/a2a/__tests__/adapters.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/adapters.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/adapters.test.js +151 -0
- package/dist/src/a2a/__tests__/adapters.test.js.map +1 -0
- package/dist/src/a2a/__tests__/events.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/events.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/events.test.js +66 -0
- package/dist/src/a2a/__tests__/events.test.js.map +1 -0
- package/dist/src/a2a/__tests__/executor.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/executor.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/executor.test.js +196 -0
- package/dist/src/a2a/__tests__/executor.test.js.map +1 -0
- package/dist/src/a2a/__tests__/server.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/server.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/server.test.js +51 -0
- package/dist/src/a2a/__tests__/server.test.js.map +1 -0
- package/dist/src/a2a/__tests__/server.test.node.d.ts +2 -0
- package/dist/src/a2a/__tests__/server.test.node.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/server.test.node.js +110 -0
- package/dist/src/a2a/__tests__/server.test.node.js.map +1 -0
- package/dist/src/a2a/a2a-agent.d.ts +132 -0
- package/dist/src/a2a/a2a-agent.d.ts.map +1 -0
- package/dist/src/a2a/a2a-agent.js +255 -0
- package/dist/src/a2a/a2a-agent.js.map +1 -0
- package/dist/src/a2a/adapters.d.ts +27 -0
- package/dist/src/a2a/adapters.d.ts.map +1 -0
- package/dist/src/a2a/adapters.js +175 -0
- package/dist/src/a2a/adapters.js.map +1 -0
- package/dist/src/a2a/events.d.ts +44 -0
- package/dist/src/a2a/events.d.ts.map +1 -0
- package/dist/src/a2a/events.js +41 -0
- package/dist/src/a2a/events.js.map +1 -0
- package/dist/src/a2a/executor.d.ts +57 -0
- package/dist/src/a2a/executor.d.ts.map +1 -0
- package/dist/src/a2a/executor.js +130 -0
- package/dist/src/a2a/executor.js.map +1 -0
- package/dist/src/a2a/express-server.d.ts +67 -0
- package/dist/src/a2a/express-server.d.ts.map +1 -0
- package/dist/src/a2a/express-server.js +95 -0
- package/dist/src/a2a/express-server.js.map +1 -0
- package/dist/src/a2a/index.d.ts +15 -0
- package/dist/src/a2a/index.d.ts.map +1 -0
- package/dist/src/a2a/index.js +15 -0
- package/dist/src/a2a/index.js.map +1 -0
- package/dist/src/a2a/logging.d.ts +8 -0
- package/dist/src/a2a/logging.d.ts.map +1 -0
- package/dist/src/a2a/logging.js +15 -0
- package/dist/src/a2a/logging.js.map +1 -0
- package/dist/src/a2a/server.d.ts +67 -0
- package/dist/src/a2a/server.d.ts.map +1 -0
- package/dist/src/a2a/server.js +67 -0
- package/dist/src/a2a/server.js.map +1 -0
- package/dist/src/agent/__tests__/agent.hook.test.js +315 -51
- package/dist/src/agent/__tests__/agent.hook.test.js.map +1 -1
- package/dist/src/agent/__tests__/agent.test.js +298 -48
- package/dist/src/agent/__tests__/agent.test.js.map +1 -1
- package/dist/src/agent/__tests__/agent.tracer.test.node.d.ts +2 -0
- package/dist/src/agent/__tests__/agent.tracer.test.node.d.ts.map +1 -0
- package/dist/src/agent/__tests__/{agent.tracer.test.js → agent.tracer.test.node.js} +62 -50
- package/dist/src/agent/__tests__/agent.tracer.test.node.js.map +1 -0
- package/dist/src/agent/__tests__/printer.test.js +7 -7
- package/dist/src/agent/__tests__/printer.test.js.map +1 -1
- package/dist/src/agent/__tests__/snapshot.test.js +50 -13
- package/dist/src/agent/__tests__/snapshot.test.js.map +1 -1
- package/dist/src/agent/agent.d.ts +55 -44
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +230 -128
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/agent/printer.d.ts.map +1 -1
- package/dist/src/agent/printer.js +3 -0
- package/dist/src/agent/printer.js.map +1 -1
- package/dist/src/agent/snapshot.d.ts +3 -3
- package/dist/src/agent/snapshot.d.ts.map +1 -1
- package/dist/src/agent/snapshot.js +16 -8
- package/dist/src/agent/snapshot.js.map +1 -1
- package/dist/src/conversation-manager/__tests__/conversation-manager.test.d.ts +2 -0
- package/dist/src/conversation-manager/__tests__/conversation-manager.test.d.ts.map +1 -0
- package/dist/src/conversation-manager/__tests__/conversation-manager.test.js +100 -0
- package/dist/src/conversation-manager/__tests__/conversation-manager.test.js.map +1 -0
- package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js +26 -10
- package/dist/src/conversation-manager/__tests__/null-conversation-manager.test.js.map +1 -1
- package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +153 -64
- package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +1 -1
- package/dist/src/conversation-manager/conversation-manager.d.ts +87 -0
- package/dist/src/conversation-manager/conversation-manager.d.ts.map +1 -0
- package/dist/src/conversation-manager/conversation-manager.js +59 -0
- package/dist/src/conversation-manager/conversation-manager.js.map +1 -0
- package/dist/src/conversation-manager/index.d.ts +1 -0
- package/dist/src/conversation-manager/index.d.ts.map +1 -1
- package/dist/src/conversation-manager/index.js +1 -0
- package/dist/src/conversation-manager/index.js.map +1 -1
- package/dist/src/conversation-manager/null-conversation-manager.d.ts +12 -8
- package/dist/src/conversation-manager/null-conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/null-conversation-manager.js +13 -7
- package/dist/src/conversation-manager/null-conversation-manager.js.map +1 -1
- package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +28 -19
- package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js +57 -42
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
- package/dist/src/errors.d.ts +8 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +11 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/hooks/__tests__/events.test.js +387 -0
- package/dist/src/hooks/__tests__/events.test.js.map +1 -1
- package/dist/src/hooks/__tests__/registry.test.js +10 -154
- package/dist/src/hooks/__tests__/registry.test.js.map +1 -1
- package/dist/src/hooks/events.d.ts +148 -44
- package/dist/src/hooks/events.d.ts.map +1 -1
- package/dist/src/hooks/events.js +148 -11
- package/dist/src/hooks/events.js.map +1 -1
- package/dist/src/hooks/index.d.ts +3 -3
- package/dist/src/hooks/index.d.ts.map +1 -1
- package/dist/src/hooks/index.js +2 -2
- package/dist/src/hooks/registry.d.ts +1 -32
- package/dist/src/hooks/registry.d.ts.map +1 -1
- package/dist/src/hooks/registry.js +1 -47
- package/dist/src/hooks/registry.js.map +1 -1
- package/dist/src/hooks/types.d.ts +0 -31
- package/dist/src/hooks/types.d.ts.map +1 -1
- package/dist/src/index.d.ts +14 -13
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -9
- package/dist/src/index.js.map +1 -1
- package/dist/src/mime.d.ts +24 -0
- package/dist/src/mime.d.ts.map +1 -0
- package/dist/src/mime.js +82 -0
- package/dist/src/mime.js.map +1 -0
- package/dist/src/models/__tests__/anthropic.test.js +79 -3
- package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
- package/dist/src/models/__tests__/bedrock.test.js +1858 -627
- package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
- package/dist/src/models/__tests__/google.test.d.ts +2 -0
- package/dist/src/models/__tests__/google.test.d.ts.map +1 -0
- package/dist/src/models/__tests__/{gemini.test.js → google.test.js} +155 -22
- package/dist/src/models/__tests__/google.test.js.map +1 -0
- package/dist/src/models/__tests__/model.test.js +25 -0
- package/dist/src/models/__tests__/model.test.js.map +1 -1
- package/dist/src/models/__tests__/openai.test.js +255 -96
- package/dist/src/models/__tests__/openai.test.js.map +1 -1
- package/dist/src/models/anthropic.d.ts.map +1 -1
- package/dist/src/models/anthropic.js +14 -14
- package/dist/src/models/anthropic.js.map +1 -1
- package/dist/src/models/bedrock.d.ts +67 -13
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +207 -28
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/{gemini → google}/adapters.d.ts +3 -3
- package/dist/src/models/{gemini → google}/adapters.d.ts.map +1 -1
- package/dist/src/models/{gemini → google}/adapters.js +66 -15
- package/dist/src/models/google/adapters.js.map +1 -0
- package/dist/src/models/{gemini → google}/errors.d.ts +7 -7
- package/dist/src/models/google/errors.d.ts.map +1 -0
- package/dist/src/models/{gemini → google}/errors.js +11 -5
- package/dist/src/models/google/errors.js.map +1 -0
- package/dist/src/models/google/index.d.ts +15 -0
- package/dist/src/models/google/index.d.ts.map +1 -0
- package/dist/src/models/google/index.js +15 -0
- package/dist/src/models/google/index.js.map +1 -0
- package/dist/src/models/{gemini → google}/model.d.ts +18 -18
- package/dist/src/models/{gemini → google}/model.d.ts.map +1 -1
- package/dist/src/models/{gemini → google}/model.js +22 -19
- package/dist/src/models/google/model.js.map +1 -0
- package/dist/src/models/{gemini → google}/types.d.ts +9 -9
- package/dist/src/models/{gemini → google}/types.d.ts.map +1 -1
- package/dist/src/models/google/types.js +5 -0
- package/dist/src/models/google/types.js.map +1 -0
- package/dist/src/models/model.d.ts +12 -0
- package/dist/src/models/model.d.ts.map +1 -1
- package/dist/src/models/model.js +6 -10
- package/dist/src/models/model.js.map +1 -1
- package/dist/src/models/openai.d.ts +44 -11
- package/dist/src/models/openai.d.ts.map +1 -1
- package/dist/src/models/openai.js +133 -79
- package/dist/src/models/openai.js.map +1 -1
- package/dist/src/models/streaming.d.ts +18 -0
- package/dist/src/models/streaming.d.ts.map +1 -1
- package/dist/src/models/streaming.js +29 -0
- package/dist/src/models/streaming.js.map +1 -1
- package/dist/src/multiagent/__tests__/events.test.js +201 -7
- package/dist/src/multiagent/__tests__/events.test.js.map +1 -1
- package/dist/src/multiagent/__tests__/graph.test.js +28 -13
- package/dist/src/multiagent/__tests__/graph.test.js.map +1 -1
- package/dist/src/multiagent/__tests__/graph.tracer.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/graph.tracer.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/graph.tracer.test.js +204 -0
- package/dist/src/multiagent/__tests__/graph.tracer.test.js.map +1 -0
- package/dist/src/multiagent/__tests__/nodes.test.js +76 -15
- package/dist/src/multiagent/__tests__/nodes.test.js.map +1 -1
- package/dist/src/multiagent/__tests__/swarm.test.js +67 -16
- package/dist/src/multiagent/__tests__/swarm.test.js.map +1 -1
- package/dist/src/multiagent/__tests__/swarm.tracer.test.d.ts +2 -0
- package/dist/src/multiagent/__tests__/swarm.tracer.test.d.ts.map +1 -0
- package/dist/src/multiagent/__tests__/swarm.tracer.test.js +235 -0
- package/dist/src/multiagent/__tests__/swarm.tracer.test.js.map +1 -0
- package/dist/src/multiagent/events.d.ts +62 -14
- package/dist/src/multiagent/events.d.ts.map +1 -1
- package/dist/src/multiagent/events.js +45 -3
- package/dist/src/multiagent/events.js.map +1 -1
- package/dist/src/multiagent/graph.d.ts +25 -11
- package/dist/src/multiagent/graph.d.ts.map +1 -1
- package/dist/src/multiagent/graph.js +76 -44
- package/dist/src/multiagent/graph.js.map +1 -1
- package/dist/src/multiagent/index.d.ts +4 -3
- package/dist/src/multiagent/index.d.ts.map +1 -1
- package/dist/src/multiagent/index.js.map +1 -1
- package/dist/src/multiagent/multiagent.d.ts +41 -0
- package/dist/src/multiagent/multiagent.d.ts.map +1 -0
- package/dist/src/multiagent/multiagent.js +2 -0
- package/dist/src/multiagent/multiagent.js.map +1 -0
- package/dist/src/multiagent/nodes.d.ts +35 -24
- package/dist/src/multiagent/nodes.d.ts.map +1 -1
- package/dist/src/multiagent/nodes.js +50 -23
- package/dist/src/multiagent/nodes.js.map +1 -1
- package/dist/src/multiagent/plugins.d.ts +70 -0
- package/dist/src/multiagent/plugins.d.ts.map +1 -0
- package/dist/src/multiagent/plugins.js +70 -0
- package/dist/src/multiagent/plugins.js.map +1 -0
- package/dist/src/multiagent/state.d.ts +10 -5
- package/dist/src/multiagent/state.d.ts.map +1 -1
- package/dist/src/multiagent/state.js +20 -6
- package/dist/src/multiagent/state.js.map +1 -1
- package/dist/src/multiagent/swarm.d.ts +41 -17
- package/dist/src/multiagent/swarm.d.ts.map +1 -1
- package/dist/src/multiagent/swarm.js +101 -42
- package/dist/src/multiagent/swarm.js.map +1 -1
- package/dist/src/plugins/__tests__/plugin.test.d.ts +2 -0
- package/dist/src/plugins/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/src/plugins/__tests__/plugin.test.js +114 -0
- package/dist/src/plugins/__tests__/plugin.test.js.map +1 -0
- package/dist/src/plugins/__tests__/registry.test.d.ts +2 -0
- package/dist/src/plugins/__tests__/registry.test.d.ts.map +1 -0
- package/dist/src/plugins/__tests__/registry.test.js +147 -0
- package/dist/src/plugins/__tests__/registry.test.js.map +1 -0
- package/dist/src/plugins/index.d.ts +30 -0
- package/dist/src/plugins/index.d.ts.map +1 -0
- package/dist/src/plugins/index.js +30 -0
- package/dist/src/plugins/index.js.map +1 -0
- package/dist/src/plugins/plugin.d.ts +74 -0
- package/dist/src/plugins/plugin.d.ts.map +1 -0
- package/dist/src/plugins/plugin.js +8 -0
- package/dist/src/plugins/plugin.js.map +1 -0
- package/dist/src/plugins/registry.d.ts +25 -0
- package/dist/src/plugins/registry.d.ts.map +1 -0
- package/dist/src/plugins/registry.js +41 -0
- package/dist/src/plugins/registry.js.map +1 -0
- package/dist/src/session/__tests__/session-manager.test.js +110 -92
- package/dist/src/session/__tests__/session-manager.test.js.map +1 -1
- package/dist/src/session/index.d.ts +0 -1
- package/dist/src/session/index.d.ts.map +1 -1
- package/dist/src/session/index.js +0 -1
- package/dist/src/session/index.js.map +1 -1
- package/dist/src/session/session-manager.d.ts +11 -8
- package/dist/src/session/session-manager.d.ts.map +1 -1
- package/dist/src/session/session-manager.js +24 -16
- package/dist/src/session/session-manager.js.map +1 -1
- package/dist/src/session/storage.d.ts +1 -1
- package/dist/src/session/storage.d.ts.map +1 -1
- package/dist/src/session/types.d.ts +2 -2
- package/dist/src/session/types.d.ts.map +1 -1
- package/dist/src/{app-state.d.ts → state-store.d.ts} +11 -11
- package/dist/src/state-store.d.ts.map +1 -0
- package/dist/src/{app-state.js → state-store.js} +8 -7
- package/dist/src/state-store.js.map +1 -0
- package/dist/src/telemetry/__tests__/config.test.js +24 -0
- package/dist/src/telemetry/__tests__/config.test.js.map +1 -1
- package/dist/src/telemetry/__tests__/config.test.node.js +56 -0
- package/dist/src/telemetry/__tests__/config.test.node.js.map +1 -1
- package/dist/src/telemetry/__tests__/local-trace.test.d.ts +2 -0
- package/dist/src/telemetry/__tests__/local-trace.test.d.ts.map +1 -0
- package/dist/src/telemetry/__tests__/local-trace.test.js +158 -0
- package/dist/src/telemetry/__tests__/local-trace.test.js.map +1 -0
- package/dist/src/telemetry/__tests__/meter.test.js +176 -9
- package/dist/src/telemetry/__tests__/meter.test.js.map +1 -1
- package/dist/src/telemetry/__tests__/tracer.test.node.js +151 -2
- package/dist/src/telemetry/__tests__/tracer.test.node.js.map +1 -1
- package/dist/src/telemetry/config.d.ts +72 -12
- package/dist/src/telemetry/config.d.ts.map +1 -1
- package/dist/src/telemetry/config.js +102 -25
- package/dist/src/telemetry/config.js.map +1 -1
- package/dist/src/telemetry/index.d.ts +10 -7
- package/dist/src/telemetry/index.d.ts.map +1 -1
- package/dist/src/telemetry/index.js +9 -6
- package/dist/src/telemetry/index.js.map +1 -1
- package/dist/src/telemetry/meter.d.ts +23 -17
- package/dist/src/telemetry/meter.d.ts.map +1 -1
- package/dist/src/telemetry/meter.js +86 -41
- package/dist/src/telemetry/meter.js.map +1 -1
- package/dist/src/telemetry/tracer.d.ts +134 -18
- package/dist/src/telemetry/tracer.d.ts.map +1 -1
- package/dist/src/telemetry/tracer.js +325 -38
- package/dist/src/telemetry/tracer.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +51 -0
- package/dist/src/telemetry/types.d.ts.map +1 -1
- package/dist/src/telemetry/utils.d.ts +10 -0
- package/dist/src/telemetry/utils.d.ts.map +1 -0
- package/dist/src/telemetry/utils.js +13 -0
- package/dist/src/telemetry/utils.js.map +1 -0
- package/dist/src/tools/__tests__/structured-output-tool.test.d.ts +2 -0
- package/dist/src/tools/__tests__/structured-output-tool.test.d.ts.map +1 -0
- package/dist/src/tools/__tests__/structured-output-tool.test.js +84 -0
- package/dist/src/tools/__tests__/structured-output-tool.test.js.map +1 -0
- package/dist/src/tools/__tests__/tool.test.js +22 -1
- package/dist/src/tools/__tests__/tool.test.js.map +1 -1
- package/dist/src/tools/function-tool.d.ts +11 -1
- package/dist/src/tools/function-tool.d.ts.map +1 -1
- package/dist/src/tools/function-tool.js +64 -3
- package/dist/src/tools/function-tool.js.map +1 -1
- package/dist/src/tools/structured-output-tool.d.ts +41 -0
- package/dist/src/tools/structured-output-tool.d.ts.map +1 -0
- package/dist/src/tools/structured-output-tool.js +82 -0
- package/dist/src/tools/structured-output-tool.js.map +1 -0
- package/dist/src/tools/tool.d.ts +2 -2
- package/dist/src/tools/tool.d.ts.map +1 -1
- package/dist/src/tools/zod-tool.js +1 -1
- package/dist/src/tools/zod-tool.js.map +1 -1
- package/dist/src/{utils/zod.d.ts → tools/zod-utils.d.ts} +1 -1
- package/dist/src/tools/zod-utils.d.ts.map +1 -0
- package/dist/src/{utils/zod.js → tools/zod-utils.js} +1 -1
- package/dist/src/tools/zod-utils.js.map +1 -0
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/__tests__/agent.test.js +127 -0
- package/dist/src/types/__tests__/agent.test.js.map +1 -1
- package/dist/src/types/__tests__/media.test.js +22 -16
- package/dist/src/types/__tests__/media.test.js.map +1 -1
- package/dist/src/types/agent.d.ts +101 -7
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js +26 -0
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/media.d.ts +27 -30
- package/dist/src/types/media.d.ts.map +1 -1
- package/dist/src/types/media.js +15 -56
- package/dist/src/types/media.js.map +1 -1
- package/dist/src/types/messages.d.ts +18 -4
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js +22 -26
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/types/serializable.d.ts +34 -4
- package/dist/src/types/serializable.d.ts.map +1 -1
- package/dist/src/types/serializable.js +31 -2
- package/dist/src/types/serializable.js.map +1 -1
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +17 -4
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
- package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
- package/dist/src/vended-tools/bash/bash.js +16 -14
- package/dist/src/vended-tools/bash/bash.js.map +1 -1
- package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.d.ts.map +1 -0
- package/dist/src/vended-tools/{file_editor → file-editor}/__tests__/file-editor.test.node.js +11 -4
- package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +1 -0
- package/dist/src/vended-tools/{file_editor → file-editor}/file-editor.d.ts +1 -1
- package/dist/src/vended-tools/{file_editor → file-editor}/file-editor.d.ts.map +1 -1
- package/dist/src/vended-tools/{file_editor → file-editor}/file-editor.js +2 -2
- package/dist/src/vended-tools/{file_editor → file-editor}/file-editor.js.map +1 -1
- package/dist/src/vended-tools/{file_editor → file-editor}/index.d.ts.map +1 -1
- package/dist/src/vended-tools/file-editor/index.js.map +1 -0
- package/dist/src/vended-tools/{file_editor → file-editor}/types.d.ts.map +1 -1
- package/dist/src/vended-tools/file-editor/types.js.map +1 -0
- package/dist/src/vended-tools/http-request/__tests__/http-request.test.d.ts.map +1 -0
- package/dist/src/vended-tools/{http_request → http-request}/__tests__/http-request.test.js.map +1 -1
- package/dist/src/vended-tools/{http_request → http-request}/http-request.d.ts.map +1 -1
- package/dist/src/vended-tools/{http_request → http-request}/http-request.js.map +1 -1
- package/dist/src/vended-tools/{http_request → http-request}/index.d.ts.map +1 -1
- package/dist/src/vended-tools/http-request/index.js.map +1 -0
- package/dist/src/vended-tools/{http_request → http-request}/types.d.ts.map +1 -1
- package/dist/src/vended-tools/http-request/types.js.map +1 -0
- package/dist/src/vended-tools/notebook/__tests__/notebook.test.js +5 -4
- package/dist/src/vended-tools/notebook/__tests__/notebook.test.js.map +1 -1
- package/dist/src/vended-tools/notebook/notebook.js +2 -2
- package/dist/src/vended-tools/notebook/notebook.js.map +1 -1
- package/package.json +63 -17
- package/dist/src/__fixtures__/mock-hook-provider.d.ts +0 -10
- package/dist/src/__fixtures__/mock-hook-provider.d.ts.map +0 -1
- package/dist/src/__fixtures__/mock-hook-provider.js.map +0 -1
- package/dist/src/__tests__/app-state.test.d.ts +0 -2
- package/dist/src/__tests__/app-state.test.d.ts.map +0 -1
- package/dist/src/__tests__/app-state.test.js.map +0 -1
- package/dist/src/agent/__tests__/agent.tracer.test.d.ts +0 -2
- package/dist/src/agent/__tests__/agent.tracer.test.d.ts.map +0 -1
- package/dist/src/agent/__tests__/agent.tracer.test.js.map +0 -1
- package/dist/src/app-state.d.ts.map +0 -1
- package/dist/src/app-state.js.map +0 -1
- package/dist/src/models/__tests__/gemini.test.d.ts +0 -2
- package/dist/src/models/__tests__/gemini.test.d.ts.map +0 -1
- package/dist/src/models/__tests__/gemini.test.js.map +0 -1
- package/dist/src/models/gemini/adapters.js.map +0 -1
- package/dist/src/models/gemini/errors.d.ts.map +0 -1
- package/dist/src/models/gemini/errors.js.map +0 -1
- package/dist/src/models/gemini/model.js.map +0 -1
- package/dist/src/models/gemini/types.js +0 -5
- package/dist/src/models/gemini/types.js.map +0 -1
- package/dist/src/multiagent/base.d.ts +0 -25
- package/dist/src/multiagent/base.d.ts.map +0 -1
- package/dist/src/multiagent/base.js +0 -2
- package/dist/src/multiagent/base.js.map +0 -1
- package/dist/src/structured-output/__tests__/context.test.d.ts +0 -2
- package/dist/src/structured-output/__tests__/context.test.d.ts.map +0 -1
- package/dist/src/structured-output/__tests__/context.test.js +0 -201
- package/dist/src/structured-output/__tests__/context.test.js.map +0 -1
- package/dist/src/structured-output/__tests__/exceptions.test.d.ts +0 -2
- package/dist/src/structured-output/__tests__/exceptions.test.d.ts.map +0 -1
- package/dist/src/structured-output/__tests__/exceptions.test.js +0 -103
- package/dist/src/structured-output/__tests__/exceptions.test.js.map +0 -1
- package/dist/src/structured-output/__tests__/tool.test.d.ts +0 -2
- package/dist/src/structured-output/__tests__/tool.test.d.ts.map +0 -1
- package/dist/src/structured-output/__tests__/tool.test.js +0 -256
- package/dist/src/structured-output/__tests__/tool.test.js.map +0 -1
- package/dist/src/structured-output/__tests__/utils.test.d.ts +0 -2
- package/dist/src/structured-output/__tests__/utils.test.d.ts.map +0 -1
- package/dist/src/structured-output/__tests__/utils.test.js +0 -183
- package/dist/src/structured-output/__tests__/utils.test.js.map +0 -1
- package/dist/src/structured-output/context.d.ts +0 -91
- package/dist/src/structured-output/context.d.ts.map +0 -1
- package/dist/src/structured-output/context.js +0 -112
- package/dist/src/structured-output/context.js.map +0 -1
- package/dist/src/structured-output/exceptions.d.ts +0 -18
- package/dist/src/structured-output/exceptions.d.ts.map +0 -1
- package/dist/src/structured-output/exceptions.js +0 -28
- package/dist/src/structured-output/exceptions.js.map +0 -1
- package/dist/src/structured-output/tool.d.ts +0 -33
- package/dist/src/structured-output/tool.d.ts.map +0 -1
- package/dist/src/structured-output/tool.js +0 -73
- package/dist/src/structured-output/tool.js.map +0 -1
- package/dist/src/structured-output/utils.d.ts +0 -23
- package/dist/src/structured-output/utils.d.ts.map +0 -1
- package/dist/src/structured-output/utils.js +0 -104
- package/dist/src/structured-output/utils.js.map +0 -1
- package/dist/src/utils/zod.d.ts.map +0 -1
- package/dist/src/utils/zod.js.map +0 -1
- package/dist/src/vended-tools/file_editor/__tests__/file-editor.test.node.d.ts.map +0 -1
- package/dist/src/vended-tools/file_editor/__tests__/file-editor.test.node.js.map +0 -1
- package/dist/src/vended-tools/file_editor/index.js.map +0 -1
- package/dist/src/vended-tools/file_editor/types.js.map +0 -1
- package/dist/src/vended-tools/http_request/__tests__/http-request.test.d.ts.map +0 -1
- package/dist/src/vended-tools/http_request/index.js.map +0 -1
- package/dist/src/vended-tools/http_request/types.js.map +0 -1
- /package/dist/src/vended-tools/{file_editor → file-editor}/__tests__/file-editor.test.node.d.ts +0 -0
- /package/dist/src/vended-tools/{file_editor → file-editor}/index.d.ts +0 -0
- /package/dist/src/vended-tools/{file_editor → file-editor}/index.js +0 -0
- /package/dist/src/vended-tools/{file_editor → file-editor}/types.d.ts +0 -0
- /package/dist/src/vended-tools/{file_editor → file-editor}/types.js +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/__tests__/http-request.test.d.ts +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/__tests__/http-request.test.js +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/http-request.d.ts +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/http-request.js +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/index.d.ts +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/index.js +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/types.d.ts +0 -0
- /package/dist/src/vended-tools/{http_request → http-request}/types.js +0 -0
|
@@ -5,6 +5,7 @@ import { OpenAIModel } from '../openai.js';
|
|
|
5
5
|
import { ContextWindowOverflowError, ModelThrottledError } from '../../errors.js';
|
|
6
6
|
import { collectIterator } from '../../__fixtures__/model-test-helpers.js';
|
|
7
7
|
import { Message, TextBlock, ToolUseBlock, ToolResultBlock, GuardContentBlock } from '../../types/messages.js';
|
|
8
|
+
import { ImageBlock, DocumentBlock, VideoBlock } from '../../types/media.js';
|
|
8
9
|
/**
|
|
9
10
|
* Helper to create a mock OpenAI client with streaming support
|
|
10
11
|
*/
|
|
@@ -42,22 +43,38 @@ describe('OpenAIModel', () => {
|
|
|
42
43
|
vi.unstubAllEnvs();
|
|
43
44
|
}
|
|
44
45
|
});
|
|
46
|
+
// Shared helper to create a mock OpenAI client that captures the request
|
|
47
|
+
const createMockClientWithCapture = (captureContainer) => {
|
|
48
|
+
return {
|
|
49
|
+
chat: {
|
|
50
|
+
completions: {
|
|
51
|
+
create: vi.fn(async (request) => {
|
|
52
|
+
captureContainer.request = request;
|
|
53
|
+
return (async function* () {
|
|
54
|
+
yield { choices: [{ delta: { role: 'assistant' }, index: 0 }] };
|
|
55
|
+
yield { choices: [{ finish_reason: 'stop', delta: {}, index: 0 }] };
|
|
56
|
+
})();
|
|
57
|
+
}),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
};
|
|
45
62
|
describe('constructor', () => {
|
|
46
63
|
it('creates an instance with required modelId', () => {
|
|
47
|
-
const provider = new OpenAIModel({ modelId: 'gpt-
|
|
64
|
+
const provider = new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4', apiKey: 'sk-test' });
|
|
48
65
|
const config = provider.getConfig();
|
|
49
|
-
expect(config.modelId).toBe('gpt-
|
|
66
|
+
expect(config.modelId).toBe('gpt-5.4');
|
|
50
67
|
});
|
|
51
68
|
it('uses custom model ID', () => {
|
|
52
69
|
const customModelId = 'gpt-3.5-turbo';
|
|
53
|
-
const provider = new OpenAIModel({ modelId: customModelId, apiKey: 'sk-test' });
|
|
70
|
+
const provider = new OpenAIModel({ api: 'chat', modelId: customModelId, apiKey: 'sk-test' });
|
|
54
71
|
expect(provider.getConfig()).toStrictEqual({
|
|
55
72
|
modelId: customModelId,
|
|
56
73
|
});
|
|
57
74
|
});
|
|
58
75
|
it('uses API key from constructor parameter', () => {
|
|
59
76
|
const apiKey = 'sk-explicit';
|
|
60
|
-
new OpenAIModel({ modelId: 'gpt-
|
|
77
|
+
new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4', apiKey });
|
|
61
78
|
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({
|
|
62
79
|
apiKey: apiKey,
|
|
63
80
|
}));
|
|
@@ -66,7 +83,7 @@ describe('OpenAIModel', () => {
|
|
|
66
83
|
if (isNode) {
|
|
67
84
|
it('uses API key from environment variable', () => {
|
|
68
85
|
vi.stubEnv('OPENAI_API_KEY', 'sk-from-env');
|
|
69
|
-
new OpenAIModel({ modelId: 'gpt-
|
|
86
|
+
new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4' });
|
|
70
87
|
// OpenAI client should be called without explicit apiKey (uses env var internally)
|
|
71
88
|
expect(OpenAI).toHaveBeenCalled();
|
|
72
89
|
});
|
|
@@ -76,7 +93,7 @@ describe('OpenAIModel', () => {
|
|
|
76
93
|
vi.stubEnv('OPENAI_API_KEY', 'sk-from-env');
|
|
77
94
|
}
|
|
78
95
|
const explicitKey = 'sk-explicit';
|
|
79
|
-
new OpenAIModel({ modelId: 'gpt-
|
|
96
|
+
new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4', apiKey: explicitKey });
|
|
80
97
|
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({
|
|
81
98
|
apiKey: explicitKey,
|
|
82
99
|
}));
|
|
@@ -85,11 +102,11 @@ describe('OpenAIModel', () => {
|
|
|
85
102
|
if (isNode) {
|
|
86
103
|
vi.stubEnv('OPENAI_API_KEY', '');
|
|
87
104
|
}
|
|
88
|
-
expect(() => new OpenAIModel({ modelId: 'gpt-
|
|
105
|
+
expect(() => new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4' })).toThrow("OpenAI API key is required. Provide it via the 'apiKey' option (string or function) or set the OPENAI_API_KEY environment variable.");
|
|
89
106
|
});
|
|
90
107
|
it('uses custom client configuration', () => {
|
|
91
108
|
const timeout = 30000;
|
|
92
|
-
new OpenAIModel({ modelId: 'gpt-
|
|
109
|
+
new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4', apiKey: 'sk-test', clientConfig: { timeout } });
|
|
93
110
|
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({
|
|
94
111
|
timeout: timeout,
|
|
95
112
|
}));
|
|
@@ -97,7 +114,7 @@ describe('OpenAIModel', () => {
|
|
|
97
114
|
it('uses provided client instance', () => {
|
|
98
115
|
vi.clearAllMocks();
|
|
99
116
|
const mockClient = {};
|
|
100
|
-
const provider = new OpenAIModel({
|
|
117
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
101
118
|
// Should not create a new OpenAI client
|
|
102
119
|
expect(OpenAI).not.toHaveBeenCalled();
|
|
103
120
|
expect(provider).toBeDefined();
|
|
@@ -106,7 +123,8 @@ describe('OpenAIModel', () => {
|
|
|
106
123
|
vi.clearAllMocks();
|
|
107
124
|
const mockClient = {};
|
|
108
125
|
new OpenAIModel({
|
|
109
|
-
|
|
126
|
+
api: 'chat',
|
|
127
|
+
modelId: 'gpt-5.4',
|
|
110
128
|
apiKey: 'sk-test',
|
|
111
129
|
client: mockClient,
|
|
112
130
|
clientConfig: { timeout: 30000 },
|
|
@@ -120,12 +138,13 @@ describe('OpenAIModel', () => {
|
|
|
120
138
|
vi.stubEnv('OPENAI_API_KEY', '');
|
|
121
139
|
}
|
|
122
140
|
const mockClient = {};
|
|
123
|
-
expect(() => new OpenAIModel({
|
|
141
|
+
expect(() => new OpenAIModel({ api: 'chat', client: mockClient })).not.toThrow();
|
|
124
142
|
});
|
|
125
143
|
it('accepts function-based API key', () => {
|
|
126
144
|
const apiKeyFn = vi.fn(async () => 'sk-dynamic');
|
|
127
145
|
new OpenAIModel({
|
|
128
|
-
|
|
146
|
+
api: 'chat',
|
|
147
|
+
modelId: 'gpt-5.4',
|
|
129
148
|
apiKey: apiKeyFn,
|
|
130
149
|
});
|
|
131
150
|
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({
|
|
@@ -138,7 +157,8 @@ describe('OpenAIModel', () => {
|
|
|
138
157
|
return 'sk-async-key';
|
|
139
158
|
};
|
|
140
159
|
new OpenAIModel({
|
|
141
|
-
|
|
160
|
+
api: 'chat',
|
|
161
|
+
modelId: 'gpt-5.4',
|
|
142
162
|
apiKey: apiKeyFn,
|
|
143
163
|
});
|
|
144
164
|
expect(OpenAI).toHaveBeenCalledWith(expect.objectContaining({
|
|
@@ -148,16 +168,17 @@ describe('OpenAIModel', () => {
|
|
|
148
168
|
});
|
|
149
169
|
describe('updateConfig', () => {
|
|
150
170
|
it('merges new config with existing config', () => {
|
|
151
|
-
const provider = new OpenAIModel({ modelId: 'gpt-
|
|
152
|
-
provider.updateConfig({ modelId: 'gpt-
|
|
171
|
+
const provider = new OpenAIModel({ api: 'chat', modelId: 'gpt-5.4', apiKey: 'sk-test', temperature: 0.5 });
|
|
172
|
+
provider.updateConfig({ modelId: 'gpt-5.4', temperature: 0.8, maxTokens: 2048 });
|
|
153
173
|
expect(provider.getConfig()).toStrictEqual({
|
|
154
|
-
modelId: 'gpt-
|
|
174
|
+
modelId: 'gpt-5.4',
|
|
155
175
|
temperature: 0.8,
|
|
156
176
|
maxTokens: 2048,
|
|
157
177
|
});
|
|
158
178
|
});
|
|
159
179
|
it('preserves fields not included in the update', () => {
|
|
160
180
|
const provider = new OpenAIModel({
|
|
181
|
+
api: 'chat',
|
|
161
182
|
apiKey: 'sk-test',
|
|
162
183
|
modelId: 'gpt-3.5-turbo',
|
|
163
184
|
temperature: 0.5,
|
|
@@ -174,13 +195,14 @@ describe('OpenAIModel', () => {
|
|
|
174
195
|
describe('getConfig', () => {
|
|
175
196
|
it('returns the current configuration', () => {
|
|
176
197
|
const provider = new OpenAIModel({
|
|
177
|
-
|
|
198
|
+
api: 'chat',
|
|
199
|
+
modelId: 'gpt-5.4',
|
|
178
200
|
apiKey: 'sk-test',
|
|
179
201
|
maxTokens: 1024,
|
|
180
202
|
temperature: 0.7,
|
|
181
203
|
});
|
|
182
204
|
expect(provider.getConfig()).toStrictEqual({
|
|
183
|
-
modelId: 'gpt-
|
|
205
|
+
modelId: 'gpt-5.4',
|
|
184
206
|
maxTokens: 1024,
|
|
185
207
|
temperature: 0.7,
|
|
186
208
|
});
|
|
@@ -190,7 +212,7 @@ describe('OpenAIModel', () => {
|
|
|
190
212
|
describe('validation', () => {
|
|
191
213
|
it('throws error when messages array is empty', async () => {
|
|
192
214
|
const mockClient = createMockClient(async function* () { });
|
|
193
|
-
const provider = new OpenAIModel({
|
|
215
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
194
216
|
await expect(async () => {
|
|
195
217
|
await collectIterator(provider.stream([]));
|
|
196
218
|
}).rejects.toThrow('At least one message is required');
|
|
@@ -204,7 +226,7 @@ describe('OpenAIModel', () => {
|
|
|
204
226
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
205
227
|
};
|
|
206
228
|
});
|
|
207
|
-
const provider = new OpenAIModel({
|
|
229
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
208
230
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
209
231
|
// System prompt that's only whitespace should not be sent
|
|
210
232
|
const events = await collectIterator(provider.stream(messages, { systemPrompt: ' ' }));
|
|
@@ -215,7 +237,8 @@ describe('OpenAIModel', () => {
|
|
|
215
237
|
it('throws error for streaming with n > 1', async () => {
|
|
216
238
|
const mockClient = createMockClient(async function* () { });
|
|
217
239
|
const provider = new OpenAIModel({
|
|
218
|
-
|
|
240
|
+
api: 'chat',
|
|
241
|
+
modelId: 'gpt-5.4',
|
|
219
242
|
client: mockClient,
|
|
220
243
|
params: { n: 2 },
|
|
221
244
|
});
|
|
@@ -228,7 +251,7 @@ describe('OpenAIModel', () => {
|
|
|
228
251
|
});
|
|
229
252
|
it('throws error for tool spec without name or description', async () => {
|
|
230
253
|
const mockClient = createMockClient(async function* () { });
|
|
231
|
-
const provider = new OpenAIModel({
|
|
254
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
232
255
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
233
256
|
await expect(async () => {
|
|
234
257
|
for await (const _ of provider.stream(messages, {
|
|
@@ -240,7 +263,7 @@ describe('OpenAIModel', () => {
|
|
|
240
263
|
});
|
|
241
264
|
it('throws error for empty tool result content', async () => {
|
|
242
265
|
const mockClient = createMockClient(async function* () { });
|
|
243
|
-
const provider = new OpenAIModel({
|
|
266
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
244
267
|
const messages = [
|
|
245
268
|
new Message({
|
|
246
269
|
role: 'user',
|
|
@@ -268,7 +291,7 @@ describe('OpenAIModel', () => {
|
|
|
268
291
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
269
292
|
};
|
|
270
293
|
});
|
|
271
|
-
const provider = new OpenAIModel({
|
|
294
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
272
295
|
const messages = [
|
|
273
296
|
new Message({ role: 'user', content: [new TextBlock('Run tool')] }),
|
|
274
297
|
new Message({
|
|
@@ -300,7 +323,7 @@ describe('OpenAIModel', () => {
|
|
|
300
323
|
});
|
|
301
324
|
it('throws error for circular reference in tool input', async () => {
|
|
302
325
|
const mockClient = createMockClient(async function* () { });
|
|
303
|
-
const provider = new OpenAIModel({
|
|
326
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
304
327
|
const circular = { a: 1 };
|
|
305
328
|
circular.self = circular;
|
|
306
329
|
const messages = [
|
|
@@ -339,7 +362,7 @@ describe('OpenAIModel', () => {
|
|
|
339
362
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
340
363
|
};
|
|
341
364
|
});
|
|
342
|
-
const provider = new OpenAIModel({
|
|
365
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
343
366
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
344
367
|
const events = await collectIterator(provider.stream(messages));
|
|
345
368
|
// Now includes complete content block lifecycle: start, deltas, stop
|
|
@@ -375,7 +398,7 @@ describe('OpenAIModel', () => {
|
|
|
375
398
|
usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 },
|
|
376
399
|
};
|
|
377
400
|
});
|
|
378
|
-
const provider = new OpenAIModel({
|
|
401
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
379
402
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
380
403
|
const events = await collectIterator(provider.stream(messages));
|
|
381
404
|
const metadataEvent = events.find((e) => e.type === 'modelMetadataEvent');
|
|
@@ -402,7 +425,7 @@ describe('OpenAIModel', () => {
|
|
|
402
425
|
usage: {}, // Empty usage object
|
|
403
426
|
};
|
|
404
427
|
});
|
|
405
|
-
const provider = new OpenAIModel({
|
|
428
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
406
429
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
407
430
|
const events = await collectIterator(provider.stream(messages));
|
|
408
431
|
const metadataEvent = events.find((e) => e.type === 'modelMetadataEvent');
|
|
@@ -431,7 +454,7 @@ describe('OpenAIModel', () => {
|
|
|
431
454
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
432
455
|
};
|
|
433
456
|
});
|
|
434
|
-
const provider = new OpenAIModel({
|
|
457
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
435
458
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
436
459
|
const events = await collectIterator(provider.stream(messages));
|
|
437
460
|
// Should not emit event for empty content
|
|
@@ -451,7 +474,7 @@ describe('OpenAIModel', () => {
|
|
|
451
474
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
452
475
|
};
|
|
453
476
|
});
|
|
454
|
-
const provider = new OpenAIModel({
|
|
477
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
455
478
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
456
479
|
// Suppress console.warn for this test
|
|
457
480
|
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
@@ -508,7 +531,7 @@ describe('OpenAIModel', () => {
|
|
|
508
531
|
choices: [{ finish_reason: 'tool_calls', delta: {}, index: 0 }],
|
|
509
532
|
};
|
|
510
533
|
});
|
|
511
|
-
const provider = new OpenAIModel({
|
|
534
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
512
535
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Calculate 2+2')] })];
|
|
513
536
|
const events = await collectIterator(provider.stream(messages));
|
|
514
537
|
// Verify key events in sequence
|
|
@@ -583,7 +606,7 @@ describe('OpenAIModel', () => {
|
|
|
583
606
|
choices: [{ finish_reason: 'tool_calls', delta: {}, index: 0 }],
|
|
584
607
|
};
|
|
585
608
|
});
|
|
586
|
-
const provider = new OpenAIModel({
|
|
609
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
587
610
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
588
611
|
const events = await collectIterator(provider.stream(messages));
|
|
589
612
|
// Should emit stop events for both tool calls
|
|
@@ -618,7 +641,7 @@ describe('OpenAIModel', () => {
|
|
|
618
641
|
choices: [{ finish_reason: 'stop', delta: {}, index: 0 }],
|
|
619
642
|
};
|
|
620
643
|
});
|
|
621
|
-
const provider = new OpenAIModel({
|
|
644
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
622
645
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
623
646
|
// Suppress console.warn for this test
|
|
624
647
|
vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
@@ -658,7 +681,7 @@ describe('OpenAIModel', () => {
|
|
|
658
681
|
yield { choices: [{ delta: { tool_calls: [{ index: 0, function: { arguments: '20}' } }] }, index: 0 }] };
|
|
659
682
|
yield { choices: [{ finish_reason: 'tool_calls', delta: {}, index: 0 }] };
|
|
660
683
|
});
|
|
661
|
-
const provider = new OpenAIModel({
|
|
684
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
662
685
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
663
686
|
const events = await collectIterator(provider.stream(messages));
|
|
664
687
|
// Extract and concatenate all tool input deltas
|
|
@@ -696,7 +719,7 @@ describe('OpenAIModel', () => {
|
|
|
696
719
|
};
|
|
697
720
|
yield { choices: [{ finish_reason: 'tool_calls', delta: {}, index: 0 }] };
|
|
698
721
|
});
|
|
699
|
-
const provider = new OpenAIModel({
|
|
722
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
700
723
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Calculate 2+2')] })];
|
|
701
724
|
const events = await collectIterator(provider.stream(messages));
|
|
702
725
|
// Should have text deltas followed by tool events
|
|
@@ -732,7 +755,7 @@ describe('OpenAIModel', () => {
|
|
|
732
755
|
choices: [{ finish_reason: openai, delta: {}, index: 0 }],
|
|
733
756
|
};
|
|
734
757
|
});
|
|
735
|
-
const provider = new OpenAIModel({
|
|
758
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
736
759
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
737
760
|
const events = await collectIterator(provider.stream(messages));
|
|
738
761
|
const stopEvent = events.find((e) => e.type === 'modelMessageStopEvent');
|
|
@@ -749,7 +772,7 @@ describe('OpenAIModel', () => {
|
|
|
749
772
|
choices: [{ finish_reason: 'new_unknown_reason', delta: {}, index: 0 }],
|
|
750
773
|
};
|
|
751
774
|
});
|
|
752
|
-
const provider = new OpenAIModel({
|
|
775
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
753
776
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
754
777
|
const events = await collectIterator(provider.stream(messages));
|
|
755
778
|
// Should convert unknown stop reason to camelCase
|
|
@@ -780,7 +803,8 @@ describe('OpenAIModel', () => {
|
|
|
780
803
|
},
|
|
781
804
|
};
|
|
782
805
|
const provider = new OpenAIModel({
|
|
783
|
-
|
|
806
|
+
api: 'chat',
|
|
807
|
+
modelId: 'gpt-5.4',
|
|
784
808
|
client: mockClient,
|
|
785
809
|
temperature: 0.7,
|
|
786
810
|
maxTokens: 1000,
|
|
@@ -802,7 +826,7 @@ describe('OpenAIModel', () => {
|
|
|
802
826
|
expect(callCount).toBe(1);
|
|
803
827
|
expect(capturedRequest).toBeDefined();
|
|
804
828
|
expect(capturedRequest).toEqual({
|
|
805
|
-
model: 'gpt-
|
|
829
|
+
model: 'gpt-5.4',
|
|
806
830
|
stream: true,
|
|
807
831
|
stream_options: { include_usage: true },
|
|
808
832
|
temperature: 0.7,
|
|
@@ -826,26 +850,10 @@ describe('OpenAIModel', () => {
|
|
|
826
850
|
});
|
|
827
851
|
});
|
|
828
852
|
describe('systemPrompt handling', () => {
|
|
829
|
-
// Create mock client factory that captures request in provided container
|
|
830
|
-
const createMockClientWithCapture = (captureContainer) => {
|
|
831
|
-
return {
|
|
832
|
-
chat: {
|
|
833
|
-
completions: {
|
|
834
|
-
create: vi.fn(async (request) => {
|
|
835
|
-
captureContainer.request = request;
|
|
836
|
-
return (async function* () {
|
|
837
|
-
yield { choices: [{ delta: { role: 'assistant' }, index: 0 }] };
|
|
838
|
-
yield { choices: [{ finish_reason: 'stop', delta: {}, index: 0 }] };
|
|
839
|
-
})();
|
|
840
|
-
}),
|
|
841
|
-
},
|
|
842
|
-
},
|
|
843
|
-
};
|
|
844
|
-
};
|
|
845
853
|
it('formats array system prompt with text blocks only', async () => {
|
|
846
854
|
const captured = { request: null };
|
|
847
855
|
const mockClient = createMockClientWithCapture(captured);
|
|
848
|
-
const provider = new OpenAIModel({
|
|
856
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
849
857
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
850
858
|
await collectIterator(provider.stream(messages, {
|
|
851
859
|
systemPrompt: [
|
|
@@ -863,7 +871,7 @@ describe('OpenAIModel', () => {
|
|
|
863
871
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
864
872
|
const captured = { request: null };
|
|
865
873
|
const mockClient = createMockClientWithCapture(captured);
|
|
866
|
-
const provider = new OpenAIModel({
|
|
874
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
867
875
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
868
876
|
collectIterator(provider.stream(messages, {
|
|
869
877
|
systemPrompt: [
|
|
@@ -885,7 +893,7 @@ describe('OpenAIModel', () => {
|
|
|
885
893
|
it('handles empty array system prompt', async () => {
|
|
886
894
|
const captured = { request: null };
|
|
887
895
|
const mockClient = createMockClientWithCapture(captured);
|
|
888
|
-
const provider = new OpenAIModel({
|
|
896
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
889
897
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
890
898
|
await collectIterator(provider.stream(messages, {
|
|
891
899
|
systemPrompt: [],
|
|
@@ -897,7 +905,7 @@ describe('OpenAIModel', () => {
|
|
|
897
905
|
it('formats array system prompt with single text block', async () => {
|
|
898
906
|
const captured = { request: null };
|
|
899
907
|
const mockClient = createMockClientWithCapture(captured);
|
|
900
|
-
const provider = new OpenAIModel({
|
|
908
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
901
909
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
902
910
|
await collectIterator(provider.stream(messages, {
|
|
903
911
|
systemPrompt: [{ type: 'textBlock', text: 'You are a helpful assistant' }],
|
|
@@ -912,7 +920,7 @@ describe('OpenAIModel', () => {
|
|
|
912
920
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
913
921
|
const captured = { request: null };
|
|
914
922
|
const mockClient = createMockClientWithCapture(captured);
|
|
915
|
-
const provider = new OpenAIModel({
|
|
923
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
916
924
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
917
925
|
await collectIterator(provider.stream(messages, {
|
|
918
926
|
systemPrompt: [
|
|
@@ -940,7 +948,7 @@ describe('OpenAIModel', () => {
|
|
|
940
948
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
941
949
|
const captured = { request: null };
|
|
942
950
|
const mockClient = createMockClientWithCapture(captured);
|
|
943
|
-
const provider = new OpenAIModel({
|
|
951
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
944
952
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
945
953
|
await collectIterator(provider.stream(messages, {
|
|
946
954
|
systemPrompt: [
|
|
@@ -969,7 +977,7 @@ describe('OpenAIModel', () => {
|
|
|
969
977
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
970
978
|
const captured = { request: null };
|
|
971
979
|
const mockClient = createMockClientWithCapture(captured);
|
|
972
|
-
const provider = new OpenAIModel({
|
|
980
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
973
981
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hello')] })];
|
|
974
982
|
await collectIterator(provider.stream(messages, {
|
|
975
983
|
systemPrompt: [
|
|
@@ -991,27 +999,11 @@ describe('OpenAIModel', () => {
|
|
|
991
999
|
});
|
|
992
1000
|
});
|
|
993
1001
|
describe('guard content in messages', () => {
|
|
994
|
-
// Create mock client factory that captures request in provided container
|
|
995
|
-
const createMockClientWithCapture = (captureContainer) => {
|
|
996
|
-
return {
|
|
997
|
-
chat: {
|
|
998
|
-
completions: {
|
|
999
|
-
create: vi.fn(async (request) => {
|
|
1000
|
-
captureContainer.request = request;
|
|
1001
|
-
return (async function* () {
|
|
1002
|
-
yield { choices: [{ delta: { role: 'assistant' }, index: 0 }] };
|
|
1003
|
-
yield { choices: [{ finish_reason: 'stop', delta: {}, index: 0 }] };
|
|
1004
|
-
})();
|
|
1005
|
-
}),
|
|
1006
|
-
},
|
|
1007
|
-
},
|
|
1008
|
-
};
|
|
1009
|
-
};
|
|
1010
1002
|
it('warns and filters guard content from user messages', async () => {
|
|
1011
1003
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
1012
1004
|
const captured = { request: null };
|
|
1013
1005
|
const mockClient = createMockClientWithCapture(captured);
|
|
1014
|
-
const provider = new OpenAIModel({
|
|
1006
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1015
1007
|
const messages = [
|
|
1016
1008
|
new Message({
|
|
1017
1009
|
role: 'user',
|
|
@@ -1029,7 +1021,7 @@ describe('OpenAIModel', () => {
|
|
|
1029
1021
|
];
|
|
1030
1022
|
await collectIterator(provider.stream(messages));
|
|
1031
1023
|
// Verify warning was logged
|
|
1032
|
-
expect(warnSpy).toHaveBeenCalledWith('
|
|
1024
|
+
expect(warnSpy).toHaveBeenCalledWith('block_type=<guardContentBlock> | unsupported content type in openai user message | skipping');
|
|
1033
1025
|
// Verify guard content filtered out
|
|
1034
1026
|
expect(captured.request).toBeDefined();
|
|
1035
1027
|
expect(captured.request.messages).toEqual([
|
|
@@ -1047,7 +1039,7 @@ describe('OpenAIModel', () => {
|
|
|
1047
1039
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
1048
1040
|
const captured = { request: null };
|
|
1049
1041
|
const mockClient = createMockClientWithCapture(captured);
|
|
1050
|
-
const provider = new OpenAIModel({
|
|
1042
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1051
1043
|
const imageBytes = new Uint8Array([1, 2, 3, 4]);
|
|
1052
1044
|
const messages = [
|
|
1053
1045
|
new Message({
|
|
@@ -1065,7 +1057,7 @@ describe('OpenAIModel', () => {
|
|
|
1065
1057
|
];
|
|
1066
1058
|
await collectIterator(provider.stream(messages));
|
|
1067
1059
|
// Verify warning was logged
|
|
1068
|
-
expect(warnSpy).toHaveBeenCalledWith('
|
|
1060
|
+
expect(warnSpy).toHaveBeenCalledWith('block_type=<guardContentBlock> | unsupported content type in openai user message | skipping');
|
|
1069
1061
|
// Verify guard content filtered out
|
|
1070
1062
|
expect(captured.request).toBeDefined();
|
|
1071
1063
|
expect(captured.request.messages).toEqual([
|
|
@@ -1077,7 +1069,7 @@ describe('OpenAIModel', () => {
|
|
|
1077
1069
|
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
1078
1070
|
const captured = { request: null };
|
|
1079
1071
|
const mockClient = createMockClientWithCapture(captured);
|
|
1080
|
-
const provider = new OpenAIModel({
|
|
1072
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1081
1073
|
const messages = [
|
|
1082
1074
|
new Message({
|
|
1083
1075
|
role: 'user',
|
|
@@ -1093,13 +1085,180 @@ describe('OpenAIModel', () => {
|
|
|
1093
1085
|
];
|
|
1094
1086
|
await collectIterator(provider.stream(messages));
|
|
1095
1087
|
// Verify warning was logged
|
|
1096
|
-
expect(warnSpy).toHaveBeenCalledWith('
|
|
1088
|
+
expect(warnSpy).toHaveBeenCalledWith('block_type=<guardContentBlock> | unsupported content type in openai user message | skipping');
|
|
1097
1089
|
// Verify no user message added (only guard content)
|
|
1098
1090
|
expect(captured.request).toBeDefined();
|
|
1099
1091
|
expect(captured.request.messages).toEqual([]);
|
|
1100
1092
|
warnSpy.mockRestore();
|
|
1101
1093
|
});
|
|
1102
1094
|
});
|
|
1095
|
+
describe('media blocks', () => {
|
|
1096
|
+
it('formats image block in user message as image_url with base64', async () => {
|
|
1097
|
+
const captured = { request: null };
|
|
1098
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1099
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1100
|
+
const imageBytes = new Uint8Array([72, 101, 108, 108, 111]);
|
|
1101
|
+
const messages = [
|
|
1102
|
+
new Message({
|
|
1103
|
+
role: 'user',
|
|
1104
|
+
content: [
|
|
1105
|
+
new TextBlock('What is in this image?'),
|
|
1106
|
+
new ImageBlock({ format: 'png', source: { bytes: imageBytes } }),
|
|
1107
|
+
],
|
|
1108
|
+
}),
|
|
1109
|
+
];
|
|
1110
|
+
await collectIterator(provider.stream(messages));
|
|
1111
|
+
const userMsg = captured.request.messages[0];
|
|
1112
|
+
expect(userMsg.role).toBe('user');
|
|
1113
|
+
expect(userMsg.content).toHaveLength(2);
|
|
1114
|
+
expect(userMsg.content[0]).toEqual({ type: 'text', text: 'What is in this image?' });
|
|
1115
|
+
expect(userMsg.content[1]).toEqual({
|
|
1116
|
+
type: 'image_url',
|
|
1117
|
+
image_url: { url: 'data:image/png;base64,SGVsbG8=' },
|
|
1118
|
+
});
|
|
1119
|
+
});
|
|
1120
|
+
it('formats image block in user message with URL source', async () => {
|
|
1121
|
+
const captured = { request: null };
|
|
1122
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1123
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1124
|
+
const messages = [
|
|
1125
|
+
new Message({
|
|
1126
|
+
role: 'user',
|
|
1127
|
+
content: [new ImageBlock({ format: 'jpeg', source: { url: 'https://example.com/img.jpg' } })],
|
|
1128
|
+
}),
|
|
1129
|
+
];
|
|
1130
|
+
await collectIterator(provider.stream(messages));
|
|
1131
|
+
const userMsg = captured.request.messages[0];
|
|
1132
|
+
expect(userMsg.content[0]).toEqual({
|
|
1133
|
+
type: 'image_url',
|
|
1134
|
+
image_url: { url: 'https://example.com/img.jpg' },
|
|
1135
|
+
});
|
|
1136
|
+
});
|
|
1137
|
+
it('formats document block with bytes source as file in user message', async () => {
|
|
1138
|
+
const captured = { request: null };
|
|
1139
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1140
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1141
|
+
const docBytes = new Uint8Array([1, 2, 3]);
|
|
1142
|
+
const messages = [
|
|
1143
|
+
new Message({
|
|
1144
|
+
role: 'user',
|
|
1145
|
+
content: [new DocumentBlock({ name: 'report.pdf', format: 'pdf', source: { bytes: docBytes } })],
|
|
1146
|
+
}),
|
|
1147
|
+
];
|
|
1148
|
+
await collectIterator(provider.stream(messages));
|
|
1149
|
+
const userMsg = captured.request.messages[0];
|
|
1150
|
+
expect(userMsg.content[0]).toEqual({
|
|
1151
|
+
type: 'file',
|
|
1152
|
+
file: { file_data: 'data:application/pdf;base64,AQID', filename: 'report.pdf' },
|
|
1153
|
+
});
|
|
1154
|
+
});
|
|
1155
|
+
it('splits image from tool result into separate user message', async () => {
|
|
1156
|
+
const captured = { request: null };
|
|
1157
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1158
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1159
|
+
const imageBytes = new Uint8Array([72, 101, 108, 108, 111]);
|
|
1160
|
+
const messages = [
|
|
1161
|
+
new Message({
|
|
1162
|
+
role: 'user',
|
|
1163
|
+
content: [
|
|
1164
|
+
new ToolResultBlock({
|
|
1165
|
+
toolUseId: 'tool-1',
|
|
1166
|
+
status: 'success',
|
|
1167
|
+
content: [
|
|
1168
|
+
new TextBlock('Screenshot captured'),
|
|
1169
|
+
new ImageBlock({ format: 'png', source: { bytes: imageBytes } }),
|
|
1170
|
+
],
|
|
1171
|
+
}),
|
|
1172
|
+
],
|
|
1173
|
+
}),
|
|
1174
|
+
];
|
|
1175
|
+
await collectIterator(provider.stream(messages));
|
|
1176
|
+
// Tool message with text only
|
|
1177
|
+
const toolMsg = captured.request.messages[0];
|
|
1178
|
+
expect(toolMsg.role).toBe('tool');
|
|
1179
|
+
expect(toolMsg.tool_call_id).toBe('tool-1');
|
|
1180
|
+
expect(toolMsg.content).toBe('Screenshot captured');
|
|
1181
|
+
// Separate user message with image
|
|
1182
|
+
const userMsg = captured.request.messages[1];
|
|
1183
|
+
expect(userMsg.role).toBe('user');
|
|
1184
|
+
expect(userMsg.content[0]).toEqual({
|
|
1185
|
+
type: 'image_url',
|
|
1186
|
+
image_url: { url: 'data:image/png;base64,SGVsbG8=' },
|
|
1187
|
+
});
|
|
1188
|
+
});
|
|
1189
|
+
it('injects placeholder text when tool result contains only images', async () => {
|
|
1190
|
+
const captured = { request: null };
|
|
1191
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1192
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1193
|
+
const messages = [
|
|
1194
|
+
new Message({
|
|
1195
|
+
role: 'user',
|
|
1196
|
+
content: [
|
|
1197
|
+
new ToolResultBlock({
|
|
1198
|
+
toolUseId: 'tool-1',
|
|
1199
|
+
status: 'success',
|
|
1200
|
+
content: [new ImageBlock({ format: 'png', source: { bytes: new Uint8Array([1]) } })],
|
|
1201
|
+
}),
|
|
1202
|
+
],
|
|
1203
|
+
}),
|
|
1204
|
+
];
|
|
1205
|
+
await collectIterator(provider.stream(messages));
|
|
1206
|
+
const toolMsg = captured.request.messages[0];
|
|
1207
|
+
expect(toolMsg.content).toContain('Tool successfully returned an image');
|
|
1208
|
+
});
|
|
1209
|
+
it('skips document block in tool result with warning', async () => {
|
|
1210
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
1211
|
+
const captured = { request: null };
|
|
1212
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1213
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1214
|
+
const messages = [
|
|
1215
|
+
new Message({
|
|
1216
|
+
role: 'user',
|
|
1217
|
+
content: [
|
|
1218
|
+
new ToolResultBlock({
|
|
1219
|
+
toolUseId: 'tool-1',
|
|
1220
|
+
status: 'success',
|
|
1221
|
+
content: [
|
|
1222
|
+
new TextBlock('result'),
|
|
1223
|
+
new DocumentBlock({ name: 'doc.pdf', format: 'pdf', source: { bytes: new Uint8Array([1]) } }),
|
|
1224
|
+
],
|
|
1225
|
+
}),
|
|
1226
|
+
],
|
|
1227
|
+
}),
|
|
1228
|
+
];
|
|
1229
|
+
await collectIterator(provider.stream(messages));
|
|
1230
|
+
const toolMsg = captured.request.messages[0];
|
|
1231
|
+
expect(toolMsg.content).toBe('result');
|
|
1232
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
1233
|
+
warnSpy.mockRestore();
|
|
1234
|
+
});
|
|
1235
|
+
it('skips video block in tool result with warning', async () => {
|
|
1236
|
+
const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => { });
|
|
1237
|
+
const captured = { request: null };
|
|
1238
|
+
const mockClient = createMockClientWithCapture(captured);
|
|
1239
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1240
|
+
const messages = [
|
|
1241
|
+
new Message({
|
|
1242
|
+
role: 'user',
|
|
1243
|
+
content: [
|
|
1244
|
+
new ToolResultBlock({
|
|
1245
|
+
toolUseId: 'tool-1',
|
|
1246
|
+
status: 'success',
|
|
1247
|
+
content: [
|
|
1248
|
+
new TextBlock('result'),
|
|
1249
|
+
new VideoBlock({ format: 'mp4', source: { bytes: new Uint8Array([1]) } }),
|
|
1250
|
+
],
|
|
1251
|
+
}),
|
|
1252
|
+
],
|
|
1253
|
+
}),
|
|
1254
|
+
];
|
|
1255
|
+
await collectIterator(provider.stream(messages));
|
|
1256
|
+
const toolMsg = captured.request.messages[0];
|
|
1257
|
+
expect(toolMsg.content).toBe('result');
|
|
1258
|
+
expect(warnSpy).toHaveBeenCalled();
|
|
1259
|
+
warnSpy.mockRestore();
|
|
1260
|
+
});
|
|
1261
|
+
});
|
|
1103
1262
|
describe('error handling', () => {
|
|
1104
1263
|
it('throws ContextWindowOverflowError for structured error with code', async () => {
|
|
1105
1264
|
const mockClient = {
|
|
@@ -1113,7 +1272,7 @@ describe('OpenAIModel', () => {
|
|
|
1113
1272
|
},
|
|
1114
1273
|
},
|
|
1115
1274
|
};
|
|
1116
|
-
const provider = new OpenAIModel({
|
|
1275
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1117
1276
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1118
1277
|
await expect(async () => {
|
|
1119
1278
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1131,7 +1290,7 @@ describe('OpenAIModel', () => {
|
|
|
1131
1290
|
},
|
|
1132
1291
|
},
|
|
1133
1292
|
};
|
|
1134
|
-
const provider = new OpenAIModel({
|
|
1293
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1135
1294
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1136
1295
|
await expect(async () => {
|
|
1137
1296
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1156,7 +1315,7 @@ describe('OpenAIModel', () => {
|
|
|
1156
1315
|
},
|
|
1157
1316
|
},
|
|
1158
1317
|
};
|
|
1159
|
-
const provider = new OpenAIModel({
|
|
1318
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1160
1319
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1161
1320
|
await expect(async () => {
|
|
1162
1321
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1174,7 +1333,7 @@ describe('OpenAIModel', () => {
|
|
|
1174
1333
|
},
|
|
1175
1334
|
},
|
|
1176
1335
|
};
|
|
1177
|
-
const provider = new OpenAIModel({
|
|
1336
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1178
1337
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1179
1338
|
await expect(async () => {
|
|
1180
1339
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1189,7 +1348,7 @@ describe('OpenAIModel', () => {
|
|
|
1189
1348
|
// Stream interruption
|
|
1190
1349
|
throw new Error('Network connection lost');
|
|
1191
1350
|
});
|
|
1192
|
-
const provider = new OpenAIModel({
|
|
1351
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1193
1352
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1194
1353
|
await expect(async () => {
|
|
1195
1354
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1209,7 +1368,7 @@ describe('OpenAIModel', () => {
|
|
|
1209
1368
|
},
|
|
1210
1369
|
},
|
|
1211
1370
|
};
|
|
1212
|
-
const provider = new OpenAIModel({
|
|
1371
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1213
1372
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1214
1373
|
await expect(async () => {
|
|
1215
1374
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1229,7 +1388,7 @@ describe('OpenAIModel', () => {
|
|
|
1229
1388
|
},
|
|
1230
1389
|
},
|
|
1231
1390
|
};
|
|
1232
|
-
const provider = new OpenAIModel({
|
|
1391
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1233
1392
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1234
1393
|
await expect(async () => {
|
|
1235
1394
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1247,7 +1406,7 @@ describe('OpenAIModel', () => {
|
|
|
1247
1406
|
},
|
|
1248
1407
|
},
|
|
1249
1408
|
};
|
|
1250
|
-
const provider = new OpenAIModel({
|
|
1409
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1251
1410
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1252
1411
|
await expect(async () => {
|
|
1253
1412
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1265,7 +1424,7 @@ describe('OpenAIModel', () => {
|
|
|
1265
1424
|
},
|
|
1266
1425
|
},
|
|
1267
1426
|
};
|
|
1268
|
-
const provider = new OpenAIModel({
|
|
1427
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1269
1428
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1270
1429
|
await expect(async () => {
|
|
1271
1430
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1274,7 +1433,7 @@ describe('OpenAIModel', () => {
|
|
|
1274
1433
|
}).rejects.toThrow(ModelThrottledError);
|
|
1275
1434
|
});
|
|
1276
1435
|
it('preserves original error as cause in ModelThrottledError', async () => {
|
|
1277
|
-
const originalError = new Error('Request too large for gpt-
|
|
1436
|
+
const originalError = new Error('Request too large for gpt-5.4 on tokens per min');
|
|
1278
1437
|
originalError.status = 429;
|
|
1279
1438
|
const mockClient = {
|
|
1280
1439
|
chat: {
|
|
@@ -1285,7 +1444,7 @@ describe('OpenAIModel', () => {
|
|
|
1285
1444
|
},
|
|
1286
1445
|
},
|
|
1287
1446
|
};
|
|
1288
|
-
const provider = new OpenAIModel({
|
|
1447
|
+
const provider = new OpenAIModel({ api: 'chat', client: mockClient });
|
|
1289
1448
|
const messages = [new Message({ role: 'user', content: [new TextBlock('Hi')] })];
|
|
1290
1449
|
try {
|
|
1291
1450
|
for await (const _ of provider.stream(messages)) {
|
|
@@ -1297,7 +1456,7 @@ describe('OpenAIModel', () => {
|
|
|
1297
1456
|
expect(error).toBeInstanceOf(ModelThrottledError);
|
|
1298
1457
|
const throttleError = error;
|
|
1299
1458
|
expect(throttleError.cause).toBe(originalError);
|
|
1300
|
-
expect(throttleError.message).toBe('Request too large for gpt-
|
|
1459
|
+
expect(throttleError.message).toBe('Request too large for gpt-5.4 on tokens per min');
|
|
1301
1460
|
}
|
|
1302
1461
|
});
|
|
1303
1462
|
});
|