@opencode-ai/ai 0.0.0-beta-17595 → 0.0.0-beta-17727

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.
Files changed (74) hide show
  1. package/README.md +17 -6
  2. package/dist/cache-policy.js +3 -5
  3. package/dist/protocols/anthropic-messages.d.ts +26 -28
  4. package/dist/protocols/anthropic-messages.js +21 -9
  5. package/dist/protocols/gemini.d.ts +5 -9
  6. package/dist/protocols/gemini.js +5 -4
  7. package/dist/protocols/open-responses.d.ts +200 -38
  8. package/dist/protocols/open-responses.js +115 -42
  9. package/dist/protocols/openai-chat.d.ts +17 -15
  10. package/dist/protocols/openai-chat.js +8 -2
  11. package/dist/protocols/openai-compatible-chat.d.ts +3 -3
  12. package/dist/protocols/openai-compatible-responses.d.ts +31 -5
  13. package/dist/protocols/openai-responses.d.ts +171 -33
  14. package/dist/protocols/openai-responses.js +4 -2
  15. package/dist/protocols/shared.d.ts +8 -14
  16. package/dist/protocols/shared.js +8 -14
  17. package/dist/protocols/utils/bedrock-cache.js +3 -4
  18. package/dist/protocols/utils/cache.js +3 -6
  19. package/dist/protocols/utils/open-responses-options.d.ts +49 -14
  20. package/dist/protocols/utils/open-responses-options.js +40 -22
  21. package/dist/protocols/utils/openai-options.d.ts +7 -5
  22. package/dist/protocols/utils/openai-options.js +3 -3
  23. package/dist/provider-package.d.ts +0 -5
  24. package/dist/providers/amazon-bedrock-mantle.d.ts +47 -19
  25. package/dist/providers/amazon-bedrock-mantle.js +0 -1
  26. package/dist/providers/amazon-bedrock.d.ts +3 -9
  27. package/dist/providers/amazon-bedrock.js +0 -1
  28. package/dist/providers/anthropic-compatible.d.ts +11 -11
  29. package/dist/providers/anthropic-compatible.js +0 -1
  30. package/dist/providers/anthropic.d.ts +12 -12
  31. package/dist/providers/anthropic.js +0 -1
  32. package/dist/providers/azure.d.ts +44 -16
  33. package/dist/providers/azure.js +0 -1
  34. package/dist/providers/cloudflare.d.ts +11 -11
  35. package/dist/providers/google-vertex-chat.d.ts +5 -5
  36. package/dist/providers/google-vertex-chat.js +0 -1
  37. package/dist/providers/google-vertex-messages.d.ts +11 -11
  38. package/dist/providers/google-vertex-messages.js +0 -1
  39. package/dist/providers/google-vertex-responses.d.ts +33 -7
  40. package/dist/providers/google-vertex-responses.js +1 -2
  41. package/dist/providers/google-vertex.d.ts +5 -7
  42. package/dist/providers/google-vertex.js +1 -2
  43. package/dist/providers/google.d.ts +4 -4
  44. package/dist/providers/google.js +0 -1
  45. package/dist/providers/open-responses-options.d.ts +3 -13
  46. package/dist/providers/openai-compatible-responses.d.ts +33 -7
  47. package/dist/providers/openai-compatible-responses.js +0 -1
  48. package/dist/providers/openai-compatible.d.ts +13 -12
  49. package/dist/providers/openai-compatible.js +1 -1
  50. package/dist/providers/openai-options.d.ts +2 -4
  51. package/dist/providers/openai-options.js +3 -3
  52. package/dist/providers/openai.d.ts +48 -20
  53. package/dist/providers/openai.js +0 -1
  54. package/dist/providers/openrouter.d.ts +16 -17
  55. package/dist/providers/openrouter.js +1 -2
  56. package/dist/providers/xai.d.ts +50 -24
  57. package/dist/providers/xai.js +1 -2
  58. package/dist/route/client.d.ts +2 -6
  59. package/dist/route/client.js +1 -2
  60. package/dist/route/framing.d.ts +2 -2
  61. package/dist/route/protocol.d.ts +1 -2
  62. package/dist/route/protocol.js +1 -2
  63. package/dist/schema/errors.js +2 -1
  64. package/dist/schema/events.d.ts +5 -3
  65. package/dist/schema/events.js +5 -2
  66. package/dist/schema/ids.d.ts +0 -13
  67. package/dist/schema/ids.js +0 -9
  68. package/dist/schema/messages.d.ts +7 -7
  69. package/dist/schema/messages.js +5 -2
  70. package/dist/schema/options.d.ts +6 -22
  71. package/dist/schema/options.js +6 -30
  72. package/dist/testing.d.ts +2 -1
  73. package/dist/testing.js +7 -2
  74. package/package.json +5 -5
@@ -63,8 +63,11 @@ const OpenResponsesFunctionCallOutput = Schema.Union([
63
63
  ]);
