@alvin0/ai-agent-sdk-provider-http 0.1.3 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +252 -22
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +426 -74
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const HTTP_PROVIDER_ERROR_CODES = Object.freeze({
|
|
|
12
12
|
HEADER_INVALID: "HTTP_HEADER_INVALID",
|
|
13
13
|
HEADER_RESERVED: "HTTP_HEADER_RESERVED",
|
|
14
14
|
HEADER_COLLISION: "HTTP_HEADER_COLLISION",
|
|
15
|
+
QUERY_INVALID: "HTTP_QUERY_INVALID",
|
|
15
16
|
WIRE_BODY_INVALID: "HTTP_WIRE_BODY_INVALID",
|
|
16
17
|
WIRE_BODY_TOO_LARGE: "HTTP_WIRE_BODY_TOO_LARGE",
|
|
17
18
|
STREAM_MEDIA_TYPE_INVALID: "HTTP_STREAM_MEDIA_TYPE_INVALID",
|
|
@@ -225,6 +226,11 @@ const DEFAULT_TRANSPORT_HEADERS = Object.freeze({
|
|
|
225
226
|
accept: "text/event-stream"
|
|
226
227
|
});
|
|
227
228
|
const HEADER_NAME = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
229
|
+
/**
|
|
230
|
+
* Connection-level names `fetch` itself forbids or that would corrupt the
|
|
231
|
+
* request no matter which layer sets them. Never overridable, by design
|
|
232
|
+
* (decision 12): this is the one category ordinary layering cannot reach.
|
|
233
|
+
*/
|
|
228
234
|
const FORBIDDEN_TRANSPORT_NAMES = /* @__PURE__ */ new Set([
|
|
229
235
|
"connection",
|
|
230
236
|
"content-length",
|
|
@@ -236,9 +242,6 @@ const FORBIDDEN_TRANSPORT_NAMES = /* @__PURE__ */ new Set([
|
|
|
236
242
|
"transfer-encoding",
|
|
237
243
|
"upgrade"
|
|
238
244
|
]);
|
|
239
|
-
const TRANSPORT_OWNED_NAMES = /* @__PURE__ */ new Set(["accept", "content-type"]);
|
|
240
|
-
const SDK_OWNED_NAMES = /* @__PURE__ */ new Set(["user-agent"]);
|
|
241
|
-
const SDK_OWNED_PREFIXES = ["x-ai-agent-sdk-"];
|
|
242
245
|
const SENSITIVE_NAME = /authorization|api[-_]?key|token|secret|cookie|account[-_]?id|signature/i;
|
|
243
246
|
/** Conservative fallback used in addition to exact authentication provenance. */
|
|
244
247
|
function isSensitiveHeaderName(name) {
|
|
@@ -262,20 +265,30 @@ function captureHeaderLayer(input) {
|
|
|
262
265
|
headers: Object.freeze(output)
|
|
263
266
|
});
|
|
264
267
|
}
|
|
265
|
-
/**
|
|
268
|
+
/**
|
|
269
|
+
* Merge case-insensitive header layers in precedence order and return one
|
|
270
|
+
* detached snapshot.
|
|
271
|
+
*
|
|
272
|
+
* A later layer in `layers` wins over an earlier one for the same name — the
|
|
273
|
+
* caller's array order IS the precedence order (transport, sdk-attribution,
|
|
274
|
+
* wire-protocol, endpoint, auth, per decision 12: the user's own
|
|
275
|
+
* configuration always outranks what the SDK sets for itself). Only two
|
|
276
|
+
* things stay hard-blocked regardless of position: a connection-level name
|
|
277
|
+
* `fetch` itself forbids ({@link FORBIDDEN_TRANSPORT_NAMES}, plus `sec-*` /
|
|
278
|
+
* `proxy-*`), and a credential-shaped name arriving from any layer other
|
|
279
|
+
* than `'auth'` — not because it cannot be overridden, but so the SDK always
|
|
280
|
+
* knows which headers to redact in logs.
|
|
281
|
+
*/
|
|
266
282
|
function mergeHeaderLayers(layers) {
|
|
267
283
|
const output = Object.create(null);
|
|
268
|
-
const owners = /* @__PURE__ */ new Map();
|
|
269
284
|
const sensitive = /* @__PURE__ */ new Set();
|
|
270
285
|
for (const raw of layers) {
|
|
271
286
|
const input = captureHeaderLayer(raw);
|
|
272
287
|
for (const [name, value] of Object.entries(input.headers)) {
|
|
273
|
-
const first = owners.get(name);
|
|
274
|
-
if (first !== void 0) throw headerError(`Header ownership collision between ${first} and ${input.layer}`, "HEADER_COLLISION");
|
|
275
288
|
validateHeaderOwnership(name, input.layer);
|
|
276
|
-
owners.set(name, input.layer);
|
|
277
289
|
output[name] = value;
|
|
278
290
|
if (input.layer === "auth") sensitive.add(name);
|
|
291
|
+
else sensitive.delete(name);
|
|
279
292
|
}
|
|
280
293
|
}
|
|
281
294
|
return Object.freeze({
|
|
@@ -294,9 +307,6 @@ function validateHeaderShape(name, value) {
|
|
|
294
307
|
}
|
|
295
308
|
function validateHeaderOwnership(name, layer) {
|
|
296
309
|
if (FORBIDDEN_TRANSPORT_NAMES.has(name) || name.startsWith("sec-") || name.startsWith("proxy-")) throw headerError("Header name is reserved by the transport", "HEADER_RESERVED");
|
|
297
|
-
if (TRANSPORT_OWNED_NAMES.has(name) && layer !== "transport") throw headerError("Header name is owned by the transport layer", "HEADER_RESERVED");
|
|
298
|
-
if (SDK_OWNED_NAMES.has(name) && layer !== "sdk-attribution") throw headerError("Header name is owned by SDK attribution", "HEADER_RESERVED");
|
|
299
|
-
if (SDK_OWNED_PREFIXES.some((prefix) => name.startsWith(prefix)) && layer !== "sdk-attribution") throw headerError("Header prefix is owned by SDK attribution", "HEADER_RESERVED");
|
|
300
310
|
if (isSensitiveHeaderName(name) && layer !== "auth") throw headerError("Credential headers must be supplied by auth", "HEADER_RESERVED");
|
|
301
311
|
}
|
|
302
312
|
function headerError(message, key) {
|
|
@@ -557,6 +567,19 @@ function redactHeaders(headers, sensitiveHeaderNames = []) {
|
|
|
557
567
|
const provenance = new Set(sensitiveHeaderNames.map((name) => name.toLowerCase()));
|
|
558
568
|
return Object.fromEntries(Object.entries(headers).map(([name, value]) => [name, provenance.has(name.toLowerCase()) || isSensitiveHeaderName(name) ? "[REDACTED]" : value]));
|
|
559
569
|
}
|
|
570
|
+
/** Replace credential-bearing query-string values, by name, before logging a URL. */
|
|
571
|
+
function redactQueryUrl(url, sensitiveParamNames = []) {
|
|
572
|
+
if (sensitiveParamNames.length === 0) return url;
|
|
573
|
+
const provenance = new Set(sensitiveParamNames.map((name) => name.toLowerCase()));
|
|
574
|
+
let parsed;
|
|
575
|
+
try {
|
|
576
|
+
parsed = new URL(url);
|
|
577
|
+
} catch {
|
|
578
|
+
return url;
|
|
579
|
+
}
|
|
580
|
+
for (const name of [...parsed.searchParams.keys()]) if (provenance.has(name.toLowerCase())) parsed.searchParams.set(name, "[REDACTED]");
|
|
581
|
+
return parsed.href;
|
|
582
|
+
}
|
|
560
583
|
/** Local correlation id for a diagnostic record, without requiring a crypto global. */
|
|
561
584
|
function requestLogId() {
|
|
562
585
|
return globalThis.crypto?.randomUUID?.() ?? `request-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
@@ -821,17 +844,18 @@ async function* withTransportSession(input, use) {
|
|
|
821
844
|
const url = endpoint.href;
|
|
822
845
|
const origin = endpoint.origin;
|
|
823
846
|
const headers = connection.headers;
|
|
847
|
+
const logId = requestLogId();
|
|
824
848
|
try {
|
|
825
849
|
const loggerSignal = AbortSignal.any([signal, AbortSignal.timeout(limits.requestLoggerTimeoutMs)]);
|
|
826
850
|
await raceWithSignal(Promise.resolve(input.observeRequest?.({
|
|
827
851
|
schemaVersion: 1,
|
|
828
852
|
type: "provider-request",
|
|
829
|
-
id:
|
|
853
|
+
id: logId,
|
|
830
854
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
831
855
|
provider,
|
|
832
856
|
model,
|
|
833
857
|
method: "POST",
|
|
834
|
-
url,
|
|
858
|
+
url: redactQueryUrl(url, connection.sensitiveQueryParamNames),
|
|
835
859
|
headers: redactHeaders(headers, connection.sensitiveHeaderNames),
|
|
836
860
|
body: preparedBody.value,
|
|
837
861
|
bodyBytes: preparedBody.bytes
|
|
@@ -883,6 +907,7 @@ async function* withTransportSession(input, use) {
|
|
|
883
907
|
url,
|
|
884
908
|
origin,
|
|
885
909
|
signal,
|
|
910
|
+
requestLogId: logId,
|
|
886
911
|
accept: input.accept,
|
|
887
912
|
limits,
|
|
888
913
|
...providerRequestId === void 0 ? {} : { providerRequestId },
|
|
@@ -996,7 +1021,10 @@ function applyModelContextPolicy(info, policy, configured, providerOverride) {
|
|
|
996
1021
|
standardPriceInputTokens
|
|
997
1022
|
})) if (value !== void 0 && (!Number.isSafeInteger(value) || value <= 0)) throw new TypeError(`${name} must be a positive safe integer`);
|
|
998
1023
|
if (maxContextWindow !== void 0 && (contextWindow !== void 0 && contextWindow > maxContextWindow || defaultContextWindow !== void 0 && defaultContextWindow > maxContextWindow)) throw new RangeError("contextWindow exceeds maxContextWindow");
|
|
999
|
-
if (contextWindow === void 0)
|
|
1024
|
+
if (contextWindow === void 0) {
|
|
1025
|
+
const { context: _partial, ...withoutContext } = info;
|
|
1026
|
+
return withoutContext;
|
|
1027
|
+
}
|
|
1000
1028
|
return {
|
|
1001
1029
|
...info,
|
|
1002
1030
|
context: {
|
|
@@ -1023,26 +1051,34 @@ function catalogModelInfo(provider, model) {
|
|
|
1023
1051
|
id: model.id,
|
|
1024
1052
|
name: model.name ?? model.id,
|
|
1025
1053
|
...model.description === void 0 ? {} : { description: model.description },
|
|
1026
|
-
inputModalities: model.inputModalities
|
|
1054
|
+
...model.inputModalities === void 0 ? {} : { inputModalities: model.inputModalities },
|
|
1027
1055
|
...model.outputModalities === void 0 ? {} : { outputModalities: model.outputModalities },
|
|
1028
1056
|
...model.nativeTools === void 0 ? {} : { nativeTools: model.nativeTools }
|
|
1029
1057
|
};
|
|
1030
1058
|
}
|
|
1031
|
-
/**
|
|
1059
|
+
/**
|
|
1060
|
+
* Resolve exact metadata from an advisory catalog without opening a connection.
|
|
1061
|
+
*
|
|
1062
|
+
* `defaultMaxTokens`/`defaultContextWindow` are the ROUTE's own configured
|
|
1063
|
+
* fallbacks (an adapter's `defaultMaxTokens`/`defaultContextWindow` options),
|
|
1064
|
+
* not an invented number — omit them and, absent a model-level value too, the
|
|
1065
|
+
* field is left off `ResolvedModelInfo` entirely so the registry's own
|
|
1066
|
+
* RuntimeDefaults/SDK-constant tier can fill it instead of this adapter guessing.
|
|
1067
|
+
*/
|
|
1032
1068
|
function resolvedCatalogModelInfo(provider, modelId, models, defaultMaxTokens, defaultContextWindow) {
|
|
1033
1069
|
const configured = models.find((entry) => entry.id === modelId);
|
|
1070
|
+
const resolvedMaxTokens = configured?.defaultMaxTokens ?? configured?.maxTokens ?? defaultMaxTokens;
|
|
1034
1071
|
return applyModelContextPolicy({
|
|
1035
1072
|
...configured === void 0 ? {
|
|
1036
1073
|
provider,
|
|
1037
1074
|
id: modelId,
|
|
1038
|
-
name: modelId
|
|
1039
|
-
inputModalities: ["text"]
|
|
1075
|
+
name: modelId
|
|
1040
1076
|
} : catalogModelInfo(provider, configured),
|
|
1041
|
-
|
|
1042
|
-
defaultMaxTokens: configured?.defaultMaxTokens ?? configured?.maxTokens ?? defaultMaxTokens,
|
|
1077
|
+
...resolvedMaxTokens === void 0 ? {} : { defaultMaxTokens: resolvedMaxTokens },
|
|
1043
1078
|
...configured?.maxTokens === void 0 ? {} : { maxOutputTokens: configured.maxTokens },
|
|
1044
1079
|
...configured?.reasoning === void 0 ? {} : { reasoning: configured.reasoning },
|
|
1045
|
-
...configured?.outputModalities === void 0 ? {} : { outputModalities: configured.outputModalities }
|
|
1080
|
+
...configured?.outputModalities === void 0 ? {} : { outputModalities: configured.outputModalities },
|
|
1081
|
+
...defaultContextWindow === void 0 ? {} : { context: { defaultContextWindow } }
|
|
1046
1082
|
}, void 0, configured);
|
|
1047
1083
|
}
|
|
1048
1084
|
|
|
@@ -1093,6 +1129,19 @@ function resolveSseLimits(connection) {
|
|
|
1093
1129
|
maxEventChars: positiveInteger(connection.maxSseEventChars ?? 1048576, "maxSseEventChars")
|
|
1094
1130
|
});
|
|
1095
1131
|
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Mirror every decoded SSE event into `sink` on the way through, unchanged.
|
|
1134
|
+
*
|
|
1135
|
+
* `sink` grows only as fast as `parseSseBounded` already lets it — bounded by
|
|
1136
|
+
* the SAME `maxEvents`/`maxEventChars` this generator's caller resolved — so
|
|
1137
|
+
* this adds no bound of its own and no risk of it drifting from the real one.
|
|
1138
|
+
*/
|
|
1139
|
+
async function* tapSseEvents(events, sink) {
|
|
1140
|
+
for await (const event of events) {
|
|
1141
|
+
sink.push(event);
|
|
1142
|
+
yield event;
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1096
1145
|
/** Base for every HTTP provider adapter in this package. */
|
|
1097
1146
|
var HttpModelAdapter = class extends ModelAdapter {
|
|
1098
1147
|
/**
|
|
@@ -1114,6 +1163,15 @@ var HttpModelAdapter = class extends ModelAdapter {
|
|
|
1114
1163
|
*/
|
|
1115
1164
|
observeRequest(_record) {}
|
|
1116
1165
|
/**
|
|
1166
|
+
* Observe the exact, header-redacted wire response once a stream ends.
|
|
1167
|
+
*
|
|
1168
|
+
* The default is a no-op so library users do not silently persist model
|
|
1169
|
+
* output. Fired best-effort from a `finally`, after the consumer has
|
|
1170
|
+
* already seen every chunk — a slow or failing sink here can neither delay
|
|
1171
|
+
* nor break the real call.
|
|
1172
|
+
*/
|
|
1173
|
+
observeResponse(_record) {}
|
|
1174
|
+
/**
|
|
1117
1175
|
* Map a non-2xx response to a stable code. Override only to add codes this
|
|
1118
1176
|
* provider reports that the shared mapping cannot infer from the status.
|
|
1119
1177
|
*/
|
|
@@ -1130,12 +1188,12 @@ var HttpModelAdapter = class extends ModelAdapter {
|
|
|
1130
1188
|
return this.captureConnection(await this.connect(provider, signal)).models.map((model) => catalogModelInfo(provider, model));
|
|
1131
1189
|
}
|
|
1132
1190
|
async resolveModel(provider, model, signal) {
|
|
1133
|
-
const connection = this.captureConnection(await this.connect(provider, signal));
|
|
1191
|
+
const connection = this.captureConnection(await this.connect(provider, signal, void 0, model));
|
|
1134
1192
|
return this.decorateModel(this.modelInfoFor(connection, provider, model), connection);
|
|
1135
1193
|
}
|
|
1136
1194
|
async prepareCall(provider, model, signal, context) {
|
|
1137
1195
|
context?.declareProviderAttemptAccounting?.();
|
|
1138
|
-
const connection = this.captureConnection(await this.connect(provider, signal, context));
|
|
1196
|
+
const connection = this.captureConnection(await this.connect(provider, signal, context, model));
|
|
1139
1197
|
const info = this.decorateModel(this.modelInfoFor(connection, provider, model), connection);
|
|
1140
1198
|
const wireBody = {};
|
|
1141
1199
|
return {
|
|
@@ -1155,7 +1213,7 @@ var HttpModelAdapter = class extends ModelAdapter {
|
|
|
1155
1213
|
/** Resolve a connection first, for the un-prepared entry point. */
|
|
1156
1214
|
async *runResolving(options, context) {
|
|
1157
1215
|
context?.declareProviderAttemptAccounting?.();
|
|
1158
|
-
const connection = this.captureConnection(await this.connect(options.provider, options.signal, context));
|
|
1216
|
+
const connection = this.captureConnection(await this.connect(options.provider, options.signal, context, options.model));
|
|
1159
1217
|
const info = this.decorateModel(this.modelInfoFor(connection, options.provider, options.model), connection);
|
|
1160
1218
|
yield* this.run(options, connection, info, context, {});
|
|
1161
1219
|
}
|
|
@@ -1181,13 +1239,16 @@ var HttpModelAdapter = class extends ModelAdapter {
|
|
|
1181
1239
|
*/
|
|
1182
1240
|
async *run(options, connection, model, context, wireBodyCache = {}) {
|
|
1183
1241
|
context?.declareProviderAttemptAccounting?.();
|
|
1184
|
-
if (options.messages.some((message) => contentHasImage(message.content)) && model.inputModalities
|
|
1185
|
-
if (options.messages.some((message) => contentHasDocument(message.content)) && model.inputModalities
|
|
1242
|
+
if (options.messages.some((message) => contentHasImage(message.content)) && model.inputModalities !== void 0 && !model.inputModalities.includes("image")) throw new ModelError(`${this.displayName} model "${options.model}" does not accept image input`, MODEL_ERROR_CODES.UNSUPPORTED_CONTENT);
|
|
1243
|
+
if (options.messages.some((message) => contentHasDocument(message.content)) && model.inputModalities !== void 0 && !model.inputModalities.includes("document")) throw new ModelError(`${this.displayName} model "${options.model}" does not accept document input`, MODEL_ERROR_CODES.UNSUPPORTED_CONTENT);
|
|
1244
|
+
const resolvedMaxTokens = options.maxTokens ?? model.defaultMaxTokens ?? connection.defaultMaxTokens;
|
|
1186
1245
|
const request = {
|
|
1187
1246
|
options,
|
|
1188
1247
|
model,
|
|
1189
1248
|
connection,
|
|
1190
|
-
|
|
1249
|
+
...resolvedMaxTokens === void 0 ? {} : { maxTokens: resolvedMaxTokens },
|
|
1250
|
+
...context?.agentId === void 0 ? {} : { agentId: context.agentId },
|
|
1251
|
+
...context?.providerOptions?.body === void 0 ? {} : { providerOptionsBody: context.providerOptions.body }
|
|
1191
1252
|
};
|
|
1192
1253
|
const sseLimits = resolveSseLimits(connection);
|
|
1193
1254
|
const adapter = this;
|
|
@@ -1234,39 +1295,61 @@ var HttpModelAdapter = class extends ModelAdapter {
|
|
|
1234
1295
|
const declaredLength = response.headers.get("content-length");
|
|
1235
1296
|
if (declaredLength !== null && /^\d+$/.test(declaredLength) && Number(declaredLength) > maxResponseBytes) throw new ModelError(`${this.displayName} response exceeds the ${maxResponseBytes}-byte limit`, MODEL_ERROR_CODES.TRANSPORT);
|
|
1236
1297
|
const idleDeadline = createStreamIdleDeadline(request.connection.streamIdleTimeoutMs, this.displayName, 3e4);
|
|
1237
|
-
const
|
|
1298
|
+
const rawFrames = [];
|
|
1299
|
+
const events = tapSseEvents(parseSseBounded(boundedResponseBody(response.body, maxResponseBytes, session.limits.maxResponseChunks, this.displayName, session.signal), idleDeadline.activity, 3e4, {
|
|
1238
1300
|
maxEvents: sse.maxEvents,
|
|
1239
1301
|
maxEventChars: sse.maxEventChars
|
|
1240
|
-
});
|
|
1302
|
+
}), rawFrames);
|
|
1241
1303
|
const translated = requireTerminalFinish(this.translate(events, request), this.displayName);
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1304
|
+
try {
|
|
1305
|
+
for await (const chunk of idleDeadline.guard(translated)) {
|
|
1306
|
+
if (chunk.type === "usage-progress") {
|
|
1307
|
+
session.reportUsage(chunk.usage, false);
|
|
1308
|
+
const validated = validateUsageCounters(chunk.usage, true);
|
|
1309
|
+
if (Object.keys(validated.reported).length > 0) yield {
|
|
1310
|
+
type: "usage-progress",
|
|
1311
|
+
usage: validated.reported,
|
|
1312
|
+
...session.attemptId === void 0 ? {} : { attemptId: session.attemptId }
|
|
1313
|
+
};
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
if (chunk.type === "usage") {
|
|
1317
|
+
session.reportUsage(chunk.usage);
|
|
1318
|
+
const validated = validateUsageCounters(chunk.usage, true);
|
|
1319
|
+
if (!validated.complete) continue;
|
|
1320
|
+
yield {
|
|
1321
|
+
type: "usage",
|
|
1322
|
+
usage: validated.reported
|
|
1323
|
+
};
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
if (chunk.type === "finish") {
|
|
1327
|
+
const status = chunk.reason.kind === "aborted" ? "aborted" : chunk.reason.kind === "error" ? "error" : "success";
|
|
1328
|
+
session.reportOutcome(status, chunk.reason.kind === "error" || chunk.reason.kind === "aborted" ? chunk.reason.failure : void 0);
|
|
1329
|
+
}
|
|
1330
|
+
yield chunk;
|
|
1266
1331
|
}
|
|
1267
|
-
|
|
1332
|
+
} finally {
|
|
1333
|
+
this.emitResponseLog(request, session, rawFrames);
|
|
1268
1334
|
}
|
|
1269
1335
|
}
|
|
1336
|
+
/** Best-effort delivery of one response record; see `observeResponse`'s doc comment. */
|
|
1337
|
+
async emitResponseLog(request, session, frames) {
|
|
1338
|
+
try {
|
|
1339
|
+
await this.observeResponse({
|
|
1340
|
+
schemaVersion: 1,
|
|
1341
|
+
type: "provider-response",
|
|
1342
|
+
id: session.requestLogId,
|
|
1343
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1344
|
+
provider: request.options.provider,
|
|
1345
|
+
model: request.options.model,
|
|
1346
|
+
status: session.response.status,
|
|
1347
|
+
headers: redactHeaders(Object.fromEntries(session.response.headers.entries())),
|
|
1348
|
+
...session.providerRequestId === void 0 ? {} : { providerRequestId: session.providerRequestId },
|
|
1349
|
+
frames
|
|
1350
|
+
});
|
|
1351
|
+
} catch {}
|
|
1352
|
+
}
|
|
1270
1353
|
async prepareWireBody(request, signal) {
|
|
1271
1354
|
signal.throwIfAborted();
|
|
1272
1355
|
const value = await raceWithSignal(Promise.resolve(this.buildBody(request)), signal);
|
|
@@ -1552,8 +1635,70 @@ function observeModelCatalogOperation(context, provider, origin, task) {
|
|
|
1552
1635
|
}, task);
|
|
1553
1636
|
}
|
|
1554
1637
|
|
|
1638
|
+
//#endregion
|
|
1639
|
+
//#region src/common/request-path.ts
|
|
1640
|
+
/** Fold extra query parameters onto a request path, resolving a function form first. */
|
|
1641
|
+
function appendQuery(path, query) {
|
|
1642
|
+
const resolved = typeof query === "function" ? query() : query;
|
|
1643
|
+
if (resolved === void 0) return path;
|
|
1644
|
+
const params = new URLSearchParams(resolved).toString();
|
|
1645
|
+
if (params.length === 0) return path;
|
|
1646
|
+
return `${path}${path.includes("?") ? "&" : "?"}${params}`;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
//#endregion
|
|
1650
|
+
//#region src/common/body-merge.ts
|
|
1651
|
+
/**
|
|
1652
|
+
* Deep-merge `override` onto a serialized request body.
|
|
1653
|
+
*
|
|
1654
|
+
* The user's value always wins, including over a field the SDK itself set
|
|
1655
|
+
* (`model`, `max_tokens`, `reasoning`, `stream`, …) — decision 12. A `null`
|
|
1656
|
+
* value deletes the key outright, the escape hatch for removing an SDK-set
|
|
1657
|
+
* field without reaching for `transformRequest`. Two plain objects at the same
|
|
1658
|
+
* key merge recursively; anything else (an array, a primitive, a plain object
|
|
1659
|
+
* merging onto a non-object) replaces the base value wholesale — merging an
|
|
1660
|
+
* array element-wise would silently reorder or interleave items the caller
|
|
1661
|
+
* never asked to touch.
|
|
1662
|
+
*/
|
|
1663
|
+
function mergeRequestBody(base, override) {
|
|
1664
|
+
const target = isPlainObject(base) ? { ...base } : {};
|
|
1665
|
+
for (const [key, value] of Object.entries(override)) {
|
|
1666
|
+
if (value === null) {
|
|
1667
|
+
delete target[key];
|
|
1668
|
+
continue;
|
|
1669
|
+
}
|
|
1670
|
+
const existing = target[key];
|
|
1671
|
+
target[key] = isPlainObject(value) && isPlainObject(existing) ? mergeRequestBody(existing, value) : value;
|
|
1672
|
+
}
|
|
1673
|
+
return target;
|
|
1674
|
+
}
|
|
1675
|
+
function isPlainObject(value) {
|
|
1676
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
|
|
1677
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1678
|
+
return prototype === Object.prototype || prototype === null;
|
|
1679
|
+
}
|
|
1680
|
+
|
|
1555
1681
|
//#endregion
|
|
1556
1682
|
//#region src/configurable/http-provider.ts
|
|
1683
|
+
/** Normalize a single scheme or an array of schemes into an array. */
|
|
1684
|
+
function authSchemesOf(auth) {
|
|
1685
|
+
return Array.isArray(auth) ? auth : [auth];
|
|
1686
|
+
}
|
|
1687
|
+
/** Union several name/value records, case-insensitively, failing fast on a name two entries both set. */
|
|
1688
|
+
function unionByName(entries, kind) {
|
|
1689
|
+
const output = {};
|
|
1690
|
+
const owners = /* @__PURE__ */ new Map();
|
|
1691
|
+
entries.forEach((entry, index) => {
|
|
1692
|
+
for (const [name, value] of Object.entries(entry)) {
|
|
1693
|
+
const lower = name.toLowerCase();
|
|
1694
|
+
const first = owners.get(lower);
|
|
1695
|
+
if (first !== void 0 && first !== index) throw new AgentSdkError(`Two auth schemes both produced the \`${lower}\` ${kind}`, HTTP_PROVIDER_ERROR_CODES.HEADER_COLLISION);
|
|
1696
|
+
owners.set(lower, index);
|
|
1697
|
+
output[name] = value;
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
return output;
|
|
1701
|
+
}
|
|
1557
1702
|
const DEFAULT_CATALOG_TTL_MS = 3e5;
|
|
1558
1703
|
const DEFAULT_CATALOG_STALE_TTL_MS = 0;
|
|
1559
1704
|
const DEFAULT_CATALOG_FAILURE_BACKOFF_MS = 5e3;
|
|
@@ -1589,10 +1734,12 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1589
1734
|
catalogFailureBackoffMs: nonNegativeFinite(options.catalogFailureBackoffMs ?? DEFAULT_CATALOG_FAILURE_BACKOFF_MS, "catalogFailureBackoffMs"),
|
|
1590
1735
|
maxCatalogModels,
|
|
1591
1736
|
maxCatalogBytes,
|
|
1592
|
-
auth: Object.freeze(
|
|
1737
|
+
auth: Object.freeze(authSchemesOf(options.auth).map((scheme) => Object.freeze({ ...scheme }))),
|
|
1593
1738
|
...models === void 0 ? {} : { models },
|
|
1594
1739
|
...options.headers === void 0 || typeof options.headers === "function" ? {} : { headers: Object.freeze({ ...options.headers }) },
|
|
1595
|
-
...options.baseHeaders === void 0 ? {} : { baseHeaders: Object.freeze({ ...options.baseHeaders }) }
|
|
1740
|
+
...options.baseHeaders === void 0 ? {} : { baseHeaders: Object.freeze({ ...options.baseHeaders }) },
|
|
1741
|
+
...options.query === void 0 || typeof options.query === "function" ? {} : { query: Object.freeze({ ...options.query }) },
|
|
1742
|
+
...options.body === void 0 ? {} : { body: Object.freeze({ ...options.body }) }
|
|
1596
1743
|
});
|
|
1597
1744
|
this.displayName = options.displayName;
|
|
1598
1745
|
this.dialect = resolveDialect(options.protocol, options.dialect);
|
|
@@ -1609,7 +1756,7 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1609
1756
|
resolveModel(provider, model, signal) {
|
|
1610
1757
|
if (!this.hasStaticCatalog()) return super.resolveModel(provider, model, signal);
|
|
1611
1758
|
signal?.throwIfAborted();
|
|
1612
|
-
return Promise.resolve(this.decorateModel(resolvedCatalogModelInfo(provider, model, this.options.models ?? [], this.options.defaultMaxTokens
|
|
1759
|
+
return Promise.resolve(this.decorateModel(resolvedCatalogModelInfo(provider, model, this.options.models ?? [], this.options.defaultMaxTokens, this.options.defaultContextWindow)));
|
|
1613
1760
|
}
|
|
1614
1761
|
async modelCatalog(provider, options = {}) {
|
|
1615
1762
|
if (this.hasStaticCatalog()) {
|
|
@@ -1638,26 +1785,70 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1638
1785
|
staticModels(provider) {
|
|
1639
1786
|
return Object.freeze((this.options.models ?? []).map((model) => Object.freeze(catalogModelInfo(provider, model))));
|
|
1640
1787
|
}
|
|
1641
|
-
/** Resolve
|
|
1642
|
-
async
|
|
1643
|
-
const auth = this.options.auth;
|
|
1788
|
+
/** Resolve one scheme for one operation, as either a header or a query param. */
|
|
1789
|
+
async authSchemeResolved(auth, provider, signal, context) {
|
|
1644
1790
|
switch (auth.kind) {
|
|
1645
|
-
case "none": return {
|
|
1646
|
-
|
|
1791
|
+
case "none": return {
|
|
1792
|
+
headers: {},
|
|
1793
|
+
query: {}
|
|
1794
|
+
};
|
|
1795
|
+
case "bearer": return {
|
|
1796
|
+
headers: { authorization: `Bearer ${await observeCredentialOperation(context, provider, "resolve", () => credential(auth.token, this.displayName, auth.label ?? "the `auth.token` option", signal, context))}` },
|
|
1797
|
+
query: {}
|
|
1798
|
+
};
|
|
1647
1799
|
case "header": {
|
|
1648
1800
|
const value = await observeCredentialOperation(context, provider, "resolve", () => credential(auth.value, this.displayName, auth.label ?? `the \`${auth.name}\` credential`, signal, context));
|
|
1649
|
-
return {
|
|
1801
|
+
return {
|
|
1802
|
+
headers: { [auth.name]: value },
|
|
1803
|
+
query: {}
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
case "query": {
|
|
1807
|
+
const value = await observeCredentialOperation(context, provider, "resolve", () => credential(auth.value, this.displayName, auth.label ?? `the \`${auth.name}\` query credential`, signal, context));
|
|
1808
|
+
return {
|
|
1809
|
+
headers: {},
|
|
1810
|
+
query: { [auth.name]: value }
|
|
1811
|
+
};
|
|
1650
1812
|
}
|
|
1651
|
-
case "dynamic": return {
|
|
1652
|
-
|
|
1813
|
+
case "dynamic": return {
|
|
1814
|
+
headers: await observeCredentialOperation(context, provider, "resolve", async () => await auth.resolve(signal, context, provider)),
|
|
1815
|
+
query: {}
|
|
1816
|
+
};
|
|
1817
|
+
default: return {
|
|
1818
|
+
headers: {},
|
|
1819
|
+
query: {}
|
|
1820
|
+
};
|
|
1653
1821
|
}
|
|
1654
1822
|
}
|
|
1655
|
-
|
|
1823
|
+
/**
|
|
1824
|
+
* Resolve every configured scheme in parallel and union their headers and
|
|
1825
|
+
* query params.
|
|
1826
|
+
*
|
|
1827
|
+
* Two schemes producing the same header name (or the same query param name)
|
|
1828
|
+
* fail fast, before the merged result ever reaches {@link mergeHeaderLayers}
|
|
1829
|
+
* — a collision here is a configuration mistake (the same credential
|
|
1830
|
+
* declared twice, or two schemes racing for `authorization`), not something
|
|
1831
|
+
* a later-layer-wins policy should paper over.
|
|
1832
|
+
*/
|
|
1833
|
+
async authHeaders(provider, signal, context) {
|
|
1834
|
+
const schemes = authSchemesOf(this.options.auth);
|
|
1835
|
+
const resolved = await Promise.all(schemes.map((scheme) => this.authSchemeResolved(scheme, provider, signal, context)));
|
|
1836
|
+
return {
|
|
1837
|
+
headers: unionByName(resolved.map((entry) => entry.headers), "header"),
|
|
1838
|
+
query: unionByName(resolved.map((entry) => entry.query), "query param")
|
|
1839
|
+
};
|
|
1840
|
+
}
|
|
1841
|
+
async connect(provider, signal, context, model) {
|
|
1656
1842
|
const timeoutMs = positiveFinite(this.options.requestTimeoutMs ?? 6e5, "requestTimeoutMs");
|
|
1657
1843
|
const timeout = AbortSignal.timeout(timeoutMs);
|
|
1658
1844
|
const operationSignal = signal === void 0 ? timeout : AbortSignal.any([signal, timeout]);
|
|
1659
1845
|
const baseUrl = this.options.baseUrl.replace(/\/+$/, "");
|
|
1660
|
-
const extra = typeof this.options.headers === "function" ? this.options.headers(
|
|
1846
|
+
const extra = typeof this.options.headers === "function" ? this.options.headers({
|
|
1847
|
+
provider,
|
|
1848
|
+
...context?.agentId === void 0 ? {} : { agentId: context.agentId },
|
|
1849
|
+
...operationSignal === void 0 ? {} : { signal: operationSignal }
|
|
1850
|
+
}) : this.options.headers ?? {};
|
|
1851
|
+
const modelEntry = model === void 0 ? void 0 : this.options.models?.find((candidate) => candidate.id === model);
|
|
1661
1852
|
const publicLayers = [
|
|
1662
1853
|
captureHeaderLayer({
|
|
1663
1854
|
layer: "transport",
|
|
@@ -1674,6 +1865,14 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1674
1865
|
captureHeaderLayer({
|
|
1675
1866
|
layer: "endpoint",
|
|
1676
1867
|
headers: extra
|
|
1868
|
+
}),
|
|
1869
|
+
captureHeaderLayer({
|
|
1870
|
+
layer: "endpoint",
|
|
1871
|
+
headers: modelEntry?.headers ?? {}
|
|
1872
|
+
}),
|
|
1873
|
+
captureHeaderLayer({
|
|
1874
|
+
layer: "endpoint",
|
|
1875
|
+
headers: context?.providerOptions?.headers ?? {}
|
|
1677
1876
|
})
|
|
1678
1877
|
];
|
|
1679
1878
|
mergeHeaderLayers(publicLayers);
|
|
@@ -1687,6 +1886,10 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1687
1886
|
baseUrl,
|
|
1688
1887
|
headers,
|
|
1689
1888
|
sensitiveHeaderNames: merged.sensitiveHeaderNames,
|
|
1889
|
+
...Object.keys(auth.query).length === 0 ? {} : {
|
|
1890
|
+
queryOverrides: auth.query,
|
|
1891
|
+
sensitiveQueryParamNames: Object.freeze(Object.keys(auth.query))
|
|
1892
|
+
},
|
|
1690
1893
|
streamIdleTimeoutMs: this.options.streamIdleTimeoutMs ?? 3e5,
|
|
1691
1894
|
requestTimeoutMs: this.options.requestTimeoutMs ?? 6e5,
|
|
1692
1895
|
maxRequestBytes: this.options.maxRequestBytes ?? 33554432,
|
|
@@ -1700,8 +1903,8 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1700
1903
|
...this.options.requestLoggerTimeoutMs === void 0 ? {} : { requestLoggerTimeoutMs: this.options.requestLoggerTimeoutMs },
|
|
1701
1904
|
retryPolicy: this.retry,
|
|
1702
1905
|
models: this.options.models ?? await this.resolveCatalog(provider, baseUrl, headers, operationSignal, context),
|
|
1703
|
-
defaultMaxTokens: this.options.defaultMaxTokens
|
|
1704
|
-
defaultContextWindow: this.options.defaultContextWindow
|
|
1906
|
+
...this.options.defaultMaxTokens === void 0 ? {} : { defaultMaxTokens: this.options.defaultMaxTokens },
|
|
1907
|
+
...this.options.defaultContextWindow === void 0 ? {} : { defaultContextWindow: this.options.defaultContextWindow }
|
|
1705
1908
|
};
|
|
1706
1909
|
}
|
|
1707
1910
|
/** Run the discovery hook, memoized, tolerating failure. */
|
|
@@ -1744,14 +1947,29 @@ var ConfiguredHttpAdapter = class extends HttpModelAdapter {
|
|
|
1744
1947
|
observeRequest(record) {
|
|
1745
1948
|
return this.options.requestLogger?.(record);
|
|
1746
1949
|
}
|
|
1950
|
+
observeResponse(record) {
|
|
1951
|
+
return this.options.responseLogger?.(record);
|
|
1952
|
+
}
|
|
1747
1953
|
providerErrorCode(status, detail) {
|
|
1748
1954
|
return this.options.errorCode?.(status, detail) ?? super.providerErrorCode(status, detail);
|
|
1749
1955
|
}
|
|
1750
1956
|
endpointPath(request) {
|
|
1751
|
-
|
|
1957
|
+
const base = this.options.path ?? this.options.protocol.endpointPath(request, this.dialect);
|
|
1958
|
+
const withRouteQuery = appendQuery(base, this.options.query);
|
|
1959
|
+
return request.connection.queryOverrides === void 0 ? withRouteQuery : appendQuery(withRouteQuery, request.connection.queryOverrides);
|
|
1752
1960
|
}
|
|
1753
1961
|
buildBody(request) {
|
|
1754
|
-
|
|
1962
|
+
const serialized = this.options.protocol.serialize(request, this.dialect);
|
|
1963
|
+
const withRouteBody = this.options.body === void 0 ? serialized : mergeRequestBody(serialized, this.options.body);
|
|
1964
|
+
const modelBody = this.options.models?.find((candidate) => candidate.id === request.model.id)?.body;
|
|
1965
|
+
const withModelBody = modelBody === void 0 ? withRouteBody : mergeRequestBody(withRouteBody, modelBody);
|
|
1966
|
+
const merged = request.providerOptionsBody === void 0 ? withModelBody : mergeRequestBody(withModelBody, request.providerOptionsBody);
|
|
1967
|
+
return this.options.transformRequest === void 0 ? merged : this.options.transformRequest(merged, {
|
|
1968
|
+
provider: request.options.provider,
|
|
1969
|
+
model: request.model.id,
|
|
1970
|
+
...request.agentId === void 0 ? {} : { agentId: request.agentId },
|
|
1971
|
+
...request.options.signal === void 0 ? {} : { signal: request.options.signal }
|
|
1972
|
+
});
|
|
1755
1973
|
}
|
|
1756
1974
|
translate(events, request) {
|
|
1757
1975
|
return this.options.protocol.translate(events, request, this.displayName);
|
|
@@ -1813,6 +2031,97 @@ function createHttpProvider(options) {
|
|
|
1813
2031
|
return new ConfiguredHttpAdapter(options);
|
|
1814
2032
|
}
|
|
1815
2033
|
|
|
2034
|
+
//#endregion
|
|
2035
|
+
//#region src/configurable/field-fallback.ts
|
|
2036
|
+
/**
|
|
2037
|
+
* Fall back to a build of the SAME adapter without an optional wire field,
|
|
2038
|
+
* permanently, the first time a dispatch is rejected in a way that names it.
|
|
2039
|
+
*
|
|
2040
|
+
* Exists for opportunistic fields this SDK adds when a caller opts in — a
|
|
2041
|
+
* caching hint, for instance — that the OFFICIAL vendor accepts but a
|
|
2042
|
+
* compatible gateway behind the same adapter option may not. Decision 7
|
|
2043
|
+
* (this workspace's redesign plan) rules out guessing which gateways support
|
|
2044
|
+
* such a field ahead of time; this is the alternative that costs nothing
|
|
2045
|
+
* when the field IS understood and self-heals, once, the one time it is
|
|
2046
|
+
* not — rather than failing every call to that gateway forever.
|
|
2047
|
+
*
|
|
2048
|
+
* @module ai-agent-sdk/providers/configurable/field-fallback
|
|
2049
|
+
*/
|
|
2050
|
+
/**
|
|
2051
|
+
* Delegates to `withField` until a dispatch fails in a way
|
|
2052
|
+
* `isFieldRejection` recognizes, then delegates to `withoutField` for the
|
|
2053
|
+
* rest of this instance's lifetime — including the call that just failed,
|
|
2054
|
+
* retried transparently so the caller never sees the rejection.
|
|
2055
|
+
*
|
|
2056
|
+
* Metadata methods (`resolveModel`, `listModels`, `modelCatalog`,
|
|
2057
|
+
* `providerInfo`, `providerRetryPolicy`) always read from `withField`: the
|
|
2058
|
+
* two builds differ only in the one wire field this wraps, never in what
|
|
2059
|
+
* models or capabilities the route reports.
|
|
2060
|
+
*/
|
|
2061
|
+
var FieldFallbackAdapter = class extends ModelAdapter {
|
|
2062
|
+
#withField;
|
|
2063
|
+
#withoutField;
|
|
2064
|
+
#isFieldRejection;
|
|
2065
|
+
#disabled = false;
|
|
2066
|
+
constructor(withField, withoutField, options) {
|
|
2067
|
+
super();
|
|
2068
|
+
this.#withField = withField;
|
|
2069
|
+
this.#withoutField = withoutField;
|
|
2070
|
+
this.#isFieldRejection = options.isFieldRejection;
|
|
2071
|
+
}
|
|
2072
|
+
providerInfo(provider) {
|
|
2073
|
+
return this.#withField.providerInfo(provider);
|
|
2074
|
+
}
|
|
2075
|
+
providerRetryPolicy(provider) {
|
|
2076
|
+
return this.#withField.providerRetryPolicy(provider);
|
|
2077
|
+
}
|
|
2078
|
+
listModels(provider, signal) {
|
|
2079
|
+
return this.#withField.listModels(provider, signal);
|
|
2080
|
+
}
|
|
2081
|
+
modelCatalog(provider, options = {}) {
|
|
2082
|
+
return this.#withField.modelCatalog(provider, options);
|
|
2083
|
+
}
|
|
2084
|
+
resolveModel(provider, model, signal) {
|
|
2085
|
+
return this.#withField.resolveModel(provider, model, signal);
|
|
2086
|
+
}
|
|
2087
|
+
async prepareCall(provider, model, signal, context) {
|
|
2088
|
+
if (this.#disabled) return this.#withoutField.prepareCall(provider, model, signal, context);
|
|
2089
|
+
const prepared = await this.#withField.prepareCall(provider, model, signal, context);
|
|
2090
|
+
return {
|
|
2091
|
+
model: prepared.model,
|
|
2092
|
+
stream: (options, invocation) => this.#dispatch((o, c) => prepared.stream(o, c), () => this.#withoutField.prepareCall(provider, model, signal, context).then((fallback) => (o, c) => fallback.stream(o, c)), options, invocation)
|
|
2093
|
+
};
|
|
2094
|
+
}
|
|
2095
|
+
stream(options, context) {
|
|
2096
|
+
if (this.#disabled) return this.#withoutField.stream(options, context);
|
|
2097
|
+
return this.#dispatch((o, c) => this.#withField.stream(o, c), () => Promise.resolve((o, c) => this.#withoutField.stream(o, c)), options, context);
|
|
2098
|
+
}
|
|
2099
|
+
/**
|
|
2100
|
+
* Run one dispatch, and on a recognized field rejection, disable the field
|
|
2101
|
+
* permanently and re-dispatch through `fallback` — transparently, before
|
|
2102
|
+
* the caller has seen anything but the fallback's own output.
|
|
2103
|
+
*
|
|
2104
|
+
* Safe because a field rejection is always a non-2xx response the shared
|
|
2105
|
+
* HTTP chain throws BEFORE any chunk streams (`withTransportSession` in
|
|
2106
|
+
* `provider-http`'s transport layer): nothing from the failed attempt ever
|
|
2107
|
+
* reaches this generator's consumer, so retrying from scratch never
|
|
2108
|
+
* duplicates output.
|
|
2109
|
+
*/
|
|
2110
|
+
async *#dispatch(primary, prepareFallback, options, context) {
|
|
2111
|
+
if (this.#disabled) {
|
|
2112
|
+
yield* (await prepareFallback())(options, context);
|
|
2113
|
+
return;
|
|
2114
|
+
}
|
|
2115
|
+
try {
|
|
2116
|
+
yield* primary(options, context);
|
|
2117
|
+
} catch (error) {
|
|
2118
|
+
if (!this.#isFieldRejection(error)) throw error;
|
|
2119
|
+
this.#disabled = true;
|
|
2120
|
+
yield* (await prepareFallback())(options, context);
|
|
2121
|
+
}
|
|
2122
|
+
}
|
|
2123
|
+
};
|
|
2124
|
+
|
|
1816
2125
|
//#endregion
|
|
1817
2126
|
//#region src/common/wire-body.ts
|
|
1818
2127
|
const WIRE_BODY_LIMITS = Object.freeze({
|
|
@@ -1866,17 +2175,25 @@ function createRuntimeHttpProvider(options) {
|
|
|
1866
2175
|
const describeModel = optionalCapturedMethod(source, "describeModel");
|
|
1867
2176
|
const errorCode = optionalCapturedMethod(source, "errorCode");
|
|
1868
2177
|
const requestLogger = optionalCapturedMethod(source, "requestLogger");
|
|
2178
|
+
const responseLogger = optionalCapturedMethod(source, "responseLogger");
|
|
2179
|
+
const transformRequest = optionalCapturedMethod(source, "transformRequest");
|
|
1869
2180
|
const headers = captureHeaders(source);
|
|
2181
|
+
const query = captureQuery(source);
|
|
2182
|
+
const path = capturePath(source);
|
|
1870
2183
|
const legacy = {
|
|
1871
2184
|
displayName,
|
|
1872
2185
|
protocol,
|
|
1873
2186
|
baseUrl: baseUrl.href,
|
|
1874
2187
|
auth,
|
|
1875
2188
|
...copyOptional(source, "allowInsecureHttp"),
|
|
2189
|
+
...path === void 0 ? {} : { path },
|
|
1876
2190
|
...copyJsonOptional(source, "models", "models"),
|
|
1877
2191
|
...copyJsonOptional(source, "dialect", "dialect"),
|
|
1878
2192
|
...fetch === void 0 ? {} : { fetch },
|
|
1879
2193
|
...headers === void 0 ? {} : { headers },
|
|
2194
|
+
...query === void 0 ? {} : { query },
|
|
2195
|
+
...copyJsonOptional(source, "body", "body"),
|
|
2196
|
+
...transformRequest === void 0 ? {} : { transformRequest },
|
|
1880
2197
|
...copyOptional(source, "catalogTtlMs"),
|
|
1881
2198
|
...copyOptional(source, "catalogStaleTtlMs"),
|
|
1882
2199
|
...copyOptional(source, "catalogFailureBackoffMs"),
|
|
@@ -1898,6 +2215,7 @@ function createRuntimeHttpProvider(options) {
|
|
|
1898
2215
|
...errorCode === void 0 ? {} : { errorCode },
|
|
1899
2216
|
...copyHeaderOptional(source, "baseHeaders", "transport"),
|
|
1900
2217
|
...requestLogger === void 0 ? {} : { requestLogger },
|
|
2218
|
+
...responseLogger === void 0 ? {} : { responseLogger },
|
|
1901
2219
|
...discover === void 0 ? {} : { discoverModels: async (context) => discover({
|
|
1902
2220
|
provider: context.provider ?? "",
|
|
1903
2221
|
baseUrl: new URL(context.baseUrl),
|
|
@@ -1937,6 +2255,10 @@ function captureRuntimeProtocol(value) {
|
|
|
1937
2255
|
}
|
|
1938
2256
|
}
|
|
1939
2257
|
function captureRuntimeAuth(value, baseUrl) {
|
|
2258
|
+
if (Array.isArray(value)) return value.map((entry) => captureRuntimeAuthScheme(entry, baseUrl));
|
|
2259
|
+
return captureRuntimeAuthScheme(value, baseUrl);
|
|
2260
|
+
}
|
|
2261
|
+
function captureRuntimeAuthScheme(value, baseUrl) {
|
|
1940
2262
|
const source = plainObject(value, "runtime HTTP auth");
|
|
1941
2263
|
const kind = ownData(source, "kind");
|
|
1942
2264
|
if (kind === "none") return Object.freeze({ kind });
|
|
@@ -1954,6 +2276,15 @@ function captureRuntimeAuth(value, baseUrl) {
|
|
|
1954
2276
|
...copyOptional(source, "label")
|
|
1955
2277
|
});
|
|
1956
2278
|
}
|
|
2279
|
+
if (kind === "query") {
|
|
2280
|
+
const name = boundedIdentifier(ownData(source, "name"), 256, "auth query param name");
|
|
2281
|
+
return Object.freeze({
|
|
2282
|
+
kind,
|
|
2283
|
+
name,
|
|
2284
|
+
value: captureCredential(ownData(source, "value")),
|
|
2285
|
+
...copyOptional(source, "label")
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
1957
2288
|
if (kind === "dynamic") {
|
|
1958
2289
|
const resolve = capturedMethod(source, "resolve");
|
|
1959
2290
|
return Object.freeze({
|
|
@@ -2001,8 +2332,29 @@ function captureHeaders(source) {
|
|
|
2001
2332
|
const value = ownData(source, "headers", false);
|
|
2002
2333
|
if (value === void 0) return void 0;
|
|
2003
2334
|
if (typeof value !== "function") return snapshotHeaders(value, "endpoint");
|
|
2335
|
+
const captured = (ctx) => Reflect.apply(value, source, [ctx]);
|
|
2336
|
+
return (ctx) => snapshotHeaders(captured(ctx), "endpoint");
|
|
2337
|
+
}
|
|
2338
|
+
function capturePath(source) {
|
|
2339
|
+
const value = ownData(source, "path", false);
|
|
2340
|
+
return value === void 0 ? void 0 : boundedIdentifier(value, 2048, "path");
|
|
2341
|
+
}
|
|
2342
|
+
function captureQuery(source) {
|
|
2343
|
+
const value = ownData(source, "query", false);
|
|
2344
|
+
if (value === void 0) return void 0;
|
|
2345
|
+
if (typeof value !== "function") return snapshotQuery(value);
|
|
2004
2346
|
const captured = (...args) => Reflect.apply(value, source, args);
|
|
2005
|
-
return () =>
|
|
2347
|
+
return () => snapshotQuery(captured());
|
|
2348
|
+
}
|
|
2349
|
+
function snapshotQuery(value) {
|
|
2350
|
+
const snapshot = snapshotJsonObject({ query: value }, HTTP_RUNTIME_OPTION_LIMITS).query;
|
|
2351
|
+
if (snapshot === null || typeof snapshot !== "object" || Array.isArray(snapshot)) throw new AgentSdkError("Runtime HTTP query must be a record", HTTP_PROVIDER_ERROR_CODES.QUERY_INVALID);
|
|
2352
|
+
const output = {};
|
|
2353
|
+
for (const [key, entry] of Object.entries(snapshot)) {
|
|
2354
|
+
if (typeof entry !== "string") throw new AgentSdkError("Runtime HTTP query values must be strings", HTTP_PROVIDER_ERROR_CODES.QUERY_INVALID);
|
|
2355
|
+
output[key] = entry;
|
|
2356
|
+
}
|
|
2357
|
+
return Object.freeze(output);
|
|
2006
2358
|
}
|
|
2007
2359
|
function snapshotHeaders(value, layer) {
|
|
2008
2360
|
return mergeHeaderLayers([{
|
|
@@ -2066,7 +2418,7 @@ function endpointHeaders(headers, defaults = {}) {
|
|
|
2066
2418
|
layer: "endpoint",
|
|
2067
2419
|
headers: value
|
|
2068
2420
|
}]).headers;
|
|
2069
|
-
if (typeof headers === "function") return () => capture(headers());
|
|
2421
|
+
if (typeof headers === "function") return (ctx) => capture(headers(ctx));
|
|
2070
2422
|
const fixed = capture(headers ?? {});
|
|
2071
2423
|
return () => fixed;
|
|
2072
2424
|
}
|
|
@@ -2273,5 +2625,5 @@ function parseJsonBody(text, displayName) {
|
|
|
2273
2625
|
}
|
|
2274
2626
|
|
|
2275
2627
|
//#endregion
|
|
2276
|
-
export { DEFAULT_MAX_ERROR_BODY_BYTES, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_MAX_RESPONSE_BYTES, DEFAULT_MAX_RESPONSE_CHUNKS, DEFAULT_REQUEST_LOGGER_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, HTTP_PROTOCOL_API_VERSION, HTTP_PROVIDER_ERROR_CODES, HttpModelAdapter, JSON_MEDIA_TYPES, applyModelContextPolicy, captureTransportConnection, createHttpProvider, createModelContextPolicy, createRuntimeHttpProvider, defineWireProtocol, embeddingCatalogModelInfo, endpointHeaders, httpErrorCode, isJsonMediaType, observeCredentialOperation, observeModelCatalogOperation, parseErrorBody, parseSse, redactHeaders, requestIdFrom, resolveDialect, resolveTransportLimits, resolvedEmbeddingCatalogModelInfo, retryAfterMs, transportJson };
|
|
2628
|
+
export { DEFAULT_MAX_ERROR_BODY_BYTES, DEFAULT_MAX_REQUEST_BYTES, DEFAULT_MAX_RESPONSE_BYTES, DEFAULT_MAX_RESPONSE_CHUNKS, DEFAULT_REQUEST_LOGGER_TIMEOUT_MS, DEFAULT_REQUEST_TIMEOUT_MS, DEFAULT_STREAM_IDLE_TIMEOUT_MS, FieldFallbackAdapter, HTTP_PROTOCOL_API_VERSION, HTTP_PROVIDER_ERROR_CODES, HttpModelAdapter, JSON_MEDIA_TYPES, applyModelContextPolicy, captureTransportConnection, createHttpProvider, createModelContextPolicy, createRuntimeHttpProvider, defineWireProtocol, embeddingCatalogModelInfo, endpointHeaders, httpErrorCode, isJsonMediaType, observeCredentialOperation, observeModelCatalogOperation, parseErrorBody, parseSse, redactHeaders, requestIdFrom, resolveDialect, resolveTransportLimits, resolvedEmbeddingCatalogModelInfo, retryAfterMs, transportJson };
|
|
2277
2629
|
//# sourceMappingURL=index.js.map
|