@providerprotocol/ai 0.0.7 → 0.0.9
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/dist/anthropic/index.js +1 -1
- package/dist/{chunk-QUUX4G7U.js → chunk-W4BB4BG2.js} +19 -1
- package/dist/chunk-W4BB4BG2.js.map +1 -0
- package/dist/google/index.js +1 -1
- package/dist/index.d.ts +12 -0
- package/dist/index.js +1 -1
- package/dist/ollama/index.js +1 -1
- package/dist/openai/index.d.ts +385 -14
- package/dist/openai/index.js +110 -17
- package/dist/openai/index.js.map +1 -1
- package/dist/openrouter/index.js +1 -1
- package/dist/xai/index.js +1 -1
- package/package.json +1 -1
- package/src/openai/index.ts +29 -1
- package/src/providers/openai/index.ts +30 -0
- package/src/providers/openai/transform.responses.ts +51 -19
- package/src/providers/openai/types.ts +510 -16
- package/src/types/messages.ts +24 -1
- package/dist/chunk-QUUX4G7U.js.map +0 -1
|
@@ -3,7 +3,7 @@ import type { Message } from '../../types/messages.ts';
|
|
|
3
3
|
import type { StreamEvent } from '../../types/stream.ts';
|
|
4
4
|
import type { Tool, ToolCall } from '../../types/tool.ts';
|
|
5
5
|
import type { TokenUsage } from '../../types/turn.ts';
|
|
6
|
-
import type { ContentBlock, TextBlock, ImageBlock } from '../../types/content.ts';
|
|
6
|
+
import type { ContentBlock, TextBlock, ImageBlock, AssistantContent } from '../../types/content.ts';
|
|
7
7
|
import {
|
|
8
8
|
AssistantMessage,
|
|
9
9
|
isUserMessage,
|
|
@@ -16,11 +16,13 @@ import type {
|
|
|
16
16
|
OpenAIResponsesInputItem,
|
|
17
17
|
OpenAIResponsesContentPart,
|
|
18
18
|
OpenAIResponsesTool,
|
|
19
|
+
OpenAIResponsesToolUnion,
|
|
19
20
|
OpenAIResponsesResponse,
|
|
20
21
|
OpenAIResponsesStreamEvent,
|
|
21
22
|
OpenAIResponsesOutputItem,
|
|
22
23
|
OpenAIResponsesMessageOutput,
|
|
23
24
|
OpenAIResponsesFunctionCallOutput,
|
|
25
|
+
OpenAIResponsesImageGenerationOutput,
|
|
24
26
|
} from './types.ts';
|
|
25
27
|
|
|
26
28
|
/**
|
|
@@ -36,16 +38,23 @@ export function transformRequest(
|
|
|
36
38
|
): OpenAIResponsesRequest {
|
|
37
39
|
const params = request.params ?? ({} as OpenAIResponsesParams);
|
|
38
40
|
|
|
41
|
+
// Extract built-in tools from params before spreading
|
|
42
|
+
const builtInTools = params.tools as OpenAIResponsesToolUnion[] | undefined;
|
|
43
|
+
const { tools: _paramsTools, ...restParams } = params;
|
|
44
|
+
|
|
39
45
|
// Spread params to pass through all fields, then set required fields
|
|
40
46
|
const openaiRequest: OpenAIResponsesRequest = {
|
|
41
|
-
...
|
|
47
|
+
...restParams,
|
|
42
48
|
model: modelId,
|
|
43
49
|
input: transformInputItems(request.messages, request.system),
|
|
44
50
|
};
|
|
45
51
|
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
52
|
+
// Merge tools: UPP function tools from request + built-in tools from params
|
|
53
|
+
const functionTools: OpenAIResponsesToolUnion[] = request.tools?.map(transformTool) ?? [];
|
|
54
|
+
const allTools: OpenAIResponsesToolUnion[] = [...functionTools, ...(builtInTools ?? [])];
|
|
55
|
+
|
|
56
|
+
if (allTools.length > 0) {
|
|
57
|
+
openaiRequest.tools = allTools;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
60
|
// Structured output via text.format (overrides params.text if set)
|
|
@@ -276,8 +285,8 @@ function transformTool(tool: Tool): OpenAIResponsesTool {
|
|
|
276
285
|
* Transform OpenAI Responses API response to UPP LLMResponse
|
|
277
286
|
*/
|
|
278
287
|
export function transformResponse(data: OpenAIResponsesResponse): LLMResponse {
|
|
279
|
-
// Extract
|
|
280
|
-
const
|
|
288
|
+
// Extract content and tool calls from output items
|
|
289
|
+
const content: AssistantContent[] = [];
|
|
281
290
|
const toolCalls: ToolCall[] = [];
|
|
282
291
|
const functionCallItems: Array<{
|
|
283
292
|
id: string;
|
|
@@ -291,20 +300,19 @@ export function transformResponse(data: OpenAIResponsesResponse): LLMResponse {
|
|
|
291
300
|
for (const item of data.output) {
|
|
292
301
|
if (item.type === 'message') {
|
|
293
302
|
const messageItem = item as OpenAIResponsesMessageOutput;
|
|
294
|
-
for (const
|
|
295
|
-
if (
|
|
296
|
-
|
|
303
|
+
for (const part of messageItem.content) {
|
|
304
|
+
if (part.type === 'output_text') {
|
|
305
|
+
content.push({ type: 'text', text: part.text });
|
|
297
306
|
// Try to parse as JSON for structured output (native JSON mode)
|
|
298
|
-
// Only set data if text is valid JSON
|
|
299
307
|
if (structuredData === undefined) {
|
|
300
308
|
try {
|
|
301
|
-
structuredData = JSON.parse(
|
|
309
|
+
structuredData = JSON.parse(part.text);
|
|
302
310
|
} catch {
|
|
303
311
|
// Not valid JSON - that's fine, might not be structured output
|
|
304
312
|
}
|
|
305
313
|
}
|
|
306
|
-
} else if (
|
|
307
|
-
|
|
314
|
+
} else if (part.type === 'refusal') {
|
|
315
|
+
content.push({ type: 'text', text: part.refusal });
|
|
308
316
|
hadRefusal = true;
|
|
309
317
|
}
|
|
310
318
|
}
|
|
@@ -327,11 +335,20 @@ export function transformResponse(data: OpenAIResponsesResponse): LLMResponse {
|
|
|
327
335
|
name: functionCall.name,
|
|
328
336
|
arguments: functionCall.arguments,
|
|
329
337
|
});
|
|
338
|
+
} else if (item.type === 'image_generation_call') {
|
|
339
|
+
const imageGen = item as OpenAIResponsesImageGenerationOutput;
|
|
340
|
+
if (imageGen.result) {
|
|
341
|
+
content.push({
|
|
342
|
+
type: 'image',
|
|
343
|
+
mimeType: 'image/png',
|
|
344
|
+
source: { type: 'base64', data: imageGen.result },
|
|
345
|
+
} as ImageBlock);
|
|
346
|
+
}
|
|
330
347
|
}
|
|
331
348
|
}
|
|
332
349
|
|
|
333
350
|
const message = new AssistantMessage(
|
|
334
|
-
|
|
351
|
+
content,
|
|
335
352
|
toolCalls.length > 0 ? toolCalls : undefined,
|
|
336
353
|
{
|
|
337
354
|
id: data.id,
|
|
@@ -339,7 +356,6 @@ export function transformResponse(data: OpenAIResponsesResponse): LLMResponse {
|
|
|
339
356
|
openai: {
|
|
340
357
|
model: data.model,
|
|
341
358
|
status: data.status,
|
|
342
|
-
// Store response_id for multi-turn tool calling
|
|
343
359
|
response_id: data.id,
|
|
344
360
|
functionCallItems:
|
|
345
361
|
functionCallItems.length > 0 ? functionCallItems : undefined,
|
|
@@ -388,6 +404,7 @@ export interface ResponsesStreamState {
|
|
|
388
404
|
number,
|
|
389
405
|
{ itemId?: string; callId?: string; name?: string; arguments: string }
|
|
390
406
|
>;
|
|
407
|
+
images: string[]; // Base64 image data from image_generation_call outputs
|
|
391
408
|
status: string;
|
|
392
409
|
inputTokens: number;
|
|
393
410
|
outputTokens: number;
|
|
@@ -403,6 +420,7 @@ export function createStreamState(): ResponsesStreamState {
|
|
|
403
420
|
model: '',
|
|
404
421
|
textByIndex: new Map(),
|
|
405
422
|
toolCalls: new Map(),
|
|
423
|
+
images: [],
|
|
406
424
|
status: 'in_progress',
|
|
407
425
|
inputTokens: 0,
|
|
408
426
|
outputTokens: 0,
|
|
@@ -479,6 +497,11 @@ export function transformStreamEvent(
|
|
|
479
497
|
existing.arguments = functionCall.arguments;
|
|
480
498
|
}
|
|
481
499
|
state.toolCalls.set(event.output_index, existing);
|
|
500
|
+
} else if (event.item.type === 'image_generation_call') {
|
|
501
|
+
const imageGen = event.item as OpenAIResponsesImageGenerationOutput;
|
|
502
|
+
if (imageGen.result) {
|
|
503
|
+
state.images.push(imageGen.result);
|
|
504
|
+
}
|
|
482
505
|
}
|
|
483
506
|
events.push({
|
|
484
507
|
type: 'content_block_stop',
|
|
@@ -579,13 +602,13 @@ export function transformStreamEvent(
|
|
|
579
602
|
* Build LLMResponse from accumulated stream state
|
|
580
603
|
*/
|
|
581
604
|
export function buildResponseFromState(state: ResponsesStreamState): LLMResponse {
|
|
582
|
-
const
|
|
605
|
+
const content: AssistantContent[] = [];
|
|
583
606
|
let structuredData: unknown;
|
|
584
607
|
|
|
585
608
|
// Combine all text content
|
|
586
609
|
for (const [, text] of state.textByIndex) {
|
|
587
610
|
if (text) {
|
|
588
|
-
|
|
611
|
+
content.push({ type: 'text', text });
|
|
589
612
|
// Try to parse as JSON for structured output (native JSON mode)
|
|
590
613
|
if (structuredData === undefined) {
|
|
591
614
|
try {
|
|
@@ -597,6 +620,15 @@ export function buildResponseFromState(state: ResponsesStreamState): LLMResponse
|
|
|
597
620
|
}
|
|
598
621
|
}
|
|
599
622
|
|
|
623
|
+
// Add any generated images
|
|
624
|
+
for (const imageData of state.images) {
|
|
625
|
+
content.push({
|
|
626
|
+
type: 'image',
|
|
627
|
+
mimeType: 'image/png',
|
|
628
|
+
source: { type: 'base64', data: imageData },
|
|
629
|
+
} as ImageBlock);
|
|
630
|
+
}
|
|
631
|
+
|
|
600
632
|
const toolCalls: ToolCall[] = [];
|
|
601
633
|
const functionCallItems: Array<{
|
|
602
634
|
id: string;
|
|
@@ -633,7 +665,7 @@ export function buildResponseFromState(state: ResponsesStreamState): LLMResponse
|
|
|
633
665
|
}
|
|
634
666
|
|
|
635
667
|
const message = new AssistantMessage(
|
|
636
|
-
|
|
668
|
+
content,
|
|
637
669
|
toolCalls.length > 0 ? toolCalls : undefined,
|
|
638
670
|
{
|
|
639
671
|
id: state.id,
|