@alvin0/ai-agent-sdk-provider-openai 0.1.0 → 0.1.1

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 CHANGED
@@ -20,9 +20,10 @@ Use `openAiAdapter()` for manual route registration. Both APIs are Universal and
20
20
  require an explicit `apiKey`; environment lookup belongs to a Node wrapper.
21
21
 
22
22
  Both accept `models: [{ id, contextWindow, maxTokens }]` plus provider-level
23
- `defaultContextWindow` and `defaultMaxTokens` fallbacks. Currently a catalog
24
- model's `maxTokens` is both its default output budget and its SDK output ceiling;
25
- set a lower `maxTokens` on the agent to request less output. See the
23
+ `defaultContextWindow` and `defaultMaxTokens` fallbacks. A catalog model's
24
+ `maxTokens` is its SDK output ceiling and, unless `models[].defaultMaxTokens`
25
+ is set, its default output budget. Provider fallback budgets are not hard ceilings.
26
+ Keep the operating context below any extended-context price threshold. See the
26
27
  [provider model limits guide](../../web-documents/en/09-providers/index.md) for an example
27
28
  and precedence rules. These declarations do not increase server-side limits.
28
29
 
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { ComposableModelProviderPlugin, CredentialInput, ModelTarget } from "@alvin0/ai-agent-sdk-core/provider";
2
- import { CredentialSource, HttpModelAdapter, ProviderCatalogModel, ProviderRequestLogger } from "@alvin0/ai-agent-sdk-provider-http";
1
+ import { ComposableEmbeddingProviderPlugin, ComposableModelProviderPlugin, CredentialInput, ModelTarget } from "@alvin0/ai-agent-sdk-core/provider";
2
+ import { CredentialSource, EmbeddingCatalogModel, HttpModelAdapter, ProviderCatalogModel, ProviderRequestLogger } from "@alvin0/ai-agent-sdk-provider-http";
3
3
  import { ResponsesDialect, openAiResponsesProtocol } from "@alvin0/ai-agent-sdk-protocol-responses";
4
4
  import { ModelProviderPlugin, RetryPolicyConfig } from "@alvin0/ai-agent-sdk-core";
5
+ import { EmbeddingAdapter } from "@alvin0/ai-agent-sdk-core/embedding";
5
6
  //#region src/adapter.d.ts
6
7
  /** The OpenAI API base. */
7
8
  declare const OPENAI_BASE_URL = "https://api.openai.com/v1";
@@ -73,5 +74,65 @@ declare function openAiPlugin(options: OpenAiProviderOptions): ComposableModelPr
73
74
  };
74
75
  declare function openAiPlugin(options: OpenAiPluginOptions): ModelProviderPlugin;
75
76
  //#endregion
76
- export { OPENAI_BASE_URL, type OpenAiAdapterOptions, type OpenAiCredential, type OpenAiPluginOptions, type OpenAiProviderOptions, type ResponsesDialect, openAiAdapter, openAiPlugin, openAiResponsesProtocol };
77
+ //#region src/embedding.d.ts
78
+ /** Options for {@link openAiEmbeddingAdapter} and {@link openAiEmbeddingPlugin}. */
79
+ interface OpenAiEmbeddingProviderOptions {
80
+ /** Injected API key or credential source; universal packages never read the environment. */
81
+ readonly apiKey: CredentialInput;
82
+ /**
83
+ * Endpoint base; defaults to {@link OPENAI_BASE_URL}.
84
+ *
85
+ * Point this at a self-hosted OpenAI-compatible endpoint. Declare that
86
+ * endpoint's models through {@link models}: the compatibility claim is the
87
+ * configuration's, not this adapter's (Requirement 15.3).
88
+ */
89
+ readonly baseUrl?: string;
90
+ /** Organization to bill, when the key belongs to several. */
91
+ readonly organization?: string;
92
+ /** Project to attribute usage to. */
93
+ readonly project?: string;
94
+ /** Plugin id; also the default route. Defaults to `'openai'`. */
95
+ readonly id?: string;
96
+ /** Registry routes the plugin claims. Defaults to `[id]`. */
97
+ readonly routes?: readonly string[];
98
+ /**
99
+ * Advisory embedding catalog.
100
+ *
101
+ * Empty by default, for the same reason the generation adapter ships no model
102
+ * list: a stale built-in catalog would name retired models. A declared entry is
103
+ * what makes `dimensions` reachable on the wire and what states the embedding
104
+ * space, so a route that cares about either declares its models.
105
+ */
106
+ readonly models?: readonly EmbeddingCatalogModel[];
107
+ /** Permit cleartext HTTP explicitly, for trusted local endpoints only. */
108
+ readonly allowInsecureHttp?: boolean;
109
+ readonly requestTimeoutMs?: number;
110
+ readonly maxRequestBytes?: number;
111
+ readonly maxResponseBytes?: number;
112
+ readonly maxResponseChunks?: number;
113
+ readonly maxErrorBodyBytes?: number;
114
+ readonly requestLoggerTimeoutMs?: number;
115
+ /** Retry policy this route owns. */
116
+ readonly retryPolicy?: RetryPolicyConfig;
117
+ readonly fetch?: typeof globalThis.fetch;
118
+ }
119
+ /**
120
+ * Create an OpenAI embedding adapter.
121
+ * @param options - credential, endpoint, catalog and transport bounds.
122
+ * @returns the adapter, ready to register on an embedding route.
123
+ */
124
+ declare function openAiEmbeddingAdapter(options: OpenAiEmbeddingProviderOptions): EmbeddingAdapter;
125
+ /**
126
+ * Preferred transactional plugin for installing OpenAI embeddings.
127
+ *
128
+ * Its `kind` is `'embedding-provider-plugin'`, so it installs beside
129
+ * {@link openAiPlugin} on the same route without either standing in for the other.
130
+ * @param options - credential, endpoint, catalog and transport bounds.
131
+ * @returns an inert plugin; the adapter is constructed during activation.
132
+ */
133
+ declare function openAiEmbeddingPlugin(options: OpenAiEmbeddingProviderOptions): ComposableEmbeddingProviderPlugin & {
134
+ readonly family: 'openai';
135
+ };
136
+ //#endregion
137
+ export { OPENAI_BASE_URL, type OpenAiAdapterOptions, type OpenAiCredential, type OpenAiEmbeddingProviderOptions, type OpenAiPluginOptions, type OpenAiProviderOptions, type ResponsesDialect, openAiAdapter, openAiEmbeddingAdapter, openAiEmbeddingPlugin, openAiPlugin, openAiResponsesProtocol };
77
138
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/adapter.ts"],"mappings":";;;;;;cAkCa;;KAGD,mBAAmB;;UAGd;;EAEf,QAAQ;;;;;;EAMR;;EAEA;;EAEA;;;;;;;;EAQA,kBAAkB;;EAElB;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA,cAAc;;EAEd,gBAAgB;EAChB,eAAe,WAAW;;;;;;;iBAQZ,cAAc,SAAS,uBAAuB;UAiC7C,4BAA4B;;WAElC;;UAGM,8BAA8B,KAAK;WACzC,wBAAwB;WACxB,QAAQ;WACR;WACA;;;iBAIK,aACd,SAAS,wBACR;WAA2C;;iBAC9B,aAAa,SAAS,sBAAsB"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/adapter.ts","../src/embedding.ts"],"mappings":";;;;;;;cAmCa;;KAGD,mBAAmB;;UAGd;;EAEf,QAAQ;;;;;;EAMR;;EAEA;;EAEA;;;;;;;;EAQA,kBAAkB;;EAElB;;EAEA;;EAEA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;EAEA,cAAc;;EAEd,gBAAgB;EAChB,eAAe,WAAW;;;;;;;iBAQZ,cAAc,SAAS,uBAAuB;UAkC7C,4BAA4B;;WAElC;;UAGM,8BAA8B,KAAK;WACzC,wBAAwB;WACxB,QAAQ;WACR;WACA;;;iBAIK,aACd,SAAS,wBACR;WAA2C;;iBAC9B,aAAa,SAAS,sBAAsB;;;;UC1B3C;;WAEN,QAAQ;;;;;;;;WAQR;;WAEA;;WAEA;;WAEA;;WAEA;;;;;;;;;WASA,kBAAkB;;WAElB;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA,cAAc;WACd,eAAe,WAAW;;;;;;;iBAkcrB,uBACd,SAAS,iCACR;;;;;;;;;iBAYa,sBACd,SAAS,iCACR;WAA+C"}
package/dist/index.js CHANGED
@@ -1,7 +1,24 @@
1
- import { defineModelProviderPlugin } from "@alvin0/ai-agent-sdk-core/provider";
2
- import { createHttpProvider, createRuntimeHttpProvider } from "@alvin0/ai-agent-sdk-provider-http";
1
+ import { defineEmbeddingProviderPlugin, defineModelProviderPlugin } from "@alvin0/ai-agent-sdk-core/provider";
2
+ import { captureTransportConnection, createHttpProvider, createModelContextPolicy, createRuntimeHttpProvider, embeddingCatalogModelInfo, resolvedEmbeddingCatalogModelInfo, transportJson } from "@alvin0/ai-agent-sdk-provider-http";
3
3
  import { openAiResponsesProtocol, openAiResponsesProtocol as openAiResponsesProtocol$1 } from "@alvin0/ai-agent-sdk-protocol-responses";
4
+ import { resolveRetryPolicy } from "@alvin0/ai-agent-sdk-core";
5
+ import { EMBEDDING_ERROR_CODES, EmbeddingAdapter, EmbeddingError, defaultEmbeddingProfile, deriveSpaceId, resolveBatchLimits, validateBatchResult } from "@alvin0/ai-agent-sdk-core/embedding";
4
6
 
7
+ //#region src/context-policy.ts
8
+ const GPT_56 = {
9
+ defaultContextWindow: 272e3,
10
+ maxContextWindow: 105e4,
11
+ standardPriceInputTokens: 272e3
12
+ };
13
+ function openAiContextPolicy(options) {
14
+ return createModelContextPolicy(options.baseUrl === void 0 || options.baseUrl.replace(/\/$/, "") === "https://api.openai.com/v1" ? {
15
+ "gpt-5.6-luna": GPT_56,
16
+ "gpt-5.6-sol": GPT_56,
17
+ "gpt-5.6-terra": GPT_56
18
+ } : {}, options.models, options.defaultContextWindow);
19
+ }
20
+
21
+ //#endregion
5
22
  //#region src/adapter.ts
6
23
  /** The OpenAI API base. */
7
24
  const OPENAI_BASE_URL = "https://api.openai.com/v1";
