@warlock.js/ai-openai 4.12.0 → 4.14.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/CHANGELOG.md +11 -0
- package/cjs/index.cjs +29 -75
- package/cjs/index.cjs.map +1 -1
- package/esm/config.type.d.mts +15 -9
- package/esm/config.type.d.mts.map +1 -1
- package/esm/image.d.mts +8 -6
- package/esm/image.d.mts.map +1 -1
- package/esm/image.mjs +9 -9
- package/esm/image.mjs.map +1 -1
- package/esm/index.d.mts +3 -4
- package/esm/index.mjs +3 -4
- package/esm/sdk.d.mts +11 -8
- package/esm/sdk.d.mts.map +1 -1
- package/esm/sdk.mjs +11 -8
- package/esm/sdk.mjs.map +1 -1
- package/esm/speech.d.mts +6 -6
- package/esm/speech.d.mts.map +1 -1
- package/esm/speech.mjs +6 -16
- package/esm/speech.mjs.map +1 -1
- package/esm/transcription.d.mts +6 -3
- package/esm/transcription.d.mts.map +1 -1
- package/esm/transcription.mjs +6 -13
- package/esm/transcription.mjs.map +1 -1
- package/llms-full.txt +1 -1
- package/package.json +3 -3
- package/skills/setup-openai/SKILL.md +1 -1
- package/esm/known-image-models.d.mts +0 -30
- package/esm/known-image-models.d.mts.map +0 -1
- package/esm/known-image-models.mjs +0 -33
- package/esm/known-image-models.mjs.map +0 -1
package/esm/index.d.mts
CHANGED
|
@@ -2,7 +2,6 @@ import { OpenAIEmbedderConfig, OpenAIImageConfig, OpenAISDKConfig, OpenAISpeechC
|
|
|
2
2
|
import { OpenAISDK } from "./sdk.mjs";
|
|
3
3
|
import { OpenAIEmbedder } from "./embedder.mjs";
|
|
4
4
|
import { OpenAIImageModel } from "./image.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
export { OPENAI_IMAGE_MODEL_PREFIXES, OpenAIEmbedder, type OpenAIEmbedderConfig, type OpenAIImageConfig, OpenAIImageModel, OpenAISDK, type OpenAISDKConfig, type OpenAISpeechConfig, OpenAISpeechModel, type OpenAITranscriptionConfig, OpenAITranscriptionModel, isOpenAIImageModel, isOpenAISpeechModel, isOpenAITranscriptionModel };
|
|
5
|
+
import { OpenAISpeechModel } from "./speech.mjs";
|
|
6
|
+
import { OpenAITranscriptionModel } from "./transcription.mjs";
|
|
7
|
+
export { OpenAIEmbedder, type OpenAIEmbedderConfig, type OpenAIImageConfig, OpenAIImageModel, OpenAISDK, type OpenAISDKConfig, type OpenAISpeechConfig, OpenAISpeechModel, type OpenAITranscriptionConfig, OpenAITranscriptionModel };
|
package/esm/index.mjs
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { OpenAIEmbedder } from "./embedder.mjs";
|
|
2
|
-
import { OPENAI_IMAGE_MODEL_PREFIXES, isOpenAIImageModel } from "./known-image-models.mjs";
|
|
3
2
|
import { OpenAIImageModel } from "./image.mjs";
|
|
4
|
-
import { OpenAISpeechModel
|
|
5
|
-
import { OpenAITranscriptionModel
|
|
3
|
+
import { OpenAISpeechModel } from "./speech.mjs";
|
|
4
|
+
import { OpenAITranscriptionModel } from "./transcription.mjs";
|
|
6
5
|
import { OpenAISDK } from "./sdk.mjs";
|
|
7
6
|
|
|
8
|
-
export {
|
|
7
|
+
export { OpenAIEmbedder, OpenAIImageModel, OpenAISDK, OpenAISpeechModel, OpenAITranscriptionModel };
|
package/esm/sdk.d.mts
CHANGED
|
@@ -75,9 +75,10 @@ declare class OpenAISDK implements SDKAdapterContract {
|
|
|
75
75
|
embedder(config: OpenAIEmbedderConfig): EmbedderContract;
|
|
76
76
|
/**
|
|
77
77
|
* Build an `OpenAIImageModel` bound to this SDK's client for use with
|
|
78
|
-
* `ai.image({ model, prompt })`.
|
|
79
|
-
*
|
|
80
|
-
*
|
|
78
|
+
* `ai.image({ model, prompt })`. `config.name` is passed through to
|
|
79
|
+
* `client.images.generate` as given — no id is rejected locally, so
|
|
80
|
+
* an unsupported model fails at OpenAI, not here. Metering follows
|
|
81
|
+
* the family: `gpt-image-*` is token-metered, `dall-e-*` per-image.
|
|
81
82
|
*
|
|
82
83
|
* Pricing resolution mirrors `model()`: per-model `config.pricing`
|
|
83
84
|
* wins, otherwise the SDK-level registry entry keyed by `config.name`,
|
|
@@ -92,9 +93,10 @@ declare class OpenAISDK implements SDKAdapterContract {
|
|
|
92
93
|
image(config: OpenAIImageConfig): ImageModelContract;
|
|
93
94
|
/**
|
|
94
95
|
* Build an `OpenAISpeechModel` (text-to-speech) bound to this SDK's
|
|
95
|
-
* client, for use with `ai.speech({ model, text })`.
|
|
96
|
-
*
|
|
97
|
-
* at
|
|
96
|
+
* client, for use with `ai.speech({ model, text })`. `config.name` is
|
|
97
|
+
* passed through to `audio.speech.create` as given — no id is
|
|
98
|
+
* rejected locally, so an unsupported model fails at OpenAI, not
|
|
99
|
+
* here.
|
|
98
100
|
*
|
|
99
101
|
* @example
|
|
100
102
|
* const tts = openai.speech({ name: "tts-1", voice: "alloy" });
|
|
@@ -104,8 +106,9 @@ declare class OpenAISDK implements SDKAdapterContract {
|
|
|
104
106
|
/**
|
|
105
107
|
* Build an `OpenAITranscriptionModel` (speech-to-text) bound to this
|
|
106
108
|
* SDK's client, for use with `ai.transcribe({ model, audio })`.
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
+
* `config.name` is passed through to `audio.transcriptions.create`
|
|
110
|
+
* as given — no id is rejected locally, so an unsupported model
|
|
111
|
+
* fails at OpenAI, not here.
|
|
109
112
|
*
|
|
110
113
|
* @example
|
|
111
114
|
* const stt = openai.transcribe({ name: "whisper-1" });
|
package/esm/sdk.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../ai-openai/src/sdk.ts"],"mappings":";;;;;;AA2DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,SAAA,YAAqB,kBAAA;EAAA,iBACf,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,OAAA;cAEE,MAAA,EAAQ,eAAA;
|
|
1
|
+
{"version":3,"file":"sdk.d.mts","names":[],"sources":["../../../../../../ai-openai/src/sdk.ts"],"mappings":";;;;;;AA2DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAAa,SAAA,YAAqB,kBAAA;EAAA,iBACf,MAAA;EAAA,iBACA,QAAA;EAAA,iBACA,OAAA;cAEE,MAAA,EAAQ,eAAA;EA0EpB;;;;;;;;;;;;EAlDA,KAAA,CAAM,MAAA,EAAQ,iBAAA,GAAoB,aAAA;EAoFuC;;;;;;;EArEnE,KAAA,CAAM,IAAA,UAAc,MAAA,YAAkB,OAAA;;;;;;;;;;;EAc5C,QAAA,CAAS,MAAA,EAAQ,oBAAA,GAAuB,gBAAA;;;;;;;;;;;;;;;;;;EAqBxC,KAAA,CAAM,MAAA,EAAQ,iBAAA,GAAoB,kBAAA;;;;;;;;;;;;EAmBlC,MAAA,CAAO,MAAA,EAAQ,kBAAA,GAAqB,mBAAA;;;;;;;;;;;;EAepC,UAAA,CAAW,MAAA,EAAQ,yBAAA,GAA4B,0BAAA;AAAA"}
|
package/esm/sdk.mjs
CHANGED
|
@@ -93,9 +93,10 @@ var OpenAISDK = class {
|
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
95
|
* Build an `OpenAIImageModel` bound to this SDK's client for use with
|
|
96
|
-
* `ai.image({ model, prompt })`.
|
|
97
|
-
*
|
|
98
|
-
*
|
|
96
|
+
* `ai.image({ model, prompt })`. `config.name` is passed through to
|
|
97
|
+
* `client.images.generate` as given — no id is rejected locally, so
|
|
98
|
+
* an unsupported model fails at OpenAI, not here. Metering follows
|
|
99
|
+
* the family: `gpt-image-*` is token-metered, `dall-e-*` per-image.
|
|
99
100
|
*
|
|
100
101
|
* Pricing resolution mirrors `model()`: per-model `config.pricing`
|
|
101
102
|
* wins, otherwise the SDK-level registry entry keyed by `config.name`,
|
|
@@ -117,9 +118,10 @@ var OpenAISDK = class {
|
|
|
117
118
|
}
|
|
118
119
|
/**
|
|
119
120
|
* Build an `OpenAISpeechModel` (text-to-speech) bound to this SDK's
|
|
120
|
-
* client, for use with `ai.speech({ model, text })`.
|
|
121
|
-
*
|
|
122
|
-
* at
|
|
121
|
+
* client, for use with `ai.speech({ model, text })`. `config.name` is
|
|
122
|
+
* passed through to `audio.speech.create` as given — no id is
|
|
123
|
+
* rejected locally, so an unsupported model fails at OpenAI, not
|
|
124
|
+
* here.
|
|
123
125
|
*
|
|
124
126
|
* @example
|
|
125
127
|
* const tts = openai.speech({ name: "tts-1", voice: "alloy" });
|
|
@@ -131,8 +133,9 @@ var OpenAISDK = class {
|
|
|
131
133
|
/**
|
|
132
134
|
* Build an `OpenAITranscriptionModel` (speech-to-text) bound to this
|
|
133
135
|
* SDK's client, for use with `ai.transcribe({ model, audio })`.
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
+
* `config.name` is passed through to `audio.transcriptions.create`
|
|
137
|
+
* as given — no id is rejected locally, so an unsupported model
|
|
138
|
+
* fails at OpenAI, not here.
|
|
136
139
|
*
|
|
137
140
|
* @example
|
|
138
141
|
* const stt = openai.transcribe({ name: "whisper-1" });
|
package/esm/sdk.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../ai-openai/src/sdk.ts"],"sourcesContent":["import OpenAI from \"openai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n SpeechModelContract,\n TranscriptionModelContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n OpenAIEmbedderConfig,\n OpenAIImageConfig,\n OpenAIModelConfig,\n OpenAISDKConfig,\n OpenAISpeechConfig,\n OpenAITranscriptionConfig,\n} from \"./config.type\";\nimport { OpenAIEmbedder } from \"./embedder\";\nimport { OpenAIImageModel } from \"./image\";\nimport { OpenAIModel } from \"./model\";\nimport { OpenAISpeechModel } from \"./speech\";\nimport { OpenAITranscriptionModel } from \"./transcription\";\n\n/**\n * OpenAI-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for any OpenAI-compatible provider\n * (OpenAI, Azure OpenAI, OpenRouter, local gateways speaking the Chat\n * Completions protocol). A single `OpenAISDK` instance holds one live\n * `OpenAI` client, shared by every `ModelContract` it produces via\n * `model()`. Users construct one SDK per provider/account and reuse it\n * across all agents, workflows, and supervisors that target that\n * provider.\n *\n * **Responsibility.**\n * - Owns: a long-lived `OpenAI` client (authentication, base URL) and\n * its lifetime scope. Factory for `OpenAIModel` instances — each\n * model call gets a reference to the same client.\n * - Does NOT own: anything per-call (tool execution, message history,\n * streaming loop) — those live in `OpenAIModel` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): the `OpenAI` client is heavy to construct and\n * designed to be reused; keeping it on `this` makes that reuse\n * explicit and aligns with the PascalCase naming convention readers\n * expect from a constructor.\n *\n * @example\n * const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });\n * const model = openai.model({ name: \"gpt-4o\", temperature: 0.7 });\n * const tokens = await openai.count(\"Hello world\");\n *\n * @example\n * // Compose into an `ai.openai` namespace for ergonomic agent wiring\n * const ai = { agent, tool, systemPrompt, persona, instruction, openai: new OpenAISDK({ apiKey }) };\n * const myAgent = ai.agent({ model: ai.openai.model({ name: \"gpt-4o-mini\" }) });\n */\nexport class OpenAISDK implements SDKAdapterContract {\n private readonly client: OpenAI;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: OpenAISDKConfig) {\n // Peel off the framework-only keys and forward every other upstream\n // `ClientOptions` (timeout, maxRetries, defaultHeaders, fetch,\n // organization, project, …) verbatim — they type-check, so dropping them\n // is a silent footgun. Mirrors the Bedrock/Google/Ollama adapters.\n const { provider, pricing, ...clientOptions } = config;\n\n this.client = new OpenAI(clientOptions);\n this.provider = provider ?? \"openai\";\n this.pricing = pricing;\n }\n\n /**\n * Build an `OpenAIModel` bound to this SDK's client. Each call returns\n * a fresh model instance, but all instances share the underlying\n * `OpenAI` client — connection pools, rate limits, and authentication\n * state stay unified across every model produced here. The SDK's\n * `provider` label is forwarded so every model self-identifies as\n * coming from the same upstream.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: OpenAIModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: OpenAIModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new OpenAIModel(this.client, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate for a given text. Uses a\n * character-heuristic (`approximateTokenCount`) from the core package\n * — good enough for budgeting and quota guards, not for billing.\n * Accepts an optional model id for future per-model tokenizer\n * dispatch; currently ignored.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build an `OpenAIEmbedder` bound to this SDK's client. Each call\n * returns a fresh embedder instance sharing the same underlying\n * `OpenAI` client — connection pools and authentication stay unified\n * across every embedder produced here.\n *\n * @example\n * const embedder = openai.embedder({ name: \"text-embedding-3-small\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: OpenAIEmbedderConfig): EmbedderContract {\n return new OpenAIEmbedder(this.client, config);\n }\n\n /**\n * Build an `OpenAIImageModel` bound to this SDK's client for use with\n * `ai.image({ model, prompt })`.
|
|
1
|
+
{"version":3,"file":"sdk.mjs","names":[],"sources":["../../../../../../ai-openai/src/sdk.ts"],"sourcesContent":["import OpenAI from \"openai\";\nimport type {\n EmbedderContract,\n ImageModelContract,\n ModelContract,\n ModelPricing,\n SDKAdapterContract,\n SpeechModelContract,\n TranscriptionModelContract,\n} from \"@warlock.js/ai\";\nimport { approximateTokenCount } from \"@warlock.js/ai\";\nimport type {\n OpenAIEmbedderConfig,\n OpenAIImageConfig,\n OpenAIModelConfig,\n OpenAISDKConfig,\n OpenAISpeechConfig,\n OpenAITranscriptionConfig,\n} from \"./config.type\";\nimport { OpenAIEmbedder } from \"./embedder\";\nimport { OpenAIImageModel } from \"./image\";\nimport { OpenAIModel } from \"./model\";\nimport { OpenAISpeechModel } from \"./speech\";\nimport { OpenAITranscriptionModel } from \"./transcription\";\n\n/**\n * OpenAI-backed implementation of `SDKAdapterContract`.\n *\n * **Role.** The package entry point for any OpenAI-compatible provider\n * (OpenAI, Azure OpenAI, OpenRouter, local gateways speaking the Chat\n * Completions protocol). A single `OpenAISDK` instance holds one live\n * `OpenAI` client, shared by every `ModelContract` it produces via\n * `model()`. Users construct one SDK per provider/account and reuse it\n * across all agents, workflows, and supervisors that target that\n * provider.\n *\n * **Responsibility.**\n * - Owns: a long-lived `OpenAI` client (authentication, base URL) and\n * its lifetime scope. Factory for `OpenAIModel` instances — each\n * model call gets a reference to the same client.\n * - Does NOT own: anything per-call (tool execution, message history,\n * streaming loop) — those live in `OpenAIModel` and the agent runtime.\n *\n * Modeled as a class (see §4.2 of code-style.md — \"long-lived state\n * across many calls\"): the `OpenAI` client is heavy to construct and\n * designed to be reused; keeping it on `this` makes that reuse\n * explicit and aligns with the PascalCase naming convention readers\n * expect from a constructor.\n *\n * @example\n * const openai = new OpenAISDK({ apiKey: process.env.OPENAI_API_KEY! });\n * const model = openai.model({ name: \"gpt-4o\", temperature: 0.7 });\n * const tokens = await openai.count(\"Hello world\");\n *\n * @example\n * // Compose into an `ai.openai` namespace for ergonomic agent wiring\n * const ai = { agent, tool, systemPrompt, persona, instruction, openai: new OpenAISDK({ apiKey }) };\n * const myAgent = ai.agent({ model: ai.openai.model({ name: \"gpt-4o-mini\" }) });\n */\nexport class OpenAISDK implements SDKAdapterContract {\n private readonly client: OpenAI;\n private readonly provider: string;\n private readonly pricing?: Record<string, ModelPricing>;\n\n public constructor(config: OpenAISDKConfig) {\n // Peel off the framework-only keys and forward every other upstream\n // `ClientOptions` (timeout, maxRetries, defaultHeaders, fetch,\n // organization, project, …) verbatim — they type-check, so dropping them\n // is a silent footgun. Mirrors the Bedrock/Google/Ollama adapters.\n const { provider, pricing, ...clientOptions } = config;\n\n this.client = new OpenAI(clientOptions);\n this.provider = provider ?? \"openai\";\n this.pricing = pricing;\n }\n\n /**\n * Build an `OpenAIModel` bound to this SDK's client. Each call returns\n * a fresh model instance, but all instances share the underlying\n * `OpenAI` client — connection pools, rate limits, and authentication\n * state stay unified across every model produced here. The SDK's\n * `provider` label is forwarded so every model self-identifies as\n * coming from the same upstream.\n *\n * Pricing resolution: per-model `config.pricing` wins; otherwise the\n * SDK-level registry entry keyed by `config.name`; otherwise\n * `undefined` (no cost computed).\n */\n public model(config: OpenAIModelConfig): ModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: OpenAIModelConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new OpenAIModel(this.client, resolvedConfig, this.provider);\n }\n\n /**\n * Rough token-count estimate for a given text. Uses a\n * character-heuristic (`approximateTokenCount`) from the core package\n * — good enough for budgeting and quota guards, not for billing.\n * Accepts an optional model id for future per-model tokenizer\n * dispatch; currently ignored.\n */\n public async count(text: string, _model?: string): Promise<number> {\n return approximateTokenCount(text);\n }\n\n /**\n * Build an `OpenAIEmbedder` bound to this SDK's client. Each call\n * returns a fresh embedder instance sharing the same underlying\n * `OpenAI` client — connection pools and authentication stay unified\n * across every embedder produced here.\n *\n * @example\n * const embedder = openai.embedder({ name: \"text-embedding-3-small\" });\n * const { vector } = await embedder.embed(\"Hello world\");\n */\n public embedder(config: OpenAIEmbedderConfig): EmbedderContract {\n return new OpenAIEmbedder(this.client, config);\n }\n\n /**\n * Build an `OpenAIImageModel` bound to this SDK's client for use with\n * `ai.image({ model, prompt })`. `config.name` is passed through to\n * `client.images.generate` as given — no id is rejected locally, so\n * an unsupported model fails at OpenAI, not here. Metering follows\n * the family: `gpt-image-*` is token-metered, `dall-e-*` per-image.\n *\n * Pricing resolution mirrors `model()`: per-model `config.pricing`\n * wins, otherwise the SDK-level registry entry keyed by `config.name`,\n * otherwise `undefined` (no cost computed). A token-priced\n * `gpt-image-1` entry can live in the same SDK registry as the chat\n * models.\n *\n * @example\n * const model = openai.image({ name: \"gpt-image-1\" });\n * const { data } = await ai.image({ model, prompt: \"a red bicycle\" });\n */\n public image(config: OpenAIImageConfig): ImageModelContract {\n const resolvedPricing = config.pricing ?? this.pricing?.[config.name];\n const resolvedConfig: OpenAIImageConfig =\n resolvedPricing === config.pricing ? config : { ...config, pricing: resolvedPricing };\n\n return new OpenAIImageModel(this.client, resolvedConfig, this.provider);\n }\n\n /**\n * Build an `OpenAISpeechModel` (text-to-speech) bound to this SDK's\n * client, for use with `ai.speech({ model, text })`. `config.name` is\n * passed through to `audio.speech.create` as given — no id is\n * rejected locally, so an unsupported model fails at OpenAI, not\n * here.\n *\n * @example\n * const tts = openai.speech({ name: \"tts-1\", voice: \"alloy\" });\n * const { data } = await ai.speech({ model: tts, text: \"Hello\" });\n */\n public speech(config: OpenAISpeechConfig): SpeechModelContract {\n return new OpenAISpeechModel(this.client, config, this.provider);\n }\n\n /**\n * Build an `OpenAITranscriptionModel` (speech-to-text) bound to this\n * SDK's client, for use with `ai.transcribe({ model, audio })`.\n * `config.name` is passed through to `audio.transcriptions.create`\n * as given — no id is rejected locally, so an unsupported model\n * fails at OpenAI, not here.\n *\n * @example\n * const stt = openai.transcribe({ name: \"whisper-1\" });\n * const { data } = await ai.transcribe({ model: stt, audio });\n */\n public transcribe(config: OpenAITranscriptionConfig): TranscriptionModelContract {\n return new OpenAITranscriptionModel(this.client, config, this.provider);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2DA,IAAa,YAAb,MAAqD;CAKnD,AAAO,YAAY,QAAyB;EAK1C,MAAM,EAAE,UAAU,SAAS,GAAG,kBAAkB;EAEhD,KAAK,SAAS,IAAI,OAAO,aAAa;EACtC,KAAK,WAAW,YAAY;EAC5B,KAAK,UAAU;CACjB;;;;;;;;;;;;;CAcA,AAAO,MAAM,QAA0C;EACrD,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,OAAO,IAAI,YAAY,KAAK,QAAQ,gBAAgB,KAAK,QAAQ;CACnE;;;;;;;;CASA,MAAa,MAAM,MAAc,QAAkC;EACjE,OAAO,sBAAsB,IAAI;CACnC;;;;;;;;;;;CAYA,AAAO,SAAS,QAAgD;EAC9D,OAAO,IAAI,eAAe,KAAK,QAAQ,MAAM;CAC/C;;;;;;;;;;;;;;;;;;CAmBA,AAAO,MAAM,QAA+C;EAC1D,MAAM,kBAAkB,OAAO,WAAW,KAAK,UAAU,OAAO;EAChE,MAAM,iBACJ,oBAAoB,OAAO,UAAU,SAAS;GAAE,GAAG;GAAQ,SAAS;EAAgB;EAEtF,OAAO,IAAI,iBAAiB,KAAK,QAAQ,gBAAgB,KAAK,QAAQ;CACxE;;;;;;;;;;;;CAaA,AAAO,OAAO,QAAiD;EAC7D,OAAO,IAAI,kBAAkB,KAAK,QAAQ,QAAQ,KAAK,QAAQ;CACjE;;;;;;;;;;;;CAaA,AAAO,WAAW,QAA+D;EAC/E,OAAO,IAAI,yBAAyB,KAAK,QAAQ,QAAQ,KAAK,QAAQ;CACxE;AACF"}
|
package/esm/speech.d.mts
CHANGED
|
@@ -3,16 +3,16 @@ import OpenAI from "openai";
|
|
|
3
3
|
import { SpeechGenerationResponse, SpeechModelContract, SpeechModelPricing, SpeechOptions } from "@warlock.js/ai";
|
|
4
4
|
|
|
5
5
|
//#region ../ai-openai/src/speech.d.ts
|
|
6
|
-
/** True when `name` is a recognized OpenAI text-to-speech model. */
|
|
7
|
-
declare function isOpenAISpeechModel(name: string): boolean;
|
|
8
6
|
/**
|
|
9
7
|
* OpenAI-backed implementation of `SpeechModelContract` (text-to-speech)
|
|
10
8
|
* via `audio.speech.create`. Standalone primitive — no relation to chat
|
|
11
9
|
* completions or the agent loop. Consumed by the `ai.speech()` verb.
|
|
12
10
|
*
|
|
13
|
-
* **
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* **No model-id validation.** `config.name` is forwarded to
|
|
12
|
+
* `audio.speech.create` exactly as given — the constructor never
|
|
13
|
+
* inspects it. OpenAI ships and retires TTS model ids on its own
|
|
14
|
+
* schedule, so an unrecognized id fails at OpenAI (wrapped into the
|
|
15
|
+
* typed `AIError` hierarchy by `generate()`), not here.
|
|
16
16
|
*
|
|
17
17
|
* @example
|
|
18
18
|
* const tts = new OpenAISpeechModel(client, { name: "tts-1", voice: "alloy" }, "openai");
|
|
@@ -29,5 +29,5 @@ declare class OpenAISpeechModel implements SpeechModelContract {
|
|
|
29
29
|
generate(text: string, options?: SpeechOptions): Promise<SpeechGenerationResponse>;
|
|
30
30
|
}
|
|
31
31
|
//#endregion
|
|
32
|
-
export { OpenAISpeechModel
|
|
32
|
+
export { OpenAISpeechModel };
|
|
33
33
|
//# sourceMappingURL=speech.d.mts.map
|
package/esm/speech.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speech.d.mts","names":[],"sources":["../../../../../../ai-openai/src/speech.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"speech.d.mts","names":[],"sources":["../../../../../../ai-openai/src/speech.ts"],"mappings":";;;;;;;AA8CA;;;;;;;;;;;;;cAAa,iBAAA,YAA6B,mBAAA;EAAA,SACxB,IAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA,GAAU,kBAAA;EAAA,iBAET,MAAA;EAAA,iBACA,YAAA;EAAA,iBACA,MAAA;cAEE,MAAA,EAAQ,MAAA,EAAQ,MAAA,EAAQ,kBAAA,EAAoB,QAAA;EAQlD,QAAA,CAAS,IAAA,UAAc,OAAA,GAAU,aAAA,GAAgB,OAAA,CAAQ,wBAAA;AAAA"}
|
package/esm/speech.mjs
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
1
|
import { wrapOpenAIError } from "./utils/wrap-openai-error.mjs";
|
|
2
2
|
import "./utils/index.mjs";
|
|
3
|
-
import { InvalidRequestError } from "@warlock.js/ai";
|
|
4
3
|
import { log } from "@warlock.js/logger";
|
|
5
4
|
|
|
6
5
|
//#region ../ai-openai/src/speech.ts
|
|
7
6
|
const LOG_MODULE = "ai.openai";
|
|
8
|
-
/** Model-id prefixes OpenAI exposes through the **Speech** (TTS) API. */
|
|
9
|
-
const SPEECH_MODEL_PREFIXES = [
|
|
10
|
-
"tts-1",
|
|
11
|
-
"gpt-4o-mini-tts",
|
|
12
|
-
"gpt-audio"
|
|
13
|
-
];
|
|
14
|
-
/** True when `name` is a recognized OpenAI text-to-speech model. */
|
|
15
|
-
function isOpenAISpeechModel(name) {
|
|
16
|
-
return SPEECH_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
17
|
-
}
|
|
18
7
|
/** Map a neutral output container hint to its IANA audio media type. */
|
|
19
8
|
function audioMediaType(format) {
|
|
20
9
|
switch (format) {
|
|
@@ -31,9 +20,11 @@ function audioMediaType(format) {
|
|
|
31
20
|
* via `audio.speech.create`. Standalone primitive — no relation to chat
|
|
32
21
|
* completions or the agent loop. Consumed by the `ai.speech()` verb.
|
|
33
22
|
*
|
|
34
|
-
* **
|
|
35
|
-
*
|
|
36
|
-
*
|
|
23
|
+
* **No model-id validation.** `config.name` is forwarded to
|
|
24
|
+
* `audio.speech.create` exactly as given — the constructor never
|
|
25
|
+
* inspects it. OpenAI ships and retires TTS model ids on its own
|
|
26
|
+
* schedule, so an unrecognized id fails at OpenAI (wrapped into the
|
|
27
|
+
* typed `AIError` hierarchy by `generate()`), not here.
|
|
37
28
|
*
|
|
38
29
|
* @example
|
|
39
30
|
* const tts = new OpenAISpeechModel(client, { name: "tts-1", voice: "alloy" }, "openai");
|
|
@@ -42,7 +33,6 @@ function audioMediaType(format) {
|
|
|
42
33
|
var OpenAISpeechModel = class {
|
|
43
34
|
constructor(client, config, provider = "openai") {
|
|
44
35
|
this.logger = log;
|
|
45
|
-
if (!isOpenAISpeechModel(config.name)) throw new InvalidRequestError(`"${config.name}" is not a known OpenAI text-to-speech model. Use a \`tts-1\` / \`tts-1-hd\` / \`gpt-4o-mini-tts\` model with openai.speech({ name }).`);
|
|
46
36
|
this.client = client;
|
|
47
37
|
this.name = config.name;
|
|
48
38
|
this.provider = provider;
|
|
@@ -90,5 +80,5 @@ var OpenAISpeechModel = class {
|
|
|
90
80
|
};
|
|
91
81
|
|
|
92
82
|
//#endregion
|
|
93
|
-
export { OpenAISpeechModel
|
|
83
|
+
export { OpenAISpeechModel };
|
|
94
84
|
//# sourceMappingURL=speech.mjs.map
|
package/esm/speech.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speech.mjs","names":[],"sources":["../../../../../../ai-openai/src/speech.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"file":"speech.mjs","names":[],"sources":["../../../../../../ai-openai/src/speech.ts"],"sourcesContent":["import {\n type SpeechGenerationResponse,\n type SpeechModelContract,\n type SpeechModelPricing,\n type SpeechOptions,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport type OpenAI from \"openai\";\nimport type { OpenAISpeechConfig } from \"./config.type\";\nimport { wrapOpenAIError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.openai\";\n\n/** Map a neutral output container hint to its IANA audio media type. */\nfunction audioMediaType(format: string | undefined): string {\n switch (format) {\n case \"opus\":\n return \"audio/opus\";\n case \"aac\":\n return \"audio/aac\";\n case \"flac\":\n return \"audio/flac\";\n case \"wav\":\n return \"audio/wav\";\n case \"pcm\":\n return \"audio/pcm\";\n default:\n return \"audio/mpeg\";\n }\n}\n\n/**\n * OpenAI-backed implementation of `SpeechModelContract` (text-to-speech)\n * via `audio.speech.create`. Standalone primitive — no relation to chat\n * completions or the agent loop. Consumed by the `ai.speech()` verb.\n *\n * **No model-id validation.** `config.name` is forwarded to\n * `audio.speech.create` exactly as given — the constructor never\n * inspects it. OpenAI ships and retires TTS model ids on its own\n * schedule, so an unrecognized id fails at OpenAI (wrapped into the\n * typed `AIError` hierarchy by `generate()`), not here.\n *\n * @example\n * const tts = new OpenAISpeechModel(client, { name: \"tts-1\", voice: \"alloy\" }, \"openai\");\n * const { audio } = await tts.generate(\"Welcome aboard.\");\n */\nexport class OpenAISpeechModel implements SpeechModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly pricing?: SpeechModelPricing;\n\n private readonly client: OpenAI;\n private readonly defaultVoice?: string;\n private readonly logger: Logger = log;\n\n public constructor(client: OpenAI, config: OpenAISpeechConfig, provider: string = \"openai\") {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n this.defaultVoice = config.voice;\n }\n\n public async generate(text: string, options?: SpeechOptions): Promise<SpeechGenerationResponse> {\n const format = options?.format ?? \"mp3\";\n\n this.logger.debug(LOG_MODULE, \"speech.request\", \"audio.speech.create\", {\n model: this.name,\n characters: text.length,\n });\n\n let response: Response;\n\n try {\n response = await this.client.audio.speech.create(\n {\n model: this.name,\n input: text,\n voice: options?.voice ?? this.defaultVoice ?? \"alloy\",\n response_format: format as OpenAI.Audio.SpeechCreateParams[\"response_format\"],\n ...(options?.speed !== undefined ? { speed: options.speed } : {}),\n ...(options?.instructions !== undefined ? { instructions: options.instructions } : {}),\n },\n options?.signal ? { signal: options.signal } : undefined,\n );\n } catch (thrown) {\n const wrapped = wrapOpenAIError(thrown);\n this.logger.error(LOG_MODULE, \"speech.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n throw wrapped;\n }\n\n const base64 = Buffer.from(await response.arrayBuffer()).toString(\"base64\");\n\n return {\n audio: { type: \"base64\", base64, mediaType: audioMediaType(format) },\n // The Speech API reports no token usage; spend is priced per\n // character (or per token for gpt-4o-mini-tts) by `ai.speech()`.\n usage: { input: 0, output: 0, total: 0 },\n characters: text.length,\n };\n }\n}\n"],"mappings":";;;;;AAWA,MAAM,aAAa;;AAGnB,SAAS,eAAe,QAAoC;CAC1D,QAAQ,QAAR;EACE,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,QACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,KAAK,OACH,OAAO;EACT,SACE,OAAO;CACX;AACF;;;;;;;;;;;;;;;;AAiBA,IAAa,oBAAb,MAA8D;CAS5D,AAAO,YAAY,QAAgB,QAA4B,WAAmB,UAAU;gBAF1D;EAGhC,KAAK,SAAS;EACd,KAAK,OAAO,OAAO;EACnB,KAAK,WAAW;EAChB,KAAK,UAAU,OAAO;EACtB,KAAK,eAAe,OAAO;CAC7B;CAEA,MAAa,SAAS,MAAc,SAA4D;EAC9F,MAAM,SAAS,SAAS,UAAU;EAElC,KAAK,OAAO,MAAM,YAAY,kBAAkB,uBAAuB;GACrE,OAAO,KAAK;GACZ,YAAY,KAAK;EACnB,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,WAAW,MAAM,KAAK,OAAO,MAAM,OAAO,OACxC;IACE,OAAO,KAAK;IACZ,OAAO;IACP,OAAO,SAAS,SAAS,KAAK,gBAAgB;IAC9C,iBAAiB;IACjB,GAAI,SAAS,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;IAC/D,GAAI,SAAS,iBAAiB,SAAY,EAAE,cAAc,QAAQ,aAAa,IAAI,CAAC;GACtF,GACA,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,MACjD;EACF,SAAS,QAAQ;GACf,MAAM,UAAU,gBAAgB,MAAM;GACtC,KAAK,OAAO,MAAM,YAAY,gBAAgB,QAAQ,SAAS;IAC7D,MAAM,QAAQ;IACd,SAAS,QAAQ;GACnB,CAAC;GACD,MAAM;EACR;EAIA,OAAO;GACL,OAAO;IAAE,MAAM;IAAU,QAHZ,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC,CAAC,CAAC,SAAS,QAGlC;IAAG,WAAW,eAAe,MAAM;GAAE;GAGnE,OAAO;IAAE,OAAO;IAAG,QAAQ;IAAG,OAAO;GAAE;GACvC,YAAY,KAAK;EACnB;CACF;AACF"}
|
package/esm/transcription.d.mts
CHANGED
|
@@ -3,13 +3,16 @@ import OpenAI from "openai";
|
|
|
3
3
|
import { AudioInput, TranscribeOptions, TranscriptionModelContract, TranscriptionModelPricing, TranscriptionResponse } from "@warlock.js/ai";
|
|
4
4
|
|
|
5
5
|
//#region ../ai-openai/src/transcription.d.ts
|
|
6
|
-
/** True when `name` is a recognized OpenAI speech-to-text model. */
|
|
7
|
-
declare function isOpenAITranscriptionModel(name: string): boolean;
|
|
8
6
|
/**
|
|
9
7
|
* OpenAI-backed implementation of `TranscriptionModelContract`
|
|
10
8
|
* (speech-to-text) via `audio.transcriptions.create`. Consumed by the
|
|
11
9
|
* `ai.transcribe()` verb.
|
|
12
10
|
*
|
|
11
|
+
* **No model-id validation.** `config.name` is forwarded to
|
|
12
|
+
* `audio.transcriptions.create` exactly as given — the constructor
|
|
13
|
+
* never inspects it. An unrecognized id fails at OpenAI (wrapped into
|
|
14
|
+
* the typed `AIError` hierarchy by `transcribe()`), not here.
|
|
15
|
+
*
|
|
13
16
|
* **Response format.** Defaults to `verbose_json` for `whisper-1` (so
|
|
14
17
|
* the run gets a `duration` + timestamped `segments`) and `json` for
|
|
15
18
|
* the token-metered `gpt-4o-transcribe` family. Base64 audio is wrapped
|
|
@@ -29,5 +32,5 @@ declare class OpenAITranscriptionModel implements TranscriptionModelContract {
|
|
|
29
32
|
transcribe(audio: AudioInput, options?: TranscribeOptions): Promise<TranscriptionResponse>;
|
|
30
33
|
}
|
|
31
34
|
//#endregion
|
|
32
|
-
export { OpenAITranscriptionModel
|
|
35
|
+
export { OpenAITranscriptionModel };
|
|
33
36
|
//# sourceMappingURL=transcription.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcription.d.mts","names":[],"sources":["../../../../../../ai-openai/src/transcription.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"transcription.d.mts","names":[],"sources":["../../../../../../ai-openai/src/transcription.ts"],"mappings":";;;;;;;AAiDA;;;;;;;;;;;;;;;;;cAAa,wBAAA,YAAoC,0BAAA;EAAA,SAC/B,IAAA;EAAA,SACA,QAAA;EAAA,SACA,OAAA,GAAU,yBAAA;EAAA,iBAET,MAAA;EAAA,iBACA,MAAA;cAGf,MAAA,EAAQ,MAAA,EACR,MAAA,EAAQ,yBAAA,EACR,QAAA;EAQW,UAAA,CACX,KAAA,EAAO,UAAA,EACP,OAAA,GAAU,iBAAA,GACT,OAAA,CAAQ,qBAAA;AAAA"}
|
package/esm/transcription.mjs
CHANGED
|
@@ -1,26 +1,20 @@
|
|
|
1
1
|
import { wrapOpenAIError } from "./utils/wrap-openai-error.mjs";
|
|
2
2
|
import "./utils/index.mjs";
|
|
3
3
|
import { toFile } from "openai";
|
|
4
|
-
import { InvalidRequestError } from "@warlock.js/ai";
|
|
5
4
|
import { log } from "@warlock.js/logger";
|
|
6
5
|
|
|
7
6
|
//#region ../ai-openai/src/transcription.ts
|
|
8
7
|
const LOG_MODULE = "ai.openai";
|
|
9
|
-
/** Model-id prefixes OpenAI exposes through the **Transcription** (STT) API. */
|
|
10
|
-
const TRANSCRIPTION_MODEL_PREFIXES = [
|
|
11
|
-
"whisper",
|
|
12
|
-
"gpt-4o-transcribe",
|
|
13
|
-
"gpt-4o-mini-transcribe"
|
|
14
|
-
];
|
|
15
|
-
/** True when `name` is a recognized OpenAI speech-to-text model. */
|
|
16
|
-
function isOpenAITranscriptionModel(name) {
|
|
17
|
-
return TRANSCRIPTION_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
18
|
-
}
|
|
19
8
|
/**
|
|
20
9
|
* OpenAI-backed implementation of `TranscriptionModelContract`
|
|
21
10
|
* (speech-to-text) via `audio.transcriptions.create`. Consumed by the
|
|
22
11
|
* `ai.transcribe()` verb.
|
|
23
12
|
*
|
|
13
|
+
* **No model-id validation.** `config.name` is forwarded to
|
|
14
|
+
* `audio.transcriptions.create` exactly as given — the constructor
|
|
15
|
+
* never inspects it. An unrecognized id fails at OpenAI (wrapped into
|
|
16
|
+
* the typed `AIError` hierarchy by `transcribe()`), not here.
|
|
17
|
+
*
|
|
24
18
|
* **Response format.** Defaults to `verbose_json` for `whisper-1` (so
|
|
25
19
|
* the run gets a `duration` + timestamped `segments`) and `json` for
|
|
26
20
|
* the token-metered `gpt-4o-transcribe` family. Base64 audio is wrapped
|
|
@@ -33,7 +27,6 @@ function isOpenAITranscriptionModel(name) {
|
|
|
33
27
|
var OpenAITranscriptionModel = class {
|
|
34
28
|
constructor(client, config, provider = "openai") {
|
|
35
29
|
this.logger = log;
|
|
36
|
-
if (!isOpenAITranscriptionModel(config.name)) throw new InvalidRequestError(`"${config.name}" is not a known OpenAI transcription model. Use a \`whisper-1\` / \`gpt-4o-transcribe\` / \`gpt-4o-mini-transcribe\` model with openai.transcribe({ name }).`);
|
|
37
30
|
this.client = client;
|
|
38
31
|
this.name = config.name;
|
|
39
32
|
this.provider = provider;
|
|
@@ -90,5 +83,5 @@ var OpenAITranscriptionModel = class {
|
|
|
90
83
|
};
|
|
91
84
|
|
|
92
85
|
//#endregion
|
|
93
|
-
export { OpenAITranscriptionModel
|
|
86
|
+
export { OpenAITranscriptionModel };
|
|
94
87
|
//# sourceMappingURL=transcription.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transcription.mjs","names":[],"sources":["../../../../../../ai-openai/src/transcription.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"file":"transcription.mjs","names":[],"sources":["../../../../../../ai-openai/src/transcription.ts"],"sourcesContent":["import {\n type AudioInput,\n type TranscribeOptions,\n type TranscriptionModelContract,\n type TranscriptionModelPricing,\n type TranscriptionResponse,\n type TranscriptionSegment,\n} from \"@warlock.js/ai\";\nimport { log, type Logger } from \"@warlock.js/logger\";\nimport OpenAI, { toFile } from \"openai\";\nimport type { OpenAITranscriptionConfig } from \"./config.type\";\nimport { wrapOpenAIError } from \"./utils\";\n\nconst LOG_MODULE = \"ai.openai\";\n\n/** Defensive view over the response, whose shape varies by `response_format`. */\ntype RawTranscription = {\n text: string;\n duration?: number;\n language?: string;\n segments?: Array<{ text: string; start?: number; end?: number }>;\n usage?: {\n type?: string;\n seconds?: number;\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n };\n};\n\n/**\n * OpenAI-backed implementation of `TranscriptionModelContract`\n * (speech-to-text) via `audio.transcriptions.create`. Consumed by the\n * `ai.transcribe()` verb.\n *\n * **No model-id validation.** `config.name` is forwarded to\n * `audio.transcriptions.create` exactly as given — the constructor\n * never inspects it. An unrecognized id fails at OpenAI (wrapped into\n * the typed `AIError` hierarchy by `transcribe()`), not here.\n *\n * **Response format.** Defaults to `verbose_json` for `whisper-1` (so\n * the run gets a `duration` + timestamped `segments`) and `json` for\n * the token-metered `gpt-4o-transcribe` family. Base64 audio is wrapped\n * in an uploadable via the SDK's `toFile`.\n *\n * @example\n * const stt = new OpenAITranscriptionModel(client, { name: \"whisper-1\" }, \"openai\");\n * const { text } = await stt.transcribe({ base64, mediaType: \"audio/mpeg\" });\n */\nexport class OpenAITranscriptionModel implements TranscriptionModelContract {\n public readonly name: string;\n public readonly provider: string;\n public readonly pricing?: TranscriptionModelPricing;\n\n private readonly client: OpenAI;\n private readonly logger: Logger = log;\n\n public constructor(\n client: OpenAI,\n config: OpenAITranscriptionConfig,\n provider: string = \"openai\",\n ) {\n this.client = client;\n this.name = config.name;\n this.provider = provider;\n this.pricing = config.pricing;\n }\n\n public async transcribe(\n audio: AudioInput,\n options?: TranscribeOptions,\n ): Promise<TranscriptionResponse> {\n const isWhisper = this.name.startsWith(\"whisper\");\n const format = options?.format ?? (isWhisper ? \"verbose_json\" : \"json\");\n\n const file = await toFile(Buffer.from(audio.base64, \"base64\"), audio.filename ?? \"audio\", {\n type: audio.mediaType,\n });\n\n this.logger.debug(LOG_MODULE, \"transcription.request\", \"audio.transcriptions.create\", {\n model: this.name,\n format,\n });\n\n let raw: unknown;\n\n try {\n raw = await this.client.audio.transcriptions.create(\n {\n model: this.name,\n file,\n response_format: format as OpenAI.Audio.TranscriptionCreateParams[\"response_format\"],\n ...(options?.language ? { language: options.language } : {}),\n ...(options?.prompt ? { prompt: options.prompt } : {}),\n } as OpenAI.Audio.TranscriptionCreateParamsNonStreaming,\n options?.signal ? { signal: options.signal } : undefined,\n );\n } catch (thrown) {\n const wrapped = wrapOpenAIError(thrown);\n this.logger.error(LOG_MODULE, \"transcription.error\", wrapped.message, {\n code: wrapped.code,\n context: wrapped.context,\n });\n throw wrapped;\n }\n\n const response = raw as RawTranscription;\n\n const segments: TranscriptionSegment[] | undefined = response.segments?.map((segment) => ({\n text: segment.text,\n ...(segment.start !== undefined ? { start: segment.start } : {}),\n ...(segment.end !== undefined ? { end: segment.end } : {}),\n }));\n\n const durationSeconds =\n response.duration ?? (response.usage?.type === \"duration\" ? response.usage.seconds : undefined);\n\n const usage =\n response.usage?.type === \"tokens\"\n ? {\n input: response.usage.input_tokens ?? 0,\n output: response.usage.output_tokens ?? 0,\n total: response.usage.total_tokens ?? 0,\n }\n : { input: 0, output: 0, total: 0 };\n\n return {\n text: response.text,\n ...(segments && segments.length > 0 ? { segments } : {}),\n ...(durationSeconds !== undefined ? { durationSeconds } : {}),\n usage,\n };\n }\n}\n"],"mappings":";;;;;;AAaA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;AAoCnB,IAAa,2BAAb,MAA4E;CAQ1E,AAAO,YACL,QACA,QACA,WAAmB,UACnB;gBANgC;EAOhC,KAAK,SAAS;EACd,KAAK,OAAO,OAAO;EACnB,KAAK,WAAW;EAChB,KAAK,UAAU,OAAO;CACxB;CAEA,MAAa,WACX,OACA,SACgC;EAChC,MAAM,YAAY,KAAK,KAAK,WAAW,SAAS;EAChD,MAAM,SAAS,SAAS,WAAW,YAAY,iBAAiB;EAEhE,MAAM,OAAO,MAAM,OAAO,OAAO,KAAK,MAAM,QAAQ,QAAQ,GAAG,MAAM,YAAY,SAAS,EACxF,MAAM,MAAM,UACd,CAAC;EAED,KAAK,OAAO,MAAM,YAAY,yBAAyB,+BAA+B;GACpF,OAAO,KAAK;GACZ;EACF,CAAC;EAED,IAAI;EAEJ,IAAI;GACF,MAAM,MAAM,KAAK,OAAO,MAAM,eAAe,OAC3C;IACE,OAAO,KAAK;IACZ;IACA,iBAAiB;IACjB,GAAI,SAAS,WAAW,EAAE,UAAU,QAAQ,SAAS,IAAI,CAAC;IAC1D,GAAI,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,CAAC;GACtD,GACA,SAAS,SAAS,EAAE,QAAQ,QAAQ,OAAO,IAAI,MACjD;EACF,SAAS,QAAQ;GACf,MAAM,UAAU,gBAAgB,MAAM;GACtC,KAAK,OAAO,MAAM,YAAY,uBAAuB,QAAQ,SAAS;IACpE,MAAM,QAAQ;IACd,SAAS,QAAQ;GACnB,CAAC;GACD,MAAM;EACR;EAEA,MAAM,WAAW;EAEjB,MAAM,WAA+C,SAAS,UAAU,KAAK,aAAa;GACxF,MAAM,QAAQ;GACd,GAAI,QAAQ,UAAU,SAAY,EAAE,OAAO,QAAQ,MAAM,IAAI,CAAC;GAC9D,GAAI,QAAQ,QAAQ,SAAY,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;EAC1D,EAAE;EAEF,MAAM,kBACJ,SAAS,aAAa,SAAS,OAAO,SAAS,aAAa,SAAS,MAAM,UAAU;EAEvF,MAAM,QACJ,SAAS,OAAO,SAAS,WACrB;GACE,OAAO,SAAS,MAAM,gBAAgB;GACtC,QAAQ,SAAS,MAAM,iBAAiB;GACxC,OAAO,SAAS,MAAM,gBAAgB;EACxC,IACA;GAAE,OAAO;GAAG,QAAQ;GAAG,OAAO;EAAE;EAEtC,OAAO;GACL,MAAM,SAAS;GACf,GAAI,YAAY,SAAS,SAAS,IAAI,EAAE,SAAS,IAAI,CAAC;GACtD,GAAI,oBAAoB,SAAY,EAAE,gBAAgB,IAAI,CAAC;GAC3D;EACF;CACF;AACF"}
|
package/llms-full.txt
CHANGED
|
@@ -97,7 +97,7 @@ const { data } = await ai.image({ model: gpt, prompt: "a red bicycle", size: "10
|
|
|
97
97
|
|
|
98
98
|
- `gpt-image-*` is token-metered (price with `{ input, output }`) and always returns base64 bytes — the adapter never sends `response_format` (the API rejects it).
|
|
99
99
|
- `dall-e-*` is per-image (price with `{ perImage }` / `perImageBySize`); defaults to base64, opt into a hosted URL with `options: { responseFormat: "url" }`.
|
|
100
|
-
-
|
|
100
|
+
- The model id is **not validated locally** — `openai.image({ name })` passes it straight to `client.images.generate`, so an id OpenAI does not serve fails at the provider (wrapped into the typed `AIError` hierarchy), not at construction. Same for `openai.speech({ name })` and `openai.transcribe({ name })`. There are no model-id helpers to consult: `isOpenAIImageModel()`, `OPENAI_IMAGE_MODEL_PREFIXES`, `isOpenAISpeechModel()` and `isOpenAITranscriptionModel()` were all removed in 4.13.0 — branch on your own id list if you need one. The verb surface (envelope, options, cost-truth) lives in [`@warlock.js/ai/generate-images/SKILL.md`](@warlock.js/ai/generate-images/SKILL.md).
|
|
101
101
|
|
|
102
102
|
## Streaming
|
|
103
103
|
|
package/package.json
CHANGED
|
@@ -14,12 +14,12 @@
|
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"openai": "^6.34.0",
|
|
17
|
-
"@warlock.js/logger": "4.
|
|
17
|
+
"@warlock.js/logger": "4.14.0"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@warlock.js/ai": "4.
|
|
20
|
+
"@warlock.js/ai": "4.14.0"
|
|
21
21
|
},
|
|
22
|
-
"version": "4.
|
|
22
|
+
"version": "4.14.0",
|
|
23
23
|
"main": "./cjs/index.cjs",
|
|
24
24
|
"module": "./esm/index.mjs",
|
|
25
25
|
"types": "./esm/index.d.mts",
|
|
@@ -89,7 +89,7 @@ const { data } = await ai.image({ model: gpt, prompt: "a red bicycle", size: "10
|
|
|
89
89
|
|
|
90
90
|
- `gpt-image-*` is token-metered (price with `{ input, output }`) and always returns base64 bytes — the adapter never sends `response_format` (the API rejects it).
|
|
91
91
|
- `dall-e-*` is per-image (price with `{ perImage }` / `perImageBySize`); defaults to base64, opt into a hosted URL with `options: { responseFormat: "url" }`.
|
|
92
|
-
-
|
|
92
|
+
- The model id is **not validated locally** — `openai.image({ name })` passes it straight to `client.images.generate`, so an id OpenAI does not serve fails at the provider (wrapped into the typed `AIError` hierarchy), not at construction. Same for `openai.speech({ name })` and `openai.transcribe({ name })`. There are no model-id helpers to consult: `isOpenAIImageModel()`, `OPENAI_IMAGE_MODEL_PREFIXES`, `isOpenAISpeechModel()` and `isOpenAITranscriptionModel()` were all removed in 4.13.0 — branch on your own id list if you need one. The verb surface (envelope, options, cost-truth) lives in [`@warlock.js/ai/generate-images/SKILL.md`](@warlock.js/ai/generate-images/SKILL.md).
|
|
93
93
|
|
|
94
94
|
## Streaming
|
|
95
95
|
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
//#region ../ai-openai/src/known-image-models.d.ts
|
|
2
|
-
/**
|
|
3
|
-
* Model-id prefixes OpenAI exposes through the **Images** API
|
|
4
|
-
* (`client.images.generate`). The two live families:
|
|
5
|
-
*
|
|
6
|
-
* - `gpt-image-*` — token-metered, always returns base64 bytes (no
|
|
7
|
-
* `response_format` knob), supports `output_format` + `background`.
|
|
8
|
-
* - `dall-e-*` — per-image-metered, returns a URL or base64 via
|
|
9
|
-
* `response_format`.
|
|
10
|
-
*
|
|
11
|
-
* Used by {@link isOpenAIImageModel} for the construction-time guard so
|
|
12
|
-
* `openai.image({ name: "gpt-4o" })` fails fast with a curated error
|
|
13
|
-
* instead of a downstream 400 — mirroring the embedder/vision guards.
|
|
14
|
-
*/
|
|
15
|
-
declare const OPENAI_IMAGE_MODEL_PREFIXES: readonly ["gpt-image", "dall-e"];
|
|
16
|
-
/**
|
|
17
|
-
* True when `name` is a recognized OpenAI image-generation model. A
|
|
18
|
-
* prefix match (not an exact list) so dated snapshots
|
|
19
|
-
* (`gpt-image-1-mini`, `dall-e-3`) are covered without a maintenance
|
|
20
|
-
* burden every time OpenAI ships a point release.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* isOpenAIImageModel("gpt-image-1"); // true
|
|
24
|
-
* isOpenAIImageModel("dall-e-3"); // true
|
|
25
|
-
* isOpenAIImageModel("gpt-4o"); // false
|
|
26
|
-
*/
|
|
27
|
-
declare function isOpenAIImageModel(name: string): boolean;
|
|
28
|
-
//#endregion
|
|
29
|
-
export { OPENAI_IMAGE_MODEL_PREFIXES, isOpenAIImageModel };
|
|
30
|
-
//# sourceMappingURL=known-image-models.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"known-image-models.d.mts","names":[],"sources":["../../../../../../ai-openai/src/known-image-models.ts"],"mappings":";;AAaA;;;;AAA2E;AAa3E;;;;AAA+C;;;cAblC,2BAAA;;;;;;;;;;;;iBAaG,kBAAA,CAAmB,IAAY"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
//#region ../ai-openai/src/known-image-models.ts
|
|
2
|
-
/**
|
|
3
|
-
* Model-id prefixes OpenAI exposes through the **Images** API
|
|
4
|
-
* (`client.images.generate`). The two live families:
|
|
5
|
-
*
|
|
6
|
-
* - `gpt-image-*` — token-metered, always returns base64 bytes (no
|
|
7
|
-
* `response_format` knob), supports `output_format` + `background`.
|
|
8
|
-
* - `dall-e-*` — per-image-metered, returns a URL or base64 via
|
|
9
|
-
* `response_format`.
|
|
10
|
-
*
|
|
11
|
-
* Used by {@link isOpenAIImageModel} for the construction-time guard so
|
|
12
|
-
* `openai.image({ name: "gpt-4o" })` fails fast with a curated error
|
|
13
|
-
* instead of a downstream 400 — mirroring the embedder/vision guards.
|
|
14
|
-
*/
|
|
15
|
-
const OPENAI_IMAGE_MODEL_PREFIXES = ["gpt-image", "dall-e"];
|
|
16
|
-
/**
|
|
17
|
-
* True when `name` is a recognized OpenAI image-generation model. A
|
|
18
|
-
* prefix match (not an exact list) so dated snapshots
|
|
19
|
-
* (`gpt-image-1-mini`, `dall-e-3`) are covered without a maintenance
|
|
20
|
-
* burden every time OpenAI ships a point release.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* isOpenAIImageModel("gpt-image-1"); // true
|
|
24
|
-
* isOpenAIImageModel("dall-e-3"); // true
|
|
25
|
-
* isOpenAIImageModel("gpt-4o"); // false
|
|
26
|
-
*/
|
|
27
|
-
function isOpenAIImageModel(name) {
|
|
28
|
-
return OPENAI_IMAGE_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
//#endregion
|
|
32
|
-
export { OPENAI_IMAGE_MODEL_PREFIXES, isOpenAIImageModel };
|
|
33
|
-
//# sourceMappingURL=known-image-models.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"known-image-models.mjs","names":[],"sources":["../../../../../../ai-openai/src/known-image-models.ts"],"sourcesContent":["/**\n * Model-id prefixes OpenAI exposes through the **Images** API\n * (`client.images.generate`). The two live families:\n *\n * - `gpt-image-*` — token-metered, always returns base64 bytes (no\n * `response_format` knob), supports `output_format` + `background`.\n * - `dall-e-*` — per-image-metered, returns a URL or base64 via\n * `response_format`.\n *\n * Used by {@link isOpenAIImageModel} for the construction-time guard so\n * `openai.image({ name: \"gpt-4o\" })` fails fast with a curated error\n * instead of a downstream 400 — mirroring the embedder/vision guards.\n */\nexport const OPENAI_IMAGE_MODEL_PREFIXES = [\"gpt-image\", \"dall-e\"] as const;\n\n/**\n * True when `name` is a recognized OpenAI image-generation model. A\n * prefix match (not an exact list) so dated snapshots\n * (`gpt-image-1-mini`, `dall-e-3`) are covered without a maintenance\n * burden every time OpenAI ships a point release.\n *\n * @example\n * isOpenAIImageModel(\"gpt-image-1\"); // true\n * isOpenAIImageModel(\"dall-e-3\"); // true\n * isOpenAIImageModel(\"gpt-4o\"); // false\n */\nexport function isOpenAIImageModel(name: string): boolean {\n return OPENAI_IMAGE_MODEL_PREFIXES.some((prefix) => name.startsWith(prefix));\n}\n"],"mappings":";;;;;;;;;;;;;;AAaA,MAAa,8BAA8B,CAAC,aAAa,QAAQ;;;;;;;;;;;;AAajE,SAAgB,mBAAmB,MAAuB;CACxD,OAAO,4BAA4B,MAAM,WAAW,KAAK,WAAW,MAAM,CAAC;AAC7E"}
|