64
64
  export const InputItem = Schema.Union([
65
65
  Schema.Struct({ role: Schema.tag("system"), content: Schema.String }),
66
+ Schema.Struct({ role: Schema.tag("developer"), content: Schema.String }),
66
67
  Schema.Struct({ role: Schema.tag("user"), content: Schema.Array(OpenResponsesInputContent) }),
67
68
  Schema.Struct({
69
+ type: Schema.tag("message"),
70
+ id: Schema.optionalKey(Schema.String),
68
71
  role: Schema.tag("assistant"),
69
72
  content: Schema.Array(OpenResponsesOutputText),
70
73
  phase: Schema.optionalKey(MessagePhase),
@@ -73,6 +76,7 @@ export const InputItem = Schema.Union([
73
76
  OpenResponsesItemReference,
74
77
  Schema.Struct({
75
78
  type: Schema.tag("function_call"),
79
+ id: Schema.optionalKey(Schema.String),
76
80
  call_id: Schema.String,
77
81
  name: Schema.String,
78
82
  arguments: Schema.String,
@@ -93,6 +97,11 @@ export const Tool = Schema.Struct({
93
97
  export const ToolChoice = Schema.Union([
94
98
  Schema.Literals(["auto", "none", "required"]),
95
99
  Schema.Struct({ type: Schema.tag("function"), name: Schema.String }),
100
+ Schema.Struct({
101
+ type: Schema.tag("allowed_tools"),
102
+ mode: Schema.Literals(["auto", "none", "required"]),
103
+ tools: Schema.Array(Schema.Struct({ type: Schema.tag("function"), name: Schema.String })),
104
+ }),
96
105
  ]);
97
106
  // Fields shared between the HTTP body and the WebSocket `response.create`
98
107
  // message. The HTTP body adds `stream: true`; the WebSocket message adds
@@ -105,6 +114,13 @@ export const coreFields = {
105
114
  tools: optionalArray(Tool),
106
115
  tool_choice: Schema.optional(ToolChoice),
107
116
  store: Schema.optional(Schema.Boolean),
117
+ metadata: Schema.optional(Schema.Record(Schema.String, Schema.String)),
118
+ safety_identifier: Schema.optional(Schema.String),
119
+ stream_options: Schema.optional(Schema.Struct({
120
+ include_obfuscation: Schema.optional(Schema.Boolean),
121
+ })),
122
+ top_logprobs: Schema.optional(Schema.Int.check(Schema.isBetween({ minimum: 0, maximum: 20 }))),
123
+ truncation: Schema.optional(OpenResponsesOptions.TruncationSchema),
108
124
  service_tier: Schema.optional(OpenResponsesOptions.ServiceTierSchema),
109
125
  prompt_cache_key: Schema.optional(Schema.String),
110
126
  include: optionalArray(OpenResponsesOptions.ResponseIncludableSchema),
@@ -116,8 +132,12 @@ export const coreFields = {
116
132
  verbosity: Schema.optional(OpenResponsesOptions.TextVerbositySchema),
117
133
  })),
118
134
  max_output_tokens: Schema.optional(Schema.Number),
135
+ max_tool_calls: Schema.optional(Schema.Int),
136
+ parallel_tool_calls: Schema.optional(Schema.Boolean),
119
137
  temperature: Schema.optional(Schema.Number),
120
138
  top_p: Schema.optional(Schema.Number),
139
+ presence_penalty: Schema.optional(Schema.Number),
140
+ frequency_penalty: Schema.optional(Schema.Number),
121
141
  };
122
142
  const OpenResponsesBody = Schema.Struct({
123
143
  ...coreFields,
@@ -193,6 +213,19 @@ export const Event = Schema.StructWithRest(Schema.Struct({
193
213
  status_code: Schema.optional(Schema.Unknown),
194
214
  headers: Schema.optional(Schema.Unknown),
195
215
  }), [Schema.Record(Schema.String, Schema.Unknown)]);
216
+ const RefusalEvent = Schema.Union([
217
+ Schema.Struct({
218
+ type: Schema.tag("response.refusal.delta"),
219
+ item_id: Schema.String,
220
+ delta: Schema.String,
221
+ }),
222
+ Schema.Struct({
223
+ type: Schema.tag("response.refusal.done"),
224
+ item_id: Schema.String,
225
+ refusal: Schema.String,
226
+ }),
227
+ ]);
228
+ const isRefusalEvent = Schema.is(RefusalEvent);
196
229
  const BASE = { id: ADAPTER, name: NAME };
197
230
  // =============================================================================
198
231
  // Request Lowering
@@ -205,7 +238,7 @@ export const lowerTool = Effect.fn("OpenResponses.lowerTool")(function* (protoco
205
238
  name: tool.name,
206
239
  description: tool.description,
207
240
  parameters: ToolSchemaProjection.responses(inputSchema),
208
- // TODO: Read this from Responses tool options so direct LLM callers can opt into strict schemas.
241
+ // The common tool definition does not currently express Responses strict-schema policy.
209
242
  strict: false,
210
243
  };
211
244
  });
@@ -215,31 +248,39 @@ export const lowerToolChoice = (protocolName, toolChoice) => ProviderShared.matc
215
248
  required: () => "required",
216
249
  tool: (toolName) => ({ type: "function", name: toolName }),
217
250
  });
218
- const lowerToolCall = (part) => ({
219
- type: "function_call",
220
- call_id: part.id,
221
- name: part.name,
222
- arguments: ProviderShared.encodeJson(part.input),
223
- });
251
+ const itemID = (providerMetadata, providerMetadataKey) => {
252
+ const metadata = providerMetadata?.[providerMetadataKey];
253
+ return ProviderShared.isRecord(metadata) && typeof metadata.itemId === "string" && metadata.itemId.length > 0
254
+ ? metadata.itemId
255
+ : undefined;
256
+ };
257
+ const lowerToolCall = (part, providerMetadataKey) => {
258
+ const id = itemID(part.providerMetadata, providerMetadataKey);
259
+ return {
260
+ type: "function_call",
261
+ ...(id ? { id } : {}),
262
+ call_id: part.id,
263
+ name: part.name,
264
+ arguments: ProviderShared.encodeJson(part.input),
265
+ };
266
+ };
224
267
  const lowerReasoning = (part, providerMetadataKey) => {
225
268
  const metadata = part.providerMetadata?.[providerMetadataKey];
226
- if (!ProviderShared.isRecord(metadata) || typeof metadata.itemId !== "string" || metadata.itemId.length === 0)
269
+ const id = itemID(part.providerMetadata, providerMetadataKey);
270
+ if (!ProviderShared.isRecord(metadata) || !id)
227
271
  return undefined;
228
272
  const encryptedContent = typeof metadata.reasoningEncryptedContent === "string" || metadata.reasoningEncryptedContent === null
229
273
  ? metadata.reasoningEncryptedContent
230
274
  : undefined;
231
275
  return {
232
276
  type: "reasoning",
233
- id: metadata.itemId,
277
+ id,
234
278
  summary: part.text.length > 0 ? [{ type: "summary_text", text: part.text }] : [],
235
279
  encrypted_content: encryptedContent,
236
280
  };
237
281
  };
238
282
  const hostedToolItemID = (part, providerMetadataKey) => {
239
- const metadata = part.providerMetadata?.[providerMetadataKey];
240
- return ProviderShared.isRecord(metadata) && typeof metadata.itemId === "string" && metadata.itemId.length > 0
241
- ? metadata.itemId
242
- : undefined;
283
+ return itemID(part.providerMetadata, providerMetadataKey);
243
284
  };
244
285
  const lowerMedia = Effect.fn("OpenResponses.lowerMedia")(function* (part, request, extension) {
245
286
  const media = ProviderShared.normalizeMedia(part);
@@ -285,15 +326,10 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
285
326
  const providerMetadataKey = request.model.route.providerMetadataKey ?? "openresponses";
286
327
  for (const message of request.messages) {
287
328
  if (message.role === "system") {
288
- const part = yield* ProviderShared.wrappedSystemUpdate(extension.name, message);
289
- const previous = input.at(-1);
290
- if (previous && "role" in previous && previous.role === "user")
291
- input[input.length - 1] = {
292
- role: "user",
293
- content: [...previous.content, { type: "input_text", text: part.text }],
294
- };
295
- else
296
- input.push({ role: "user", content: [{ type: "input_text", text: part.text }] });
329
+ input.push({
330
+ role: "developer",
331
+ content: ProviderShared.joinText(yield* ProviderShared.systemUpdateText(extension.name, message)),
332
+ });
297
333
  continue;
298
334
  }
299
335
  if (message.role === "user") {
@@ -313,15 +349,18 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
313
349
  return;
314
350
  const groups = content.reduce((groups, part) => {
315
351
  const metadata = part.providerMetadata?.[providerMetadataKey];
352
+ const id = itemID(part.providerMetadata, providerMetadataKey);
316
353
  const phase = ProviderShared.isRecord(metadata) ? messagePhase(metadata.phase, extension) : undefined;
317
354
  const group = groups.at(-1);
318
- if (group && group.phase === phase)
355
+ if (group && group.id === id && group.phase === phase)
319
356
  group.parts.push(part);
320
357
  else
321
- groups.push({ phase, parts: [part] });
358
+ groups.push({ id, phase, parts: [part] });
322
359
  return groups;
323
360
  }, []);
324
361
  input.push(...groups.map((group) => ({
362
+ type: "message",
363
+ ...(group.id === undefined ? {} : { id: group.id }),
325
364
  role: "assistant",
326
365
  content: group.parts.map((part) => ({ type: "output_text", text: part.text })),
327
366
  ...(group.phase === undefined ? {} : { phase: group.phase }),
@@ -351,20 +390,15 @@ const lowerMessages = Effect.fn("OpenResponses.lowerMessages")(function* (reques
351
390
  existing.encrypted_content = reasoning.encrypted_content;
352
391
  continue;
353
392
  }
354
- const replay = {
355
- type: reasoning.type,
356
- summary: reasoning.summary,
357
- encrypted_content: reasoning.encrypted_content,
358
- };
359
- reasoningItems[reasoning.id] = replay;
360
- input.push(replay);
393
+ reasoningItems[reasoning.id] = reasoning;
394
+ input.push(reasoning);
361
395
  continue;
362
396
  }
363
397
  if (part.type === "tool-call") {
364
398
  flushText();
365
399
  if (part.providerExecuted === true)
366
400
  continue;
367
- input.push(lowerToolCall(part));
401
+ input.push(lowerToolCall(part, providerMetadataKey));
368
402
  continue;
369
403
  }
370
404
  if (part.type === "tool-result" && part.providerExecuted === true) {
@@ -415,6 +449,12 @@ const lowerOptions = (request) => {
415
449
  return {
416
450
  ...(options.instructions ? { instructions: options.instructions } : {}),
417
451
  ...(options.store !== undefined ? { store: options.store } : {}),
452
+ ...(options.metadata ? { metadata: options.metadata } : {}),
453
+ ...(options.safetyIdentifier ? { safety_identifier: options.safetyIdentifier } : {}),
454
+ ...(options.streamOptions?.includeObfuscation !== undefined
455
+ ? { stream_options: { include_obfuscation: options.streamOptions.includeObfuscation } }
456
+ : {}),
457
+ ...(options.topLogprobs !== undefined ? { top_logprobs: options.topLogprobs } : {}),
418
458
  ...(request.promptCacheKey ? { prompt_cache_key: request.promptCacheKey } : {}),
419
459
  ...(options.include ? { include: options.include } : {}),
420
460
  ...(options.reasoningEffort || options.reasoningSummary
@@ -422,6 +462,19 @@ const lowerOptions = (request) => {
422
462
  : {}),
423
463
  ...(options.textVerbosity ? { text: { verbosity: options.textVerbosity } } : {}),
424
464
  ...(options.serviceTier ? { service_tier: options.serviceTier } : {}),
465
+ ...(options.maxToolCalls !== undefined ? { max_tool_calls: options.maxToolCalls } : {}),
466
+ ...(options.parallelToolCalls !== undefined ? { parallel_tool_calls: options.parallelToolCalls } : {}),
467
+ ...(options.truncation ? { truncation: options.truncation } : {}),
468
+ };
469
+ };
470
+ const allowedToolChoice = (request) => {
471
+ const allowed = OpenResponsesOptions.resolve(request).allowedTools;
472
+ if (!allowed)
473
+ return undefined;
474
+ return {
475
+ type: "allowed_tools",
476
+ mode: allowed.mode,
477
+ tools: allowed.toolNames.map((name) => ({ type: "function", name })),
425
478
  };
426
479
  };
427
480
  export const fromRequestWithExtension = Effect.fn("OpenResponses.fromRequestWithExtension")(function* (request, extension) {
@@ -433,11 +486,14 @@ export const fromRequestWithExtension = Effect.fn("OpenResponses.fromRequestWith
433
486
  tools: request.tools.length === 0
434
487
  ? undefined
435
488
  : yield* Effect.forEach(request.tools, (tool) => lowerTool(extension.name, tool, ToolSchemaProjection.modelCompatibility(tool.inputSchema, toolSchemaCompatibility))),
436
- tool_choice: request.toolChoice ? yield* lowerToolChoice(extension.name, request.toolChoice) : undefined,
489
+ tool_choice: allowedToolChoice(request) ??
490
+ (request.toolChoice ? yield* lowerToolChoice(extension.name, request.toolChoice) : undefined),
437
491
  stream: true,
438
492
  max_output_tokens: generation?.maxTokens,
439
493
  temperature: generation?.temperature,
440
494
  top_p: generation?.topP,
495
+ presence_penalty: generation?.presencePenalty,
496
+ frequency_penalty: generation?.frequencyPenalty,
441
497
  ...lowerOptions(request),
442
498
  };
443
499
  });
@@ -500,7 +556,7 @@ const onOutputTextDelta = (state, event, id) => {
500
556
  return [state, NO_EVENTS];
501
557
  const events = [];
502
558
  const phase = state.messagePhases[id];
503
- const metadata = phase === undefined ? undefined : providerMetadata(state, { phase });
559
+ const metadata = providerMetadata(state, { itemId: id, ...(phase === undefined ? {} : { phase }) });
504
560
  const lifecycle = Lifecycle.textStart(state.lifecycle, events, id, metadata);
505
561
  return [{ ...state, lifecycle: Lifecycle.textDelta(lifecycle, events, id, event.delta) }, events];
506
562
  };
@@ -684,7 +740,7 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
684
740
  return [
685
741
  {
686
742
  ...state,
687
- lifecycle: Lifecycle.textEnd(state.lifecycle, events, item.id, phase === undefined ? undefined : providerMetadata(state, { phase })),
743
+ lifecycle: Lifecycle.textEnd(state.lifecycle, events, item.id, providerMetadata(state, { itemId: item.id, ...(phase === undefined ? {} : { phase }) })),
688
744
  messageItems,
689
745
  messagePhases,
690
746
  },
@@ -696,7 +752,11 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
696
752
  return [state, NO_EVENTS];
697
753
  const tools = state.tools[item.id]
698
754
  ? state.tools
699
- : ToolStream.start(state.tools, item.id, { id: item.call_id, name: item.name });
755
+ : ToolStream.start(state.tools, item.id, {
756
+ id: item.call_id,
757
+ name: item.name,
758
+ providerMetadata: providerMetadata(state, { itemId: item.id }),
759
+ });
700
760
  const result = item.arguments === undefined
701
761
  ? yield* ToolStream.finish(state.id, tools, item.id)
702
762
  : yield* ToolStream.finishWithInput(state.id, tools, item.id, item.arguments);
@@ -739,11 +799,17 @@ const onOutputItemDone = Effect.fn("OpenResponses.onOutputItemDone")(function* (
739
799
  }
740
800
  return [state, NO_EVENTS];
741
801
  });
742
- const onResponseFinish = (state, event) => {
743
- const events = [];
802
+ const onResponseFinish = Effect.fn("OpenResponses.onResponseFinish")(function* (state, event) {
803
+ // Some compatible providers omit output_item.done even after completing the response.
804
+ const pending = event.type === "response.completed"
805
+ ? yield* ToolStream.finishAll(state.id, state.tools)
806
+ : { tools: state.tools, events: NO_EVENTS };
807
+ const events = [...pending.events];
808
+ const hasFunctionCall = pending.events.some((event) => LLMEvent.is.toolCall(event) || LLMEvent.is.toolInputError(event)) ||
809
+ state.hasFunctionCall;
744
810
  const lifecycle = Lifecycle.finish(state.lifecycle, events, {
745
811
  reason: {
746
- normalized: mapFinishReason(event, state.hasFunctionCall),
812
+ normalized: mapFinishReason(event, hasFunctionCall),
747
813
  raw: event.response?.incomplete_details?.reason,
748
814
  },
749
815
  usage: mapUsage(event.response?.usage, state.providerMetadataKey),
@@ -754,8 +820,8 @@ const onResponseFinish = (state, event) => {
754
820
  })
755
821
  : undefined,
756
822
  });
757
- return [{ ...state, lifecycle }, events];
758
- };
823
+ return [{ ...state, lifecycle, hasFunctionCall, tools: pending.tools }, events];
824
+ });
759
825
  // Build a single human-readable message from whatever the provider supplied.
760
826
  // When both code and message are present, prefix the code so consumers see
761
827
  // the failure mode (e.g. `rate_limit_exceeded: Slow down`) instead of just
@@ -792,6 +858,13 @@ export const step = (state, event) => {
792
858
  ? onOutputTextDelta(state, event, event.item_id)
793
859
  : onOutputTextDone(state, event, event.item_id));
794
860
  }
861
+ if (event.type === "response.refusal.delta" || event.type === "response.refusal.done") {
862
+ if (!isRefusalEvent(event))
863
+ return ProviderShared.eventError(state.id, `${event.type} is malformed`);
864
+ return Effect.succeed(event.type === "response.refusal.delta"
865
+ ? onOutputTextDelta(state, event, event.item_id)
866
+ : onOutputTextDone(state, { ...event, text: event.refusal }, event.item_id));
867
+ }
795
868
  if (event.type === "response.reasoning.delta" || event.type === "response.reasoning_summary_text.delta") {
796
869
  if (!event.item_id)
797
870
  return ProviderShared.eventError(state.id, `${event.type} is missing item_id`);
@@ -823,7 +896,7 @@ export const step = (state, event) => {
823
896
  return onOutputItemDone(state, event);
824
897
  }
825
898
  if (event.type === "response.completed" || event.type === "response.incomplete")
826
- return Effect.succeed(onResponseFinish(state, event));
899
+ return onResponseFinish(state, event);
827
900
  if (event.type === "response.failed")
828
901
  return providerError(state, event, `${state.name} response failed`);
829
902
  if (event.type === "error")
@@ -95,7 +95,7 @@ export declare const bodyFields: {
95
95
  }>>;
96
96
  store: Schema.optional<Schema.Boolean>;
97
97
  prompt_cache_key: Schema.optional<Schema.String>;
98
- reasoning_effort: Schema.optional<Schema.String>;
98
+ reasoning_effort: Schema.optional<Schema.declare<import("./utils/open-responses-options.js").ReasoningEffort, import("./utils/open-responses-options.js").ReasoningEffort>>;
99
99
  max_completion_tokens: Schema.optional<Schema.Number>;
100
100
  max_tokens: Schema.optional<Schema.Number>;
101
101
  temperature: Schema.optional<Schema.Number>;
@@ -189,7 +189,7 @@ declare const OpenAIChatBody: Schema.Struct<{
189
189
  }>>;
190
190
  store: Schema.optional<Schema.Boolean>;
191
191
  prompt_cache_key: Schema.optional<Schema.String>;
192
- reasoning_effort: Schema.optional<Schema.String>;
192
+ reasoning_effort: Schema.optional<Schema.declare<import("./utils/open-responses-options.js").ReasoningEffort, import("./utils/open-responses-options.js").ReasoningEffort>>;
193
193
  max_completion_tokens: Schema.optional<Schema.Number>;
194
194
  max_tokens: Schema.optional<Schema.Number>;
195
195
  temperature: Schema.optional<Schema.Number>;
@@ -204,6 +204,7 @@ export declare const OpenAIChatEvent: Schema.Struct<{
204
204
  readonly choices: Schema.optional<Schema.NullOr<Schema.$Array<Schema.Struct<{
205
205
  readonly delta: Schema.optional<Schema.NullOr<Schema.StructWithRest<Schema.Struct<{
206
206
  readonly content: Schema.optional<Schema.NullOr<Schema.String>>;
207
+ readonly refusal: Schema.optional<Schema.NullOr<Schema.String>>;
207
208
  readonly reasoning_content: Schema.optional<Schema.NullOr<Schema.String>>;
208
209
  readonly reasoning: Schema.optional<Schema.NullOr<Schema.String>>;
209
210
  readonly reasoning_text: Schema.optional<Schema.NullOr<Schema.String>>;
@@ -263,7 +264,7 @@ interface LoweringOptions {
263
264
  readonly cacheControl?: (cache: CacheHint | undefined) => Schema.Schema.Type<typeof OpenAIChatCacheControl> | undefined;
264
265
  }
265
266
  export declare const fromRequest: (request: LLMRequest, options?: LoweringOptions | undefined) => Effect.Effect<{
266
- reasoning_effort?: string | undefined;
267
+ reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
267
268
  prompt_cache_key?: string | undefined;
268
269
  store?: boolean | undefined;
269
270
  temperature: number | undefined;
@@ -347,7 +348,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
347
348
  readonly ttl?: string | undefined;
348
349
  } | undefined;
349
350
  }[] | undefined;
350
- tool_choice: "required" | "none" | "auto" | {
351
+ tool_choice: "required" | "auto" | "none" | {
351
352
  type: "function";
352
353
  function: {
353
354
  name: string;
@@ -358,7 +359,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
358
359
  include_usage: boolean;
359
360
  };
360
361
  } | {
361
- reasoning_effort?: string | undefined;
362
+ reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
362
363
  prompt_cache_key?: string | undefined;
363
364
  store?: boolean | undefined;
364
365
  temperature: number | undefined;
@@ -442,7 +443,7 @@ export declare const fromRequest: (request: LLMRequest, options?: LoweringOption
442
443
  readonly ttl?: string | undefined;
443
444
  } | undefined;
444
445
  }[] | undefined;
445
- tool_choice: "required" | "none" | "auto" | {
446
+ tool_choice: "required" | "auto" | "none" | {
446
447
  type: "function";
447
448
  function: {
448
449
  name: string;
@@ -521,7 +522,6 @@ export declare const protocol: Protocol<{
521
522
  } | undefined;
522
523
  })[];
523
524
  readonly stream: true;
524
- readonly stop?: readonly string[] | undefined;
525
525
  readonly max_completion_tokens?: number | undefined;
526
526
  readonly max_tokens?: number | undefined;
527
527
  readonly tools?: readonly {
@@ -538,9 +538,10 @@ export declare const protocol: Protocol<{
538
538
  readonly ttl?: string | undefined;
539
539
  } | undefined;
540
540
  }[] | undefined;
541
+ readonly stop?: readonly string[] | undefined;
541
542
  readonly temperature?: number | undefined;
542
543
  readonly seed?: number | undefined;
543
- readonly tool_choice?: "required" | "none" | "auto" | {
544
+ readonly tool_choice?: "required" | "auto" | "none" | {
544
545
  readonly type: "function";
545
546
  readonly function: {
546
547
  readonly name: string;
@@ -552,7 +553,7 @@ export declare const protocol: Protocol<{
552
553
  readonly include_usage: boolean;
553
554
  } | undefined;
554
555
  readonly prompt_cache_key?: string | undefined;
555
- readonly reasoning_effort?: string | undefined;
556
+ readonly reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
556
557
  readonly frequency_penalty?: number | undefined;
557
558
  readonly presence_penalty?: number | undefined;
558
559
  }, string, {
@@ -584,6 +585,7 @@ export declare const protocol: Protocol<{
584
585
  readonly reasoning_content?: string | null | undefined;
585
586
  readonly reasoning_text?: string | null | undefined;
586
587
  readonly content?: string | null | undefined;
588
+ readonly refusal?: string | null | undefined;
587
589
  readonly tool_calls?: readonly {
588
590
  readonly function?: {
589
591
  readonly name?: string | null | undefined;
@@ -660,7 +662,6 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
660
662
  } | undefined;
661
663
  })[];
662
664
  readonly stream: true;
663
- readonly stop?: readonly string[] | undefined;
664
665
  readonly max_completion_tokens?: number | undefined;
665
666
  readonly max_tokens?: number | undefined;
666
667
  readonly tools?: readonly {
@@ -677,9 +678,10 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
677
678
  readonly ttl?: string | undefined;
678
679
  } | undefined;
679
680
  }[] | undefined;
681
+ readonly stop?: readonly string[] | undefined;
680
682
  readonly temperature?: number | undefined;
681
683
  readonly seed?: number | undefined;
682
- readonly tool_choice?: "required" | "none" | "auto" | {
684
+ readonly tool_choice?: "required" | "auto" | "none" | {
683
685
  readonly type: "function";
684
686
  readonly function: {
685
687
  readonly name: string;
@@ -691,7 +693,7 @@ export declare const httpTransport: HttpTransport.HttpJsonTransport<{
691
693
  readonly include_usage: boolean;
692
694
  } | undefined;
693
695
  readonly prompt_cache_key?: string | undefined;
694
- readonly reasoning_effort?: string | undefined;
696
+ readonly reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
695
697
  readonly frequency_penalty?: number | undefined;
696
698
  readonly presence_penalty?: number | undefined;
697
699
  }, string>;
@@ -757,7 +759,6 @@ export declare const route: Route<{
757
759
  } | undefined;
758
760
  })[];
759
761
  readonly stream: true;
760
- readonly stop?: readonly string[] | undefined;
761
762
  readonly max_completion_tokens?: number | undefined;
762
763
  readonly max_tokens?: number | undefined;
763
764
  readonly tools?: readonly {
@@ -774,9 +775,10 @@ export declare const route: Route<{
774
775
  readonly ttl?: string | undefined;
775
776
  } | undefined;
776
777
  }[] | undefined;
778
+ readonly stop?: readonly string[] | undefined;
777
779
  readonly temperature?: number | undefined;
778
780
  readonly seed?: number | undefined;
779
- readonly tool_choice?: "required" | "none" | "auto" | {
781
+ readonly tool_choice?: "required" | "auto" | "none" | {
780
782
  readonly type: "function";
781
783
  readonly function: {
782
784
  readonly name: string;
@@ -788,7 +790,7 @@ export declare const route: Route<{
788
790
  readonly include_usage: boolean;
789
791
  } | undefined;
790
792
  readonly prompt_cache_key?: string | undefined;
791
- readonly reasoning_effort?: string | undefined;
793
+ readonly reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
792
794
  readonly frequency_penalty?: number | undefined;
793
795
  readonly presence_penalty?: number | undefined;
794
796
  }, HttpTransport.HttpPrepared<string>>;
@@ -13,7 +13,7 @@ import { Lifecycle } from "./utils/lifecycle.js";
13
13
  import { ToolSchemaProjection } from "./utils/tool-schema.js";
14
14
  import { ToolStream } from "./utils/tool-stream.js";
15
15
  const ADAPTER = "openai-chat";
16
- const RESERVED_REASONING_FIELDS = new Set(["role", "content", "tool_calls"]);
16
+ const RESERVED_REASONING_FIELDS = new Set(["role", "content", "refusal", "tool_calls"]);
17
17
  export const DEFAULT_BASE_URL = "https://api.openai.com/v1";
18
18
  export const PATH = "/chat/completions";
19
19
  // =============================================================================
@@ -144,6 +144,7 @@ const OpenAIChatToolCallDelta = Schema.Struct({
144
144
  });
145
145
  const OpenAIChatDelta = Schema.StructWithRest(Schema.Struct({
146
146
  content: optionalNull(Schema.String),
147
+ refusal: optionalNull(Schema.String),
147
148
  reasoning_content: optionalNull(Schema.String),
148
149
  reasoning: optionalNull(Schema.String),
149
150
  reasoning_text: optionalNull(Schema.String),
@@ -568,6 +569,7 @@ const step = (state, event) => Effect.gen(function* () {
568
569
  let lifecycle = state.lifecycle;
569
570
  const reasoning = reasoningDelta(delta, state.reasoningField);
570
571
  const hasLateContent = Boolean(delta?.content) ||
572
+ Boolean(delta?.refusal) ||
571
573
  reasoning !== undefined ||
572
574
  (Array.isArray(delta?.reasoning_details) && delta.reasoning_details.length > 0) ||
573
575
  toolDeltas.some((tool) => Boolean(tool.id) || Boolean(tool.function?.name) || Boolean(tool.function?.arguments));
@@ -587,13 +589,17 @@ const step = (state, event) => Effect.gen(function* () {
587
589
  lifecycle = Lifecycle.reasoningDelta(lifecycle, events, "reasoning-0", text, deltaMetadata);
588
590
  else if (reasoningDetailsObserved &&
589
591
  !lifecycle.reasoning.has("reasoning-0") &&
590
- (Boolean(delta?.content) || toolDeltas.length > 0))
592
+ (Boolean(delta?.content) || Boolean(delta?.refusal) || toolDeltas.length > 0))
591
593
  lifecycle = Lifecycle.reasoningStart(lifecycle, events, "reasoning-0", deltaMetadata);
592
594
  const reasoningEmitted = state.reasoningEmitted || lifecycle.reasoning.has("reasoning-0");
593
595
  if (delta?.content) {
594
596
  lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
595
597
  lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.content);
596
598
  }
599
+ if (delta?.refusal) {
600
+ lifecycle = Lifecycle.reasoningEnd(lifecycle, events, "reasoning-0", reasoningMetadata(reasoningField, reasoningDetailsObserved ? state.reasoningDetails : undefined));
601
+ lifecycle = Lifecycle.textDelta(lifecycle, events, "text-0", delta.refusal);
602
+ }
597
603
  // Compatible providers may omit indexes. Prefer durable identity, then use
598
604
  // batch position for parallel deltas or the latest call for sparse chunks.
599
605
  for (const [position, tool] of toolDeltas.entries()) {
@@ -69,7 +69,6 @@ export declare const route: Route<{
69
69
  } | undefined;
70
70
  })[];
71
71
  readonly stream: true;
72
- readonly stop?: readonly string[] | undefined;
73
72
  readonly max_completion_tokens?: number | undefined;
74
73
  readonly max_tokens?: number | undefined;
75
74
  readonly tools?: readonly {
@@ -86,9 +85,10 @@ export declare const route: Route<{
86
85
  readonly ttl?: string | undefined;
87
86
  } | undefined;
88
87
  }[] | undefined;
88
+ readonly stop?: readonly string[] | undefined;
89
89
  readonly temperature?: number | undefined;
90
90
  readonly seed?: number | undefined;
91
- readonly tool_choice?: "required" | "none" | "auto" | {
91
+ readonly tool_choice?: "required" | "auto" | "none" | {
92
92
  readonly type: "function";
93
93
  readonly function: {
94
94
  readonly name: string;
@@ -100,7 +100,7 @@ export declare const route: Route<{
100
100
  readonly include_usage: boolean;
101
101
  } | undefined;
102
102
  readonly prompt_cache_key?: string | undefined;
103
- readonly reasoning_effort?: string | undefined;
103
+ readonly reasoning_effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
104
104
  readonly frequency_penalty?: number | undefined;
105
105
  readonly presence_penalty?: number | undefined;
106
106
  }, import("../route/transport/http.js").HttpPrepared<string>>;
@@ -20,6 +20,9 @@ export declare const route: Route<{
20
20
  } | {
21
21
  readonly role: "system";
22
22
  readonly content: string;
23
+ } | {
24
+ readonly role: "developer";
25
+ readonly content: string;
23
26
  } | {
24
27
  readonly role: "user";
25
28
  readonly content: readonly ({
@@ -35,17 +38,20 @@ export declare const route: Route<{
35
38
  readonly text: string;
36
39
  })[];
37
40
  } | {
41
+ readonly type: "message";
38
42
  readonly content: readonly {
39
43
  readonly type: "output_text";
40
44
  readonly text: string;
41
45
  }[];
42
46
  readonly role: "assistant";
47
+ readonly id?: string | undefined;
43
48
  readonly phase?: "commentary" | "final_answer" | undefined;
44
49
  } | {
45
50
  readonly type: "function_call";
46
- readonly call_id: string;
47
51
  readonly name: string;
48
52
  readonly arguments: string;
53
+ readonly call_id: string;
54
+ readonly id?: string | undefined;
49
55
  } | {
50
56
  readonly type: "function_call_output";
51
57
  readonly call_id: string;
@@ -64,10 +70,13 @@ export declare const route: Route<{
64
70
  })[];
65
71
  readonly model: string;
66
72
  readonly stream: true;
73
+ readonly metadata?: {
74
+ readonly [x: string]: string;
75
+ } | undefined;
67
76
  readonly instructions?: string | undefined;
68
77
  readonly reasoning?: {
69
78
  readonly summary?: "auto" | "concise" | "detailed" | undefined;
70
- readonly effort?: string | undefined;
79
+ readonly effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
71
80
  } | undefined;
72
81
  readonly tools?: readonly {
73
82
  readonly type: "function";
@@ -79,18 +88,35 @@ export declare const route: Route<{
79
88
  readonly strict?: boolean | undefined;
80
89
  }[] | undefined;
81
90
  readonly text?: {
82
- readonly verbosity?: "low" | "medium" | "high" | undefined;
91
+ readonly verbosity?: import("./utils/open-responses-options.js").TextVerbosity | undefined;
83
92
  } | undefined;
84
93
  readonly temperature?: number | undefined;
85
- readonly tool_choice?: "required" | "none" | "auto" | {
94
+ readonly tool_choice?: "required" | "auto" | "none" | {
86
95
  readonly type: "function";
87
96
  readonly name: string;
97
+ } | {
98
+ readonly type: "allowed_tools";
99
+ readonly mode: "required" | "auto" | "none";
100
+ readonly tools: readonly {
101
+ readonly type: "function";
102
+ readonly name: string;
103
+ }[];
88
104
  } | undefined;
89
105
  readonly top_p?: number | undefined;
90
- readonly include?: readonly ("file_search_call.results" | "web_search_call.results" | "web_search_call.action.sources" | "message.input_image.image_url" | "computer_call_output.output.image_url" | "code_interpreter_call.outputs" | "reasoning.encrypted_content" | "message.output_text.logprobs")[] | undefined;
91
106
  readonly store?: boolean | undefined;
107
+ readonly include?: readonly import("./utils/open-responses-options.js").ResponseIncludable[] | undefined;
108
+ readonly truncation?: "auto" | "disabled" | undefined;
109
+ readonly stream_options?: {
110
+ readonly include_obfuscation?: boolean | undefined;
111
+ } | undefined;
92
112
  readonly prompt_cache_key?: string | undefined;
113
+ readonly frequency_penalty?: number | undefined;
114
+ readonly presence_penalty?: number | undefined;
115
+ readonly safety_identifier?: string | undefined;
116
+ readonly top_logprobs?: number | undefined;
93
117
  readonly service_tier?: "default" | "auto" | "flex" | "priority" | undefined;
94
118
  readonly max_output_tokens?: number | undefined;
119
+ readonly max_tool_calls?: number | undefined;
120
+ readonly parallel_tool_calls?: boolean | undefined;
95
121
  }, import("../route/transport/http.js").HttpPrepared<string>>;
96
122
  export * as OpenAICompatibleResponses from "./openai-compatible-responses.js";