@veryfront/ext-llm-openai 0.1.1186 → 0.1.1189

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 (39) hide show
  1. package/README.md +49 -2
  2. package/esm/_dnt.polyfills.d.ts +12 -0
  3. package/esm/_dnt.polyfills.d.ts.map +1 -0
  4. package/esm/_dnt.polyfills.js +15 -0
  5. package/esm/index.d.ts +1 -0
  6. package/esm/index.d.ts.map +1 -1
  7. package/esm/index.js +7 -1
  8. package/esm/openai-chat-request-builder.d.ts +5 -43
  9. package/esm/openai-chat-request-builder.d.ts.map +1 -1
  10. package/esm/openai-chat-request-builder.js +18 -4
  11. package/esm/openai-chat-stream.d.ts +8 -1
  12. package/esm/openai-chat-stream.d.ts.map +1 -1
  13. package/esm/openai-chat-stream.js +286 -104
  14. package/esm/openai-provider-options.d.ts +6 -0
  15. package/esm/openai-provider-options.d.ts.map +1 -0
  16. package/esm/openai-provider-options.js +14 -0
  17. package/esm/openai-provider.d.ts +6 -5
  18. package/esm/openai-provider.d.ts.map +1 -1
  19. package/esm/openai-provider.js +579 -129
  20. package/esm/openai-reasoning-models.d.ts +3 -6
  21. package/esm/openai-reasoning-models.d.ts.map +1 -1
  22. package/esm/openai-responses-request-builder.d.ts.map +1 -1
  23. package/esm/openai-responses-request-builder.js +240 -19
  24. package/esm/openai-responses-stream.d.ts +12 -1
  25. package/esm/openai-responses-stream.d.ts.map +1 -1
  26. package/esm/openai-responses-stream.js +1053 -113
  27. package/esm/openai-sse-buffer.d.ts +8 -0
  28. package/esm/openai-sse-buffer.d.ts.map +1 -0
  29. package/esm/openai-sse-buffer.js +47 -0
  30. package/esm/openai-stream-metadata.d.ts +6 -0
  31. package/esm/openai-stream-metadata.d.ts.map +1 -0
  32. package/esm/openai-stream-metadata.js +10 -0
  33. package/esm/openai-tool-input.d.ts +10 -0
  34. package/esm/openai-tool-input.d.ts.map +1 -0
  35. package/esm/openai-tool-input.js +30 -0
  36. package/esm/openai-web-search.d.ts +35 -0
  37. package/esm/openai-web-search.d.ts.map +1 -0
  38. package/esm/openai-web-search.js +369 -0
  39. package/package.json +3 -3
@@ -1,10 +1,7 @@
1
+ import type { RuntimeReasoningOption } from "veryfront/provider/types";
1
2
  export type OpenAIReasoningEffort = "low" | "medium" | "high";
