@skyold/provider-adapters 0.1.0-beta.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/LICENSE +201 -0
- package/README.md +59 -0
- package/README.zh-CN.md +15 -0
- package/dist/anthropic-messages/adapter.d.ts +3 -0
- package/dist/anthropic-messages/adapter.d.ts.map +1 -0
- package/dist/anthropic-messages/adapter.js +50 -0
- package/dist/anthropic-messages/adapter.js.map +1 -0
- package/dist/anthropic-messages/codec.d.ts +7 -0
- package/dist/anthropic-messages/codec.d.ts.map +1 -0
- package/dist/anthropic-messages/codec.js +581 -0
- package/dist/anthropic-messages/codec.js.map +1 -0
- package/dist/anthropic-messages/sse.d.ts +7 -0
- package/dist/anthropic-messages/sse.d.ts.map +1 -0
- package/dist/anthropic-messages/sse.js +77 -0
- package/dist/anthropic-messages/sse.js.map +1 -0
- package/dist/builtin-registry.d.ts +17 -0
- package/dist/builtin-registry.d.ts.map +1 -0
- package/dist/builtin-registry.js +110 -0
- package/dist/builtin-registry.js.map +1 -0
- package/dist/image-response-json.d.ts +36 -0
- package/dist/image-response-json.d.ts.map +1 -0
- package/dist/image-response-json.js +193 -0
- package/dist/image-response-json.js.map +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/openai-chat/adapter.d.ts +3 -0
- package/dist/openai-chat/adapter.d.ts.map +1 -0
- package/dist/openai-chat/adapter.js +83 -0
- package/dist/openai-chat/adapter.js.map +1 -0
- package/dist/openai-chat/codec.d.ts +7 -0
- package/dist/openai-chat/codec.d.ts.map +1 -0
- package/dist/openai-chat/codec.js +584 -0
- package/dist/openai-chat/codec.js.map +1 -0
- package/dist/openai-chat/sse.d.ts +3 -0
- package/dist/openai-chat/sse.d.ts.map +1 -0
- package/dist/openai-chat/sse.js +64 -0
- package/dist/openai-chat/sse.js.map +1 -0
- package/dist/openai-embeddings/adapter.d.ts +3 -0
- package/dist/openai-embeddings/adapter.d.ts.map +1 -0
- package/dist/openai-embeddings/adapter.js +90 -0
- package/dist/openai-embeddings/adapter.js.map +1 -0
- package/dist/openai-embeddings/codec.d.ts +7 -0
- package/dist/openai-embeddings/codec.d.ts.map +1 -0
- package/dist/openai-embeddings/codec.js +120 -0
- package/dist/openai-embeddings/codec.js.map +1 -0
- package/dist/openai-images/adapter.d.ts +4 -0
- package/dist/openai-images/adapter.d.ts.map +1 -0
- package/dist/openai-images/adapter.js +103 -0
- package/dist/openai-images/adapter.js.map +1 -0
- package/dist/openai-images/codec.d.ts +24 -0
- package/dist/openai-images/codec.d.ts.map +1 -0
- package/dist/openai-images/codec.js +979 -0
- package/dist/openai-images/codec.js.map +1 -0
- package/dist/openai-responses/adapter.d.ts +3 -0
- package/dist/openai-responses/adapter.d.ts.map +1 -0
- package/dist/openai-responses/adapter.js +102 -0
- package/dist/openai-responses/adapter.js.map +1 -0
- package/dist/openai-responses/codec.d.ts +7 -0
- package/dist/openai-responses/codec.d.ts.map +1 -0
- package/dist/openai-responses/codec.js +1086 -0
- package/dist/openai-responses/codec.js.map +1 -0
- package/dist/openai-responses/sse.d.ts +7 -0
- package/dist/openai-responses/sse.d.ts.map +1 -0
- package/dist/openai-responses/sse.js +82 -0
- package/dist/openai-responses/sse.js.map +1 -0
- package/dist/ppio-video/adapter.d.ts +37 -0
- package/dist/ppio-video/adapter.d.ts.map +1 -0
- package/dist/ppio-video/adapter.js +155 -0
- package/dist/ppio-video/adapter.js.map +1 -0
- package/dist/ppio-video/codec.d.ts +19 -0
- package/dist/ppio-video/codec.d.ts.map +1 -0
- package/dist/ppio-video/codec.js +172 -0
- package/dist/ppio-video/codec.js.map +1 -0
- package/dist/ppio-video/estimator.d.ts +21 -0
- package/dist/ppio-video/estimator.d.ts.map +1 -0
- package/dist/ppio-video/estimator.js +23 -0
- package/dist/ppio-video/estimator.js.map +1 -0
- package/dist/registry.d.ts +15 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +36 -0
- package/dist/registry.js.map +1 -0
- package/dist/transport-profile.d.ts +17 -0
- package/dist/transport-profile.d.ts.map +1 -0
- package/dist/transport-profile.js +36 -0
- package/dist/transport-profile.js.map +1 -0
- package/dist/volc-embeddings/adapter.d.ts +4 -0
- package/dist/volc-embeddings/adapter.d.ts.map +1 -0
- package/dist/volc-embeddings/adapter.js +92 -0
- package/dist/volc-embeddings/adapter.js.map +1 -0
- package/dist/volc-embeddings/codec.d.ts +8 -0
- package/dist/volc-embeddings/codec.d.ts.map +1 -0
- package/dist/volc-embeddings/codec.js +196 -0
- package/dist/volc-embeddings/codec.js.map +1 -0
- package/dist/volc-images/adapter.d.ts +3 -0
- package/dist/volc-images/adapter.d.ts.map +1 -0
- package/dist/volc-images/adapter.js +96 -0
- package/dist/volc-images/adapter.js.map +1 -0
- package/dist/volc-images/codec.d.ts +13 -0
- package/dist/volc-images/codec.d.ts.map +1 -0
- package/dist/volc-images/codec.js +581 -0
- package/dist/volc-images/codec.js.map +1 -0
- package/dist/volc-video/adapter.d.ts +40 -0
- package/dist/volc-video/adapter.d.ts.map +1 -0
- package/dist/volc-video/adapter.js +165 -0
- package/dist/volc-video/adapter.js.map +1 -0
- package/dist/volc-video/codec.d.ts +26 -0
- package/dist/volc-video/codec.d.ts.map +1 -0
- package/dist/volc-video/codec.js +203 -0
- package/dist/volc-video/codec.js.map +1 -0
- package/dist/volc-video/estimator.d.ts +18 -0
- package/dist/volc-video/estimator.d.ts.map +1 -0
- package/dist/volc-video/estimator.js +21 -0
- package/dist/volc-video/estimator.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,1086 @@
|
|
|
1
|
+
import { parseOpenAiResponsesSseFrames, PROVIDER_STREAM_INVALID } from './sse.js';
|
|
2
|
+
const PROTOCOL_FAMILY = 'openai-responses/v1';
|
|
3
|
+
const RESPONSE_INVALID = 'PROVIDER_RESPONSE_INVALID';
|
|
4
|
+
const MAX_ERROR_BODY_BYTES = 1024 * 1024;
|
|
5
|
+
const encoder = new TextEncoder();
|
|
6
|
+
const decoder = new TextDecoder();
|
|
7
|
+
const REQUEST_FIELDS = new Set([
|
|
8
|
+
'input',
|
|
9
|
+
'instructions',
|
|
10
|
+
'tools',
|
|
11
|
+
'tool_choice',
|
|
12
|
+
'reasoning',
|
|
13
|
+
'max_output_tokens',
|
|
14
|
+
'max_tool_calls',
|
|
15
|
+
'parallel_tool_calls',
|
|
16
|
+
'temperature',
|
|
17
|
+
'top_p',
|
|
18
|
+
'store',
|
|
19
|
+
'stream',
|
|
20
|
+
]);
|
|
21
|
+
export const openAiResponsesCodec = {
|
|
22
|
+
protocolFamily: PROTOCOL_FAMILY,
|
|
23
|
+
encodeProviderRequest(task, providerModel) {
|
|
24
|
+
if (task.dispatchProtocolFamily !== PROTOCOL_FAMILY || task.taskKind !== 'chat') {
|
|
25
|
+
throw new Error('OPENAI_RESPONSES_TASK_UNSUPPORTED');
|
|
26
|
+
}
|
|
27
|
+
const body = { model: providerModel };
|
|
28
|
+
for (const [key, value] of Object.entries(task.input)) {
|
|
29
|
+
if (key === 'model')
|
|
30
|
+
continue;
|
|
31
|
+
if (!REQUEST_FIELDS.has(key))
|
|
32
|
+
throw new Error('OPENAI_RESPONSES_REQUEST_UNSUPPORTED_FIELD');
|
|
33
|
+
if (key === 'store' && value !== false)
|
|
34
|
+
throw new Error('OPENAI_RESPONSES_STORE_UNSUPPORTED');
|
|
35
|
+
if (key !== 'store' && key !== 'stream')
|
|
36
|
+
body[key] = value;
|
|
37
|
+
}
|
|
38
|
+
if (body['input'] === undefined)
|
|
39
|
+
throw new Error('OPENAI_RESPONSES_REQUEST_INVALID');
|
|
40
|
+
body['store'] = false;
|
|
41
|
+
body['stream'] = task.executionMode === 'stream';
|
|
42
|
+
return encoder.encode(JSON.stringify(body));
|
|
43
|
+
},
|
|
44
|
+
async decodeProviderStart(response) {
|
|
45
|
+
const responseMetadata = metadata(response);
|
|
46
|
+
if (response.status < 200 || response.status >= 300) {
|
|
47
|
+
return failedStart(responseMetadata, response.status, response.body);
|
|
48
|
+
}
|
|
49
|
+
if (isAsyncIterable(response.body))
|
|
50
|
+
return streamStart(response.body, responseMetadata);
|
|
51
|
+
return syncStart(response.body, responseMetadata);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
function syncStart(body, responseMetadata) {
|
|
55
|
+
try {
|
|
56
|
+
const response = parseResponse(parseJson(decoder.decode(body), RESPONSE_INVALID), RESPONSE_INVALID);
|
|
57
|
+
const usage = parseUsage(response.usage, RESPONSE_INVALID);
|
|
58
|
+
const result = toResult(response.output, response.status, usage, response.incompleteReason);
|
|
59
|
+
const normalizedResponse = {
|
|
60
|
+
...response.normalizedResponse,
|
|
61
|
+
...(usage ? { usage } : {}),
|
|
62
|
+
};
|
|
63
|
+
let terminal;
|
|
64
|
+
switch (response.status) {
|
|
65
|
+
case 'completed':
|
|
66
|
+
terminal = {
|
|
67
|
+
status: 'succeeded',
|
|
68
|
+
acceptanceState: 'accepted',
|
|
69
|
+
retryable: false,
|
|
70
|
+
result,
|
|
71
|
+
normalizedResponse,
|
|
72
|
+
...(usage ? { usage } : {}),
|
|
73
|
+
};
|
|
74
|
+
break;
|
|
75
|
+
case 'incomplete':
|
|
76
|
+
if (!response.incompleteReason)
|
|
77
|
+
throw new Error(RESPONSE_INVALID);
|
|
78
|
+
terminal = {
|
|
79
|
+
status: 'incomplete',
|
|
80
|
+
acceptanceState: 'accepted',
|
|
81
|
+
retryable: false,
|
|
82
|
+
result,
|
|
83
|
+
normalizedResponse,
|
|
84
|
+
...(usage ? { usage } : {}),
|
|
85
|
+
incompleteDetails: { reason: response.incompleteReason },
|
|
86
|
+
};
|
|
87
|
+
break;
|
|
88
|
+
case 'failed':
|
|
89
|
+
if (!response.providerError)
|
|
90
|
+
throw new Error(RESPONSE_INVALID);
|
|
91
|
+
terminal = {
|
|
92
|
+
status: 'failed',
|
|
93
|
+
acceptanceState: 'accepted',
|
|
94
|
+
failureOrigin: 'provider',
|
|
95
|
+
failureCode: response.providerError.code,
|
|
96
|
+
retryable: false,
|
|
97
|
+
result,
|
|
98
|
+
normalizedResponse,
|
|
99
|
+
...(usage ? { usage } : {}),
|
|
100
|
+
providerError: response.providerError,
|
|
101
|
+
};
|
|
102
|
+
break;
|
|
103
|
+
case 'cancelled':
|
|
104
|
+
terminal = {
|
|
105
|
+
status: 'cancelled',
|
|
106
|
+
acceptanceState: 'accepted',
|
|
107
|
+
retryable: false,
|
|
108
|
+
result,
|
|
109
|
+
normalizedResponse,
|
|
110
|
+
...(usage ? { usage } : {}),
|
|
111
|
+
};
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
kind: 'sync',
|
|
116
|
+
acceptance: { state: 'accepted' },
|
|
117
|
+
responseMetadata: {
|
|
118
|
+
...responseMetadata,
|
|
119
|
+
...(response.normalizedResponse.model
|
|
120
|
+
? { observedModel: response.normalizedResponse.model }
|
|
121
|
+
: {}),
|
|
122
|
+
},
|
|
123
|
+
terminal,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return invalidSyncStart(responseMetadata);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function invalidSyncStart(responseMetadata) {
|
|
131
|
+
return {
|
|
132
|
+
kind: 'sync',
|
|
133
|
+
acceptance: { state: 'accepted' },
|
|
134
|
+
responseMetadata,
|
|
135
|
+
terminal: {
|
|
136
|
+
status: 'failed',
|
|
137
|
+
acceptanceState: 'accepted',
|
|
138
|
+
failureOrigin: 'provider',
|
|
139
|
+
failureCode: RESPONSE_INVALID,
|
|
140
|
+
retryable: false,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function failedStart(responseMetadata, status, body) {
|
|
145
|
+
const rateLimited = status === 429;
|
|
146
|
+
const errorBody = await collectErrorBody(body);
|
|
147
|
+
const providerError = errorBody ? tryParseErrorBody(errorBody) : undefined;
|
|
148
|
+
return {
|
|
149
|
+
kind: 'sync',
|
|
150
|
+
acceptance: { state: 'not-accepted' },
|
|
151
|
+
responseMetadata,
|
|
152
|
+
terminal: {
|
|
153
|
+
status: 'failed',
|
|
154
|
+
acceptanceState: 'not-accepted',
|
|
155
|
+
failureOrigin: 'provider',
|
|
156
|
+
failureCode: rateLimited ? 'PROVIDER_RATE_LIMITED' : 'PROVIDER_REQUEST_FAILED',
|
|
157
|
+
retryable: rateLimited || status >= 500,
|
|
158
|
+
...(providerError ? { providerError } : {}),
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function streamStart(body, responseMetadata) {
|
|
163
|
+
let resolveTerminal;
|
|
164
|
+
let terminalSettled = false;
|
|
165
|
+
let aborted = false;
|
|
166
|
+
const terminal = new Promise((resolve) => {
|
|
167
|
+
resolveTerminal = resolve;
|
|
168
|
+
});
|
|
169
|
+
const settle = (outcome) => {
|
|
170
|
+
if (terminalSettled)
|
|
171
|
+
return;
|
|
172
|
+
terminalSettled = true;
|
|
173
|
+
resolveTerminal(outcome);
|
|
174
|
+
};
|
|
175
|
+
const events = (async function* () {
|
|
176
|
+
let responseId;
|
|
177
|
+
let previousSequence = -1;
|
|
178
|
+
let usage;
|
|
179
|
+
const items = new Map();
|
|
180
|
+
const itemIndexes = new Map();
|
|
181
|
+
const completedItems = new Map();
|
|
182
|
+
try {
|
|
183
|
+
for await (const frame of parseOpenAiResponsesSseFrames(body)) {
|
|
184
|
+
if (aborted)
|
|
185
|
+
return;
|
|
186
|
+
const value = record(parseJson(frame.data, PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
187
|
+
if (value['type'] !== frame.event)
|
|
188
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
189
|
+
const sequenceNumber = requiredSequence(value, previousSequence);
|
|
190
|
+
previousSequence = sequenceNumber;
|
|
191
|
+
switch (frame.event) {
|
|
192
|
+
case 'response.created': {
|
|
193
|
+
if (responseId !== undefined)
|
|
194
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
195
|
+
responseId = responseIdFrom(value, PROVIDER_STREAM_INVALID);
|
|
196
|
+
yield event('response.started', responseId, sequenceNumber);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
case 'response.in_progress': {
|
|
200
|
+
const id = requireResponseId(value, responseId);
|
|
201
|
+
const response = record(value['response'], PROVIDER_STREAM_INVALID);
|
|
202
|
+
if (response['status'] !== 'in_progress')
|
|
203
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
204
|
+
yield {
|
|
205
|
+
...event('response.in_progress', id, sequenceNumber),
|
|
206
|
+
status: 'in_progress',
|
|
207
|
+
};
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
case 'response.output_item.added': {
|
|
211
|
+
const id = requireResponseId(value, responseId);
|
|
212
|
+
const outputIndex = requiredIndex(value['output_index']);
|
|
213
|
+
const parsed = parseOutputItem(record(value['item'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
214
|
+
if (parsed.status !== 'in_progress')
|
|
215
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
216
|
+
if (items.has(outputIndex) || itemIndexes.has(parsed.id)) {
|
|
217
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
218
|
+
}
|
|
219
|
+
const state = stateFromAdded(parsed, outputIndex);
|
|
220
|
+
items.set(outputIndex, state);
|
|
221
|
+
itemIndexes.set(parsed.id, outputIndex);
|
|
222
|
+
yield {
|
|
223
|
+
...event('output.item.added', id, sequenceNumber),
|
|
224
|
+
itemId: parsed.id,
|
|
225
|
+
outputIndex,
|
|
226
|
+
itemKind: parsed.kind,
|
|
227
|
+
item: parsed.normalized,
|
|
228
|
+
};
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
case 'response.content_part.added': {
|
|
232
|
+
const id = requireResponseId(value, responseId);
|
|
233
|
+
const outputIndex = requiredIndex(value['output_index']);
|
|
234
|
+
const itemId = requiredString(value['item_id'], PROVIDER_STREAM_INVALID);
|
|
235
|
+
const contentIndex = requiredIndex(value['content_index']);
|
|
236
|
+
const item = requireMessageItem(items, itemIndexes, outputIndex, itemId);
|
|
237
|
+
if (item.contents.has(contentIndex))
|
|
238
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
239
|
+
const part = parseMessagePart(record(value['part'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
240
|
+
if (part.value !== '')
|
|
241
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
242
|
+
item.contents.set(contentIndex, {
|
|
243
|
+
kind: part.kind,
|
|
244
|
+
value: part.value,
|
|
245
|
+
streamDone: false,
|
|
246
|
+
closed: false,
|
|
247
|
+
});
|
|
248
|
+
yield {
|
|
249
|
+
type: 'output.content_part.added',
|
|
250
|
+
eventId: `${id}:${sequenceNumber}`,
|
|
251
|
+
sequenceNumber,
|
|
252
|
+
responseId: id,
|
|
253
|
+
itemId,
|
|
254
|
+
outputIndex,
|
|
255
|
+
contentIndex,
|
|
256
|
+
part: part.normalized,
|
|
257
|
+
};
|
|
258
|
+
break;
|
|
259
|
+
}
|
|
260
|
+
case 'response.output_text.delta': {
|
|
261
|
+
const id = requireResponseId(value, responseId);
|
|
262
|
+
const indexed = contentCoordinates(value);
|
|
263
|
+
const content = requireContent(items, itemIndexes, indexed, 'text');
|
|
264
|
+
if (content.streamDone)
|
|
265
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
266
|
+
const delta = stringValue(value['delta'], PROVIDER_STREAM_INVALID);
|
|
267
|
+
content.value += delta;
|
|
268
|
+
yield {
|
|
269
|
+
...event('output.text.delta', id, sequenceNumber),
|
|
270
|
+
...indexed,
|
|
271
|
+
delta,
|
|
272
|
+
};
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
case 'response.output_text.done': {
|
|
276
|
+
const id = requireResponseId(value, responseId);
|
|
277
|
+
const indexed = contentCoordinates(value);
|
|
278
|
+
const content = requireContent(items, itemIndexes, indexed, 'text');
|
|
279
|
+
const text = stringValue(value['text'], PROVIDER_STREAM_INVALID);
|
|
280
|
+
if (content.streamDone || text !== content.value)
|
|
281
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
282
|
+
content.streamDone = true;
|
|
283
|
+
yield {
|
|
284
|
+
...event('output.text.completed', id, sequenceNumber),
|
|
285
|
+
...indexed,
|
|
286
|
+
text,
|
|
287
|
+
};
|
|
288
|
+
break;
|
|
289
|
+
}
|
|
290
|
+
case 'response.refusal.delta': {
|
|
291
|
+
const id = requireResponseId(value, responseId);
|
|
292
|
+
const indexed = contentCoordinates(value);
|
|
293
|
+
const content = requireContent(items, itemIndexes, indexed, 'refusal');
|
|
294
|
+
if (content.streamDone)
|
|
295
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
296
|
+
const delta = stringValue(value['delta'], PROVIDER_STREAM_INVALID);
|
|
297
|
+
content.value += delta;
|
|
298
|
+
yield {
|
|
299
|
+
...event('output.refusal.delta', id, sequenceNumber),
|
|
300
|
+
...indexed,
|
|
301
|
+
delta,
|
|
302
|
+
};
|
|
303
|
+
break;
|
|
304
|
+
}
|
|
305
|
+
case 'response.refusal.done': {
|
|
306
|
+
const id = requireResponseId(value, responseId);
|
|
307
|
+
const indexed = contentCoordinates(value);
|
|
308
|
+
const content = requireContent(items, itemIndexes, indexed, 'refusal');
|
|
309
|
+
const refusal = stringValue(value['refusal'], PROVIDER_STREAM_INVALID);
|
|
310
|
+
if (content.streamDone || refusal !== content.value)
|
|
311
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
312
|
+
content.streamDone = true;
|
|
313
|
+
yield {
|
|
314
|
+
...event('output.refusal.completed', id, sequenceNumber),
|
|
315
|
+
...indexed,
|
|
316
|
+
refusal,
|
|
317
|
+
};
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
case 'response.content_part.done': {
|
|
321
|
+
const id = requireResponseId(value, responseId);
|
|
322
|
+
const indexed = contentCoordinates(value);
|
|
323
|
+
const content = requireContent(items, itemIndexes, indexed);
|
|
324
|
+
const part = parseMessagePart(record(value['part'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
325
|
+
if (content.closed ||
|
|
326
|
+
!content.streamDone ||
|
|
327
|
+
part.kind !== content.kind ||
|
|
328
|
+
part.value !== content.value) {
|
|
329
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
330
|
+
}
|
|
331
|
+
content.closed = true;
|
|
332
|
+
yield {
|
|
333
|
+
type: 'output.content_part.completed',
|
|
334
|
+
eventId: `${id}:${sequenceNumber}`,
|
|
335
|
+
sequenceNumber,
|
|
336
|
+
responseId: id,
|
|
337
|
+
...indexed,
|
|
338
|
+
part: part.normalized,
|
|
339
|
+
};
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
case 'response.function_call_arguments.delta': {
|
|
343
|
+
const id = requireResponseId(value, responseId);
|
|
344
|
+
const indexed = itemCoordinates(value);
|
|
345
|
+
const item = requireFunctionItem(items, itemIndexes, indexed.outputIndex, indexed.itemId);
|
|
346
|
+
if (item.argumentsDone)
|
|
347
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
348
|
+
const delta = stringValue(value['delta'], PROVIDER_STREAM_INVALID);
|
|
349
|
+
item.arguments += delta;
|
|
350
|
+
yield {
|
|
351
|
+
...event('output.tool_call.delta', id, sequenceNumber),
|
|
352
|
+
...indexed,
|
|
353
|
+
callId: item.callId,
|
|
354
|
+
name: item.name,
|
|
355
|
+
argumentsDelta: delta,
|
|
356
|
+
};
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
case 'response.function_call_arguments.done': {
|
|
360
|
+
const id = requireResponseId(value, responseId);
|
|
361
|
+
const indexed = itemCoordinates(value);
|
|
362
|
+
const item = requireFunctionItem(items, itemIndexes, indexed.outputIndex, indexed.itemId);
|
|
363
|
+
const name = requiredString(value['name'], PROVIDER_STREAM_INVALID);
|
|
364
|
+
const args = stringValue(value['arguments'], PROVIDER_STREAM_INVALID);
|
|
365
|
+
if (item.argumentsDone || name !== item.name || args !== item.arguments) {
|
|
366
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
367
|
+
}
|
|
368
|
+
item.argumentsDone = true;
|
|
369
|
+
yield {
|
|
370
|
+
...event('output.tool_call.completed', id, sequenceNumber),
|
|
371
|
+
...indexed,
|
|
372
|
+
callId: item.callId,
|
|
373
|
+
name,
|
|
374
|
+
arguments: args,
|
|
375
|
+
};
|
|
376
|
+
break;
|
|
377
|
+
}
|
|
378
|
+
case 'response.reasoning_summary_part.added': {
|
|
379
|
+
const id = requireResponseId(value, responseId);
|
|
380
|
+
const indexed = summaryCoordinates(value);
|
|
381
|
+
const item = requireReasoningItem(items, itemIndexes, indexed.outputIndex, indexed.itemId);
|
|
382
|
+
if (item.summaries.has(indexed.contentIndex))
|
|
383
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
384
|
+
const part = parseSummaryPart(record(value['part'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
385
|
+
if (part.text !== '')
|
|
386
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
387
|
+
item.summaries.set(indexed.contentIndex, {
|
|
388
|
+
value: part.text,
|
|
389
|
+
streamDone: false,
|
|
390
|
+
closed: false,
|
|
391
|
+
});
|
|
392
|
+
yield {
|
|
393
|
+
type: 'output.content_part.added',
|
|
394
|
+
eventId: `${id}:${sequenceNumber}`,
|
|
395
|
+
sequenceNumber,
|
|
396
|
+
responseId: id,
|
|
397
|
+
...indexed,
|
|
398
|
+
part: { type: 'reasoning_summary', text: part.text },
|
|
399
|
+
};
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
case 'response.reasoning_summary_text.delta': {
|
|
403
|
+
const id = requireResponseId(value, responseId);
|
|
404
|
+
const indexed = summaryCoordinates(value);
|
|
405
|
+
const summary = requireSummary(items, itemIndexes, indexed);
|
|
406
|
+
if (summary.streamDone)
|
|
407
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
408
|
+
const delta = stringValue(value['delta'], PROVIDER_STREAM_INVALID);
|
|
409
|
+
summary.value += delta;
|
|
410
|
+
yield {
|
|
411
|
+
...event('output.reasoning_summary.delta', id, sequenceNumber),
|
|
412
|
+
...indexed,
|
|
413
|
+
delta,
|
|
414
|
+
};
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
case 'response.reasoning_summary_text.done': {
|
|
418
|
+
const id = requireResponseId(value, responseId);
|
|
419
|
+
const indexed = summaryCoordinates(value);
|
|
420
|
+
const summary = requireSummary(items, itemIndexes, indexed);
|
|
421
|
+
const text = stringValue(value['text'], PROVIDER_STREAM_INVALID);
|
|
422
|
+
if (summary.streamDone || text !== summary.value)
|
|
423
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
424
|
+
summary.streamDone = true;
|
|
425
|
+
yield {
|
|
426
|
+
...event('output.reasoning_summary.completed', id, sequenceNumber),
|
|
427
|
+
...indexed,
|
|
428
|
+
text,
|
|
429
|
+
};
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
case 'response.reasoning_summary_part.done': {
|
|
433
|
+
const id = requireResponseId(value, responseId);
|
|
434
|
+
const indexed = summaryCoordinates(value);
|
|
435
|
+
const summary = requireSummary(items, itemIndexes, indexed);
|
|
436
|
+
const part = parseSummaryPart(record(value['part'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
437
|
+
if (summary.closed || !summary.streamDone || part.text !== summary.value) {
|
|
438
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
439
|
+
}
|
|
440
|
+
summary.closed = true;
|
|
441
|
+
yield {
|
|
442
|
+
type: 'output.content_part.completed',
|
|
443
|
+
eventId: `${id}:${sequenceNumber}`,
|
|
444
|
+
sequenceNumber,
|
|
445
|
+
responseId: id,
|
|
446
|
+
...indexed,
|
|
447
|
+
part: { type: 'reasoning_summary', text: part.text },
|
|
448
|
+
};
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
case 'response.output_item.done': {
|
|
452
|
+
const id = requireResponseId(value, responseId);
|
|
453
|
+
const outputIndex = requiredIndex(value['output_index']);
|
|
454
|
+
const parsed = parseOutputItem(record(value['item'], PROVIDER_STREAM_INVALID), PROVIDER_STREAM_INVALID);
|
|
455
|
+
const state = requireItem(items, itemIndexes, outputIndex, parsed.id);
|
|
456
|
+
if (state.closed ||
|
|
457
|
+
(parsed.status !== 'completed' && parsed.status !== 'incomplete') ||
|
|
458
|
+
parsed.kind !== state.kind) {
|
|
459
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
460
|
+
}
|
|
461
|
+
const normalized = normalizedFromState(state);
|
|
462
|
+
if (JSON.stringify(parsed.normalized) !== JSON.stringify(normalized)) {
|
|
463
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
464
|
+
}
|
|
465
|
+
state.closed = true;
|
|
466
|
+
state.finalStatus = parsed.status;
|
|
467
|
+
completedItems.set(outputIndex, normalized);
|
|
468
|
+
yield {
|
|
469
|
+
...event('output.item.completed', id, sequenceNumber),
|
|
470
|
+
itemId: parsed.id,
|
|
471
|
+
outputIndex,
|
|
472
|
+
itemKind: parsed.kind,
|
|
473
|
+
status: parsed.status,
|
|
474
|
+
item: normalized,
|
|
475
|
+
};
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
case 'response.completed': {
|
|
479
|
+
const id = requireResponseId(value, responseId);
|
|
480
|
+
assertItemStatuses(items, new Set(['completed']));
|
|
481
|
+
const response = record(value['response'], PROVIDER_STREAM_INVALID);
|
|
482
|
+
if (response['status'] !== 'completed')
|
|
483
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
484
|
+
usage = parseUsage(response['usage'], PROVIDER_STREAM_INVALID) ?? usage;
|
|
485
|
+
const terminalOutcome = {
|
|
486
|
+
status: 'succeeded',
|
|
487
|
+
acceptanceState: 'accepted',
|
|
488
|
+
retryable: false,
|
|
489
|
+
result: toResult(sortedItems(completedItems), 'completed', usage),
|
|
490
|
+
...(usage ? { usage } : {}),
|
|
491
|
+
};
|
|
492
|
+
settle(terminalOutcome);
|
|
493
|
+
yield {
|
|
494
|
+
...event('response.completed', id, sequenceNumber),
|
|
495
|
+
...(usage ? { usage } : {}),
|
|
496
|
+
};
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
case 'response.incomplete': {
|
|
500
|
+
const id = requireResponseId(value, responseId);
|
|
501
|
+
assertItemStatuses(items, new Set(['completed', 'incomplete']));
|
|
502
|
+
const response = record(value['response'], PROVIDER_STREAM_INVALID);
|
|
503
|
+
if (response['status'] !== 'incomplete')
|
|
504
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
505
|
+
const reason = incompleteReason(response, PROVIDER_STREAM_INVALID);
|
|
506
|
+
usage = parseUsage(response['usage'], PROVIDER_STREAM_INVALID) ?? usage;
|
|
507
|
+
const terminalOutcome = {
|
|
508
|
+
status: 'incomplete',
|
|
509
|
+
acceptanceState: 'accepted',
|
|
510
|
+
retryable: false,
|
|
511
|
+
result: toResult(sortedItems(completedItems), 'incomplete', usage, reason),
|
|
512
|
+
...(usage ? { usage } : {}),
|
|
513
|
+
incompleteDetails: { reason },
|
|
514
|
+
};
|
|
515
|
+
settle(terminalOutcome);
|
|
516
|
+
yield {
|
|
517
|
+
...event('response.incomplete', id, sequenceNumber),
|
|
518
|
+
reason,
|
|
519
|
+
status: 'incomplete',
|
|
520
|
+
incompleteDetails: { reason },
|
|
521
|
+
...(usage ? { usage } : {}),
|
|
522
|
+
};
|
|
523
|
+
return;
|
|
524
|
+
}
|
|
525
|
+
case 'response.failed': {
|
|
526
|
+
const id = requireResponseId(value, responseId);
|
|
527
|
+
const response = record(value['response'], PROVIDER_STREAM_INVALID);
|
|
528
|
+
if (response['status'] !== 'failed')
|
|
529
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
530
|
+
const providerError = parseProviderError(response['error'], PROVIDER_STREAM_INVALID);
|
|
531
|
+
if (!providerError)
|
|
532
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
533
|
+
usage = parseUsage(response['usage'], PROVIDER_STREAM_INVALID) ?? usage;
|
|
534
|
+
settle(providerFailure(providerError, usage));
|
|
535
|
+
yield failureEvent(id, sequenceNumber, providerError, usage);
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
case 'response.cancelled': {
|
|
539
|
+
const id = requireResponseId(value, responseId);
|
|
540
|
+
const response = record(value['response'], PROVIDER_STREAM_INVALID);
|
|
541
|
+
if (response['status'] !== 'cancelled')
|
|
542
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
543
|
+
usage = parseUsage(response['usage'], PROVIDER_STREAM_INVALID) ?? usage;
|
|
544
|
+
const terminalOutcome = {
|
|
545
|
+
status: 'cancelled',
|
|
546
|
+
acceptanceState: 'accepted',
|
|
547
|
+
retryable: false,
|
|
548
|
+
result: toResult(sortedItems(completedItems), 'cancelled', usage),
|
|
549
|
+
...(usage ? { usage } : {}),
|
|
550
|
+
};
|
|
551
|
+
settle(terminalOutcome);
|
|
552
|
+
yield {
|
|
553
|
+
...event('response.cancelled', id, sequenceNumber),
|
|
554
|
+
status: 'cancelled',
|
|
555
|
+
...(usage ? { usage } : {}),
|
|
556
|
+
};
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
case 'error': {
|
|
560
|
+
const providerError = parseProviderError(value, PROVIDER_STREAM_INVALID);
|
|
561
|
+
if (!providerError)
|
|
562
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
563
|
+
settle(providerFailure(providerError));
|
|
564
|
+
if (responseId)
|
|
565
|
+
yield failureEvent(responseId, sequenceNumber, providerError);
|
|
566
|
+
return;
|
|
567
|
+
}
|
|
568
|
+
default:
|
|
569
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
573
|
+
}
|
|
574
|
+
catch {
|
|
575
|
+
if (aborted)
|
|
576
|
+
return;
|
|
577
|
+
settle({
|
|
578
|
+
status: 'failed',
|
|
579
|
+
acceptanceState: 'accepted',
|
|
580
|
+
failureOrigin: 'provider',
|
|
581
|
+
failureCode: RESPONSE_INVALID,
|
|
582
|
+
retryable: false,
|
|
583
|
+
});
|
|
584
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
585
|
+
}
|
|
586
|
+
finally {
|
|
587
|
+
if (!terminalSettled) {
|
|
588
|
+
settle({ status: 'cancelled', acceptanceState: 'accepted', retryable: false });
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
})();
|
|
592
|
+
return {
|
|
593
|
+
kind: 'stream',
|
|
594
|
+
acceptance: { state: 'accepted' },
|
|
595
|
+
responseMetadata,
|
|
596
|
+
events,
|
|
597
|
+
terminal,
|
|
598
|
+
abort: () => {
|
|
599
|
+
aborted = true;
|
|
600
|
+
settle({ status: 'cancelled', acceptanceState: 'accepted', retryable: false });
|
|
601
|
+
},
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function parseResponse(value, error) {
|
|
605
|
+
const response = record(value, error);
|
|
606
|
+
const output = Array.isArray(response['output']) ? response['output'] : undefined;
|
|
607
|
+
if (!output)
|
|
608
|
+
throw new Error(error);
|
|
609
|
+
const status = providerStatus(response['status'], error);
|
|
610
|
+
const providerError = parseProviderError(response['error'], error);
|
|
611
|
+
const reason = status === 'incomplete' ? incompleteReason(response, error) : undefined;
|
|
612
|
+
const parsedOutput = output.map((item) => parseOutputItem(record(item, error), error));
|
|
613
|
+
if (response['object'] !== undefined && response['object'] !== 'response')
|
|
614
|
+
throw new Error(error);
|
|
615
|
+
const model = optionalString(response['model'], error);
|
|
616
|
+
if (response['store'] !== undefined && response['store'] !== false)
|
|
617
|
+
throw new Error(error);
|
|
618
|
+
return {
|
|
619
|
+
id: requiredString(response['id'], error),
|
|
620
|
+
status,
|
|
621
|
+
output: parsedOutput.map((item) => item.normalized),
|
|
622
|
+
normalizedResponse: {
|
|
623
|
+
protocolFamily: PROTOCOL_FAMILY,
|
|
624
|
+
id: requiredString(response['id'], error),
|
|
625
|
+
object: 'response',
|
|
626
|
+
status,
|
|
627
|
+
...(model ? { model } : {}),
|
|
628
|
+
store: false,
|
|
629
|
+
output: parsedOutput.map((item) => item.normalizedResponse),
|
|
630
|
+
...(reason ? { incompleteDetails: { reason } } : {}),
|
|
631
|
+
...(providerError ? { error: providerError } : {}),
|
|
632
|
+
},
|
|
633
|
+
...(response['usage'] === undefined || response['usage'] === null
|
|
634
|
+
? {}
|
|
635
|
+
: { usage: response['usage'] }),
|
|
636
|
+
...(providerError ? { providerError } : {}),
|
|
637
|
+
...(reason ? { incompleteReason: reason } : {}),
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
function parseOutputItem(value, error) {
|
|
641
|
+
const id = requiredString(value['id'], error);
|
|
642
|
+
const status = outputItemStatus(value['status'], error);
|
|
643
|
+
if (value['type'] === 'message') {
|
|
644
|
+
const content = Array.isArray(value['content']) ? value['content'] : undefined;
|
|
645
|
+
if (!content)
|
|
646
|
+
throw new Error(error);
|
|
647
|
+
const parts = content.map((part) => parseMessagePart(record(part, error), error));
|
|
648
|
+
const role = optionalString(value['role'], error);
|
|
649
|
+
if (role !== undefined && role !== 'assistant')
|
|
650
|
+
throw new Error(error);
|
|
651
|
+
return {
|
|
652
|
+
id,
|
|
653
|
+
kind: 'message',
|
|
654
|
+
status,
|
|
655
|
+
normalized: {
|
|
656
|
+
type: 'message',
|
|
657
|
+
content: parts.map((part) => part.normalized),
|
|
658
|
+
},
|
|
659
|
+
normalizedResponse: {
|
|
660
|
+
id,
|
|
661
|
+
type: 'message',
|
|
662
|
+
status,
|
|
663
|
+
...(role === 'assistant' ? { role } : {}),
|
|
664
|
+
content: parts.map((part) => part.normalizedResponse),
|
|
665
|
+
},
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
if (value['type'] === 'function_call') {
|
|
669
|
+
return {
|
|
670
|
+
id,
|
|
671
|
+
kind: 'function_call',
|
|
672
|
+
status,
|
|
673
|
+
normalized: {
|
|
674
|
+
type: 'function_call',
|
|
675
|
+
callId: requiredString(value['call_id'], error),
|
|
676
|
+
name: requiredString(value['name'], error),
|
|
677
|
+
arguments: stringValue(value['arguments'], error),
|
|
678
|
+
},
|
|
679
|
+
normalizedResponse: {
|
|
680
|
+
id,
|
|
681
|
+
type: 'function_call',
|
|
682
|
+
status,
|
|
683
|
+
callId: requiredString(value['call_id'], error),
|
|
684
|
+
name: requiredString(value['name'], error),
|
|
685
|
+
arguments: stringValue(value['arguments'], error),
|
|
686
|
+
},
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
if (value['type'] === 'reasoning') {
|
|
690
|
+
const summary = Array.isArray(value['summary']) ? value['summary'] : undefined;
|
|
691
|
+
if (!summary)
|
|
692
|
+
throw new Error(error);
|
|
693
|
+
const parts = summary.map((part) => parseSummaryPart(record(part, error), error));
|
|
694
|
+
return {
|
|
695
|
+
id,
|
|
696
|
+
kind: 'reasoning',
|
|
697
|
+
status,
|
|
698
|
+
normalized: {
|
|
699
|
+
type: 'message',
|
|
700
|
+
content: parts.map((part) => ({
|
|
701
|
+
type: 'reasoning_summary',
|
|
702
|
+
text: part.text,
|
|
703
|
+
})),
|
|
704
|
+
},
|
|
705
|
+
normalizedResponse: { id, type: 'reasoning', status, summary: parts },
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
throw new Error(error);
|
|
709
|
+
}
|
|
710
|
+
function parseMessagePart(value, error) {
|
|
711
|
+
if (value['type'] === 'output_text') {
|
|
712
|
+
const text = stringValue(value['text'], error);
|
|
713
|
+
return {
|
|
714
|
+
kind: 'text',
|
|
715
|
+
value: text,
|
|
716
|
+
normalized: { type: 'text', text },
|
|
717
|
+
normalizedResponse: { type: 'output_text', text },
|
|
718
|
+
};
|
|
719
|
+
}
|
|
720
|
+
if (value['type'] === 'refusal') {
|
|
721
|
+
const refusal = stringValue(value['refusal'], error);
|
|
722
|
+
return {
|
|
723
|
+
kind: 'refusal',
|
|
724
|
+
value: refusal,
|
|
725
|
+
normalized: { type: 'refusal', text: refusal },
|
|
726
|
+
normalizedResponse: { type: 'refusal', refusal },
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
throw new Error(error);
|
|
730
|
+
}
|
|
731
|
+
function parseSummaryPart(value, error) {
|
|
732
|
+
if (value['type'] !== 'summary_text')
|
|
733
|
+
throw new Error(error);
|
|
734
|
+
return { type: 'summary_text', text: stringValue(value['text'], error) };
|
|
735
|
+
}
|
|
736
|
+
function stateFromAdded(parsed, outputIndex) {
|
|
737
|
+
if (parsed.kind === 'function_call') {
|
|
738
|
+
if (parsed.normalized.type !== 'function_call' || parsed.normalized.arguments !== '') {
|
|
739
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
740
|
+
}
|
|
741
|
+
return {
|
|
742
|
+
kind: 'function_call',
|
|
743
|
+
outputIndex,
|
|
744
|
+
itemId: parsed.id,
|
|
745
|
+
callId: parsed.normalized.callId,
|
|
746
|
+
name: parsed.normalized.name,
|
|
747
|
+
arguments: '',
|
|
748
|
+
argumentsDone: false,
|
|
749
|
+
closed: false,
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
if (parsed.normalized.type !== 'message' || parsed.normalized.content.length !== 0) {
|
|
753
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
754
|
+
}
|
|
755
|
+
if (parsed.kind === 'message') {
|
|
756
|
+
return {
|
|
757
|
+
kind: 'message',
|
|
758
|
+
outputIndex,
|
|
759
|
+
itemId: parsed.id,
|
|
760
|
+
contents: new Map(),
|
|
761
|
+
closed: false,
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
return {
|
|
765
|
+
kind: 'reasoning',
|
|
766
|
+
outputIndex,
|
|
767
|
+
itemId: parsed.id,
|
|
768
|
+
summaries: new Map(),
|
|
769
|
+
closed: false,
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
function requireItem(items, itemIndexes, outputIndex, itemId) {
|
|
773
|
+
const item = items.get(outputIndex);
|
|
774
|
+
if (!item || item.closed || item.itemId !== itemId || itemIndexes.get(itemId) !== outputIndex) {
|
|
775
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
776
|
+
}
|
|
777
|
+
return item;
|
|
778
|
+
}
|
|
779
|
+
function requireMessageItem(items, itemIndexes, outputIndex, itemId) {
|
|
780
|
+
const item = requireItem(items, itemIndexes, outputIndex, itemId);
|
|
781
|
+
if (item.kind !== 'message')
|
|
782
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
783
|
+
return item;
|
|
784
|
+
}
|
|
785
|
+
function requireFunctionItem(items, itemIndexes, outputIndex, itemId) {
|
|
786
|
+
const item = requireItem(items, itemIndexes, outputIndex, itemId);
|
|
787
|
+
if (item.kind !== 'function_call')
|
|
788
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
789
|
+
return item;
|
|
790
|
+
}
|
|
791
|
+
function requireReasoningItem(items, itemIndexes, outputIndex, itemId) {
|
|
792
|
+
const item = requireItem(items, itemIndexes, outputIndex, itemId);
|
|
793
|
+
if (item.kind !== 'reasoning')
|
|
794
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
795
|
+
return item;
|
|
796
|
+
}
|
|
797
|
+
function requireContent(items, itemIndexes, indexed, kind) {
|
|
798
|
+
const item = requireMessageItem(items, itemIndexes, indexed.outputIndex, indexed.itemId);
|
|
799
|
+
const content = item.contents.get(indexed.contentIndex);
|
|
800
|
+
if (!content || content.closed || (kind && content.kind !== kind)) {
|
|
801
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
802
|
+
}
|
|
803
|
+
return content;
|
|
804
|
+
}
|
|
805
|
+
function requireSummary(items, itemIndexes, indexed) {
|
|
806
|
+
const item = requireReasoningItem(items, itemIndexes, indexed.outputIndex, indexed.itemId);
|
|
807
|
+
const summary = item.summaries.get(indexed.contentIndex);
|
|
808
|
+
if (!summary || summary.closed)
|
|
809
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
810
|
+
return summary;
|
|
811
|
+
}
|
|
812
|
+
function normalizedFromState(state) {
|
|
813
|
+
if (state.kind === 'function_call') {
|
|
814
|
+
if (!state.argumentsDone)
|
|
815
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
816
|
+
return {
|
|
817
|
+
type: 'function_call',
|
|
818
|
+
callId: state.callId,
|
|
819
|
+
name: state.name,
|
|
820
|
+
arguments: state.arguments,
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
if (state.kind === 'message') {
|
|
824
|
+
const content = [...state.contents.entries()]
|
|
825
|
+
.sort(([left], [right]) => left - right)
|
|
826
|
+
.map(([, part]) => {
|
|
827
|
+
if (!part.closed)
|
|
828
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
829
|
+
return part.kind === 'text'
|
|
830
|
+
? { type: 'text', text: part.value }
|
|
831
|
+
: { type: 'refusal', text: part.value };
|
|
832
|
+
});
|
|
833
|
+
return { type: 'message', content };
|
|
834
|
+
}
|
|
835
|
+
const content = [...state.summaries.entries()]
|
|
836
|
+
.sort(([left], [right]) => left - right)
|
|
837
|
+
.map(([, part]) => {
|
|
838
|
+
if (!part.closed)
|
|
839
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
840
|
+
return { type: 'reasoning_summary', text: part.value };
|
|
841
|
+
});
|
|
842
|
+
return { type: 'message', content };
|
|
843
|
+
}
|
|
844
|
+
function assertItemStatuses(items, allowedStatuses) {
|
|
845
|
+
if ([...items.values()].some((item) => !item.closed || !item.finalStatus || !allowedStatuses.has(item.finalStatus))) {
|
|
846
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
function sortedItems(items) {
|
|
850
|
+
return [...items.entries()].sort(([left], [right]) => left - right).map(([, item]) => item);
|
|
851
|
+
}
|
|
852
|
+
function itemCoordinates(value) {
|
|
853
|
+
return {
|
|
854
|
+
itemId: requiredString(value['item_id'], PROVIDER_STREAM_INVALID),
|
|
855
|
+
outputIndex: requiredIndex(value['output_index']),
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
function contentCoordinates(value) {
|
|
859
|
+
return { ...itemCoordinates(value), contentIndex: requiredIndex(value['content_index']) };
|
|
860
|
+
}
|
|
861
|
+
function summaryCoordinates(value) {
|
|
862
|
+
return { ...itemCoordinates(value), contentIndex: requiredIndex(value['summary_index']) };
|
|
863
|
+
}
|
|
864
|
+
function providerFailure(providerError, usage) {
|
|
865
|
+
return {
|
|
866
|
+
status: 'failed',
|
|
867
|
+
acceptanceState: 'accepted',
|
|
868
|
+
failureOrigin: 'provider',
|
|
869
|
+
failureCode: providerError.code,
|
|
870
|
+
retryable: false,
|
|
871
|
+
providerError,
|
|
872
|
+
...(usage ? { usage } : {}),
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
function failureEvent(responseId, sequenceNumber, providerError, usage) {
|
|
876
|
+
return {
|
|
877
|
+
...event('response.failed', responseId, sequenceNumber),
|
|
878
|
+
status: 'failed',
|
|
879
|
+
error: { code: providerError.code, category: 'provider', retryable: false },
|
|
880
|
+
providerError,
|
|
881
|
+
...(usage ? { usage } : {}),
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
function toResult(output, status, usage, incomplete) {
|
|
885
|
+
const items = [];
|
|
886
|
+
for (const item of output) {
|
|
887
|
+
if (item.type === 'function_call')
|
|
888
|
+
items.push(item);
|
|
889
|
+
else {
|
|
890
|
+
for (const part of item.content) {
|
|
891
|
+
if (part.type === 'text')
|
|
892
|
+
items.push({ type: 'text', text: part.text });
|
|
893
|
+
if (part.type === 'refusal')
|
|
894
|
+
items.push({ type: 'refusal', text: part.text });
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
return {
|
|
899
|
+
taskKind: 'chat',
|
|
900
|
+
output: {
|
|
901
|
+
items,
|
|
902
|
+
finishReason: status,
|
|
903
|
+
...(incomplete ? { incompleteReason: incomplete } : {}),
|
|
904
|
+
},
|
|
905
|
+
...(usage ? { usage } : {}),
|
|
906
|
+
};
|
|
907
|
+
}
|
|
908
|
+
function parseUsage(value, error) {
|
|
909
|
+
if (value === undefined || value === null)
|
|
910
|
+
return undefined;
|
|
911
|
+
const usage = record(value, error);
|
|
912
|
+
const inputTokens = optionalNumber(usage['input_tokens'], error);
|
|
913
|
+
const outputTokens = optionalNumber(usage['output_tokens'], error);
|
|
914
|
+
const totalTokens = optionalNumber(usage['total_tokens'], error);
|
|
915
|
+
const inputDetails = usage['input_tokens_details'] === undefined || usage['input_tokens_details'] === null
|
|
916
|
+
? undefined
|
|
917
|
+
: record(usage['input_tokens_details'], error);
|
|
918
|
+
const outputDetails = usage['output_tokens_details'] === undefined || usage['output_tokens_details'] === null
|
|
919
|
+
? undefined
|
|
920
|
+
: record(usage['output_tokens_details'], error);
|
|
921
|
+
const cachedInputTokens = inputDetails
|
|
922
|
+
? optionalNumber(inputDetails['cached_tokens'], error)
|
|
923
|
+
: undefined;
|
|
924
|
+
const reasoningOutputTokens = outputDetails
|
|
925
|
+
? optionalNumber(outputDetails['reasoning_tokens'], error)
|
|
926
|
+
: undefined;
|
|
927
|
+
return {
|
|
928
|
+
...(inputTokens === undefined ? {} : { inputTokens }),
|
|
929
|
+
...(outputTokens === undefined ? {} : { outputTokens }),
|
|
930
|
+
...(totalTokens === undefined ? {} : { totalTokens }),
|
|
931
|
+
...(cachedInputTokens === undefined ? {} : { cachedInputTokens }),
|
|
932
|
+
...(reasoningOutputTokens === undefined ? {} : { reasoningOutputTokens }),
|
|
933
|
+
...(inputDetails
|
|
934
|
+
? {
|
|
935
|
+
inputTokenDetails: {
|
|
936
|
+
...(cachedInputTokens === undefined ? {} : { cachedTokens: cachedInputTokens }),
|
|
937
|
+
},
|
|
938
|
+
}
|
|
939
|
+
: {}),
|
|
940
|
+
...(outputDetails
|
|
941
|
+
? {
|
|
942
|
+
outputTokenDetails: {
|
|
943
|
+
...(reasoningOutputTokens === undefined
|
|
944
|
+
? {}
|
|
945
|
+
: { reasoningTokens: reasoningOutputTokens }),
|
|
946
|
+
},
|
|
947
|
+
}
|
|
948
|
+
: {}),
|
|
949
|
+
estimated: false,
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
function parseProviderError(value, error) {
|
|
953
|
+
if (value === undefined || value === null)
|
|
954
|
+
return undefined;
|
|
955
|
+
const providerError = record(value, error);
|
|
956
|
+
const code = requiredString(providerError['code'], error);
|
|
957
|
+
const message = providerError['message'];
|
|
958
|
+
if (message !== undefined && message !== null && typeof message !== 'string') {
|
|
959
|
+
throw new Error(error);
|
|
960
|
+
}
|
|
961
|
+
return { code, ...(typeof message === 'string' ? { message } : {}) };
|
|
962
|
+
}
|
|
963
|
+
function tryParseErrorBody(body) {
|
|
964
|
+
try {
|
|
965
|
+
const root = record(parseJson(decoder.decode(body), RESPONSE_INVALID), RESPONSE_INVALID);
|
|
966
|
+
return parseProviderError(root['error'], RESPONSE_INVALID);
|
|
967
|
+
}
|
|
968
|
+
catch {
|
|
969
|
+
return undefined;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
async function collectErrorBody(body) {
|
|
973
|
+
if (body instanceof Uint8Array)
|
|
974
|
+
return body;
|
|
975
|
+
const chunks = [];
|
|
976
|
+
let length = 0;
|
|
977
|
+
for await (const chunk of body) {
|
|
978
|
+
length += chunk.byteLength;
|
|
979
|
+
if (length > MAX_ERROR_BODY_BYTES)
|
|
980
|
+
return undefined;
|
|
981
|
+
chunks.push(chunk);
|
|
982
|
+
}
|
|
983
|
+
const collected = new Uint8Array(length);
|
|
984
|
+
let offset = 0;
|
|
985
|
+
for (const chunk of chunks) {
|
|
986
|
+
collected.set(chunk, offset);
|
|
987
|
+
offset += chunk.byteLength;
|
|
988
|
+
}
|
|
989
|
+
return collected;
|
|
990
|
+
}
|
|
991
|
+
function incompleteReason(response, error) {
|
|
992
|
+
const details = record(response['incomplete_details'], error);
|
|
993
|
+
return requiredString(details['reason'], error);
|
|
994
|
+
}
|
|
995
|
+
function providerStatus(value, error) {
|
|
996
|
+
if (value === 'completed' ||
|
|
997
|
+
value === 'incomplete' ||
|
|
998
|
+
value === 'failed' ||
|
|
999
|
+
value === 'cancelled') {
|
|
1000
|
+
return value;
|
|
1001
|
+
}
|
|
1002
|
+
throw new Error(error);
|
|
1003
|
+
}
|
|
1004
|
+
function outputItemStatus(value, error) {
|
|
1005
|
+
if (value === 'in_progress' || value === 'completed' || value === 'incomplete')
|
|
1006
|
+
return value;
|
|
1007
|
+
throw new Error(error);
|
|
1008
|
+
}
|
|
1009
|
+
function event(type, responseId, sequenceNumber) {
|
|
1010
|
+
return {
|
|
1011
|
+
type,
|
|
1012
|
+
eventId: `${responseId}:${sequenceNumber}`,
|
|
1013
|
+
responseId,
|
|
1014
|
+
sequenceNumber,
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
function responseIdFrom(value, error) {
|
|
1018
|
+
return requiredString(record(value['response'], error)['id'], error);
|
|
1019
|
+
}
|
|
1020
|
+
function requireResponseId(value, responseId) {
|
|
1021
|
+
if (!responseId)
|
|
1022
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
1023
|
+
if (value['response'] !== undefined &&
|
|
1024
|
+
responseIdFrom(value, PROVIDER_STREAM_INVALID) !== responseId) {
|
|
1025
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
1026
|
+
}
|
|
1027
|
+
return responseId;
|
|
1028
|
+
}
|
|
1029
|
+
function requiredSequence(value, previous) {
|
|
1030
|
+
const sequence = requiredIndex(value['sequence_number']);
|
|
1031
|
+
if (sequence <= previous)
|
|
1032
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
1033
|
+
return sequence;
|
|
1034
|
+
}
|
|
1035
|
+
function requiredIndex(value) {
|
|
1036
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
1037
|
+
throw new Error(PROVIDER_STREAM_INVALID);
|
|
1038
|
+
return value;
|
|
1039
|
+
}
|
|
1040
|
+
function requiredString(value, error) {
|
|
1041
|
+
if (typeof value !== 'string' || !value)
|
|
1042
|
+
throw new Error(error);
|
|
1043
|
+
return value;
|
|
1044
|
+
}
|
|
1045
|
+
function optionalString(value, error) {
|
|
1046
|
+
if (value === undefined || value === null)
|
|
1047
|
+
return undefined;
|
|
1048
|
+
return requiredString(value, error);
|
|
1049
|
+
}
|
|
1050
|
+
function stringValue(value, error) {
|
|
1051
|
+
if (typeof value !== 'string')
|
|
1052
|
+
throw new Error(error);
|
|
1053
|
+
return value;
|
|
1054
|
+
}
|
|
1055
|
+
function optionalNumber(value, error) {
|
|
1056
|
+
if (value === undefined)
|
|
1057
|
+
return undefined;
|
|
1058
|
+
if (!Number.isSafeInteger(value) || value < 0)
|
|
1059
|
+
throw new Error(error);
|
|
1060
|
+
return value;
|
|
1061
|
+
}
|
|
1062
|
+
function metadata(response) {
|
|
1063
|
+
const providerRequestId = response.headers['x-request-id'] ?? response.headers['request-id'];
|
|
1064
|
+
return {
|
|
1065
|
+
headersReceived: true,
|
|
1066
|
+
statusCode: response.status,
|
|
1067
|
+
...(providerRequestId ? { providerRequestId } : {}),
|
|
1068
|
+
};
|
|
1069
|
+
}
|
|
1070
|
+
function parseJson(value, error) {
|
|
1071
|
+
try {
|
|
1072
|
+
return JSON.parse(value);
|
|
1073
|
+
}
|
|
1074
|
+
catch {
|
|
1075
|
+
throw new Error(error);
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
function record(value, error) {
|
|
1079
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
1080
|
+
throw new Error(error);
|
|
1081
|
+
return value;
|
|
1082
|
+
}
|
|
1083
|
+
function isAsyncIterable(value) {
|
|
1084
|
+
return typeof value === 'object' && value !== null && Symbol.asyncIterator in value;
|
|
1085
|
+
}
|
|
1086
|
+
//# sourceMappingURL=codec.js.map
|