@@ -14,6 +31,7 @@ function openAiAdapter(options) {
14
31
  const dialect = options.store === void 0 ? {} : { store: options.store };
15
32
  return createHttpProvider({
16
33
  displayName: "OpenAI",
34
+ describeModel: openAiContextPolicy(options),
17
35
  protocol: openAiResponsesProtocol$1,
18
36
  baseUrl: options.baseUrl ?? "https://api.openai.com/v1",
19
37
  auth: {
@@ -67,6 +85,7 @@ function legacyOpenAiPlugin(options) {
67
85
  }
68
86
  function createRuntimeOpenAiAdapter(options) {
69
87
  return createRuntimeHttpProvider({
88
+ describeModel: openAiContextPolicy(options),
70
89
  displayName: "OpenAI",
71
90
  protocol: openAiResponsesProtocol$1,
72
91
  baseUrl: options.baseUrl ?? "https://api.openai.com/v1",
@@ -118,5 +137,403 @@ function transportLimits(options) {
118
137
  }
119
138
 
120
139
  //#endregion
121
- export { OPENAI_BASE_URL, openAiAdapter, openAiPlugin, openAiResponsesProtocol };
140
+ //#region src/embedding.ts
141
+ /**
142
+ * The OpenAI embeddings endpoint: `POST {baseUrl}/embeddings`.
143
+ *
144
+ * Deliberately a separate module from {@link ./adapter.ts}: it shares no protocol,
145
+ * no dialect and no request vocabulary with `openAiResponsesProtocol`, and wiring
146
+ * embedding through the generation pipeline would mean one of the two shapes
147
+ * standing in for the other (Requirement 14.1). What the two DO share is the
148
+ * transport — the fused signal, the redirect guard, the attempt ledger, the
149
+ * attribution headers — because that chain is where a missing step is expensive.
150
+ *
151
+ * Three facts about this endpoint decide most of what is here, and each has a
152
+ * plausible-looking wrong answer:
153
+ *
154
+ * - **There is no purpose parameter.** A route declares
155
+ * `purposeHandling: 'unsupported'` and this adapter sends the caller's text
156
+ * verbatim. Inventing a `"query: "` prefix would change every vector the caller
157
+ * gets while looking like a helpful default (Requirement 7.5).
158
+ * - **There is no truncation parameter.** `truncation: 'allow'` is therefore
159
+ * refused with `EMBEDDING_TRUNCATION_UNSUPPORTED` rather than accepted and
160
+ * quietly not honoured (Requirement 9.7).
161
+ * - **`dimensions` is a model-line capability, not an endpoint one.** It goes on
162
+ * the wire only when the route DECLARES the widths it supports; an `unknown`
163
+ * catalog is not a licence to send a parameter an endpoint may reject
164
+ * (Requirement 14.4).
165
+ *
166
+ * `baseUrl` is configurable because a self-hosted OpenAI-compatible endpoint is
167
+ * the only mechanism this needs (Requirement 15.1). What it is NOT is an
168
+ * inference: compatibility is a profile someone declared through
169
+ * `EmbeddingCatalogModel`, never something read off the path, and a cleartext
170
+ * `http://` base still requires `allowInsecureHttp` (Requirements 15.3, 15.5).
171
+ *
172
+ * @module ai-agent-sdk/providers/openai/embedding
173
+ */
174
+ /** Display name used in every diagnostic this module raises. */
175
+ const DISPLAY_NAME = "OpenAI";
176
+ /** Path appended to the configured base. */
177
+ const EMBEDDINGS_PATH = "/embeddings";
178
+ /** Media type this endpoint answers with, and the only one accepted back. */
179
+ const JSON_MEDIA_TYPE = "application/json";
180
+ /**
181
+ * The one encoding this adapter asks for.
182
+ *
183
+ * Base64 would halve the bytes on the wire and cost a decode step that could
184
+ * silently reorder or requantise values; float arrays are what the contract's
185
+ * fidelity rule (Requirement 14.8) is cheapest to keep.
186
+ */
187
+ const ENCODING_FORMAT = "float";
188
+ /**
189
+ * Compatibility identity prefix for an OpenAI embedding model line.
190
+ *
191
+ * Route-independent on purpose: two routes pointing at the same model line — the
192
+ * public API and a mirror of it — produce vectors in the SAME space, so keying
193
+ * the identity on the route name would make them look incompatible.
194
+ */
195
+ const IDENTITY_PREFIX = "openai";
196
+ const NEVER_ABORTED_SIGNAL = new AbortController().signal;
197
+ const NULL_LOGGER = Object.freeze({
198
+ child: () => NULL_LOGGER,
199
+ trace: () => void 0,
200
+ debug: () => void 0,
201
+ info: () => void 0,
202
+ warn: () => void 0,
203
+ error: () => void 0,
204
+ fatal: () => void 0
205
+ });
206
+ /**
207
+ * `POST /embeddings` as an {@link EmbeddingAdapter}.
208
+ *
209
+ * Private: the exported surface is {@link openAiEmbeddingAdapter}, so this class
210
+ * can change shape without a caller having come to depend on it.
211
+ */
212
+ var OpenAiEmbeddingAdapter = class extends EmbeddingAdapter {
213
+ options;
214
+ baseUrl;
215
+ models;
216
+ retry;
217
+ constructor(options) {
218
+ super();
219
+ this.options = options;
220
+ this.baseUrl = (options.baseUrl ?? "https://api.openai.com/v1").replace(/\/+$/, "");
221
+ this.models = Object.freeze([...options.models ?? []]);
222
+ this.retry = resolveRetryPolicy(options.retryPolicy, "openAiEmbedding.retryPolicy");
223
+ }
224
+ providerInfo(provider) {
225
+ return {
226
+ id: provider,
227
+ name: DISPLAY_NAME
228
+ };
229
+ }
230
+ providerRetryPolicy(_provider) {
231
+ return this.retry;
232
+ }
233
+ listEmbeddingModels(provider, signal) {
234
+ signal?.throwIfAborted();
235
+ return Promise.resolve(Object.freeze(this.models.map((model) => embeddingCatalogModelInfo(provider, model))));
236
+ }
237
+ resolveEmbeddingModel(provider, model, signal) {
238
+ signal?.throwIfAborted();
239
+ return Promise.resolve(resolvedEmbeddingCatalogModelInfo(provider, model, this.models));
240
+ }
241
+ /**
242
+ * States what this model line declares about its embedding space.
243
+ *
244
+ * Overridden rather than inherited because the default answer is derived from
245
+ * `${route}:${modelId}`, which makes one model line look like two spaces when
246
+ * it is reachable through two routes. Two things differ here: the identity is
247
+ * the model line's (see {@link IDENTITY_PREFIX}), and normalization is reported
248
+ * only when the ROUTE declared it — never inferred from OpenAI's reputation for
249
+ * returning unit vectors (Requirements 6.1, 6.3).
250
+ */
251
+ embeddingProfile(model, request) {
252
+ const base = defaultEmbeddingProfile(model, request);
253
+ return Object.freeze({
254
+ ...base,
255
+ compatibilityIdentity: model.compatibilityIdentity.state === "supported" ? model.compatibilityIdentity.value : `${IDENTITY_PREFIX}:${model.id}`,
256
+ normalization: model.normalization.state === "supported" ? model.normalization.value : base.normalization
257
+ });
258
+ }
259
+ /**
260
+ * Captures endpoint, credential and bounds ONCE, then binds dispatch to that
261
+ * capture.
262
+ *
263
+ * Overridden because this adapter's connection facts come from configuration
264
+ * and a credential resolved per operation: reading them again inside
265
+ * `embedBatch()` would let a rotating secret pair with another generation's URL,
266
+ * and would let dimensions be validated against one catalog while the request
267
+ * went out under another (Requirements 2.2, 2.3, 2.4).
268
+ */
269
+ async prepareEmbeddingCall(provider, model, options, signal, context) {
270
+ const connection = await this.connect(signal, context);
271
+ const resolved = resolvedEmbeddingCatalogModelInfo(provider, model, connection.models);
272
+ const profile = this.embeddingProfile(resolved, options);
273
+ return Object.freeze({
274
+ model: resolved,
275
+ profile,
276
+ spaceId: deriveSpaceId(profile),
277
+ limits: resolveBatchLimits(resolved, options.limits),
278
+ embedBatch: (batch, invocation = context) => this.dispatch(connection, resolved, batch, invocation)
279
+ });
280
+ }
281
+ /**
282
+ * One `Physical_Batch`, one `Provider_Attempt`.
283
+ *
284
+ * Reachable directly for an adapter used without a prepared call; the shared
285
+ * path is {@link dispatch}, so both routes send the same body under the same
286
+ * guards.
287
+ */
288
+ async embedBatch(batch, context) {
289
+ const connection = await this.connect(batch.signal, context);
290
+ const model = resolvedEmbeddingCatalogModelInfo(batch.provider, batch.model, connection.models);
291
+ return this.dispatch(connection, model, batch, context);
292
+ }
293
+ /** Everything one embedding request needs, read together, once per operation. */
294
+ async connect(signal, context) {
295
+ const headers = { authorization: `Bearer ${await resolveApiKey(this.options.apiKey, signal, context)}` };
296
+ if (this.options.organization !== void 0) headers["openai-organization"] = this.options.organization;
297
+ if (this.options.project !== void 0) headers["openai-project"] = this.options.project;
298
+ return Object.freeze({
299
+ baseUrl: this.baseUrl,
300
+ headers: Object.freeze(headers),
301
+ sensitiveHeaderNames: Object.freeze(Object.keys(headers)),
302
+ models: this.models,
303
+ retryPolicy: this.retry,
304
+ ...this.options.allowInsecureHttp === void 0 ? {} : { allowInsecureHttp: this.options.allowInsecureHttp },
305
+ ...this.options.requestTimeoutMs === void 0 ? {} : { requestTimeoutMs: this.options.requestTimeoutMs },
306
+ ...this.options.maxRequestBytes === void 0 ? {} : { maxRequestBytes: this.options.maxRequestBytes },
307
+ ...this.options.maxResponseBytes === void 0 ? {} : { maxResponseBytes: this.options.maxResponseBytes },
308
+ ...this.options.maxResponseChunks === void 0 ? {} : { maxResponseChunks: this.options.maxResponseChunks },
309
+ ...this.options.maxErrorBodyBytes === void 0 ? {} : { maxErrorBodyBytes: this.options.maxErrorBodyBytes },
310
+ ...this.options.requestLoggerTimeoutMs === void 0 ? {} : { requestLoggerTimeoutMs: this.options.requestLoggerTimeoutMs },
311
+ ...this.options.fetch === void 0 ? {} : { fetch: this.options.fetch }
312
+ });
313
+ }
314
+ /** Serialize, send through the shared chain, and map the parsed body back. */
315
+ async dispatch(connection, model, batch, context) {
316
+ if (batch.truncation === "allow") throw new EmbeddingError(`${DISPLAY_NAME} embeddings exposes no truncation parameter`, EMBEDDING_ERROR_CODES.TRUNCATION_UNSUPPORTED, {
317
+ provider: batch.provider,
318
+ model: batch.model
319
+ });
320
+ const body = {
321
+ model: batch.model,
322
+ input: batch.items.map(itemInput),
323
+ encoding_format: ENCODING_FORMAT
324
+ };
325
+ if (batch.dimensions !== void 0 && model.dimensions.state === "supported") body["dimensions"] = batch.dimensions;
326
+ const encoded = JSON.stringify(body);
327
+ return decodeEmbeddingResponse(batch, await transportJson({
328
+ connection: captureTransportConnection(connection, {
329
+ "content-type": JSON_MEDIA_TYPE,
330
+ accept: JSON_MEDIA_TYPE
331
+ }),
332
+ displayName: DISPLAY_NAME,
333
+ provider: batch.provider,
334
+ model: batch.model,
335
+ path: EMBEDDINGS_PATH,
336
+ accept: JSON_MEDIA_TYPE,
337
+ body: {
338
+ value: body,
339
+ encoded,
340
+ bytes: new TextEncoder().encode(encoded).length
341
+ },
342
+ ...batch.signal === void 0 ? {} : { signal: batch.signal },
343
+ ...context === void 0 ? {} : { context }
344
+ }, (session, payload) => Object.freeze({
345
+ payload,
346
+ ...session.providerRequestId === void 0 ? {} : { providerRequestId: session.providerRequestId }
347
+ })));
348
+ }
349
+ };
350
+ /**
351
+ * Concatenates one item's content parts into a single wire input.
352
+ *
353
+ * The rule is recorded as `documentRecipeRevision` on the profile, and revision
354
+ * `'1'` is exactly this: the text of each part, in order, with no separator and no
355
+ * added markup. It matches the effective text the contract's own length check and
356
+ * cache key derive, so a batch split, a rejection and a wire body can never
357
+ * disagree about what an item's text is. One item produces one element, so the
358
+ * provider returns exactly one vector for it (Requirement 8.7).
359
+ */
360
+ function itemInput(item) {
361
+ let text = "";
362
+ for (const part of item.contentParts) if (part.type === "text") text += part.text;
363
+ return text;
364
+ }
365
+ /**
366
+ * Maps one parsed response body onto the batch that produced it, in ONE fixed
367
+ * order.
368
+ *
369
+ * The order is the contract, not an implementation detail — the same malformed
370
+ * response has to produce the same code here as it does for every other provider,
371
+ * which is what lets a single conformance suite judge all of them:
372
+ *
373
+ * 1. a shape this contract does not recognise ⇒ `RESPONSE_MALFORMED`
374
+ * 2. `data.length !== items.length` ⇒ `VECTOR_COUNT_MISMATCH`
375
+ * 3. `{ data[i].index }` is not a permutation of `0..N-1` ⇒ `VECTOR_INDEX_INVALID`
376
+ * 4. a non-finite element ⇒ `VECTOR_VALUE_INVALID`
377
+ * 5. a width other than the one requested ⇒ `VECTOR_DIMENSIONS_MISMATCH`
378
+ *
379
+ * Steps 4 and 5 are delegated to the shared {@link validateBatchResult}, which
380
+ * already runs them in exactly this order; re-deriving them here would be a second
381
+ * place for the ordering to drift.
382
+ *
383
+ * The count check comes FIRST on purpose. Reading the entries one at a time and
384
+ * refusing the first bad index would report a mapping failure for a response whose
385
+ * real fault is that it answered a different number of inputs — two different
386
+ * repairs for a caller, told apart by which check ran first.
387
+ *
388
+ * Nothing here slices, pads, sorts or repairs a value. The `index` a vector carries
389
+ * out is the item's index in the `Logical_Call`, taken from `items[data[i].index]`,
390
+ * never its position in this batch (Requirement 8.4).
391
+ */
392
+ function decodeEmbeddingResponse(batch, received) {
393
+ const entries = readEntries(batch, received.payload);
394
+ checkEntryCount(batch, entries);
395
+ const positions = readPositions(batch, entries);
396
+ const vectors = entries.map((entry, at) => Object.freeze({
397
+ index: batch.items[positions[at]].index,
398
+ values: readValues(batch, entry)
399
+ }));
400
+ const usage = readUsage(received.payload);
401
+ const result = Object.freeze({
402
+ vectors: Object.freeze(vectors),
403
+ ...usage === void 0 ? {} : { usage },
404
+ ...received.providerRequestId === void 0 ? {} : { providerRequestId: received.providerRequestId }
405
+ });
406
+ validateBatchResult(batch, result);
407
+ return result;
408
+ }
409
+ /** A `data` array of objects, or a structural refusal naming the batch it belongs to. */
410
+ function readEntries(batch, payload) {
411
+ const data = record(payload)?.["data"];
412
+ if (!Array.isArray(data)) throw malformed(batch, "response carries no `data` array");
413
+ return data.map((entry) => {
414
+ const source = record(entry);
415
+ if (source === void 0) throw malformed(batch, "response `data` entry is not an object");
416
+ return source;
417
+ });
418
+ }
419
+ /** Step 2: one vector per input sent, counted before anything is interpreted. */
420
+ function checkEntryCount(batch, entries) {
421
+ if (entries.length === batch.items.length) return;
422
+ throw new EmbeddingError(`${DISPLAY_NAME} returned ${entries.length} vectors for ${batch.items.length} inputs`, EMBEDDING_ERROR_CODES.VECTOR_COUNT_MISMATCH, {
423
+ provider: batch.provider,
424
+ model: batch.model
425
+ });
426
+ }
427
+ /**
428
+ * Step 3: the reported positions, once they are known to be a permutation of
429
+ * `0..N-1`.
430
+ *
431
+ * A duplicate, a gap, a non-integer and an out-of-range value all land in the same
432
+ * refusal, because they all break the same thing: without a bijection between
433
+ * response entries and batch items, restoring input order would be guesswork, and
434
+ * a position to "fall back on" would silently attach one input's vector to another
435
+ * (Requirement 8.2).
436
+ */
437
+ function readPositions(batch, entries) {
438
+ const positions = [];
439
+ const seen = /* @__PURE__ */ new Set();
440
+ for (const entry of entries) {
441
+ const position = entry["index"];
442
+ if (typeof position !== "number" || !Number.isInteger(position) || position < 0 || position >= batch.items.length || seen.has(position)) throw new EmbeddingError(`${DISPLAY_NAME} returned a duplicate, missing or out-of-range vector index`, EMBEDDING_ERROR_CODES.VECTOR_INDEX_INVALID, {
443
+ provider: batch.provider,
444
+ model: batch.model
445
+ });
446
+ seen.add(position);
447
+ positions.push(position);
448
+ }
449
+ return positions;
450
+ }
451
+ /**
452
+ * Reads one `embedding` array with every number exactly as it arrived.
453
+ *
454
+ * Only the SHAPE is judged here: a non-finite or non-numeric element is step 4's
455
+ * business, so it travels through untouched and is refused by
456
+ * {@link validateBatchResult} under `VECTOR_VALUE_INVALID` rather than being
457
+ * repaired, dropped, or relabelled as a malformed shape.
458
+ */
459
+ function readValues(batch, entry) {
460
+ const values = entry["embedding"];
461
+ if (!Array.isArray(values)) throw malformed(batch, "response vector is not an array");
462
+ return Object.freeze([...values]);
463
+ }
464
+ /**
465
+ * Maps `prompt_tokens` and `total_tokens` onto the two embedding counters.
466
+ *
467
+ * There is no `outputTokens`, which is why embedding reports
468
+ * `EmbeddingTokenUsage` rather than generation's `TokenUsage`. A counter that is
469
+ * absent or unreadable stays ABSENT: a zero here would be indistinguishable from
470
+ * a provider that reported no cost at all.
471
+ */
472
+ function readUsage(payload) {
473
+ const usage = record(record(payload)?.["usage"]);
474
+ if (usage === void 0) return void 0;
475
+ const inputTokens = usage["prompt_tokens"];
476
+ const totalTokens = usage["total_tokens"];
477
+ const counters = {
478
+ ...typeof inputTokens === "number" ? { inputTokens } : {},
479
+ ...typeof totalTokens === "number" ? { totalTokens } : {}
480
+ };
481
+ return Reflect.ownKeys(counters).length === 0 ? void 0 : counters;
482
+ }
483
+ /** A plain-record view of an unknown value, or `undefined`. */
484
+ function record(value) {
485
+ if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
486
+ return value;
487
+ }
488
+ /** A structural refusal: the response is not a shape this contract recognises. */
489
+ function malformed(batch, detail) {
490
+ return new EmbeddingError(`${DISPLAY_NAME} embeddings ${detail}`, EMBEDDING_ERROR_CODES.RESPONSE_MALFORMED, {
491
+ provider: batch.provider,
492
+ model: batch.model
493
+ });
494
+ }
495
+ /** Resolves a literal key or a credential source, once per operation. */
496
+ async function resolveApiKey(apiKey, signal, context) {
497
+ const value = typeof apiKey === "string" ? apiKey : await apiKey.resolve({
498
+ signal: signal ?? NEVER_ABORTED_SIGNAL,
499
+ logger: context?.logger ?? NULL_LOGGER
500
+ });
501
+ if (typeof value !== "string" || value.trim().length === 0) throw new EmbeddingError(`${DISPLAY_NAME} embeddings requires a non-empty \`apiKey\``, EMBEDDING_ERROR_CODES.CONFIGURATION_INVALID);
502
+ return value;
503
+ }
504
+ /**
505
+ * Create an OpenAI embedding adapter.
506
+ * @param options - credential, endpoint, catalog and transport bounds.
507
+ * @returns the adapter, ready to register on an embedding route.
508
+ */
509
+ function openAiEmbeddingAdapter(options) {
510
+ return new OpenAiEmbeddingAdapter(options);
511
+ }
512
+ /**
513
+ * Preferred transactional plugin for installing OpenAI embeddings.
514
+ *
515
+ * Its `kind` is `'embedding-provider-plugin'`, so it installs beside
516
+ * {@link openAiPlugin} on the same route without either standing in for the other.
517
+ * @param options - credential, endpoint, catalog and transport bounds.
518
+ * @returns an inert plugin; the adapter is constructed during activation.
519
+ */
520
+ function openAiEmbeddingPlugin(options) {
521
+ const id = options.id ?? "openai";
522
+ const routes = Object.freeze([...options.routes ?? [id]]);
523
+ return defineEmbeddingProviderPlugin({
524
+ id,
525
+ family: "openai",
526
+ displayName: DISPLAY_NAME,
527
+ routes,
528
+ setup(registrar) {
529
+ const remove = registrar.registerEmbeddingAdapter(openAiEmbeddingAdapter(options));
530
+ return () => {
531
+ remove();
532
+ };
533
+ }
534
+ });
535
+ }
536
+
537
+ //#endregion
538
+ export { OPENAI_BASE_URL, openAiAdapter, openAiEmbeddingAdapter, openAiEmbeddingPlugin, openAiPlugin, openAiResponsesProtocol };
122
539
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["openAiResponsesProtocol"],"sources":["../src/adapter.ts"],"sourcesContent":["/**\n * The OpenAI provider: the Responses API on `api.openai.com`.\n *\n * Note how little there is here. Every endpoint fact is configuration handed to\n * {@link createHttpProvider}; the protocol, the pipeline, and the error mapping are\n * all shared. That is the intended shape for any endpoint speaking a protocol this\n * package already implements — including your own gateway.\n *\n * @module ai-agent-sdk/providers/openai/adapter\n */\n\nimport type { ModelProviderPlugin, ModelProviderRegistrar, RetryPolicyConfig } from '@alvin0/ai-agent-sdk-core'\nimport {\n defineModelProviderPlugin,\n type ComposableModelProviderPlugin,\n type CredentialInput,\n type ModelTarget,\n} from '@alvin0/ai-agent-sdk-core/provider'\nimport type {\n HttpModelAdapter,\n ProviderCatalogModel,\n ProviderRequestLogger,\n} from '@alvin0/ai-agent-sdk-provider-http'\nimport {\n createHttpProvider,\n createRuntimeHttpProvider,\n type CredentialSource,\n} from '@alvin0/ai-agent-sdk-provider-http'\nimport {\n openAiResponsesProtocol,\n type ResponsesDialect,\n} from '@alvin0/ai-agent-sdk-protocol-responses'\n\n/** The OpenAI API base. */\nexport const OPENAI_BASE_URL = 'https://api.openai.com/v1'\n\n/** How the API key is obtained. */\nexport type OpenAiCredential = CredentialSource\n\n/** Options for {@link openAiAdapter}. */\nexport interface OpenAiAdapterOptions {\n /** Injected API key or resolver. Universal packages never read environment variables. */\n apiKey: OpenAiCredential\n /**\n * Endpoint base; defaults to {@link OPENAI_BASE_URL}.\n *\n * Point this at a compatible gateway to reuse this provider wholesale.\n */\n baseUrl?: string\n /** Organization to bill, when the key belongs to several. */\n organization?: string\n /** Project to attribute usage to. */\n project?: string\n /**\n * Advisory model catalog.\n *\n * Empty by default: this package cannot know which model ids are current, and a\n * stale built-in list would name retired models. Supply entries to declare\n * capabilities the SDK cannot infer, such as image support.\n */\n models?: readonly ProviderCatalogModel[]\n /** Whether the provider may retain responses server-side. Defaults to false. */\n store?: boolean\n /** Output cap when neither caller nor catalog names one. */\n defaultMaxTokens?: number\n /** Context capacity assumed for an uncatalogued model. */\n defaultContextWindow?: number\n /** Idle bound while a stream read is outstanding. */\n streamIdleTimeoutMs?: number\n requestTimeoutMs?: number\n maxRequestBytes?: number\n maxResponseBytes?: number\n maxResponseChunks?: number\n maxSseEvents?: number\n maxSseEventChars?: number\n maxErrorBodyBytes?: number\n requestLoggerTimeoutMs?: number\n /** Retry policy this route owns. */\n retryPolicy?: RetryPolicyConfig\n /** Optional exact wire-request logger; credentials are redacted. */\n requestLogger?: ProviderRequestLogger\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI adapter.\n * @param options - credential, endpoint, and catalog overrides.\n * @returns the adapter, ready to register.\n */\nexport function openAiAdapter(options: OpenAiAdapterOptions): HttpModelAdapter {\n const dialect: Partial<ResponsesDialect> = options.store === undefined\n ? {}\n : { store: options.store }\n\n return createHttpProvider({\n displayName: 'OpenAI',\n protocol: openAiResponsesProtocol,\n baseUrl: options.baseUrl ?? OPENAI_BASE_URL,\n auth: {\n kind: 'bearer',\n token: options.apiKey,\n label: 'the `apiKey` option',\n },\n dialect,\n headers: {\n ...options.organization === undefined\n ? {}\n : { 'openai-organization': options.organization },\n ...options.project === undefined ? {} : { 'openai-project': options.project },\n },\n ...options.models === undefined ? {} : { models: options.models },\n defaultMaxTokens: options.defaultMaxTokens ?? 32_000,\n defaultContextWindow: options.defaultContextWindow ?? 128_000,\n ...options.streamIdleTimeoutMs === undefined\n ? {}\n : { streamIdleTimeoutMs: options.streamIdleTimeoutMs },\n ...transportLimits(options),\n ...options.retryPolicy === undefined ? {} : { retryPolicy: options.retryPolicy },\n ...options.requestLogger === undefined ? {} : { requestLogger: options.requestLogger },\n })\n}\n\nexport interface OpenAiPluginOptions extends OpenAiAdapterOptions {\n /** Registry routes installed by the plugin. Defaults to `['openai']`. */\n readonly routes?: readonly string[]\n}\n\nexport interface OpenAiProviderOptions extends Omit<OpenAiAdapterOptions, 'apiKey'> {\n readonly defaultModel?: string | ModelTarget\n readonly apiKey: CredentialInput\n readonly id?: string\n readonly routes?: readonly string[]\n}\n\n/** Preferred transactional plugin for installing the OpenAI provider. */\nexport function openAiPlugin(\n options: OpenAiProviderOptions,\n): ComposableModelProviderPlugin & { readonly family: 'openai' }\nexport function openAiPlugin(options: OpenAiPluginOptions): ModelProviderPlugin\nexport function openAiPlugin(\n options: OpenAiProviderOptions | OpenAiPluginOptions,\n): ModelProviderPlugin | (ComposableModelProviderPlugin & { readonly family: 'openai' }) {\n if (!usesRuntimeComposition(options)) return legacyOpenAiPlugin(options)\n const id = options.id ?? 'openai'\n const routes = Object.freeze([...(options.routes ?? [id])])\n return defineModelProviderPlugin({\n id,\n family: 'openai',\n displayName: 'OpenAI',\n routes,\n ...runtimeDefaultModel(options.defaultModel, routes),\n setup(registrar) {\n const adapter = createRuntimeOpenAiAdapter(options)\n const remove = registrar.registerAdapter(adapter)\n return () => { remove(); return undefined }\n },\n }) as ComposableModelProviderPlugin & { readonly family: 'openai' }\n}\n\nfunction legacyOpenAiPlugin(options: OpenAiPluginOptions): ModelProviderPlugin {\n const routes = Object.freeze([...(options.routes ?? ['openai'])])\n const adapter = openAiAdapter(options)\n return Object.freeze({\n id: 'openai',\n displayName: 'OpenAI',\n setup(registrar: ModelProviderRegistrar) {\n registrar.registerAdapter(routes, adapter)\n },\n })\n}\n\nfunction createRuntimeOpenAiAdapter(options: OpenAiProviderOptions): HttpModelAdapter {\n return createRuntimeHttpProvider({\n displayName: 'OpenAI',\n protocol: openAiResponsesProtocol,\n baseUrl: options.baseUrl ?? OPENAI_BASE_URL,\n auth: { kind: 'bearer', token: options.apiKey, label: 'the `apiKey` option' },\n dialect: options.store === undefined ? {} : { store: options.store },\n headers: {\n ...(options.organization === undefined ? {} : { 'openai-organization': options.organization }),\n ...(options.project === undefined ? {} : { 'openai-project': options.project }),\n },\n ...(options.models === undefined ? {} : { models: options.models }),\n defaultMaxTokens: options.defaultMaxTokens ?? 32_000,\n defaultContextWindow: options.defaultContextWindow ?? 128_000,\n ...(options.streamIdleTimeoutMs === undefined ? {} : { streamIdleTimeoutMs: options.streamIdleTimeoutMs }),\n ...transportLimits(options),\n ...(options.retryPolicy === undefined ? {} : { retryPolicy: options.retryPolicy }),\n ...(options.requestLogger === undefined ? {} : { requestLogger: options.requestLogger }),\n })\n}\n\nfunction usesRuntimeComposition(\n options: OpenAiProviderOptions | OpenAiPluginOptions,\n): options is OpenAiProviderOptions {\n if ('id' in options || 'defaultModel' in options) return true\n if (typeof options.apiKey === 'object' && options.apiKey !== null) return true\n return typeof options.apiKey !== 'function'\n}\n\nfunction runtimeDefaultModel(\n value: string | ModelTarget | undefined,\n routes: readonly string[],\n): { readonly defaultModel?: ModelTarget } {\n if (value === undefined) return {}\n if (typeof value !== 'string') return { defaultModel: value }\n if (routes.length !== 1) {\n throw new TypeError('A string defaultModel requires exactly one OpenAI route')\n }\n return { defaultModel: Object.freeze({ provider: routes[0]!, id: value }) }\n}\n\nfunction transportLimits(options: OpenAiAdapterOptions | OpenAiProviderOptions) {\n return {\n ...options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs },\n ...options.maxRequestBytes === undefined ? {} : { maxRequestBytes: options.maxRequestBytes },\n ...options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes },\n ...options.maxResponseChunks === undefined ? {} : { maxResponseChunks: options.maxResponseChunks },\n ...options.maxSseEvents === undefined ? {} : { maxSseEvents: options.maxSseEvents },\n ...options.maxSseEventChars === undefined ? {} : { maxSseEventChars: options.maxSseEventChars },\n ...options.maxErrorBodyBytes === undefined ? {} : { maxErrorBodyBytes: options.maxErrorBodyBytes },\n ...options.requestLoggerTimeoutMs === undefined ? {} : { requestLoggerTimeoutMs: options.requestLoggerTimeoutMs },\n ...options.fetch === undefined ? {} : { fetch: options.fetch },\n }\n}\n"],"mappings":";;;;;;AAkCA,MAAa,kBAAkB;;;;;;AAuD/B,SAAgB,cAAc,SAAiD;CAC7E,MAAM,UAAqC,QAAQ,UAAU,SACzD,CAAC,IACD,EAAE,OAAO,QAAQ,MAAM;CAE3B,OAAO,mBAAmB;EACxB,aAAa;EACb,UAAUA;EACV,SAAS,QAAQ;EACjB,MAAM;GACJ,MAAM;GACN,OAAO,QAAQ;GACf,OAAO;EACT;EACA;EACA,SAAS;GACP,GAAG,QAAQ,iBAAiB,SACxB,CAAC,IACD,EAAE,uBAAuB,QAAQ,aAAa;GAClD,GAAG,QAAQ,YAAY,SAAY,CAAC,IAAI,EAAE,kBAAkB,QAAQ,QAAQ;EAC9E;EACA,GAAG,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;EAChE,kBAAkB,QAAQ,oBAAoB;EAC9C,sBAAsB,QAAQ,wBAAwB;EACtD,GAAG,QAAQ,wBAAwB,SAC/B,CAAC,IACD,EAAE,qBAAqB,QAAQ,oBAAoB;EACvD,GAAG,gBAAgB,OAAO;EAC1B,GAAG,QAAQ,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;EAC/E,GAAG,QAAQ,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,QAAQ,cAAc;CACvF,CAAC;AACH;AAmBA,SAAgB,aACd,SACuF;CACvF,IAAI,CAAC,uBAAuB,OAAO,GAAG,OAAO,mBAAmB,OAAO;CACvE,MAAM,KAAK,QAAQ,MAAM;CACzB,MAAM,SAAS,OAAO,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,EAAE,CAAE,CAAC;CAC1D,OAAO,0BAA0B;EAC/B;EACA,QAAQ;EACR,aAAa;EACb;EACA,GAAG,oBAAoB,QAAQ,cAAc,MAAM;EACnD,MAAM,WAAW;GACf,MAAM,UAAU,2BAA2B,OAAO;GAClD,MAAM,SAAS,UAAU,gBAAgB,OAAO;GAChD,aAAa;IAAE,OAAO;GAAoB;EAC5C;CACF,CAAC;AACH;AAEA,SAAS,mBAAmB,SAAmD;CAC7E,MAAM,SAAS,OAAO,OAAO,CAAC,GAAI,QAAQ,UAAU,CAAC,QAAQ,CAAE,CAAC;CAChE,MAAM,UAAU,cAAc,OAAO;CACrC,OAAO,OAAO,OAAO;EACnB,IAAI;EACJ,aAAa;EACb,MAAM,WAAmC;GACvC,UAAU,gBAAgB,QAAQ,OAAO;EAC3C;CACF,CAAC;AACH;AAEA,SAAS,2BAA2B,SAAkD;CACpF,OAAO,0BAA0B;EAC/B,aAAa;EACb,UAAUA;EACV,SAAS,QAAQ;EACjB,MAAM;GAAE,MAAM;GAAU,OAAO,QAAQ;GAAQ,OAAO;EAAsB;EAC5E,SAAS,QAAQ,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;EACnE,SAAS;GACP,GAAI,QAAQ,iBAAiB,SAAY,CAAC,IAAI,EAAE,uBAAuB,QAAQ,aAAa;GAC5F,GAAI,QAAQ,YAAY,SAAY,CAAC,IAAI,EAAE,kBAAkB,QAAQ,QAAQ;EAC/E;EACA,GAAI,QAAQ,WAAW,SAAY,CAAC,IAAI,EAAE,QAAQ,QAAQ,OAAO;EACjE,kBAAkB,QAAQ,oBAAoB;EAC9C,sBAAsB,QAAQ,wBAAwB;EACtD,GAAI,QAAQ,wBAAwB,SAAY,CAAC,IAAI,EAAE,qBAAqB,QAAQ,oBAAoB;EACxG,GAAG,gBAAgB,OAAO;EAC1B,GAAI,QAAQ,gBAAgB,SAAY,CAAC,IAAI,EAAE,aAAa,QAAQ,YAAY;EAChF,GAAI,QAAQ,kBAAkB,SAAY,CAAC,IAAI,EAAE,eAAe,QAAQ,cAAc;CACxF,CAAC;AACH;AAEA,SAAS,uBACP,SACkC;CAClC,IAAI,QAAQ,WAAW,kBAAkB,SAAS,OAAO;CACzD,IAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,WAAW,MAAM,OAAO;CAC1E,OAAO,OAAO,QAAQ,WAAW;AACnC;AAEA,SAAS,oBACP,OACA,QACyC;CACzC,IAAI,UAAU,QAAW,OAAO,CAAC;CACjC,IAAI,OAAO,UAAU,UAAU,OAAO,EAAE,cAAc,MAAM;CAC5D,IAAI,OAAO,WAAW,GACpB,MAAM,IAAI,UAAU,yDAAyD;CAE/E,OAAO,EAAE,cAAc,OAAO,OAAO;EAAE,UAAU,OAAO;EAAK,IAAI;CAAM,CAAC,EAAE;AAC5E;AAEA,SAAS,gBAAgB,SAAuD;CAC9E,OAAO;EACL,GAAG,QAAQ,qBAAqB,SAAY,CAAC,IAAI,EAAE,kBAAkB,QAAQ,iBAAiB;EAC9F,GAAG,QAAQ,oBAAoB,SAAY,CAAC,IAAI,EAAE,iBAAiB,QAAQ,gBAAgB;EAC3F,GAAG,QAAQ,qBAAqB,SAAY,CAAC,IAAI,EAAE,kBAAkB,QAAQ,iBAAiB;EAC9F,GAAG,QAAQ,sBAAsB,SAAY,CAAC,IAAI,EAAE,mBAAmB,QAAQ,kBAAkB;EACjG,GAAG,QAAQ,iBAAiB,SAAY,CAAC,IAAI,EAAE,cAAc,QAAQ,aAAa;EAClF,GAAG,QAAQ,qBAAqB,SAAY,CAAC,IAAI,EAAE,kBAAkB,QAAQ,iBAAiB;EAC9F,GAAG,QAAQ,sBAAsB,SAAY,CAAC,IAAI,EAAE,mBAAmB,QAAQ,kBAAkB;EACjG,GAAG,QAAQ,2BAA2B,SAAY,CAAC,IAAI,EAAE,wBAAwB,QAAQ,uBAAuB;EAChH,GAAG,QAAQ,UAAU,SAAY,CAAC,IAAI,EAAE,OAAO,QAAQ,MAAM;CAC/D;AACF"}
1
+ {"version":3,"file":"index.js","names":["openAiResponsesProtocol"],"sources":["../src/context-policy.ts","../src/adapter.ts","../src/embedding.ts"],"sourcesContent":["import { createModelContextPolicy } from '@alvin0/ai-agent-sdk-provider-http'\nimport type { ModelContextPolicyOptions } from '@alvin0/ai-agent-sdk-provider-http'\n\n// Verified 2026-09-13: https://developers.openai.com/api/docs/models/gpt-5.6-luna\n// https://developers.openai.com/api/docs/models/gpt-5.6-sol\n// https://developers.openai.com/api/docs/models/gpt-5.6-terra\nconst GPT_56 = { defaultContextWindow: 272_000, maxContextWindow: 1_050_000, standardPriceInputTokens: 272_000 }\nexport function openAiContextPolicy(options: ModelContextPolicyOptions) {\n return createModelContextPolicy(\n options.baseUrl === undefined || options.baseUrl.replace(/\\/$/, '') === 'https://api.openai.com/v1'\n ? { 'gpt-5.6-luna': GPT_56, 'gpt-5.6-sol': GPT_56, 'gpt-5.6-terra': GPT_56 }\n : {}, options.models, options.defaultContextWindow)\n}\n","/**\n * The OpenAI provider: the Responses API on `api.openai.com`.\n *\n * Note how little there is here. Every endpoint fact is configuration handed to\n * {@link createHttpProvider}; the protocol, the pipeline, and the error mapping are\n * all shared. That is the intended shape for any endpoint speaking a protocol this\n * package already implements — including your own gateway.\n *\n * @module ai-agent-sdk/providers/openai/adapter\n */\n\nimport type { ModelProviderPlugin, ModelProviderRegistrar, RetryPolicyConfig } from '@alvin0/ai-agent-sdk-core'\nimport {\n defineModelProviderPlugin,\n type ComposableModelProviderPlugin,\n type CredentialInput,\n type ModelTarget,\n} from '@alvin0/ai-agent-sdk-core/provider'\nimport type {\n HttpModelAdapter,\n ProviderCatalogModel,\n ProviderRequestLogger,\n} from '@alvin0/ai-agent-sdk-provider-http'\nimport {\n createHttpProvider,\n createRuntimeHttpProvider,\n type CredentialSource,\n} from '@alvin0/ai-agent-sdk-provider-http'\nimport {\n openAiResponsesProtocol,\n type ResponsesDialect,\n} from '@alvin0/ai-agent-sdk-protocol-responses'\nimport { openAiContextPolicy } from './context-policy.ts'\n\n/** The OpenAI API base. */\nexport const OPENAI_BASE_URL = 'https://api.openai.com/v1'\n\n/** How the API key is obtained. */\nexport type OpenAiCredential = CredentialSource\n\n/** Options for {@link openAiAdapter}. */\nexport interface OpenAiAdapterOptions {\n /** Injected API key or resolver. Universal packages never read environment variables. */\n apiKey: OpenAiCredential\n /**\n * Endpoint base; defaults to {@link OPENAI_BASE_URL}.\n *\n * Point this at a compatible gateway to reuse this provider wholesale.\n */\n baseUrl?: string\n /** Organization to bill, when the key belongs to several. */\n organization?: string\n /** Project to attribute usage to. */\n project?: string\n /**\n * Advisory model catalog.\n *\n * Empty by default: this package cannot know which model ids are current, and a\n * stale built-in list would name retired models. Supply entries to declare\n * capabilities the SDK cannot infer, such as image support.\n */\n models?: readonly ProviderCatalogModel[]\n /** Whether the provider may retain responses server-side. Defaults to false. */\n store?: boolean\n /** Output cap when neither caller nor catalog names one. */\n defaultMaxTokens?: number\n /** Context capacity assumed for an uncatalogued model. */\n defaultContextWindow?: number\n /** Idle bound while a stream read is outstanding. */\n streamIdleTimeoutMs?: number\n requestTimeoutMs?: number\n maxRequestBytes?: number\n maxResponseBytes?: number\n maxResponseChunks?: number\n maxSseEvents?: number\n maxSseEventChars?: number\n maxErrorBodyBytes?: number\n requestLoggerTimeoutMs?: number\n /** Retry policy this route owns. */\n retryPolicy?: RetryPolicyConfig\n /** Optional exact wire-request logger; credentials are redacted. */\n requestLogger?: ProviderRequestLogger\n fetch?: typeof globalThis.fetch\n}\n\n/**\n * Create an OpenAI adapter.\n * @param options - credential, endpoint, and catalog overrides.\n * @returns the adapter, ready to register.\n */\nexport function openAiAdapter(options: OpenAiAdapterOptions): HttpModelAdapter {\n const dialect: Partial<ResponsesDialect> = options.store === undefined\n ? {}\n : { store: options.store }\n\n return createHttpProvider({\n displayName: 'OpenAI',\n describeModel: openAiContextPolicy(options),\n protocol: openAiResponsesProtocol,\n baseUrl: options.baseUrl ?? OPENAI_BASE_URL,\n auth: {\n kind: 'bearer',\n token: options.apiKey,\n label: 'the `apiKey` option',\n },\n dialect,\n headers: {\n ...options.organization === undefined\n ? {}\n : { 'openai-organization': options.organization },\n ...options.project === undefined ? {} : { 'openai-project': options.project },\n },\n ...options.models === undefined ? {} : { models: options.models },\n defaultMaxTokens: options.defaultMaxTokens ?? 32_000,\n defaultContextWindow: options.defaultContextWindow ?? 128_000,\n ...options.streamIdleTimeoutMs === undefined\n ? {}\n : { streamIdleTimeoutMs: options.streamIdleTimeoutMs },\n ...transportLimits(options),\n ...options.retryPolicy === undefined ? {} : { retryPolicy: options.retryPolicy },\n ...options.requestLogger === undefined ? {} : { requestLogger: options.requestLogger },\n })\n}\n\nexport interface OpenAiPluginOptions extends OpenAiAdapterOptions {\n /** Registry routes installed by the plugin. Defaults to `['openai']`. */\n readonly routes?: readonly string[]\n}\n\nexport interface OpenAiProviderOptions extends Omit<OpenAiAdapterOptions, 'apiKey'> {\n readonly defaultModel?: string | ModelTarget\n readonly apiKey: CredentialInput\n readonly id?: string\n readonly routes?: readonly string[]\n}\n\n/** Preferred transactional plugin for installing the OpenAI provider. */\nexport function openAiPlugin(\n options: OpenAiProviderOptions,\n): ComposableModelProviderPlugin & { readonly family: 'openai' }\nexport function openAiPlugin(options: OpenAiPluginOptions): ModelProviderPlugin\nexport function openAiPlugin(\n options: OpenAiProviderOptions | OpenAiPluginOptions,\n): ModelProviderPlugin | (ComposableModelProviderPlugin & { readonly family: 'openai' }) {\n if (!usesRuntimeComposition(options)) return legacyOpenAiPlugin(options)\n const id = options.id ?? 'openai'\n const routes = Object.freeze([...(options.routes ?? [id])])\n return defineModelProviderPlugin({\n id,\n family: 'openai',\n displayName: 'OpenAI',\n routes,\n ...runtimeDefaultModel(options.defaultModel, routes),\n setup(registrar) {\n const adapter = createRuntimeOpenAiAdapter(options)\n const remove = registrar.registerAdapter(adapter)\n return () => { remove(); return undefined }\n },\n }) as ComposableModelProviderPlugin & { readonly family: 'openai' }\n}\n\nfunction legacyOpenAiPlugin(options: OpenAiPluginOptions): ModelProviderPlugin {\n const routes = Object.freeze([...(options.routes ?? ['openai'])])\n const adapter = openAiAdapter(options)\n return Object.freeze({\n id: 'openai',\n displayName: 'OpenAI',\n setup(registrar: ModelProviderRegistrar) {\n registrar.registerAdapter(routes, adapter)\n },\n })\n}\n\nfunction createRuntimeOpenAiAdapter(options: OpenAiProviderOptions): HttpModelAdapter {\n return createRuntimeHttpProvider({\n describeModel: openAiContextPolicy(options),\n displayName: 'OpenAI',\n protocol: openAiResponsesProtocol,\n baseUrl: options.baseUrl ?? OPENAI_BASE_URL,\n auth: { kind: 'bearer', token: options.apiKey, label: 'the `apiKey` option' },\n dialect: options.store === undefined ? {} : { store: options.store },\n headers: {\n ...(options.organization === undefined ? {} : { 'openai-organization': options.organization }),\n ...(options.project === undefined ? {} : { 'openai-project': options.project }),\n },\n ...(options.models === undefined ? {} : { models: options.models }),\n defaultMaxTokens: options.defaultMaxTokens ?? 32_000,\n defaultContextWindow: options.defaultContextWindow ?? 128_000,\n ...(options.streamIdleTimeoutMs === undefined ? {} : { streamIdleTimeoutMs: options.streamIdleTimeoutMs }),\n ...transportLimits(options),\n ...(options.retryPolicy === undefined ? {} : { retryPolicy: options.retryPolicy }),\n ...(options.requestLogger === undefined ? {} : { requestLogger: options.requestLogger }),\n })\n}\n\nfunction usesRuntimeComposition(\n options: OpenAiProviderOptions | OpenAiPluginOptions,\n): options is OpenAiProviderOptions {\n if ('id' in options || 'defaultModel' in options) return true\n if (typeof options.apiKey === 'object' && options.apiKey !== null) return true\n return typeof options.apiKey !== 'function'\n}\n\nfunction runtimeDefaultModel(\n value: string | ModelTarget | undefined,\n routes: readonly string[],\n): { readonly defaultModel?: ModelTarget } {\n if (value === undefined) return {}\n if (typeof value !== 'string') return { defaultModel: value }\n if (routes.length !== 1) {\n throw new TypeError('A string defaultModel requires exactly one OpenAI route')\n }\n return { defaultModel: Object.freeze({ provider: routes[0]!, id: value }) }\n}\n\nfunction transportLimits(options: OpenAiAdapterOptions | OpenAiProviderOptions) {\n return {\n ...options.requestTimeoutMs === undefined ? {} : { requestTimeoutMs: options.requestTimeoutMs },\n ...options.maxRequestBytes === undefined ? {} : { maxRequestBytes: options.maxRequestBytes },\n ...options.maxResponseBytes === undefined ? {} : { maxResponseBytes: options.maxResponseBytes },\n ...options.maxResponseChunks === undefined ? {} : { maxResponseChunks: options.maxResponseChunks },\n ...options.maxSseEvents === undefined ? {} : { maxSseEvents: options.maxSseEvents },\n ...options.maxSseEventChars === undefined ? {} : { maxSseEventChars: options.maxSseEventChars },\n ...options.maxErrorBodyBytes === undefined ? {} : { maxErrorBodyBytes: options.maxErrorBodyBytes },\n ...options.requestLoggerTimeoutMs === undefined ? {} : { requestLoggerTimeoutMs: options.requestLoggerTimeoutMs },\n ...options.fetch === undefined ? {} : { fetch: options.fetch },\n }\n}\n","/**\n * The OpenAI embeddings endpoint: `POST {baseUrl}/embeddings`.\n *\n * Deliberately a separate module from {@link ./adapter.ts}: it shares no protocol,\n * no dialect and no request vocabulary with `openAiResponsesProtocol`, and wiring\n * embedding through the generation pipeline would mean one of the two shapes\n * standing in for the other (Requirement 14.1). What the two DO share is the\n * transport — the fused signal, the redirect guard, the attempt ledger, the\n * attribution headers — because that chain is where a missing step is expensive.\n *\n * Three facts about this endpoint decide most of what is here, and each has a\n * plausible-looking wrong answer:\n *\n * - **There is no purpose parameter.** A route declares\n * `purposeHandling: 'unsupported'` and this adapter sends the caller's text\n * verbatim. Inventing a `\"query: \"` prefix would change every vector the caller\n * gets while looking like a helpful default (Requirement 7.5).\n * - **There is no truncation parameter.** `truncation: 'allow'` is therefore\n * refused with `EMBEDDING_TRUNCATION_UNSUPPORTED` rather than accepted and\n * quietly not honoured (Requirement 9.7).\n * - **`dimensions` is a model-line capability, not an endpoint one.** It goes on\n * the wire only when the route DECLARES the widths it supports; an `unknown`\n * catalog is not a licence to send a parameter an endpoint may reject\n * (Requirement 14.4).\n *\n * `baseUrl` is configurable because a self-hosted OpenAI-compatible endpoint is\n * the only mechanism this needs (Requirement 15.1). What it is NOT is an\n * inference: compatibility is a profile someone declared through\n * `EmbeddingCatalogModel`, never something read off the path, and a cleartext\n * `http://` base still requires `allowInsecureHttp` (Requirements 15.3, 15.5).\n *\n * @module ai-agent-sdk/providers/openai/embedding\n */\n\nimport { resolveRetryPolicy, type RetryPolicyConfig } from '@alvin0/ai-agent-sdk-core'\nimport {\n EMBEDDING_ERROR_CODES,\n EmbeddingAdapter,\n EmbeddingError,\n defaultEmbeddingProfile,\n deriveSpaceId,\n resolveBatchLimits,\n validateBatchResult,\n type EmbeddingBatchRequest,\n type EmbeddingBatchResult,\n type EmbeddingItem,\n type EmbeddingModelInfo,\n type EmbeddingProfile,\n type EmbeddingProfileInput,\n type EmbeddingVector,\n type PrepareEmbeddingOptions,\n type PreparedEmbeddingCall,\n type ResolvedEmbeddingModelInfo,\n} from '@alvin0/ai-agent-sdk-core/embedding'\nimport {\n defineEmbeddingProviderPlugin,\n type ComposableEmbeddingProviderPlugin,\n type CredentialInput,\n type ModelInvocationContext,\n type ProviderInfo,\n type ProviderRequestId,\n type ResolvedRetryPolicy,\n type SdkLogger,\n} from '@alvin0/ai-agent-sdk-core/provider'\nimport {\n captureTransportConnection,\n embeddingCatalogModelInfo,\n resolvedEmbeddingCatalogModelInfo,\n transportJson,\n type EmbeddingCatalogModel,\n type EmbeddingHttpConnection,\n} from '@alvin0/ai-agent-sdk-provider-http'\nimport { OPENAI_BASE_URL } from './adapter.ts'\n\n/** Display name used in every diagnostic this module raises. */\nconst DISPLAY_NAME = 'OpenAI'\n\n/** Path appended to the configured base. */\nconst EMBEDDINGS_PATH = '/embeddings'\n\n/** Media type this endpoint answers with, and the only one accepted back. */\nconst JSON_MEDIA_TYPE = 'application/json'\n\n/**\n * The one encoding this adapter asks for.\n *\n * Base64 would halve the bytes on the wire and cost a decode step that could\n * silently reorder or requantise values; float arrays are what the contract's\n * fidelity rule (Requirement 14.8) is cheapest to keep.\n */\nconst ENCODING_FORMAT = 'float'\n\n/**\n * Compatibility identity prefix for an OpenAI embedding model line.\n *\n * Route-independent on purpose: two routes pointing at the same model line — the\n * public API and a mirror of it — produce vectors in the SAME space, so keying\n * the identity on the route name would make them look incompatible.\n */\nconst IDENTITY_PREFIX = 'openai'\n\nconst NEVER_ABORTED_SIGNAL = new AbortController().signal\n\nconst NULL_LOGGER: SdkLogger = Object.freeze({\n child: () => NULL_LOGGER,\n trace: () => undefined,\n debug: () => undefined,\n info: () => undefined,\n warn: () => undefined,\n error: () => undefined,\n fatal: () => undefined,\n})\n\n/** Options for {@link openAiEmbeddingAdapter} and {@link openAiEmbeddingPlugin}. */\nexport interface OpenAiEmbeddingProviderOptions {\n /** Injected API key or credential source; universal packages never read the environment. */\n readonly apiKey: CredentialInput\n /**\n * Endpoint base; defaults to {@link OPENAI_BASE_URL}.\n *\n * Point this at a self-hosted OpenAI-compatible endpoint. Declare that\n * endpoint's models through {@link models}: the compatibility claim is the\n * configuration's, not this adapter's (Requirement 15.3).\n */\n readonly baseUrl?: string\n /** Organization to bill, when the key belongs to several. */\n readonly organization?: string\n /** Project to attribute usage to. */\n readonly project?: string\n /** Plugin id; also the default route. Defaults to `'openai'`. */\n readonly id?: string\n /** Registry routes the plugin claims. Defaults to `[id]`. */\n readonly routes?: readonly string[]\n /**\n * Advisory embedding catalog.\n *\n * Empty by default, for the same reason the generation adapter ships no model\n * list: a stale built-in catalog would name retired models. A declared entry is\n * what makes `dimensions` reachable on the wire and what states the embedding\n * space, so a route that cares about either declares its models.\n */\n readonly models?: readonly EmbeddingCatalogModel[]\n /** Permit cleartext HTTP explicitly, for trusted local endpoints only. */\n readonly allowInsecureHttp?: boolean\n readonly requestTimeoutMs?: number\n readonly maxRequestBytes?: number\n readonly maxResponseBytes?: number\n readonly maxResponseChunks?: number\n readonly maxErrorBodyBytes?: number\n readonly requestLoggerTimeoutMs?: number\n /** Retry policy this route owns. */\n readonly retryPolicy?: RetryPolicyConfig\n readonly fetch?: typeof globalThis.fetch\n}\n\n/**\n * `POST /embeddings` as an {@link EmbeddingAdapter}.\n *\n * Private: the exported surface is {@link openAiEmbeddingAdapter}, so this class\n * can change shape without a caller having come to depend on it.\n */\nclass OpenAiEmbeddingAdapter extends EmbeddingAdapter {\n private readonly baseUrl: string\n private readonly models: readonly EmbeddingCatalogModel[]\n private readonly retry: ResolvedRetryPolicy\n\n constructor(private readonly options: OpenAiEmbeddingProviderOptions) {\n super()\n this.baseUrl = (options.baseUrl ?? OPENAI_BASE_URL).replace(/\\/+$/, '')\n this.models = Object.freeze([...(options.models ?? [])])\n this.retry = resolveRetryPolicy(options.retryPolicy, 'openAiEmbedding.retryPolicy')\n }\n\n override providerInfo(provider: string): ProviderInfo {\n return { id: provider, name: DISPLAY_NAME }\n }\n\n override providerRetryPolicy(_provider: string): ResolvedRetryPolicy {\n return this.retry\n }\n\n override listEmbeddingModels(\n provider: string,\n signal?: AbortSignal,\n ): Promise<readonly EmbeddingModelInfo[]> {\n signal?.throwIfAborted()\n return Promise.resolve(Object.freeze(\n this.models.map(model => embeddingCatalogModelInfo(provider, model)),\n ))\n }\n\n override resolveEmbeddingModel(\n provider: string,\n model: string,\n signal?: AbortSignal,\n ): Promise<ResolvedEmbeddingModelInfo> {\n signal?.throwIfAborted()\n return Promise.resolve(resolvedEmbeddingCatalogModelInfo(provider, model, this.models))\n }\n\n /**\n * States what this model line declares about its embedding space.\n *\n * Overridden rather than inherited because the default answer is derived from\n * `${route}:${modelId}`, which makes one model line look like two spaces when\n * it is reachable through two routes. Two things differ here: the identity is\n * the model line's (see {@link IDENTITY_PREFIX}), and normalization is reported\n * only when the ROUTE declared it — never inferred from OpenAI's reputation for\n * returning unit vectors (Requirements 6.1, 6.3).\n */\n override embeddingProfile(\n model: ResolvedEmbeddingModelInfo,\n request: EmbeddingProfileInput,\n ): EmbeddingProfile {\n const base = defaultEmbeddingProfile(model, request)\n return Object.freeze({\n ...base,\n compatibilityIdentity: model.compatibilityIdentity.state === 'supported'\n ? model.compatibilityIdentity.value\n : `${IDENTITY_PREFIX}:${model.id}`,\n normalization: model.normalization.state === 'supported'\n ? model.normalization.value\n : base.normalization,\n })\n }\n\n /**\n * Captures endpoint, credential and bounds ONCE, then binds dispatch to that\n * capture.\n *\n * Overridden because this adapter's connection facts come from configuration\n * and a credential resolved per operation: reading them again inside\n * `embedBatch()` would let a rotating secret pair with another generation's URL,\n * and would let dimensions be validated against one catalog while the request\n * went out under another (Requirements 2.2, 2.3, 2.4).\n */\n override async prepareEmbeddingCall(\n provider: string,\n model: string,\n options: PrepareEmbeddingOptions,\n signal?: AbortSignal,\n context?: ModelInvocationContext,\n ): Promise<PreparedEmbeddingCall> {\n const connection = await this.connect(signal, context)\n const resolved = resolvedEmbeddingCatalogModelInfo(provider, model, connection.models)\n const profile = this.embeddingProfile(resolved, options)\n return Object.freeze({\n model: resolved,\n profile,\n spaceId: deriveSpaceId(profile),\n limits: resolveBatchLimits(resolved, options.limits),\n embedBatch: (batch: EmbeddingBatchRequest, invocation = context) =>\n this.dispatch(connection, resolved, batch, invocation),\n })\n }\n\n /**\n * One `Physical_Batch`, one `Provider_Attempt`.\n *\n * Reachable directly for an adapter used without a prepared call; the shared\n * path is {@link dispatch}, so both routes send the same body under the same\n * guards.\n */\n override async embedBatch(\n batch: EmbeddingBatchRequest,\n context?: ModelInvocationContext,\n ): Promise<EmbeddingBatchResult> {\n const connection = await this.connect(batch.signal, context)\n const model = resolvedEmbeddingCatalogModelInfo(\n batch.provider,\n batch.model,\n connection.models,\n )\n return this.dispatch(connection, model, batch, context)\n }\n\n /** Everything one embedding request needs, read together, once per operation. */\n private async connect(\n signal?: AbortSignal,\n context?: ModelInvocationContext,\n ): Promise<EmbeddingHttpConnection> {\n const token = await resolveApiKey(this.options.apiKey, signal, context)\n // The credential and the endpoint-scoped account headers travel together as\n // the auth layer; the transport merges its own layer and attribution on top,\n // which is what makes attribution unforgettable (Requirement 14.7).\n const headers: Record<string, string> = { authorization: `Bearer ${token}` }\n if (this.options.organization !== undefined) {\n headers['openai-organization'] = this.options.organization\n }\n if (this.options.project !== undefined) {\n headers['openai-project'] = this.options.project\n }\n return Object.freeze({\n baseUrl: this.baseUrl,\n headers: Object.freeze(headers),\n sensitiveHeaderNames: Object.freeze(Object.keys(headers)),\n models: this.models,\n retryPolicy: this.retry,\n ...(this.options.allowInsecureHttp === undefined\n ? {}\n : { allowInsecureHttp: this.options.allowInsecureHttp }),\n ...(this.options.requestTimeoutMs === undefined\n ? {}\n : { requestTimeoutMs: this.options.requestTimeoutMs }),\n ...(this.options.maxRequestBytes === undefined\n ? {}\n : { maxRequestBytes: this.options.maxRequestBytes }),\n ...(this.options.maxResponseBytes === undefined\n ? {}\n : { maxResponseBytes: this.options.maxResponseBytes }),\n ...(this.options.maxResponseChunks === undefined\n ? {}\n : { maxResponseChunks: this.options.maxResponseChunks }),\n ...(this.options.maxErrorBodyBytes === undefined\n ? {}\n : { maxErrorBodyBytes: this.options.maxErrorBodyBytes }),\n ...(this.options.requestLoggerTimeoutMs === undefined\n ? {}\n : { requestLoggerTimeoutMs: this.options.requestLoggerTimeoutMs }),\n ...(this.options.fetch === undefined ? {} : { fetch: this.options.fetch }),\n })\n }\n\n /** Serialize, send through the shared chain, and map the parsed body back. */\n private async dispatch(\n connection: EmbeddingHttpConnection,\n model: ResolvedEmbeddingModelInfo,\n batch: EmbeddingBatchRequest,\n context?: ModelInvocationContext,\n ): Promise<EmbeddingBatchResult> {\n if (batch.truncation === 'allow') {\n // Accepting this would promise a behaviour nothing on this wire can express.\n throw new EmbeddingError(\n `${DISPLAY_NAME} embeddings exposes no truncation parameter`,\n EMBEDDING_ERROR_CODES.TRUNCATION_UNSUPPORTED,\n { provider: batch.provider, model: batch.model },\n )\n }\n\n const body: Record<string, unknown> = {\n model: batch.model,\n // One element per item, in item order. The purpose does NOT appear here:\n // this endpoint has no parameter for it and no prefix is invented.\n input: batch.items.map(itemInput),\n encoding_format: ENCODING_FORMAT,\n }\n // Declared widths only. An `unknown` capability states nothing, and sending a\n // parameter on the strength of nothing is how a compatible endpoint 400s.\n if (batch.dimensions !== undefined && model.dimensions.state === 'supported') {\n body['dimensions'] = batch.dimensions\n }\n\n const encoded = JSON.stringify(body)\n // `decode` extracts the payload and NOTHING else. The shared chain normalizes\n // anything thrown inside `decode` through `normalizeHttpBoundaryError`, which\n // has no data twin to read off an `EmbeddingError` and would flatten every\n // stable embedding code into `ModelError{code:'UNKNOWN'}`. Validating after\n // `transportJson` returns is what lets `EMBEDDING_VECTOR_COUNT_MISMATCH` and\n // its siblings reach the caller as themselves (Requirement 9.3–9.5).\n const received = await transportJson({\n connection: captureTransportConnection(connection, {\n 'content-type': JSON_MEDIA_TYPE,\n accept: JSON_MEDIA_TYPE,\n }),\n displayName: DISPLAY_NAME,\n provider: batch.provider,\n model: batch.model,\n path: EMBEDDINGS_PATH,\n accept: JSON_MEDIA_TYPE,\n body: {\n value: body,\n encoded,\n bytes: new TextEncoder().encode(encoded).length,\n },\n ...(batch.signal === undefined ? {} : { signal: batch.signal }),\n ...(context === undefined ? {} : { context }),\n }, (session, payload) => Object.freeze({\n payload,\n ...(session.providerRequestId === undefined\n ? {}\n : { providerRequestId: session.providerRequestId }),\n }))\n return decodeEmbeddingResponse(batch, received)\n }\n}\n\n/** A response body that cleared every transport guard, plus its correlation id. */\ninterface ReceivedEmbeddingResponse {\n readonly payload: unknown\n readonly providerRequestId?: ProviderRequestId\n}\n\n/**\n * Concatenates one item's content parts into a single wire input.\n *\n * The rule is recorded as `documentRecipeRevision` on the profile, and revision\n * `'1'` is exactly this: the text of each part, in order, with no separator and no\n * added markup. It matches the effective text the contract's own length check and\n * cache key derive, so a batch split, a rejection and a wire body can never\n * disagree about what an item's text is. One item produces one element, so the\n * provider returns exactly one vector for it (Requirement 8.7).\n */\nfunction itemInput(item: EmbeddingItem): string {\n let text = ''\n for (const part of item.contentParts) {\n if (part.type === 'text') text += part.text\n }\n return text\n}\n\n/**\n * Maps one parsed response body onto the batch that produced it, in ONE fixed\n * order.\n *\n * The order is the contract, not an implementation detail — the same malformed\n * response has to produce the same code here as it does for every other provider,\n * which is what lets a single conformance suite judge all of them:\n *\n * 1. a shape this contract does not recognise ⇒ `RESPONSE_MALFORMED`\n * 2. `data.length !== items.length` ⇒ `VECTOR_COUNT_MISMATCH`\n * 3. `{ data[i].index }` is not a permutation of `0..N-1` ⇒ `VECTOR_INDEX_INVALID`\n * 4. a non-finite element ⇒ `VECTOR_VALUE_INVALID`\n * 5. a width other than the one requested ⇒ `VECTOR_DIMENSIONS_MISMATCH`\n *\n * Steps 4 and 5 are delegated to the shared {@link validateBatchResult}, which\n * already runs them in exactly this order; re-deriving them here would be a second\n * place for the ordering to drift.\n *\n * The count check comes FIRST on purpose. Reading the entries one at a time and\n * refusing the first bad index would report a mapping failure for a response whose\n * real fault is that it answered a different number of inputs — two different\n * repairs for a caller, told apart by which check ran first.\n *\n * Nothing here slices, pads, sorts or repairs a value. The `index` a vector carries\n * out is the item's index in the `Logical_Call`, taken from `items[data[i].index]`,\n * never its position in this batch (Requirement 8.4).\n */\nfunction decodeEmbeddingResponse(\n batch: EmbeddingBatchRequest,\n received: ReceivedEmbeddingResponse,\n): EmbeddingBatchResult {\n const entries = readEntries(batch, received.payload)\n checkEntryCount(batch, entries)\n const positions = readPositions(batch, entries)\n const vectors: EmbeddingVector[] = entries.map((entry, at) => Object.freeze({\n // The item's index in the `Logical_Call`, not its position in this batch.\n index: batch.items[positions[at]!]!.index,\n values: readValues(batch, entry),\n }))\n const usage = readUsage(received.payload)\n const result: EmbeddingBatchResult = Object.freeze({\n vectors: Object.freeze(vectors),\n ...(usage === undefined ? {} : { usage }),\n ...(received.providerRequestId === undefined\n ? {}\n : { providerRequestId: received.providerRequestId }),\n })\n // Steps 4 and 5, plus the count and logical-index invariants restated against\n // the `Logical_Call` indexes this result now carries.\n validateBatchResult(batch, result)\n return result\n}\n\n/** A `data` array of objects, or a structural refusal naming the batch it belongs to. */\nfunction readEntries(\n batch: EmbeddingBatchRequest,\n payload: unknown,\n): readonly Readonly<Record<string, unknown>>[] {\n const data = record(payload)?.['data']\n if (!Array.isArray(data)) throw malformed(batch, 'response carries no `data` array')\n return data.map(entry => {\n const source = record(entry)\n if (source === undefined) throw malformed(batch, 'response `data` entry is not an object')\n return source\n })\n}\n\n/** Step 2: one vector per input sent, counted before anything is interpreted. */\nfunction checkEntryCount(\n batch: EmbeddingBatchRequest,\n entries: readonly unknown[],\n): void {\n if (entries.length === batch.items.length) return\n throw new EmbeddingError(\n `${DISPLAY_NAME} returned ${entries.length} vectors for ${batch.items.length} inputs`,\n EMBEDDING_ERROR_CODES.VECTOR_COUNT_MISMATCH,\n { provider: batch.provider, model: batch.model },\n )\n}\n\n/**\n * Step 3: the reported positions, once they are known to be a permutation of\n * `0..N-1`.\n *\n * A duplicate, a gap, a non-integer and an out-of-range value all land in the same\n * refusal, because they all break the same thing: without a bijection between\n * response entries and batch items, restoring input order would be guesswork, and\n * a position to \"fall back on\" would silently attach one input's vector to another\n * (Requirement 8.2).\n */\nfunction readPositions(\n batch: EmbeddingBatchRequest,\n entries: readonly Readonly<Record<string, unknown>>[],\n): readonly number[] {\n const positions: number[] = []\n const seen = new Set<number>()\n for (const entry of entries) {\n const position = entry['index']\n if (typeof position !== 'number' || !Number.isInteger(position)\n || position < 0 || position >= batch.items.length || seen.has(position)) {\n throw new EmbeddingError(\n `${DISPLAY_NAME} returned a duplicate, missing or out-of-range vector index`,\n EMBEDDING_ERROR_CODES.VECTOR_INDEX_INVALID,\n { provider: batch.provider, model: batch.model },\n )\n }\n seen.add(position)\n positions.push(position)\n }\n return positions\n}\n\n/**\n * Reads one `embedding` array with every number exactly as it arrived.\n *\n * Only the SHAPE is judged here: a non-finite or non-numeric element is step 4's\n * business, so it travels through untouched and is refused by\n * {@link validateBatchResult} under `VECTOR_VALUE_INVALID` rather than being\n * repaired, dropped, or relabelled as a malformed shape.\n */\nfunction readValues(\n batch: EmbeddingBatchRequest,\n entry: Readonly<Record<string, unknown>>,\n): readonly number[] {\n const values = entry['embedding']\n if (!Array.isArray(values)) {\n throw malformed(batch, 'response vector is not an array')\n }\n return Object.freeze([...values as readonly number[]])\n}\n\n/**\n * Maps `prompt_tokens` and `total_tokens` onto the two embedding counters.\n *\n * There is no `outputTokens`, which is why embedding reports\n * `EmbeddingTokenUsage` rather than generation's `TokenUsage`. A counter that is\n * absent or unreadable stays ABSENT: a zero here would be indistinguishable from\n * a provider that reported no cost at all.\n */\nfunction readUsage(payload: unknown): { inputTokens?: number; totalTokens?: number } | undefined {\n const usage = record(record(payload)?.['usage'])\n if (usage === undefined) return undefined\n const inputTokens = usage['prompt_tokens']\n const totalTokens = usage['total_tokens']\n const counters = {\n ...(typeof inputTokens === 'number' ? { inputTokens } : {}),\n ...(typeof totalTokens === 'number' ? { totalTokens } : {}),\n }\n return Reflect.ownKeys(counters).length === 0 ? undefined : counters\n}\n\n/** A plain-record view of an unknown value, or `undefined`. */\nfunction record(value: unknown): Readonly<Record<string, unknown>> | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return undefined\n return value as Readonly<Record<string, unknown>>\n}\n\n/** A structural refusal: the response is not a shape this contract recognises. */\nfunction malformed(batch: EmbeddingBatchRequest, detail: string): EmbeddingError {\n return new EmbeddingError(\n `${DISPLAY_NAME} embeddings ${detail}`,\n EMBEDDING_ERROR_CODES.RESPONSE_MALFORMED,\n { provider: batch.provider, model: batch.model },\n )\n}\n\n/** Resolves a literal key or a credential source, once per operation. */\nasync function resolveApiKey(\n apiKey: CredentialInput,\n signal?: AbortSignal,\n context?: ModelInvocationContext,\n): Promise<string> {\n const value = typeof apiKey === 'string'\n ? apiKey\n : await apiKey.resolve({\n signal: signal ?? NEVER_ABORTED_SIGNAL,\n logger: context?.logger ?? NULL_LOGGER,\n })\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new EmbeddingError(\n `${DISPLAY_NAME} embeddings requires a non-empty \\`apiKey\\``,\n EMBEDDING_ERROR_CODES.CONFIGURATION_INVALID,\n )\n }\n return value\n}\n\n/**\n * Create an OpenAI embedding adapter.\n * @param options - credential, endpoint, catalog and transport bounds.\n * @returns the adapter, ready to register on an embedding route.\n */\nexport function openAiEmbeddingAdapter(\n options: OpenAiEmbeddingProviderOptions,\n): EmbeddingAdapter {\n return new OpenAiEmbeddingAdapter(options)\n}\n\n/**\n * Preferred transactional plugin for installing OpenAI embeddings.\n *\n * Its `kind` is `'embedding-provider-plugin'`, so it installs beside\n * {@link openAiPlugin} on the same route without either standing in for the other.\n * @param options - credential, endpoint, catalog and transport bounds.\n * @returns an inert plugin; the adapter is constructed during activation.\n */\nexport function openAiEmbeddingPlugin(\n options: OpenAiEmbeddingProviderOptions,\n): ComposableEmbeddingProviderPlugin & { readonly family: 'openai' } {\n const id = options.id ?? 'openai'\n const routes = Object.freeze([...(options.routes ?? [id])])\n return defineEmbeddingProviderPlugin({\n id,\n family: 'openai',\n displayName: DISPLAY_NAME,\n routes,\n setup(registrar) {\n const remove = registrar.registerEmbeddingAdapter(openAiEmbeddingAdapter(options))\n return () => {\n remove()\n return undefined\n }\n },\n }) as ComposableEmbeddingProviderPlugin & { readonly family: 'openai' }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "name": "alvin0 - chaulamdinhai",
5
5
  "email": "chaulamdinhai@gmail.com"
6
6
  },
7
- "version": "0.1.0",
7
+ "version": "0.1.1",
8
8
  "description": "Universal OpenAI adapter and provider plugin for ai-agent-sdk",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -38,15 +38,15 @@
38
38
  "provenance": true
39
39
  },
40
40
  "dependencies": {
41
- "@alvin0/ai-agent-sdk-provider-http": "^0.1.0",
42
- "@alvin0/ai-agent-sdk-protocol-responses": "^0.1.0"
41
+ "@alvin0/ai-agent-sdk-provider-http": "^0.1.1",
42
+ "@alvin0/ai-agent-sdk-protocol-responses": "^0.1.1"
43
43
  },
44
44
  "peerDependencies": {
45
- "@alvin0/ai-agent-sdk-core": "^0.1.0"
45
+ "@alvin0/ai-agent-sdk-core": "^0.1.1"
46
46
  },
47
47
  "devDependencies": {
48
- "@alvin0/ai-agent-sdk-core": "^0.1.0",
49
- "@alvin0/ai-agent-sdk-testkit": "^0.1.0",
48
+ "@alvin0/ai-agent-sdk-core": "^0.1.1",
49
+ "@alvin0/ai-agent-sdk-testkit": "^0.1.1",
50
50
  "@arethetypeswrong/cli": "0.18.5",
51
51
  "playwright": "1.62.1",
52
52
  "publint": "0.3.24",