2
- export type OpenAIProviderReasoningEffort = OpenAIReasoningEffort | "max";
3
- export type OpenAIProviderReasoningOption = {
4
- enabled?: boolean;
5
- effort?: OpenAIProviderReasoningEffort;
6
- budgetTokens?: number;
7
- };
3
+ export type OpenAIProviderReasoningEffort = NonNullable<RuntimeReasoningOption["effort"]>;
4
+ export type OpenAIProviderReasoningOption = RuntimeReasoningOption;
8
5
  export type ResolvedOpenAIReasoning = {
9
6
  effort: OpenAIReasoningEffort;
10
7
  source: "default" | "explicit";
@@ -1 +1 @@
1
- {"version":3,"file":"openai-reasoning-models.d.ts","sourceRoot":"","sources":["../src/openai-reasoning-models.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,MAAM,MAAM,6BAA6B,GAAG,qBAAqB,GAAG,KAAK,CAAC;AAE1E,MAAM,MAAM,6BAA6B,GAAG;IAC1C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,6BAA6B,CAAC;IACvC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;CAChC,CAAC;AAIF,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAG5E;AAuBD,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,YAAY,SAAW,GACtB,qBAAqB,GAAG,SAAS,CAwBnC;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,6BAA6B,GAAG,SAAS,GAChD,uBAAuB,GAAG,SAAS,CAoBrC;AAED,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,uBAAuB,GACjC,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,SAAW,GAAG,OAAO,CAExF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIpE"}
1
+ {"version":3,"file":"openai-reasoning-models.d.ts","sourceRoot":"","sources":["../src/openai-reasoning-models.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAEvE,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,MAAM,MAAM,6BAA6B,GAAG,WAAW,CAAC,sBAAsB,CAAC,QAAQ,CAAC,CAAC,CAAC;AAE1F,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,CAAC;AAEnE,MAAM,MAAM,uBAAuB,GAAG;IACpC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC;CAChC,CAAC;AAIF,wBAAgB,8BAA8B,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAG5E;AAuBD,wBAAgB,+BAA+B,CAC7C,OAAO,EAAE,MAAM,EACf,YAAY,SAAW,GACtB,qBAAqB,GAAG,SAAS,CAwBnC;AAED,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,6BAA6B,GAAG,SAAS,GAChD,uBAAuB,GAAG,SAAS,CAoBrC;AAED,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,uBAAuB,GACjC,OAAO,CAIT;AAED,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,SAAW,GAAG,OAAO,CAExF;AAED,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAIpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses-request-builder.d.ts","sourceRoot":"","sources":["../src/openai-responses-request-builder.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,+BAA+B,EAEhC,MAAM,kCAAkC,CAAC;AAO1C,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,OAAO,EAAE;QACZ,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI,CAAC;IACT,KAAK,IAAI,KAAK,CAAC;QACb,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ,CAAC;AAkJF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,+BAA+B,EACxC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,gBAAgB,GACzB,sBAAsB,CAsGxB"}
1
+ {"version":3,"file":"openai-responses-request-builder.d.ts","sourceRoot":"","sources":["../src/openai-responses-request-builder.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,kCAAkC,CAAC;AAoBxF,MAAM,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE/D,MAAM,MAAM,sBAAsB,GAAG;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,wBAAwB,EAAE,CAAC;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,SAAS,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAClD,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;IAC3C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,CAAC;AAEF,KAAK,gBAAgB,GAAG;IACtB,IAAI,CAAC,OAAO,EAAE;QACZ,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,GAAG,IAAI,CAAC;IACT,KAAK,IAAI,KAAK,CAAC;QACb,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC;QACtC,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC,CAAC;CACJ,CAAC;AAyYF,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,+BAA+B,EACxC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,gBAAgB,GACzB,sBAAsB,CA+IxB"}
@@ -1,10 +1,179 @@
1
- import { readProviderOptions, stringifyJsonValue, unwrapToolInputSchema, } from "veryfront/provider/shared";
1
+ import { jsonValuesEqual, readProviderOptions, stringifyToolArguments, stringifyToolResultValue, unwrapToolInputSchema, } from "veryfront/provider/shared";
2
2
  import { rejectsOpenAISamplingParams, resolveOpenAIReasoningConfig, shouldRequestOpenAIReasoningSummary, } from "./openai-reasoning-models.js";
3
- function toSnakeCaseRecord(record) {
4
- return Object.fromEntries(Object.entries(record).map(([key, value]) => [
5
- key.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`),
6
- value,
7
- ]));
3
+ import { defineOpenAIProviderOptions } from "./openai-provider-options.js";
4
+ import { isBoundedOpenAIStreamString, MAX_OPENAI_STREAM_TOOL_NAME_BYTES, } from "./openai-stream-metadata.js";
5
+ import { normalizeOpenAIWebSearchCall, OPENAI_REASONING_ENCRYPTED_CONTENT_INCLUDE, OPENAI_WEB_SEARCH_SOURCES_INCLUDE, readOpenAIRawResponseOutputItems, resolveOpenAIWebSearchDescriptor, } from "./openai-web-search.js";
6
+ function invalidOpenAIProviderHistory() {
7
+ return new TypeError("OpenAI raw response metadata did not match canonical provider tool history");
8
+ }
9
+ function assertUniqueOpenAIToolCallIds(calls) {
10
+ const seen = new Set();
11
+ for (const call of calls) {
12
+ if (seen.has(call.id)) {
13
+ throw invalidOpenAIProviderHistory();
14
+ }
15
+ seen.add(call.id);
16
+ }
17
+ }
18
+ function assertOrderedOpenAIToolCallsEqual(left, right) {
19
+ if (left.length !== right.length) {
20
+ throw invalidOpenAIProviderHistory();
21
+ }
22
+ for (let index = 0; index < left.length; index += 1) {
23
+ const leftCall = left[index];
24
+ const rightCall = right[index];
25
+ if (!leftCall ||
26
+ !rightCall ||
27
+ leftCall.id !== rightCall.id ||
28
+ leftCall.name !== rightCall.name ||
29
+ !jsonValuesEqual(leftCall.input, rightCall.input, true)) {
30
+ throw invalidOpenAIProviderHistory();
31
+ }
32
+ }
33
+ }
34
+ function validateOpenAIProviderReplay(message, rawOutputItems) {
35
+ const metadataProviderCalls = (message.providerToolCalls ?? []).map((call) => ({
36
+ id: call.toolCallId,
37
+ name: call.toolName,
38
+ input: call.input,
39
+ }));
40
+ const contentProviderCalls = [];
41
+ const clientCalls = [];
42
+ const providerResults = [];
43
+ const contentCallKinds = [];
44
+ for (const part of message.content) {
45
+ if (part.type === "tool-call") {
46
+ const providerExecuted = part.providerExecuted === true;
47
+ const target = providerExecuted ? contentProviderCalls : clientCalls;
48
+ target.push({
49
+ id: part.toolCallId,
50
+ name: part.toolName,
51
+ input: part.input,
52
+ });
53
+ contentCallKinds.push(providerExecuted ? "provider" : "client");
54
+ continue;
55
+ }
56
+ if (part.type === "tool-result" && part.providerExecuted === true) {
57
+ providerResults.push({
58
+ id: part.toolCallId,
59
+ name: part.toolName,
60
+ result: part.result,
61
+ isError: part.isError === true,
62
+ });
63
+ }
64
+ }
65
+ assertUniqueOpenAIToolCallIds(metadataProviderCalls);
66
+ assertUniqueOpenAIToolCallIds(contentProviderCalls);
67
+ assertUniqueOpenAIToolCallIds(clientCalls);
68
+ const seenProviderResultIds = new Set();
69
+ for (const result of providerResults) {
70
+ if (seenProviderResultIds.has(result.id)) {
71
+ throw invalidOpenAIProviderHistory();
72
+ }
73
+ seenProviderResultIds.add(result.id);
74
+ }
75
+ // providerToolCalls is the legacy projection of provider-executed content.
76
+ // Coalesce it only after proving both surviving projections are identical
77
+ // occurrence-for-occurrence; duplicates or a different order are ambiguous.
78
+ if (metadataProviderCalls.length > 0 &&
79
+ contentProviderCalls.length > 0) {
80
+ assertOrderedOpenAIToolCallsEqual(metadataProviderCalls, contentProviderCalls);
81
+ }
82
+ const providerCalls = metadataProviderCalls.length > 0
83
+ ? metadataProviderCalls
84
+ : contentProviderCalls;
85
+ const rawProviderCalls = [];
86
+ const rawClientCalls = [];
87
+ const rawCallKinds = [];
88
+ for (const item of rawOutputItems) {
89
+ if (item.type === "web_search_call") {
90
+ const call = normalizeOpenAIWebSearchCall(item, () => invalidOpenAIProviderHistory());
91
+ rawProviderCalls.push({
92
+ id: call.id,
93
+ input: call.input,
94
+ result: call.result,
95
+ isError: call.isError,
96
+ });
97
+ rawCallKinds.push("provider");
98
+ continue;
99
+ }
100
+ if (item.type === "function_call") {
101
+ if (typeof item.call_id !== "string" ||
102
+ typeof item.name !== "string" ||
103
+ typeof item.arguments !== "string") {
104
+ throw invalidOpenAIProviderHistory();
105
+ }
106
+ rawClientCalls.push({
107
+ id: item.call_id,
108
+ name: item.name,
109
+ input: item.arguments,
110
+ });
111
+ rawCallKinds.push("client");
112
+ }
113
+ }
114
+ // The provider parser rejects duplicate call ids across both provider- and
115
+ // client-executed tools. Exact replay must enforce the same invariant even
116
+ // for legacy metadata that predates that parser check.
117
+ assertUniqueOpenAIToolCallIds([
118
+ ...rawProviderCalls,
119
+ ...rawClientCalls,
120
+ ]);
121
+ if (providerCalls.length > 0) {
122
+ if (providerCalls.length !== rawProviderCalls.length) {
123
+ throw invalidOpenAIProviderHistory();
124
+ }
125
+ for (let index = 0; index < providerCalls.length; index += 1) {
126
+ const canonical = providerCalls[index];
127
+ const raw = rawProviderCalls[index];
128
+ if (!canonical ||
129
+ !raw ||
130
+ canonical.id !== raw.id ||
131
+ !jsonValuesEqual(canonical.input, raw.input, true)) {
132
+ throw invalidOpenAIProviderHistory();
133
+ }
134
+ }
135
+ }
136
+ if (providerResults.length > 0) {
137
+ if (providerResults.length !== rawProviderCalls.length) {
138
+ throw invalidOpenAIProviderHistory();
139
+ }
140
+ for (let index = 0; index < providerResults.length; index += 1) {
141
+ const canonical = providerResults[index];
142
+ const raw = rawProviderCalls[index];
143
+ if (!canonical ||
144
+ !raw ||
145
+ canonical.id !== raw.id ||
146
+ canonical.isError !== raw.isError ||
147
+ !jsonValuesEqual(canonical.result, raw.result)) {
148
+ throw invalidOpenAIProviderHistory();
149
+ }
150
+ }
151
+ }
152
+ const historicalProviderName = providerCalls[0]?.name ?? providerResults[0]?.name;
153
+ if (historicalProviderName !== undefined &&
154
+ (!isBoundedOpenAIStreamString(historicalProviderName, MAX_OPENAI_STREAM_TOOL_NAME_BYTES) ||
155
+ providerCalls.some((call) => call.name !== historicalProviderName) ||
156
+ providerResults.some((result) => result.name !== historicalProviderName))) {
157
+ throw invalidOpenAIProviderHistory();
158
+ }
159
+ // Ordinary function calls have an exact provider-native representation.
160
+ // If their canonical projection survived compaction, correlate it in order;
161
+ // otherwise the already-validated raw items remain the legacy source of
162
+ // truth.
163
+ if (clientCalls.length > 0) {
164
+ assertOrderedOpenAIToolCallsEqual(clientCalls, rawClientCalls);
165
+ }
166
+ // providerToolCalls has no position relative to ordinary content calls. When
167
+ // both kinds survive in assistant content, however, their complete
168
+ // interleaving is observable and must match the raw item order. If either
169
+ // content projection was compacted, only its per-kind order can be proven;
170
+ // the exact raw item sequence remains authoritative for transmission.
171
+ if (contentProviderCalls.length > 0 && clientCalls.length > 0) {
172
+ if (contentCallKinds.length !== rawCallKinds.length ||
173
+ contentCallKinds.some((kind, index) => kind !== rawCallKinds[index])) {
174
+ throw invalidOpenAIProviderHistory();
175
+ }
176
+ }
8
177
  }
9
178
  function toOpenAIResponsesInput(prompt) {
10
179
  const instructionsParts = [];
@@ -23,6 +192,12 @@ function toOpenAIResponsesInput(prompt) {
23
192
  });
24
193
  break;
25
194
  case "assistant": {
195
+ const rawOutputItems = readOpenAIRawResponseOutputItems(message.providerMetadata);
196
+ if (rawOutputItems) {
197
+ validateOpenAIProviderReplay(message, rawOutputItems);
198
+ input.push(...rawOutputItems);
199
+ break;
200
+ }
26
201
  const messageContent = [];
27
202
  for (const part of message.content) {
28
203
  if (part.type === "text") {
@@ -45,6 +220,12 @@ function toOpenAIResponsesInput(prompt) {
45
220
  });
46
221
  continue;
47
222
  }
223
+ if (part.type === "tool-result") {
224
+ throw new TypeError("OpenAI provider-executed assistant tool results require exact raw replay metadata");
225
+ }
226
+ if (part.providerExecuted === true) {
227
+ throw new TypeError("OpenAI provider-executed assistant tool calls require exact raw replay metadata");
228
+ }
48
229
  if (messageContent.length > 0) {
49
230
  input.push({ role: "assistant", content: [...messageContent] });
50
231
  messageContent.length = 0;
@@ -53,7 +234,7 @@ function toOpenAIResponsesInput(prompt) {
53
234
  type: "function_call",
54
235
  call_id: part.toolCallId,
55
236
  name: part.toolName,
56
- arguments: stringifyJsonValue(part.input),
237
+ arguments: stringifyToolArguments(part.input),
57
238
  });
58
239
  }
59
240
  if (messageContent.length > 0) {
@@ -66,7 +247,7 @@ function toOpenAIResponsesInput(prompt) {
66
247
  input.push({
67
248
  type: "function_call_output",
68
249
  call_id: part.toolCallId,
69
- output: stringifyJsonValue(part.output.value),
250
+ output: stringifyToolResultValue(part.output.value),
70
251
  });
71
252
  }
72
253
  break;
@@ -98,10 +279,11 @@ function toOpenAIResponsesUserContent(parts) {
98
279
  }
99
280
  return content;
100
281
  }
101
- function toOpenAIResponsesTools(tools) {
282
+ function toOpenAIResponsesTools(tools, webSearch) {
102
283
  if (!tools)
103
284
  return undefined;
104
285
  const normalized = [];
286
+ let addedWebSearch = false;
105
287
  for (const tool of tools) {
106
288
  if (tool.type === "function") {
107
289
  normalized.push({
@@ -119,13 +301,10 @@ function toOpenAIResponsesTools(tools) {
119
301
  }
120
302
  if (!tool.id.startsWith("openai."))
121
303
  continue;
122
- const providerType = tool.id.slice("openai.".length);
123
- if (providerType.length === 0)
124
- continue;
125
- normalized.push({
126
- type: providerType,
127
- ...toSnakeCaseRecord(tool.args),
128
- });
304
+ if (webSearch && !addedWebSearch) {
305
+ normalized.push(webSearch.requestTool);
306
+ addedWebSearch = true;
307
+ }
129
308
  }
130
309
  return normalized.length > 0 ? normalized : undefined;
131
310
  }
@@ -162,12 +341,13 @@ export function buildOpenAIResponsesRequest(modelId, providerName, options, stre
162
341
  }
163
342
  }
164
343
  }
344
+ const webSearch = resolveOpenAIWebSearchDescriptor(options.tools);
165
345
  const { instructions, input } = toOpenAIResponsesInput(options.prompt);
166
- const responsesTools = toOpenAIResponsesTools(options.tools);
346
+ const responsesTools = toOpenAIResponsesTools(options.tools, webSearch);
167
347
  const body = {
168
348
  model: modelId,
169
349
  input,
170
- // Stay stateless: encrypted reasoning content is never round-tripped via include.
350
+ // Stay stateless and preserve the complete provider history explicitly below.
171
351
  store: false,
172
352
  ...(instructions !== undefined ? { instructions } : {}),
173
353
  ...(stream ? { stream: true } : {}),
@@ -217,6 +397,47 @@ export function buildOpenAIResponsesRequest(modelId, providerName, options, stre
217
397
  };
218
398
  // Env-BYOK users historically registered options under "openai-compatible";
219
399
  // keep merging that bucket at the lowest precedence.
220
- Object.assign(body, readProviderOptions(options.providerOptions, ...(providerName === "openai" ? ["openai-compatible"] : []), "openai", providerName));
400
+ defineOpenAIProviderOptions(body, readProviderOptions(options.providerOptions, ...(providerName === "openai" ? ["openai-compatible"] : []), "openai", providerName));
401
+ // Keep provider-native tuning extensible without allowing raw options to
402
+ // replace the runtime-owned transport, prompt, model, or privacy contract.
403
+ body.model = modelId;
404
+ body.input = input;
405
+ body.store = false;
406
+ if (instructions !== undefined) {
407
+ body.instructions = instructions;
408
+ }
409
+ else {
410
+ delete body.instructions;
411
+ }
412
+ if (stream) {
413
+ body.stream = true;
414
+ }
415
+ else {
416
+ delete body.stream;
417
+ }
418
+ const requiredIncludes = [
419
+ ...(reasoning ? [OPENAI_REASONING_ENCRYPTED_CONTENT_INCLUDE] : []),
420
+ ...(webSearch ? [OPENAI_WEB_SEARCH_SOURCES_INCLUDE] : []),
421
+ ];
422
+ if (requiredIncludes.length > 0) {
423
+ const providerIncludes = Array.isArray(body.include)
424
+ ? body.include.filter((value) => typeof value === "string")
425
+ : [];
426
+ body.include = [
427
+ ...new Set([
428
+ ...providerIncludes,
429
+ ...requiredIncludes,
430
+ ]),
431
+ ];
432
+ }
433
+ if (Object.hasOwn(body, "background")) {
434
+ delete body.background;
435
+ warnings.push({
436
+ type: "unsupported-setting",
437
+ provider: "openai",
438
+ setting: "background",
439
+ details: "Background Responses are asynchronous and cannot satisfy the runtime's immediate result contract; the value was dropped.",
440
+ });
441
+ }
221
442
  return body;
222
443
  }
@@ -1,4 +1,14 @@
1
1
  import type { RuntimeUsage } from "veryfront/provider/shared";
2
+ type OpenAIResponsesStreamContext = {
3
+ providerKind?: "openai" | "mistral" | "moonshotai";
4
+ providerLabel?: string;
5
+ webSearchToolName?: string;
6
+ preserveRawOutputItems?: boolean;
7
+ };
8
+ export declare const MAX_OPENAI_STREAM_MESSAGE_SNAPSHOT_BYTES: number;
9
+ export declare const MAX_OPENAI_RESPONSES_RAW_METADATA_BYTES: number;
10
+ export declare const MAX_OPENAI_RESPONSES_STREAM_OUTPUT_ITEMS = 4096;
11
+ export declare const MAX_OPENAI_RESPONSES_STREAM_CONTENT_PARTS = 4096;
2
12
  /**
3
13
  * The Responses API uses `input_tokens` / `output_tokens` field names
4
14
  * instead of Chat Completions' `prompt_tokens` / `completion_tokens`.
@@ -12,5 +22,6 @@ export declare function normalizeOpenAIResponsesFinishReason(raw: unknown): stri
12
22
  * Parse the Responses API streaming event grammar into the same UI part
13
23
  * shapes the existing OpenAI / Anthropic / Google streams emit.
14
24
  */
15
- export declare function streamOpenAIResponsesParts(stream: ReadableStream<Uint8Array>): AsyncIterable<unknown>;
25
+ export declare function streamOpenAIResponsesParts(stream: ReadableStream<Uint8Array>, context?: OpenAIResponsesStreamContext): AsyncIterable<unknown>;
26
+ export {};
16
27
  //# sourceMappingURL=openai-responses-stream.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai-responses-stream.d.ts","sourceRoot":"","sources":["../src/openai-responses-stream.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAc9D;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAqEtF;AAED,wBAAgB,oCAAoC,CAClD,GAAG,EAAE,OAAO,GACX,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAclD;AAED;;;GAGG;AACH,wBAAuB,0BAA0B,CAC/C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,GACjC,aAAa,CAAC,OAAO,CAAC,CAqJxB"}
1
+ {"version":3,"file":"openai-responses-stream.d.ts","sourceRoot":"","sources":["../src/openai-responses-stream.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AA8E9D,KAAK,4BAA4B,GAAG;IAClC,YAAY,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,YAAY,CAAC;IACnD,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC,CAAC;AAEF,eAAO,MAAM,wCAAwC,QAAkB,CAAC;AACxE,eAAO,MAAM,uCAAuC,QAAyC,CAAC;AAC9F,eAAO,MAAM,wCAAwC,OAAQ,CAAC;AAC9D,eAAO,MAAM,yCAAyC,OAAQ,CAAC;AA4C/D;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAqEtF;AAED,wBAAgB,oCAAoC,CAClD,GAAG,EAAE,OAAO,GACX,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiBlD;AAED;;;GAGG;AACH,wBAAuB,0BAA0B,CAC/C,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,GAAE,4BAAiC,GACzC,aAAa,CAAC,OAAO,CAAC,CAugDxB"}