@aeye/openai 0.3.9 → 0.4.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/README.md +267 -119
- package/aeye-openai.md +189 -178
- package/dist/convert.d.ts +81 -0
- package/dist/convert.d.ts.map +1 -0
- package/dist/convert.js +108 -0
- package/dist/convert.js.map +1 -0
- package/dist/decisions.d.ts +110 -0
- package/dist/decisions.d.ts.map +1 -0
- package/dist/decisions.js +48 -0
- package/dist/decisions.js.map +1 -0
- package/dist/images.d.ts +47 -0
- package/dist/images.d.ts.map +1 -0
- package/dist/images.js +80 -0
- package/dist/images.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/openai.d.ts +452 -206
- package/dist/openai.d.ts.map +1 -1
- package/dist/openai.js +912 -1424
- package/dist/openai.js.map +1 -1
- package/dist/responses.d.ts +67 -0
- package/dist/responses.d.ts.map +1 -0
- package/dist/responses.js +236 -0
- package/dist/responses.js.map +1 -0
- package/package.json +72 -72
package/aeye-openai.md
CHANGED
|
@@ -1,178 +1,189 @@
|
|
|
1
|
-
# @aeye/openai
|
|
2
|
-
|
|
3
|
-
One-line purpose: OpenAI provider for the `@aeye/ai` framework — chat, vision, reasoning, tools, structured output, image generation/edit, transcription, speech, and embeddings via the official `openai` SDK. Also the base class for any OpenAI-compatible provider.
|
|
4
|
-
|
|
5
|
-
## When to use
|
|
6
|
-
|
|
7
|
-
- You want to call OpenAI (GPT-
|
|
8
|
-
- You need a base class to build an OpenAI-compatible provider (Azure OpenAI, OpenRouter, local OpenAI-shaped endpoints). `@aeye/openrouter` is built this way.
|
|
9
|
-
|
|
10
|
-
## Install / import
|
|
11
|
-
|
|
12
|
-
```bash
|
|
13
|
-
npm install @aeye/openai openai
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
```typescript
|
|
17
|
-
import {
|
|
18
|
-
OpenAIProvider,
|
|
19
|
-
type OpenAIConfig,
|
|
20
|
-
type OpenAIHooks,
|
|
21
|
-
// error classes (from @aeye/openai)
|
|
22
|
-
ProviderError,
|
|
23
|
-
ProviderAuthError,
|
|
24
|
-
RateLimitError,
|
|
25
|
-
ProviderRateLimitError,
|
|
26
|
-
ProviderQuotaError,
|
|
27
|
-
ContextWindowError,
|
|
28
|
-
} from '@aeye/openai';
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
`@aeye/ai` and `@aeye/core` are peer/runtime dependencies (they ship as `dependencies`). The `openai` SDK and `zod` are also dependencies.
|
|
32
|
-
|
|
33
|
-
## Register with an `@aeye/ai` instance
|
|
34
|
-
|
|
35
|
-
A provider is registered by passing it into `AI.with().providers({...})`. The key you give it is the provider's local name in the registry.
|
|
36
|
-
|
|
37
|
-
```typescript
|
|
38
|
-
import { AI } from '@aeye/ai';
|
|
39
|
-
import { OpenAIProvider } from '@aeye/openai';
|
|
40
|
-
|
|
41
|
-
const openai = new OpenAIProvider({
|
|
42
|
-
apiKey: process.env.OPENAI_API_KEY!,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
const ai = AI.with()
|
|
46
|
-
.providers({ openai })
|
|
47
|
-
.create({ /* AI config: modelSources, hooks, defaultContext, ... */ });
|
|
48
|
-
|
|
49
|
-
// Chat
|
|
50
|
-
const response = await ai.chat.get({
|
|
51
|
-
messages: [{ role: 'user', content: 'Hello!' }],
|
|
52
|
-
});
|
|
53
|
-
console.log(response.content);
|
|
54
|
-
|
|
55
|
-
// Explicit model selection is done via metadata, not the provider
|
|
56
|
-
const r2 = await ai.chat.get(
|
|
57
|
-
{ messages: [{ role: 'user', content: 'Hi' }] },
|
|
58
|
-
{ metadata: { model: 'openai/gpt-
|
|
59
|
-
);
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
You can also use the provider directly without the `AI` facade:
|
|
63
|
-
|
|
64
|
-
```typescript
|
|
65
|
-
const executor = openai.createExecutor();
|
|
66
|
-
const res = await executor(
|
|
67
|
-
{ messages: [{ role: 'user', content: 'Hello!' }] },
|
|
68
|
-
{}, // AIContext
|
|
69
|
-
{ model: 'gpt-
|
|
70
|
-
);
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Authentication / credentials
|
|
74
|
-
|
|
75
|
-
- `apiKey` is **required** on `OpenAIConfig` (typed `string`). Conventionally supply `process.env.OPENAI_API_KEY`.
|
|
76
|
-
- `organization` and `project` map to the OpenAI SDK's `organization` / `project` options.
|
|
77
|
-
- `baseURL` lets you point at an OpenAI-compatible endpoint (e.g. Azure). There is no special env var handling in this package — credentials come from the config object you pass.
|
|
78
|
-
|
|
79
|
-
## Configuration (`OpenAIConfig`)
|
|
80
|
-
|
|
81
|
-
| Field | Type | Notes |
|
|
82
|
-
|-------|------|-------|
|
|
83
|
-
| `apiKey` | `string` (required) | OpenAI API key |
|
|
84
|
-
| `baseURL` | `string` | Custom/compatible endpoint |
|
|
85
|
-
| `organization` | `string` | Org ID |
|
|
86
|
-
| `project` | `string` | Project ID |
|
|
87
|
-
| `store` | `boolean` | Allow OpenAI to store call contents. Defaults to `false` |
|
|
88
|
-
| `
|
|
89
|
-
| `
|
|
90
|
-
| `
|
|
91
|
-
| `
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
1
|
+
# @aeye/openai
|
|
2
|
+
|
|
3
|
+
One-line purpose: OpenAI provider for the `@aeye/ai` framework — chat (Chat Completions or the Responses API), vision, reasoning, tools, hosted tools, structured output, audio output, image generation/edit, transcription, speech, and embeddings via the official `openai` SDK. Also the base class for any OpenAI-compatible provider.
|
|
4
|
+
|
|
5
|
+
## When to use
|
|
6
|
+
|
|
7
|
+
- You want to call OpenAI (GPT-5.x, GPT-6, GPT-4.1, gpt-audio, GPT Image, gpt-transcribe, TTS, text-embedding-3-*) through `@aeye/ai`.
|
|
8
|
+
- You need a base class to build an OpenAI-compatible provider (Azure OpenAI, OpenRouter, local OpenAI-shaped endpoints). `@aeye/openrouter` is built this way.
|
|
9
|
+
|
|
10
|
+
## Install / import
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @aeye/openai openai
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import {
|
|
18
|
+
OpenAIProvider,
|
|
19
|
+
type OpenAIConfig,
|
|
20
|
+
type OpenAIHooks,
|
|
21
|
+
// error classes (from @aeye/openai)
|
|
22
|
+
ProviderError,
|
|
23
|
+
ProviderAuthError,
|
|
24
|
+
RateLimitError,
|
|
25
|
+
ProviderRateLimitError,
|
|
26
|
+
ProviderQuotaError,
|
|
27
|
+
ContextWindowError,
|
|
28
|
+
} from '@aeye/openai';
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`@aeye/ai` and `@aeye/core` are peer/runtime dependencies (they ship as `dependencies`). The `openai` SDK (v7) and `zod` are also dependencies. Requires Node >= 22.
|
|
32
|
+
|
|
33
|
+
## Register with an `@aeye/ai` instance
|
|
34
|
+
|
|
35
|
+
A provider is registered by passing it into `AI.with().providers({...})`. The key you give it is the provider's local name in the registry.
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
import { AI } from '@aeye/ai';
|
|
39
|
+
import { OpenAIProvider } from '@aeye/openai';
|
|
40
|
+
|
|
41
|
+
const openai = new OpenAIProvider({
|
|
42
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const ai = AI.with()
|
|
46
|
+
.providers({ openai })
|
|
47
|
+
.create({ /* AI config: modelSources, hooks, defaultContext, ... */ });
|
|
48
|
+
|
|
49
|
+
// Chat
|
|
50
|
+
const response = await ai.chat.get({
|
|
51
|
+
messages: [{ role: 'user', content: 'Hello!' }],
|
|
52
|
+
});
|
|
53
|
+
console.log(response.content);
|
|
54
|
+
|
|
55
|
+
// Explicit model selection is done via metadata, not the provider
|
|
56
|
+
const r2 = await ai.chat.get(
|
|
57
|
+
{ messages: [{ role: 'user', content: 'Hi' }] },
|
|
58
|
+
{ metadata: { model: 'openai/gpt-5.4-mini' } }
|
|
59
|
+
);
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
You can also use the provider directly without the `AI` facade:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
const executor = openai.createExecutor();
|
|
66
|
+
const res = await executor(
|
|
67
|
+
{ messages: [{ role: 'user', content: 'Hello!' }] },
|
|
68
|
+
{}, // AIContext
|
|
69
|
+
{ model: 'gpt-5.4-mini' } // AIMetadata
|
|
70
|
+
);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Authentication / credentials
|
|
74
|
+
|
|
75
|
+
- `apiKey` is **required** on `OpenAIConfig` (typed `string`). Conventionally supply `process.env.OPENAI_API_KEY`.
|
|
76
|
+
- `organization` and `project` map to the OpenAI SDK's `organization` / `project` options.
|
|
77
|
+
- `baseURL` lets you point at an OpenAI-compatible endpoint (e.g. Azure). There is no special env var handling in this package — credentials come from the config object you pass.
|
|
78
|
+
|
|
79
|
+
## Configuration (`OpenAIConfig`)
|
|
80
|
+
|
|
81
|
+
| Field | Type | Notes |
|
|
82
|
+
|-------|------|-------|
|
|
83
|
+
| `apiKey` | `string` (required) | OpenAI API key |
|
|
84
|
+
| `baseURL` | `string` | Custom/compatible endpoint |
|
|
85
|
+
| `organization` | `string` | Org ID |
|
|
86
|
+
| `project` | `string` | Project ID |
|
|
87
|
+
| `store` | `boolean` | Allow OpenAI to store call contents. Defaults to `false` |
|
|
88
|
+
| `api` | `'auto' \| 'chat' \| 'responses'` | Which API chat uses. `auto` (default) picks Responses for Responses-only models (registry `metadata.responsesOnly`, else by id: codex, pre-5.6 pro, deep-research, computer-use), `hostedTools`, or `reason.mode`/`summary`/`context` |
|
|
89
|
+
| `retry` | `RetryConfig` | Per-provider retry (maxRetries, initialDelay, retryableStatuses, etc.) |
|
|
90
|
+
| `retryEvents` | `RetryEvents` | Retry lifecycle callbacks (e.g. `onRetry`) |
|
|
91
|
+
| `hooks` | `OpenAIHooks` | Per-operation `beforeRequest` / `afterRequest` / `onError` |
|
|
92
|
+
| `defaultModels` | object | Fallback model per capability: `chat`, `imageGenerate`, `imageEdit`, `imageAnalyze`, `transcription`, `speech`, `embedding`. Built-in defaults (the protected `defaults` property, overridable by subclasses): `gpt-image-2`, `gpt-5.4-mini` (image analysis), `gpt-transcribe`, `gpt-4o-mini-tts`, `text-embedding-3-small`; no chat default |
|
|
93
|
+
|
|
94
|
+
Retry config can also be overridden per request via `request.extra.retry` / `request.extra.retryEvents`.
|
|
95
|
+
|
|
96
|
+
### Hooks
|
|
97
|
+
|
|
98
|
+
`OpenAIHooks` has a block per operation in `OpenAIOperations`: `chat`, `responses`, `imageGenerate`, `imageEdit`, `transcribe`, `speech`, `embed`. Image analysis runs as chat and reports through the `chat` (or `responses`) hooks. Each block may define `beforeRequest(request, params, ctx, metadata)`, `afterRequest(request, params, response, ctx, metadata)`, and `onError(request, params, error, ctx, metadata)`. The `params` argument is the raw OpenAI SDK params, so you can inspect/mutate the exact wire payload.
|
|
99
|
+
|
|
100
|
+
## Supported capabilities
|
|
101
|
+
|
|
102
|
+
| Capability | API surface | Models |
|
|
103
|
+
|-----------|-------------|--------|
|
|
104
|
+
| Chat (+ streaming) | `ai.chat.get` / `ai.chat.stream` | GPT-5.x, GPT-6, GPT-4.1, o3 |
|
|
105
|
+
| Vision / files | `ai.chat` with `image` / `file` content (`detail`, `name`) | GPT-5.x, GPT-6, GPT-4.1 |
|
|
106
|
+
| Reasoning | `ai.chat` with `request.reason` — `effort` (`none`..`max`, clamped to the model's `reasoningEfforts`) → `reasoning_effort`; `summary`/`mode`/`context` use Responses | GPT-5.x, GPT-6, o3 |
|
|
107
|
+
| Tools / function calling | `ai.chat` with `tools` | GPT-5.x, GPT-6, GPT-4.1 |
|
|
108
|
+
| Hosted tools | `ai.chat` with `hostedTools` (Responses): `web_search` (allowedDomains only), `file_search`, `code_interpreter`, `image_generation`, `mcp`; `web_fetch` rejected | Responses models |
|
|
109
|
+
| Structured output | `ai.chat` with a schema `responseFormat` | GPT-5.x, GPT-6, GPT-4.1 (strict json_schema) |
|
|
110
|
+
| Audio output | `ai.chat` with `modalities: ['text', 'audio']` + `audio: { voice, format }` | `gpt-audio-1.5` |
|
|
111
|
+
| Image generation (+ stream) | `ai.image.generate` | GPT Image (`gpt-image-2`) |
|
|
112
|
+
| Image edit (+ stream) | `ai.image.edit` (`image` + `references`, `mask`, `inputFidelity`) | GPT Image (`gpt-image-2`) |
|
|
113
|
+
| Transcription (+ stream) | `ai.transcribe` (incl. `diarized_json` + `knownSpeakers`) | `gpt-transcribe`, `gpt-4o-transcribe-diarize`, `whisper-1` |
|
|
114
|
+
| Speech / TTS | `ai.speech` (any voice, incl. custom voice ids) | `gpt-4o-mini-tts`, `tts-1`, `tts-1-hd` |
|
|
115
|
+
| Embeddings | `ai.embed` | `text-embedding-3-small` / `-large` |
|
|
116
|
+
|
|
117
|
+
Other request fields passed through: `seed`, `verbosity`, `serviceTier`, `metadata` (Chat Completions sends it only when `store` is on), `moderate` (inline `omni-moderation-latest`), `cacheBreakpoint` on content. Responses carry `citations`, `images`, `audio`, `moderation`, `serviceTier`; `usage` counts cache writes, audio, reasoning, and hosted tool calls once each.
|
|
118
|
+
|
|
119
|
+
Through Responses, reasoning comes back encrypted (`include: reasoning.encrypted_content`, unless `store` is on) as `openai-responses-v1` reasoning details and is replayed from the assistant message's `reasoning` on later turns.
|
|
120
|
+
|
|
121
|
+
### Strict / structured output
|
|
122
|
+
|
|
123
|
+
The provider only emits OpenAI-shaped strict schemas (`supportedStrictFamilies = {'openai'}`). Strict mode for a tool or structured output engages only when the resolved model's strict format is `openai` **and** the model declares the `toolsStrict` / `structured` capability; otherwise it silently falls back to the family's non-strict descriptor. When selection supplies only a model id (no `ModelInfo`), the family is still resolved from the id, so the family's non-strict dialect is kept; strict needs the `ModelInfo` capabilities. A shared `SchemaBudget` is used so tools and the response format cooperate on per-request limits.
|
|
124
|
+
|
|
125
|
+
That default is correct for api.openai.com, which speaks exactly one dialect. **A subclass that fronts other providers' models must widen it** — `supportedStrictFamilies` is the gate on the whole family resolution, so leaving it at `{'openai'}` sends every other family's tool schemas out as LENIENT no matter what the model declares. `OpenRouterProvider` sets `{'openai', 'anthropic', 'google', 'xai'}` for this reason; `AWSProvider` sets `{'openai', 'anthropic', 'google'}`.
|
|
126
|
+
|
|
127
|
+
## Usage examples
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
// Vision
|
|
131
|
+
await ai.chat.get({
|
|
132
|
+
messages: [{
|
|
133
|
+
role: 'user',
|
|
134
|
+
content: [
|
|
135
|
+
{ type: 'text', content: 'Describe this image' },
|
|
136
|
+
{ type: 'image', content: 'https://example.com/cat.png' },
|
|
137
|
+
],
|
|
138
|
+
}],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
// Tools
|
|
142
|
+
import { z } from 'zod';
|
|
143
|
+
await ai.chat.get({
|
|
144
|
+
messages: [{ role: 'user', content: 'Weather in SF?' }],
|
|
145
|
+
tools: [{
|
|
146
|
+
name: 'get_weather',
|
|
147
|
+
description: 'Get current weather',
|
|
148
|
+
parameters: z.object({ location: z.string() }),
|
|
149
|
+
}],
|
|
150
|
+
toolChoice: 'auto',
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
// Image generation
|
|
154
|
+
await ai.image.generate.get({ prompt: 'A sunset over mountains', size: '1024x1024' });
|
|
155
|
+
|
|
156
|
+
// Embeddings
|
|
157
|
+
await ai.embed.get({ texts: ['Hello world'] });
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Extending for OpenAI-compatible providers
|
|
161
|
+
|
|
162
|
+
`OpenAIProvider<TConfig>` is designed for subclassing. Override:
|
|
163
|
+
|
|
164
|
+
- `createClient(config)` — point at a different `baseURL` / set custom headers.
|
|
165
|
+
- `convertModel(model)` — enrich `ModelInfo`.
|
|
166
|
+
- `listModels(config)` — custom model discovery.
|
|
167
|
+
- `augmentChatRequest` / `augmentChatMessage` / `augmentChatContent` / `augmentChatChunk` / `augmentChatResponse` — inject provider-specific params and parse extra response fields.
|
|
168
|
+
- `augmentImageGenerateRequest`, `augmentImageEditRequest`, `augmentTranscriptionRequest`, `augmentSpeechRequest`, `augmentEmbeddingRequest`.
|
|
169
|
+
- `supportedStrictFamilies` — widen accepted strict descriptor families.
|
|
170
|
+
- `usesResponses(request, modelId, config, model?)` — decide when chat goes to the Responses API.
|
|
171
|
+
- `defaults` — the built-in default model id per operation.
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
class AzureProvider extends OpenAIProvider {
|
|
175
|
+
readonly name = 'azure';
|
|
176
|
+
protected createClient(config: OpenAIConfig) {
|
|
177
|
+
return new OpenAI({ apiKey: config.apiKey, baseURL: 'https://my.openai.azure.com/v1' });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Gotchas
|
|
183
|
+
|
|
184
|
+
- `apiKey` is required by the type; this package does not auto-read `OPENAI_API_KEY` for you (you pass it in).
|
|
185
|
+
- Model is required at request time — supply it via `request.model`, `ctx.metadata.model`, request metadata, or `defaultModels`. Missing model throws `ProviderError`.
|
|
186
|
+
- `store` defaults to `false`; set it explicitly if you rely on OpenAI storing calls.
|
|
187
|
+
- Context-window overflow is not thrown on the chat path — the executor/streamer returns a `Response` with `finishReason: 'length'` instead.
|
|
188
|
+
- Streaming chat always sends `stream_options.include_usage: true` so usage arrives in trailing chunks.
|
|
189
|
+
- Retry types (`RetryConfig`, `RetryEvents`) are accepted structurally via `OpenAIConfig` but are not re-exported from the package entry point.
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversions from OpenAI wire shapes to @aeye shapes, shared by the Chat
|
|
3
|
+
* Completions, Responses, and media endpoints.
|
|
4
|
+
*/
|
|
5
|
+
import type { AudioFormat, Citation, Moderation, ServiceTier, Usage } from '@aeye/core';
|
|
6
|
+
import OpenAI from 'openai';
|
|
7
|
+
/**
|
|
8
|
+
* Token totals as an endpoint reports them, before splitting into Usage
|
|
9
|
+
* categories. Detail counts are subsets of their total.
|
|
10
|
+
*/
|
|
11
|
+
export interface TokenCounts {
|
|
12
|
+
input?: number;
|
|
13
|
+
output?: number;
|
|
14
|
+
cached?: number;
|
|
15
|
+
cacheWrite?: number;
|
|
16
|
+
audioInput?: number;
|
|
17
|
+
reasoning?: number;
|
|
18
|
+
audioOutput?: number;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Splits token totals into Usage categories so each token is counted once:
|
|
22
|
+
* cache reads and writes and audio come out of the input total; reasoning
|
|
23
|
+
* and audio output come out of the output total.
|
|
24
|
+
*/
|
|
25
|
+
export declare function toUsage(counts: TokenCounts): Usage;
|
|
26
|
+
/**
|
|
27
|
+
* Usage reported by Chat Completions (and OpenAI-compatible endpoints).
|
|
28
|
+
*/
|
|
29
|
+
export declare function chatUsage(usage: OpenAI.CompletionUsage): Usage;
|
|
30
|
+
/**
|
|
31
|
+
* Usage reported by the Responses API.
|
|
32
|
+
*/
|
|
33
|
+
export declare function responsesUsage(usage: OpenAI.Responses.ResponseUsage): Usage;
|
|
34
|
+
/**
|
|
35
|
+
* Usage reported by transcription: tokens for token-billed models, seconds
|
|
36
|
+
* for duration-billed ones (OpenAI-compatible routers may omit `type`).
|
|
37
|
+
*/
|
|
38
|
+
export declare function transcriptionUsage(usage: OpenAI.Audio.Transcription.Tokens | OpenAI.Audio.Transcription.Duration): Usage;
|
|
39
|
+
/**
|
|
40
|
+
* The tier a response reports it ran on.
|
|
41
|
+
*/
|
|
42
|
+
export declare function toServiceTier(tier: string | null | undefined): ServiceTier | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* A URL citation, as both Chat Completions and Responses report them.
|
|
45
|
+
*/
|
|
46
|
+
export declare function toCitation(citation: {
|
|
47
|
+
url: string;
|
|
48
|
+
title?: string;
|
|
49
|
+
start_index?: number;
|
|
50
|
+
end_index?: number;
|
|
51
|
+
}): Citation;
|
|
52
|
+
/**
|
|
53
|
+
* One side of a moderation verdict, as both Chat Completions and Responses
|
|
54
|
+
* report it: results, or an error when moderation itself failed.
|
|
55
|
+
*/
|
|
56
|
+
interface WireModerationSide {
|
|
57
|
+
type: string;
|
|
58
|
+
results?: Array<{
|
|
59
|
+
flagged: boolean;
|
|
60
|
+
categories: {
|
|
61
|
+
[category: string]: boolean;
|
|
62
|
+
};
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Moderation verdicts for the input and the output.
|
|
67
|
+
*/
|
|
68
|
+
export declare function toModeration(moderation: {
|
|
69
|
+
input: WireModerationSide;
|
|
70
|
+
output: WireModerationSide;
|
|
71
|
+
}): Moderation;
|
|
72
|
+
/**
|
|
73
|
+
* The model OpenAI runs moderation with when a request asks for it.
|
|
74
|
+
*/
|
|
75
|
+
export declare const MODERATION_MODEL = "omni-moderation-latest";
|
|
76
|
+
/**
|
|
77
|
+
* Chat Completions names 16-bit PCM `pcm16`.
|
|
78
|
+
*/
|
|
79
|
+
export declare function toChatAudioFormat(format: AudioFormat): OpenAI.Chat.ChatCompletionAudioParam['format'];
|
|
80
|
+
export {};
|
|
81
|
+
//# sourceMappingURL=convert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.d.ts","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,UAAU,EAAoB,WAAW,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAC1G,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,WAAW,GAAG,KAAK,CAoBlD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC,eAAe,GAAG,KAAK,CAU9D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,aAAa,GAAG,KAAK,CAQ3E;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,QAAQ,GAAG,KAAK,CAIxH;AAcD;;GAEG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAEtF;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,QAAQ,CAExH;AAED;;;GAGG;AACH,UAAU,kBAAkB;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,KAAK,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,UAAU,EAAE;YAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAA;SAAE,CAAA;KAAE,CAAC,CAAC;CACpF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,UAAU,EAAE;IAAE,KAAK,EAAE,kBAAkB,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAAG,UAAU,CAM9G;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,2BAA2B,CAAC;AAEzD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,QAAQ,CAAC,CAErG"}
|
package/dist/convert.js
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversions from OpenAI wire shapes to @aeye shapes, shared by the Chat
|
|
3
|
+
* Completions, Responses, and media endpoints.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Splits token totals into Usage categories so each token is counted once:
|
|
7
|
+
* cache reads and writes and audio come out of the input total; reasoning
|
|
8
|
+
* and audio output come out of the output total.
|
|
9
|
+
*/
|
|
10
|
+
export function toUsage(counts) {
|
|
11
|
+
const nonZero = (n = 0) => n > 0 ? n : undefined;
|
|
12
|
+
const usage = {};
|
|
13
|
+
const text = {
|
|
14
|
+
input: nonZero((counts.input ?? 0) - (counts.cached ?? 0) - (counts.cacheWrite ?? 0) - (counts.audioInput ?? 0)),
|
|
15
|
+
output: nonZero((counts.output ?? 0) - (counts.reasoning ?? 0) - (counts.audioOutput ?? 0)),
|
|
16
|
+
cached: nonZero(counts.cached),
|
|
17
|
+
cacheWrite: nonZero(counts.cacheWrite),
|
|
18
|
+
};
|
|
19
|
+
if (text.input || text.output || text.cached || text.cacheWrite) {
|
|
20
|
+
usage.text = text;
|
|
21
|
+
}
|
|
22
|
+
if (counts.reasoning) {
|
|
23
|
+
usage.reasoning = { output: counts.reasoning };
|
|
24
|
+
}
|
|
25
|
+
if (counts.audioInput || counts.audioOutput) {
|
|
26
|
+
usage.audio = { input: nonZero(counts.audioInput), output: nonZero(counts.audioOutput) };
|
|
27
|
+
}
|
|
28
|
+
return usage;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Usage reported by Chat Completions (and OpenAI-compatible endpoints).
|
|
32
|
+
*/
|
|
33
|
+
export function chatUsage(usage) {
|
|
34
|
+
return toUsage({
|
|
35
|
+
input: usage.prompt_tokens,
|
|
36
|
+
output: usage.completion_tokens,
|
|
37
|
+
cached: usage.prompt_tokens_details?.cached_tokens,
|
|
38
|
+
cacheWrite: usage.prompt_tokens_details?.cache_write_tokens,
|
|
39
|
+
audioInput: usage.prompt_tokens_details?.audio_tokens,
|
|
40
|
+
reasoning: usage.completion_tokens_details?.reasoning_tokens,
|
|
41
|
+
audioOutput: usage.completion_tokens_details?.audio_tokens,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Usage reported by the Responses API.
|
|
46
|
+
*/
|
|
47
|
+
export function responsesUsage(usage) {
|
|
48
|
+
return toUsage({
|
|
49
|
+
input: usage.input_tokens,
|
|
50
|
+
output: usage.output_tokens,
|
|
51
|
+
cached: usage.input_tokens_details.cached_tokens,
|
|
52
|
+
cacheWrite: usage.input_tokens_details.cache_write_tokens,
|
|
53
|
+
reasoning: usage.output_tokens_details.reasoning_tokens,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Usage reported by transcription: tokens for token-billed models, seconds
|
|
58
|
+
* for duration-billed ones (OpenAI-compatible routers may omit `type`).
|
|
59
|
+
*/
|
|
60
|
+
export function transcriptionUsage(usage) {
|
|
61
|
+
return 'seconds' in usage
|
|
62
|
+
? { audio: { seconds: usage.seconds } }
|
|
63
|
+
: toUsage({ input: usage.input_tokens, output: usage.output_tokens, audioInput: usage.input_token_details?.audio_tokens });
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Wire tiers to @aeye tiers. `priority` is the older name for `fast`.
|
|
67
|
+
*/
|
|
68
|
+
const SERVICE_TIERS = {
|
|
69
|
+
auto: 'auto',
|
|
70
|
+
default: 'default',
|
|
71
|
+
flex: 'flex',
|
|
72
|
+
fast: 'fast',
|
|
73
|
+
priority: 'fast',
|
|
74
|
+
scale: 'scale',
|
|
75
|
+
};
|
|
76
|
+
/**
|
|
77
|
+
* The tier a response reports it ran on.
|
|
78
|
+
*/
|
|
79
|
+
export function toServiceTier(tier) {
|
|
80
|
+
return tier ? SERVICE_TIERS[tier] : undefined;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* A URL citation, as both Chat Completions and Responses report them.
|
|
84
|
+
*/
|
|
85
|
+
export function toCitation(citation) {
|
|
86
|
+
return { url: citation.url, title: citation.title, start: citation.start_index, end: citation.end_index };
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Moderation verdicts for the input and the output.
|
|
90
|
+
*/
|
|
91
|
+
export function toModeration(moderation) {
|
|
92
|
+
const side = ({ results }) => results && {
|
|
93
|
+
flagged: results.some(result => result.flagged),
|
|
94
|
+
categories: [...new Set(results.flatMap(result => Object.keys(result.categories).filter(category => result.categories[category])))],
|
|
95
|
+
};
|
|
96
|
+
return { input: side(moderation.input), output: side(moderation.output) };
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The model OpenAI runs moderation with when a request asks for it.
|
|
100
|
+
*/
|
|
101
|
+
export const MODERATION_MODEL = 'omni-moderation-latest';
|
|
102
|
+
/**
|
|
103
|
+
* Chat Completions names 16-bit PCM `pcm16`.
|
|
104
|
+
*/
|
|
105
|
+
export function toChatAudioFormat(format) {
|
|
106
|
+
return format === 'pcm' ? 'pcm16' : format;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=convert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"convert.js","sourceRoot":"","sources":["../src/convert.ts"],"names":[],"mappings":"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"}
|