@yourgpt/llm-sdk 2.6.0-beta.1 → 2.6.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +112 -0
- package/dist/adapters/index.d.mts +5 -5
- package/dist/adapters/index.d.ts +5 -5
- package/dist/adapters/index.js +372 -39
- package/dist/adapters/index.mjs +372 -39
- package/dist/audio-BBSwnjo8.d.mts +92 -0
- package/dist/audio-BBSwnjo8.d.ts +92 -0
- package/dist/{base-CkeT7u-O.d.mts → base-BICaQaRS.d.mts} +7 -3
- package/dist/{base-BdTpUAWI.d.ts → base-CpRPB8u8.d.ts} +7 -3
- package/dist/fallback/index.d.mts +4 -4
- package/dist/fallback/index.d.ts +4 -4
- package/dist/index.d.mts +17 -35
- package/dist/index.d.ts +17 -35
- package/dist/index.js +229 -60
- package/dist/index.mjs +227 -61
- package/dist/providers/anthropic/index.d.mts +3 -3
- package/dist/providers/anthropic/index.d.ts +3 -3
- package/dist/providers/anthropic/index.js +123 -7
- package/dist/providers/anthropic/index.mjs +123 -7
- package/dist/providers/azure/index.d.mts +3 -3
- package/dist/providers/azure/index.d.ts +3 -3
- package/dist/providers/azure/index.js +101 -4
- package/dist/providers/azure/index.mjs +101 -4
- package/dist/providers/fireworks/index.d.mts +3 -3
- package/dist/providers/fireworks/index.d.ts +3 -3
- package/dist/providers/fireworks/index.js +321 -31
- package/dist/providers/fireworks/index.mjs +321 -31
- package/dist/providers/google/index.d.mts +3 -3
- package/dist/providers/google/index.d.ts +3 -3
- package/dist/providers/google/index.js +321 -31
- package/dist/providers/google/index.mjs +321 -31
- package/dist/providers/ollama/index.d.mts +4 -4
- package/dist/providers/ollama/index.d.ts +4 -4
- package/dist/providers/ollama/index.js +87 -2
- package/dist/providers/ollama/index.mjs +87 -2
- package/dist/providers/openai/index.d.mts +25 -6
- package/dist/providers/openai/index.d.ts +25 -6
- package/dist/providers/openai/index.js +750 -40
- package/dist/providers/openai/index.mjs +749 -41
- package/dist/providers/openrouter/index.d.mts +3 -3
- package/dist/providers/openrouter/index.d.ts +3 -3
- package/dist/providers/openrouter/index.js +321 -31
- package/dist/providers/openrouter/index.mjs +321 -31
- package/dist/providers/togetherai/index.d.mts +3 -3
- package/dist/providers/togetherai/index.d.ts +3 -3
- package/dist/providers/togetherai/index.js +321 -31
- package/dist/providers/togetherai/index.mjs +321 -31
- package/dist/providers/xai/index.d.mts +3 -3
- package/dist/providers/xai/index.d.ts +3 -3
- package/dist/providers/xai/index.js +321 -31
- package/dist/providers/xai/index.mjs +321 -31
- package/dist/{types-BWRYIvl_.d.mts → types-C3RgRbEC.d.mts} +1 -1
- package/dist/{types-CpXcT-tY.d.ts → types-DCFqkJAy.d.ts} +1 -1
- package/dist/{types-NOswlhm9.d.mts → types-DHQEMFHA.d.mts} +3 -3
- package/dist/{types-BW3csYo5.d.mts → types-Dg1Bcg1k.d.mts} +106 -3
- package/dist/{types-BW3csYo5.d.ts → types-Dg1Bcg1k.d.ts} +106 -3
- package/dist/{types-DA54bSmX.d.ts → types-Dikj3En4.d.ts} +3 -3
- package/dist/yourgpt/index.d.mts +1 -1
- package/dist/yourgpt/index.d.ts +1 -1
- package/docs/multimodal-and-audio.md +170 -0
- package/package.json +3 -2
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# Image tool results and recorded audio
|
|
2
|
+
|
|
3
|
+
These APIs are additive. Chat configuration, ordinary JSON/string tool results, and the existing screenshot `addAsUserMessage` attachment path retain their behavior. Native image tool output requires OpenAI **Responses** or Anthropic. TTS and recorded-file STT currently have an OpenAI implementation; other providers can implement the separate `SpeechModel` / `TranscriptionModel` contracts.
|
|
4
|
+
|
|
5
|
+
## Tools that return images
|
|
6
|
+
|
|
7
|
+
A tool still receives schema-validated JSON arguments. Pass an authorized image ID, URL, or crop reference in those arguments; resolve the actual bytes inside your handler. Do not ask the model to reproduce image base64 in function arguments.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { generateText, tool } from "@yourgpt/llm-sdk";
|
|
11
|
+
import { openai } from "@yourgpt/llm-sdk/openai";
|
|
12
|
+
import { z } from "zod";
|
|
13
|
+
|
|
14
|
+
const result = await generateText({
|
|
15
|
+
model: openai("gpt-5.2", { api: "responses", responses: { store: false } }),
|
|
16
|
+
prompt: "Inspect image sample.",
|
|
17
|
+
maxSteps: 3,
|
|
18
|
+
tools: {
|
|
19
|
+
inspect_image: tool({
|
|
20
|
+
description: "Read an image the caller is authorized to access",
|
|
21
|
+
parameters: z.object({ imageId: z.string() }),
|
|
22
|
+
execute: async ({ imageId }) => loadAuthorizedImage(imageId),
|
|
23
|
+
toModelOutput: (image) => ({
|
|
24
|
+
type: "content",
|
|
25
|
+
content: [
|
|
26
|
+
{ type: "text", text: image.caption },
|
|
27
|
+
{ type: "image", data: image.bytes, mediaType: "image/png" },
|
|
28
|
+
],
|
|
29
|
+
}),
|
|
30
|
+
}),
|
|
31
|
+
},
|
|
32
|
+
});
|
|
33
|
+
// result.toolResults keeps the raw handler result for your application.
|
|
34
|
+
// result.response.messages retains the model-facing content for the next turn.
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`toModelOutput` is a synchronous mapper, called once when a tool completes. It is also available on Runtime and Copilot tool definitions. For existing Runtime/Copilot handlers, returning `{ success: true, _aiContent: [...] }` uses the same native path. Explicit `toModelOutput` takes precedence. MCP image results keep their accompanying text in order.
|
|
38
|
+
|
|
39
|
+
Supported image parts:
|
|
40
|
+
|
|
41
|
+
| Part | OpenAI Responses | Anthropic |
|
|
42
|
+
| ----------------------------------------------- | ----------------------------------- | --------- |
|
|
43
|
+
| `{ type: 'image', data, mediaType }` | Yes | Yes |
|
|
44
|
+
| `{ type: 'image', url: 'https://…' }` | Yes | Yes |
|
|
45
|
+
| `{ type: 'image', fileId, provider: 'openai' }` | Yes, with an accessible OpenAI file | Rejected |
|
|
46
|
+
|
|
47
|
+
`data` accepts `Uint8Array`, canonical base64, or a base64 data URL matching `mediaType`. Supported media types: PNG, JPEG, WebP, GIF. Images are limited to 20 MiB each; provider/model aggregate limits can be smaller. The SDK does not download URLs or upload files implicitly. URL fetching happens at the selected provider. File references remain scoped to that provider/account.
|
|
48
|
+
|
|
49
|
+
OpenAI Chat Completions, Gemini, Ollama, Azure Chat and other compatible endpoints reject native image tool output clearly. Text-only mapped content still works. Custom OpenAI endpoints require explicit Responses selection and their own compatibility validation. Arbitrary array-shaped JSON results are never assumed to contain images.
|
|
50
|
+
|
|
51
|
+
Native output is carried as `modelOutput` next to the tool message's text. Preserve it when storing/restoring messages, along with `tool_call_id` / `toolCallId` and assistant tool calls. The Runtime storage helper places it at `StorageMessage.metadata.modelOutput`; a custom loader must map it back to `modelOutput`. Copilot's serialized `UIMessage` history preserves it directly, including server results in streaming execution metadata. Do not truncate image base64 or substitute it with text. Context pruning can remove complete older tool exchanges.
|
|
52
|
+
|
|
53
|
+
If an existing screenshot handler explicitly uses `addAsUserMessage`, it continues to add an attachment. When native model output is also supplied, the native output takes precedence and no extra attachment turn is created. General image generation is separate and is not implemented here.
|
|
54
|
+
|
|
55
|
+
## Speech generation on the server
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { generateSpeech } from "@yourgpt/llm-sdk";
|
|
59
|
+
import { openaiSpeech } from "@yourgpt/llm-sdk/openai";
|
|
60
|
+
|
|
61
|
+
const speech = await generateSpeech({
|
|
62
|
+
model: openaiSpeech("gpt-4o-mini-tts"), // reads server OPENAI_API_KEY
|
|
63
|
+
text: "Hello from Copilot.",
|
|
64
|
+
voice: "alloy",
|
|
65
|
+
outputFormat: "wav",
|
|
66
|
+
instructions: "Speak clearly and warmly.",
|
|
67
|
+
speed: 1,
|
|
68
|
+
signal: request.signal,
|
|
69
|
+
});
|
|
70
|
+
return new Response(new Uint8Array(speech.audio.uint8Array), {
|
|
71
|
+
headers: {
|
|
72
|
+
"Content-Type": speech.audio.mediaType,
|
|
73
|
+
"Cache-Control": "no-store",
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Returns audio bytes, a lazy `audio.base64` getter, media type/format, warnings, and provider/model/request metadata. Usage is optional and is not invented when the endpoint does not return it. This helper buffers the audio; it is not a realtime voice session or streamed audio API.
|
|
79
|
+
|
|
80
|
+
Formats: MP3, Opus/Ogg, AAC, FLAC, WAV, and raw PCM. OpenAI PCM is 24 kHz, signed 16-bit little-endian without a container header; use WAV/MP3 for ordinary browser playback. Text/instructions are bounded at 4096 characters, speed at 0.25–4. `tts-1` and `tts-1-hd` reject instructions. Unsupported options fail explicitly. Responses are bounded at 25 MB and checked for a matching audio header; the helper does not perform full codec decoding.
|
|
81
|
+
|
|
82
|
+
Browser playback, from a user click:
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const response = await fetch("/api/speech", {
|
|
86
|
+
method: "POST",
|
|
87
|
+
headers: { "Content-Type": "application/json" },
|
|
88
|
+
body: JSON.stringify({ text: "Hello from Copilot." }),
|
|
89
|
+
});
|
|
90
|
+
if (!response.ok) throw new Error("Speech generation failed");
|
|
91
|
+
const url = URL.createObjectURL(await response.blob());
|
|
92
|
+
const player = new Audio(url);
|
|
93
|
+
const release = () => URL.revokeObjectURL(url);
|
|
94
|
+
player.addEventListener("ended", release, { once: true });
|
|
95
|
+
player.addEventListener("error", release, { once: true });
|
|
96
|
+
try {
|
|
97
|
+
await player.play();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
release();
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
// On component disposal: player.pause(); release();
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Label generated speech as AI-generated. Keep provider keys and authentication/rate limiting in your server route.
|
|
106
|
+
|
|
107
|
+
## File transcription on the server
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { transcribe } from "@yourgpt/llm-sdk";
|
|
111
|
+
import { openaiTranscription } from "@yourgpt/llm-sdk/openai";
|
|
112
|
+
|
|
113
|
+
// POST /api/transcribe, behind your application's authentication.
|
|
114
|
+
const form = await request.formData();
|
|
115
|
+
const file = form.get("file");
|
|
116
|
+
if (!(file instanceof Blob))
|
|
117
|
+
return new Response("Audio file required", { status: 400 });
|
|
118
|
+
const transcript = await transcribe({
|
|
119
|
+
model: openaiTranscription("gpt-4o-mini-transcribe"),
|
|
120
|
+
audio: file,
|
|
121
|
+
language: "en",
|
|
122
|
+
signal: request.signal,
|
|
123
|
+
});
|
|
124
|
+
return Response.json(transcript);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Accepts a Blob, bytes/ArrayBuffer, or base64; bytes/base64 require `mediaType`. A filename is generated from the type unless supplied. No remote URL fetch occurs. Encoded files are limited to 25 MB and require a matching container header and filename extension. Accepted containers: MP3/MPEG/MPGA, MP4/M4A, WAV, WebM, Ogg, and FLAC. Raw PCM belongs to a separately configured realtime transcription protocol.
|
|
128
|
+
|
|
129
|
+
`text`, provider metadata and usage are returned. Segments, word timestamps, speakers, language and duration are preserved when supplied by the provider. An empty transcript is a valid outcome for silence; missing/non-string text is an invalid response.
|
|
130
|
+
|
|
131
|
+
For timestamps use `openaiTranscription('whisper-1')` with `providerOptions: { openai: { timestampGranularities: ['word', 'segment'] } }`. For speaker labels use `openaiTranscription('gpt-4o-transcribe-diarize')`; it selects `diarized_json` and automatic chunking. Diarization does not accept prompts or timestamp granularity options. Compatible GPT-4o transcription models can request `includeLogprobs: true`. The initial slice does not expose all options of the newer `gpt-transcribe` model (for example keyword lists or multiple language hints).
|
|
132
|
+
|
|
133
|
+
Both audio helpers accept `signal`, preserve cancellation, and expose `AudioAPIError` with a stable `code`, HTTP `status` and provider `requestId` when available. They do not log audio/text or retain provider error bodies. There are no automatic chargeable retries.
|
|
134
|
+
|
|
135
|
+
## Copilot microphone recording and review
|
|
136
|
+
|
|
137
|
+
`VoiceRecorder` is framework-independent and exported from `@yourgpt/copilot-sdk/core`. It makes no permission request until `start()` is called. Call it from a user gesture on HTTPS/localhost.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
import { VoiceRecorder, transcribeRecording } from "@yourgpt/copilot-sdk/core";
|
|
141
|
+
|
|
142
|
+
const recorder = new VoiceRecorder({
|
|
143
|
+
onStateChange: (state) => updateRecordingIndicator(state),
|
|
144
|
+
onError: (error) => showError(error.message),
|
|
145
|
+
});
|
|
146
|
+
let upload: AbortController | undefined;
|
|
147
|
+
|
|
148
|
+
// Record button:
|
|
149
|
+
await recorder.start();
|
|
150
|
+
|
|
151
|
+
// Stop button:
|
|
152
|
+
const recording = await recorder.stop();
|
|
153
|
+
upload = new AbortController();
|
|
154
|
+
const transcript = await transcribeRecording(recording, {
|
|
155
|
+
url: "/api/transcribe",
|
|
156
|
+
signal: upload.signal,
|
|
157
|
+
});
|
|
158
|
+
setChatDraft(transcript.text); // Review/edit, then submit through the usual chat flow.
|
|
159
|
+
// transcript.provenance identifies recorded audio and the server provider/model.
|
|
160
|
+
|
|
161
|
+
// Cancel button or component disposal:
|
|
162
|
+
upload?.abort();
|
|
163
|
+
recorder.dispose();
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
The recorder negotiates supported WebM/Opus, MP4, or Ogg/Opus containers. Stop, cancel, permission races, recorder errors and disposal release microphone tracks. Defaults: 20 MB and 60 seconds; exceeding either discards the recording and invokes `onError`. No automatic message submission, voice cloning, telephony, live transcription, or bidirectional voice call is included.
|
|
167
|
+
|
|
168
|
+
## Verification sources
|
|
169
|
+
|
|
170
|
+
Provider formats were checked against [OpenAI function outputs](https://developers.openai.com/api/docs/guides/function-calling), [Anthropic tool results](https://platform.claude.com/docs/en/agents-and-tools/tool-use/handle-tool-calls), [OpenAI speech](https://developers.openai.com/api/reference/resources/audio/subresources/speech/methods/create), and [OpenAI transcription](https://developers.openai.com/api/reference/resources/audio/subresources/transcriptions/methods/create). Vercel comparisons use its [tool output guidance](https://ai-sdk.dev/docs/ai-sdk-core/tools-and-tool-calling), [speech](https://ai-sdk.dev/docs/ai-sdk-core/speech), [transcription](https://ai-sdk.dev/docs/ai-sdk-core/transcription), and source checkout `8a5233b15b1e69573d63faee6cd0014559252ee4` (2026-10-15).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yourgpt/llm-sdk",
|
|
3
|
-
"version": "2.6.0-beta.
|
|
3
|
+
"version": "2.6.0-beta.2",
|
|
4
4
|
"description": "AI SDK for building AI Agents with any LLM",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -141,7 +141,8 @@
|
|
|
141
141
|
"files": [
|
|
142
142
|
"dist",
|
|
143
143
|
"!dist/**/*.map",
|
|
144
|
-
"README.md"
|
|
144
|
+
"README.md",
|
|
145
|
+
"docs/multimodal-and-audio.md"
|
|
145
146
|
],
|
|
146
147
|
"scripts": {
|
|
147
148
|
"build": "tsup",
|