@codehz/ai 0.7.0 → 0.7.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/dist/index.d.mts +9 -1
- package/dist/index.mjs +86 -40
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -227,7 +227,8 @@ declare const WarningCode: {
|
|
|
227
227
|
readonly CONTENT_FILTER: "CONTENT_FILTER"; /** 多 choice 仅支持 index 0,其余忽略 */
|
|
228
228
|
readonly MULTIPLE_CHOICES_IGNORED: "MULTIPLE_CHOICES_IGNORED"; /** MCP 审批流不被支持 */
|
|
229
229
|
readonly MCP_APPROVAL_REQUIRED: "MCP_APPROVAL_REQUIRED"; /** provider 侧 response.failed 等失败 */
|
|
230
|
-
readonly PROVIDER_FAILURE: "PROVIDER_FAILURE";
|
|
230
|
+
readonly PROVIDER_FAILURE: "PROVIDER_FAILURE"; /** 出站 opaque 超限被省略(避免下一轮 accept 自产毒) */
|
|
231
|
+
readonly OPAQUE_REPLAY_OMITTED: "OPAQUE_REPLAY_OMITTED";
|
|
231
232
|
};
|
|
232
233
|
type WarningCodeName = (typeof WarningCode)[keyof typeof WarningCode];
|
|
233
234
|
/** 与 WarningCodeName 同义;保留以兼容既有 KnownWarningCode 命名 */
|
|
@@ -836,6 +837,11 @@ type HttpAdapterOptions = {
|
|
|
836
837
|
fetch?: FetchFn; /** 额外请求头;后写覆盖内置鉴权 / Content-Type 等 */
|
|
837
838
|
headers?: Record<string, string>; /** 额外 body 顶层字段;浅层合并,同名键可覆盖 */
|
|
838
839
|
extraBody?: Record<string, unknown>;
|
|
840
|
+
/**
|
|
841
|
+
* 单条 opaque replay payload 体积上限(JSON.stringify 码元长度)。
|
|
842
|
+
* 默认 1 MiB;夹到 [1, 8 MiB] 硬顶。emit 与 accept 共用。
|
|
843
|
+
*/
|
|
844
|
+
maxOpaquePayloadBytes?: number;
|
|
839
845
|
};
|
|
840
846
|
type HttpAdapterDefaults = {
|
|
841
847
|
baseUrl: string;
|
|
@@ -849,6 +855,8 @@ declare abstract class HttpAdapterBase extends AdapterBase {
|
|
|
849
855
|
protected fetchFn: FetchFn;
|
|
850
856
|
protected headers: Record<string, string> | undefined;
|
|
851
857
|
protected extraBody: Record<string, unknown> | undefined;
|
|
858
|
+
/** 已 clamp 的 opaque 体积上限(emit / accept 共用)。 */
|
|
859
|
+
protected maxOpaquePayloadBytes: number;
|
|
852
860
|
constructor(options: HttpAdapterOptions, defaults: HttpAdapterDefaults);
|
|
853
861
|
/** 合并内置 headers 与构造期自定义 headers。 */
|
|
854
862
|
protected mergeHeaders(base: Record<string, string>): Record<string, string>;
|
package/dist/index.mjs
CHANGED
|
@@ -74,7 +74,9 @@ const WarningCode = {
|
|
|
74
74
|
/** MCP 审批流不被支持 */
|
|
75
75
|
MCP_APPROVAL_REQUIRED: "MCP_APPROVAL_REQUIRED",
|
|
76
76
|
/** provider 侧 response.failed 等失败 */
|
|
77
|
-
PROVIDER_FAILURE: "PROVIDER_FAILURE"
|
|
77
|
+
PROVIDER_FAILURE: "PROVIDER_FAILURE",
|
|
78
|
+
/** 出站 opaque 超限被省略(避免下一轮 accept 自产毒) */
|
|
79
|
+
OPAQUE_REPLAY_OMITTED: "OPAQUE_REPLAY_OMITTED"
|
|
78
80
|
};
|
|
79
81
|
/**
|
|
80
82
|
* 去重键:以 message 为主(与旧 string[] 行为一致)。
|
|
@@ -1558,10 +1560,23 @@ function applyExtraBody(body, extraBody) {
|
|
|
1558
1560
|
/**
|
|
1559
1561
|
* Adapter 边界安全辅助
|
|
1560
1562
|
*
|
|
1561
|
-
* - opaque replay
|
|
1563
|
+
* - opaque replay envelope(大小 / 深度;emit 与 accept 共用)
|
|
1562
1564
|
* - provider HTTP 错误 body 出站脱敏
|
|
1563
1565
|
*/
|
|
1564
|
-
|
|
1566
|
+
/** 默认单条 opaque payload 上限(JSON.stringify 的 UTF-16 码元长度)。 */
|
|
1567
|
+
const DEFAULT_MAX_OPAQUE_PAYLOAD_BYTES = 1 * 1024 * 1024;
|
|
1568
|
+
/** 硬顶:配置不可超过;挡住离谱 blob / DoS。 */
|
|
1569
|
+
const HARD_MAX_OPAQUE_PAYLOAD_BYTES = 8 * 1024 * 1024;
|
|
1570
|
+
/**
|
|
1571
|
+
* 将调用方配置的 opaque 上限夹到合法区间。
|
|
1572
|
+
* 非有限 / <1 → 默认;> HARD → HARD。
|
|
1573
|
+
*/
|
|
1574
|
+
function clampOpaquePayloadLimit(maxBytes) {
|
|
1575
|
+
if (maxBytes === void 0 || !Number.isFinite(maxBytes)) return DEFAULT_MAX_OPAQUE_PAYLOAD_BYTES;
|
|
1576
|
+
const n = Math.floor(maxBytes);
|
|
1577
|
+
if (n < 1) return DEFAULT_MAX_OPAQUE_PAYLOAD_BYTES;
|
|
1578
|
+
return Math.min(n, HARD_MAX_OPAQUE_PAYLOAD_BYTES);
|
|
1579
|
+
}
|
|
1565
1580
|
/** 测量 JSON 值嵌套深度(对象/数组);循环引用按已访问节点深度计。 */
|
|
1566
1581
|
function measureJsonDepth(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
1567
1582
|
if (value === null || typeof value !== "object") return 0;
|
|
@@ -1573,10 +1588,10 @@ function measureJsonDepth(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
|
1573
1588
|
return 1 + maxChild;
|
|
1574
1589
|
}
|
|
1575
1590
|
/**
|
|
1576
|
-
* Opaque replay 通用 envelope:必须是 object、体积 ≤
|
|
1577
|
-
* 不校验 adapter 专用字段形状。
|
|
1591
|
+
* Opaque replay 通用 envelope:必须是 object、体积 ≤ limit、深度 ≤ 8。
|
|
1592
|
+
* 不校验 adapter 专用字段形状。emit / accept 共用。
|
|
1578
1593
|
*/
|
|
1579
|
-
function validateOpaqueReplayEnvelope(payload) {
|
|
1594
|
+
function validateOpaqueReplayEnvelope(payload, options) {
|
|
1580
1595
|
if (typeof payload !== "object" || payload === null) return {
|
|
1581
1596
|
ok: false,
|
|
1582
1597
|
reason: "payload must be an object"
|
|
@@ -1594,9 +1609,10 @@ function validateOpaqueReplayEnvelope(payload) {
|
|
|
1594
1609
|
ok: false,
|
|
1595
1610
|
reason: "payload is not JSON-serializable"
|
|
1596
1611
|
};
|
|
1597
|
-
|
|
1612
|
+
const maxBytes = clampOpaquePayloadLimit(options?.maxBytes);
|
|
1613
|
+
if (raw.length > maxBytes) return {
|
|
1598
1614
|
ok: false,
|
|
1599
|
-
reason: `opaque payload exceeds max size (${raw.length} > ${
|
|
1615
|
+
reason: `opaque payload exceeds max size (${raw.length} > ${maxBytes})`
|
|
1600
1616
|
};
|
|
1601
1617
|
const depth = measureJsonDepth(payload);
|
|
1602
1618
|
if (depth > 8) return {
|
|
@@ -1605,9 +1621,9 @@ function validateOpaqueReplayEnvelope(payload) {
|
|
|
1605
1621
|
};
|
|
1606
1622
|
return { ok: true };
|
|
1607
1623
|
}
|
|
1608
|
-
/** envelope 失败时抛 AIRequestError
|
|
1609
|
-
function assertOpaqueReplayEnvelope(payload) {
|
|
1610
|
-
const result = validateOpaqueReplayEnvelope(payload);
|
|
1624
|
+
/** envelope 失败时抛 AIRequestError(入站 accept 路径)。 */
|
|
1625
|
+
function assertOpaqueReplayEnvelope(payload, options) {
|
|
1626
|
+
const result = validateOpaqueReplayEnvelope(payload, options);
|
|
1611
1627
|
if (!result.ok) throw new AIRequestError(`Invalid opaque replay payload: ${result.reason}`, "INVALID_OPAQUE_REPLAY");
|
|
1612
1628
|
}
|
|
1613
1629
|
/**
|
|
@@ -1838,6 +1854,8 @@ var HttpAdapterBase = class extends AdapterBase {
|
|
|
1838
1854
|
fetchFn;
|
|
1839
1855
|
headers;
|
|
1840
1856
|
extraBody;
|
|
1857
|
+
/** 已 clamp 的 opaque 体积上限(emit / accept 共用)。 */
|
|
1858
|
+
maxOpaquePayloadBytes;
|
|
1841
1859
|
constructor(options, defaults) {
|
|
1842
1860
|
super();
|
|
1843
1861
|
this.apiKey = options.apiKey;
|
|
@@ -1845,6 +1863,7 @@ var HttpAdapterBase = class extends AdapterBase {
|
|
|
1845
1863
|
this.fetchFn = options.fetch ?? globalThis.fetch;
|
|
1846
1864
|
this.headers = options.headers;
|
|
1847
1865
|
this.extraBody = options.extraBody;
|
|
1866
|
+
this.maxOpaquePayloadBytes = clampOpaquePayloadLimit(options.maxOpaquePayloadBytes);
|
|
1848
1867
|
}
|
|
1849
1868
|
/** 合并内置 headers 与构造期自定义 headers。 */
|
|
1850
1869
|
mergeHeaders(base) {
|
|
@@ -2130,14 +2149,26 @@ function createNdjsonLineParser(isValid) {
|
|
|
2130
2149
|
//#region src/provider/finalize-stream-turn.ts
|
|
2131
2150
|
/**
|
|
2132
2151
|
* 收敛 incomplete / finish 后的 replay + complete 路径。
|
|
2133
|
-
* adapter 负责构造 opaque payload;本 helper
|
|
2152
|
+
* adapter 负责构造 opaque payload;本 helper 统一校验体积、拼接 replay 并 complete。
|
|
2153
|
+
*
|
|
2154
|
+
* emit 与 accept 共用 envelope 上限:超限则省略 opaque(不截断)并打 warning,
|
|
2155
|
+
* 避免写出下一轮 accept 必炸的自产毒。
|
|
2134
2156
|
*/
|
|
2135
2157
|
/**
|
|
2136
2158
|
* 从 item session 生成 canonical replay,可选追加 opaque 尾项,再 yield session.complete。
|
|
2159
|
+
* 超限 opaque 会被丢弃并 yield `OPAQUE_REPLAY_OMITTED` warning。
|
|
2137
2160
|
*/
|
|
2138
2161
|
async function* finalizeStreamTurn(session, items, options = {}) {
|
|
2139
2162
|
const replay = [...replayFromOutput(items.completedItems())];
|
|
2140
|
-
|
|
2163
|
+
let opaque = options.opaque ?? null;
|
|
2164
|
+
if (opaque) {
|
|
2165
|
+
const check = validateOpaqueReplayEnvelope(opaque.payload, { maxBytes: options.maxOpaquePayloadBytes });
|
|
2166
|
+
if (!check.ok) {
|
|
2167
|
+
if (options.factory) yield options.factory.responseWarning(`Omitted opaque replay payload: ${check.reason}`, WarningCode.OPAQUE_REPLAY_OMITTED);
|
|
2168
|
+
opaque = null;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
if (opaque) replay.push(opaque);
|
|
2141
2172
|
yield* session.complete({
|
|
2142
2173
|
replay,
|
|
2143
2174
|
stopReason: options.stopReason,
|
|
@@ -2163,7 +2194,7 @@ const OPAQUE_SOURCE = {
|
|
|
2163
2194
|
* Opaque replay 统一协议(入站薄层)
|
|
2164
2195
|
*
|
|
2165
2196
|
* 过滤:仅 `source === expectedSource` 且 `purpose === "replay"` 才处理,否则忽略。
|
|
2166
|
-
* envelope:object / ≤
|
|
2197
|
+
* envelope:object / ≤limit(默认 1MiB,硬顶 8MiB)/ depth≤8;失败抛 AIRequestError / INVALID_OPAQUE_REPLAY。
|
|
2167
2198
|
* 写入 wire 尾部 assistant/model turn 前:先 rollbackTrailing*,再 append(responses 续写 id 除外)。
|
|
2168
2199
|
* 已知 shape 非法 → 抛 INVALID_OPAQUE_REPLAY;未知 shape → 静默跳过。
|
|
2169
2200
|
*/
|
|
@@ -2171,9 +2202,9 @@ const OPAQUE_SOURCE = {
|
|
|
2171
2202
|
* 接受本 adapter 的 opaque replay payload。
|
|
2172
2203
|
* source/purpose 不匹配返回 null;匹配则 assert envelope 后返回 payload object。
|
|
2173
2204
|
*/
|
|
2174
|
-
function acceptOpaqueReplay(item, expectedSource) {
|
|
2205
|
+
function acceptOpaqueReplay(item, expectedSource, options) {
|
|
2175
2206
|
if (item.source !== expectedSource || item.purpose !== "replay") return null;
|
|
2176
|
-
assertOpaqueReplayEnvelope(item.payload);
|
|
2207
|
+
assertOpaqueReplayEnvelope(item.payload, options);
|
|
2177
2208
|
return item.payload;
|
|
2178
2209
|
}
|
|
2179
2210
|
//#endregion
|
|
@@ -2465,7 +2496,7 @@ function appendCompactedWindow(input, payload) {
|
|
|
2465
2496
|
* stream / compact 共享的 input + instructions + opaque 续写映射。
|
|
2466
2497
|
* compact 不附带 tools / stream 等生成字段。
|
|
2467
2498
|
*/
|
|
2468
|
-
function mapResponsesCore(request) {
|
|
2499
|
+
function mapResponsesCore(request, options) {
|
|
2469
2500
|
const input = [];
|
|
2470
2501
|
let previousResponseId;
|
|
2471
2502
|
let usedCompactedWindow = false;
|
|
@@ -2499,7 +2530,7 @@ function mapResponsesCore(request) {
|
|
|
2499
2530
|
break;
|
|
2500
2531
|
}
|
|
2501
2532
|
case "opaque": {
|
|
2502
|
-
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.RESPONSES);
|
|
2533
|
+
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.RESPONSES, { maxBytes: options?.maxOpaquePayloadBytes });
|
|
2503
2534
|
if (!payload) break;
|
|
2504
2535
|
if (payload.kind === "compacted_window") {
|
|
2505
2536
|
assertOptionalIdFields(payload);
|
|
@@ -2530,8 +2561,8 @@ function mapResponsesCore(request) {
|
|
|
2530
2561
|
return mapped;
|
|
2531
2562
|
}
|
|
2532
2563
|
/** 构建 Responses 流式请求体;调用方再 `withExtraBody` 合并构造期扩展字段。 */
|
|
2533
|
-
function buildResponsesRequest(request) {
|
|
2534
|
-
const core = mapResponsesCore(request);
|
|
2564
|
+
function buildResponsesRequest(request, options) {
|
|
2565
|
+
const core = mapResponsesCore(request, options);
|
|
2535
2566
|
const body = {
|
|
2536
2567
|
model: request.model,
|
|
2537
2568
|
input: core.input,
|
|
@@ -2566,10 +2597,10 @@ function buildResponsesRequest(request) {
|
|
|
2566
2597
|
* 构建 Responses compact 请求体(POST /responses/compact)。
|
|
2567
2598
|
* 仅映射 model / input / instructions / previous_response_id;无 stream / tools。
|
|
2568
2599
|
*/
|
|
2569
|
-
function buildResponsesCompactRequest(request) {
|
|
2600
|
+
function buildResponsesCompactRequest(request, options) {
|
|
2570
2601
|
if (!request.model || typeof request.model !== "string" || request.model.length === 0) throw new AIRequestError("compress requires a non-empty model", "INPUT_EMPTY");
|
|
2571
2602
|
if (!Array.isArray(request.input) || request.input.length === 0) throw new AIRequestError("compress requires a non-empty input", "INPUT_EMPTY");
|
|
2572
|
-
const core = mapResponsesCore(request);
|
|
2603
|
+
const core = mapResponsesCore(request, options);
|
|
2573
2604
|
const body = {
|
|
2574
2605
|
model: request.model,
|
|
2575
2606
|
input: core.input
|
|
@@ -3321,7 +3352,7 @@ var ResponsesAdapter = class extends HttpAdapterBase {
|
|
|
3321
3352
|
super(options, { baseUrl: "https://api.openai.com/v1" });
|
|
3322
3353
|
}
|
|
3323
3354
|
buildRequest(request) {
|
|
3324
|
-
return this.withExtraBody(buildResponsesRequest(request));
|
|
3355
|
+
return this.withExtraBody(buildResponsesRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
3325
3356
|
}
|
|
3326
3357
|
/**
|
|
3327
3358
|
* 原生上下文压缩:POST /responses/compact。
|
|
@@ -3329,7 +3360,7 @@ var ResponsesAdapter = class extends HttpAdapterBase {
|
|
|
3329
3360
|
*/
|
|
3330
3361
|
async compress(request) {
|
|
3331
3362
|
request.signal?.throwIfAborted();
|
|
3332
|
-
const body = this.withExtraBody(buildResponsesCompactRequest(request));
|
|
3363
|
+
const body = this.withExtraBody(buildResponsesCompactRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
3333
3364
|
const { data } = await postProviderJson({
|
|
3334
3365
|
fetchFn: this.fetchFn,
|
|
3335
3366
|
url: `${this.baseUrl}/responses/compact`,
|
|
@@ -3346,6 +3377,7 @@ var ResponsesAdapter = class extends HttpAdapterBase {
|
|
|
3346
3377
|
output: data.output
|
|
3347
3378
|
};
|
|
3348
3379
|
if (typeof data.id === "string" && data.id.length > 0 && data.id.length <= 256) payload.id = data.id;
|
|
3380
|
+
assertOpaqueReplayEnvelope(payload, { maxBytes: this.maxOpaquePayloadBytes });
|
|
3349
3381
|
const result = { replay: [opaqueItem(OPAQUE_SOURCE.RESPONSES, "replay", payload)] };
|
|
3350
3382
|
if (data.usage) {
|
|
3351
3383
|
const usage = usageFromOpenAIResponses(data.usage);
|
|
@@ -3394,6 +3426,8 @@ var ResponsesAdapter = class extends HttpAdapterBase {
|
|
|
3394
3426
|
}) : null,
|
|
3395
3427
|
stopReason,
|
|
3396
3428
|
rawResponseId,
|
|
3429
|
+
factory,
|
|
3430
|
+
maxOpaquePayloadBytes: this.maxOpaquePayloadBytes,
|
|
3397
3431
|
onDuplicate: "silent"
|
|
3398
3432
|
});
|
|
3399
3433
|
}
|
|
@@ -3436,7 +3470,7 @@ function canonicalToMessagesBlock(b) {
|
|
|
3436
3470
|
};
|
|
3437
3471
|
throw new AIRequestError(`messages does not support content block type "${b.type}" in canonical mapping`, "UNSUPPORTED_CONTENT_BLOCK");
|
|
3438
3472
|
}
|
|
3439
|
-
function buildMessagesRequest(request) {
|
|
3473
|
+
function buildMessagesRequest(request, options) {
|
|
3440
3474
|
mapper$7.assertNoServerTools(request.serverTools);
|
|
3441
3475
|
const messages = [];
|
|
3442
3476
|
let systemPrompt;
|
|
@@ -3505,7 +3539,7 @@ function buildMessagesRequest(request) {
|
|
|
3505
3539
|
break;
|
|
3506
3540
|
}
|
|
3507
3541
|
case "opaque": {
|
|
3508
|
-
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.MESSAGES);
|
|
3542
|
+
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.MESSAGES, { maxBytes: options?.maxOpaquePayloadBytes });
|
|
3509
3543
|
if (!payload) break;
|
|
3510
3544
|
if (payload.role === "assistant" && "content" in payload) {
|
|
3511
3545
|
assertMessagesReplayContent(payload.content);
|
|
@@ -3743,6 +3777,8 @@ async function* mapMessagesStream(host, providerRequest, factory, request) {
|
|
|
3743
3777
|
}) : null,
|
|
3744
3778
|
stopReason: stopReason ? mapStopReason(stopReason) : void 0,
|
|
3745
3779
|
rawResponseId,
|
|
3780
|
+
factory,
|
|
3781
|
+
maxOpaquePayloadBytes: host.maxOpaquePayloadBytes,
|
|
3746
3782
|
onDuplicate: "silent"
|
|
3747
3783
|
});
|
|
3748
3784
|
}
|
|
@@ -3762,7 +3798,7 @@ var MessagesAdapter = class extends HttpAdapterBase {
|
|
|
3762
3798
|
this.apiVersion = options.apiVersion ?? "2023-06-01";
|
|
3763
3799
|
}
|
|
3764
3800
|
buildRequest(request) {
|
|
3765
|
-
return this.withExtraBody(buildMessagesRequest(request));
|
|
3801
|
+
return this.withExtraBody(buildMessagesRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
3766
3802
|
}
|
|
3767
3803
|
async *runStream(providerRequest, factory, request) {
|
|
3768
3804
|
yield* mapMessagesStream({
|
|
@@ -3770,7 +3806,8 @@ var MessagesAdapter = class extends HttpAdapterBase {
|
|
|
3770
3806
|
baseUrl: this.baseUrl,
|
|
3771
3807
|
apiKey: this.apiKey,
|
|
3772
3808
|
mergeHeaders: this.mergeHeaders.bind(this),
|
|
3773
|
-
apiVersion: this.apiVersion
|
|
3809
|
+
apiVersion: this.apiVersion,
|
|
3810
|
+
maxOpaquePayloadBytes: this.maxOpaquePayloadBytes
|
|
3774
3811
|
}, providerRequest, factory, request);
|
|
3775
3812
|
}
|
|
3776
3813
|
};
|
|
@@ -3821,7 +3858,7 @@ function assertChatReplayMessages(messages, field) {
|
|
|
3821
3858
|
if (!Array.isArray(messages)) throw new AIRequestError(`Invalid opaque replay payload: ${field} must be an array`, "INVALID_OPAQUE_REPLAY");
|
|
3822
3859
|
for (let i = 0; i < messages.length; i++) if (!isChatReplayMessage(messages[i])) throw new AIRequestError(`Invalid opaque replay payload: ${field}[${i}] is not a valid chat message`, "INVALID_OPAQUE_REPLAY");
|
|
3823
3860
|
}
|
|
3824
|
-
function buildChatCompletionsRequest(request) {
|
|
3861
|
+
function buildChatCompletionsRequest(request, options) {
|
|
3825
3862
|
mapper$5.assertNoServerTools(request.serverTools);
|
|
3826
3863
|
const messages = [];
|
|
3827
3864
|
if (request.instructions) messages.push({
|
|
@@ -3871,7 +3908,7 @@ function buildChatCompletionsRequest(request) {
|
|
|
3871
3908
|
});
|
|
3872
3909
|
break;
|
|
3873
3910
|
case "opaque": {
|
|
3874
|
-
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.CHAT_COMPLETIONS);
|
|
3911
|
+
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.CHAT_COMPLETIONS, { maxBytes: options?.maxOpaquePayloadBytes });
|
|
3875
3912
|
if (!payload) break;
|
|
3876
3913
|
if ("messages" in payload) {
|
|
3877
3914
|
assertChatReplayMessages(payload.messages, "messages");
|
|
@@ -4019,6 +4056,8 @@ async function* mapChatCompletionsStream(host, providerRequest, factory, request
|
|
|
4019
4056
|
yield* finalizeStreamTurn(session, items, {
|
|
4020
4057
|
stopReason,
|
|
4021
4058
|
rawResponseId,
|
|
4059
|
+
factory,
|
|
4060
|
+
maxOpaquePayloadBytes: host.maxOpaquePayloadBytes,
|
|
4022
4061
|
opaque: assistantReplayMessage ? opaqueItem(OPAQUE_SOURCE.CHAT_COMPLETIONS, "replay", {
|
|
4023
4062
|
replaceCanonical: true,
|
|
4024
4063
|
messages: [assistantReplayMessage]
|
|
@@ -4171,14 +4210,15 @@ var ChatCompletionsAdapter = class extends HttpAdapterBase {
|
|
|
4171
4210
|
super(options, { baseUrl: "https://api.openai.com/v1" });
|
|
4172
4211
|
}
|
|
4173
4212
|
buildRequest(request) {
|
|
4174
|
-
return this.withExtraBody(buildChatCompletionsRequest(request));
|
|
4213
|
+
return this.withExtraBody(buildChatCompletionsRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
4175
4214
|
}
|
|
4176
4215
|
async *runStream(providerRequest, factory, request) {
|
|
4177
4216
|
yield* mapChatCompletionsStream({
|
|
4178
4217
|
beginJsonStream: this.beginJsonStream.bind(this),
|
|
4179
4218
|
baseUrl: this.baseUrl,
|
|
4180
4219
|
apiKey: this.apiKey,
|
|
4181
|
-
mergeHeaders: this.mergeHeaders.bind(this)
|
|
4220
|
+
mergeHeaders: this.mergeHeaders.bind(this),
|
|
4221
|
+
maxOpaquePayloadBytes: this.maxOpaquePayloadBytes
|
|
4182
4222
|
}, providerRequest, factory, request);
|
|
4183
4223
|
}
|
|
4184
4224
|
};
|
|
@@ -4203,7 +4243,7 @@ function toWireOllamaToolCalls(toolCalls) {
|
|
|
4203
4243
|
arguments: tc.function.arguments
|
|
4204
4244
|
} }));
|
|
4205
4245
|
}
|
|
4206
|
-
function buildOllamaRequest(request) {
|
|
4246
|
+
function buildOllamaRequest(request, options) {
|
|
4207
4247
|
mapper$3.assertNoServerTools(request.serverTools);
|
|
4208
4248
|
const messages = [];
|
|
4209
4249
|
/** Local-only name → call id queue for best-effort tool_result association (not sent to Ollama). */
|
|
@@ -4254,7 +4294,7 @@ function buildOllamaRequest(request) {
|
|
|
4254
4294
|
});
|
|
4255
4295
|
break;
|
|
4256
4296
|
case "opaque": {
|
|
4257
|
-
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.OLLAMA);
|
|
4297
|
+
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.OLLAMA, { maxBytes: options?.maxOpaquePayloadBytes });
|
|
4258
4298
|
if (!payload) break;
|
|
4259
4299
|
if (payload.role === "assistant" && typeof payload.content === "string") {
|
|
4260
4300
|
mapper$3.rollbackTrailingAssistantMessages(messages);
|
|
@@ -4339,6 +4379,8 @@ async function* mapOllamaStream(host, providerRequest, factory, request) {
|
|
|
4339
4379
|
yield* finalizeStreamTurn(session, items, {
|
|
4340
4380
|
stopReason,
|
|
4341
4381
|
rawResponseId,
|
|
4382
|
+
factory,
|
|
4383
|
+
maxOpaquePayloadBytes: host.maxOpaquePayloadBytes,
|
|
4342
4384
|
opaque: accumulatedContent || pendingToolCalls.length > 0 ? opaqueItem(OPAQUE_SOURCE.OLLAMA, "replay", {
|
|
4343
4385
|
role: "assistant",
|
|
4344
4386
|
content: accumulatedContent,
|
|
@@ -4417,14 +4459,15 @@ var OllamaAdapter = class extends HttpAdapterBase {
|
|
|
4417
4459
|
super(options, { baseUrl: "http://localhost:11434" });
|
|
4418
4460
|
}
|
|
4419
4461
|
buildRequest(request) {
|
|
4420
|
-
return this.withExtraBody(buildOllamaRequest(request));
|
|
4462
|
+
return this.withExtraBody(buildOllamaRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
4421
4463
|
}
|
|
4422
4464
|
async *runStream(providerRequest, factory, request) {
|
|
4423
4465
|
yield* mapOllamaStream({
|
|
4424
4466
|
beginJsonStream: this.beginJsonStream.bind(this),
|
|
4425
4467
|
baseUrl: this.baseUrl,
|
|
4426
4468
|
apiKey: this.apiKey,
|
|
4427
|
-
mergeHeaders: this.mergeHeaders.bind(this)
|
|
4469
|
+
mergeHeaders: this.mergeHeaders.bind(this),
|
|
4470
|
+
maxOpaquePayloadBytes: this.maxOpaquePayloadBytes
|
|
4428
4471
|
}, providerRequest, factory, request);
|
|
4429
4472
|
}
|
|
4430
4473
|
};
|
|
@@ -4474,7 +4517,7 @@ function cloneContent(content) {
|
|
|
4474
4517
|
parts: content.parts.map(clonePart$1)
|
|
4475
4518
|
};
|
|
4476
4519
|
}
|
|
4477
|
-
function buildGeminiRequest(request) {
|
|
4520
|
+
function buildGeminiRequest(request, options) {
|
|
4478
4521
|
mapper$1.assertNoServerTools(request.serverTools);
|
|
4479
4522
|
const contents = [];
|
|
4480
4523
|
let systemInstruction;
|
|
@@ -4515,7 +4558,7 @@ function buildGeminiRequest(request) {
|
|
|
4515
4558
|
});
|
|
4516
4559
|
break;
|
|
4517
4560
|
case "opaque": {
|
|
4518
|
-
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.GEMINI);
|
|
4561
|
+
const payload = acceptOpaqueReplay(item, OPAQUE_SOURCE.GEMINI, { maxBytes: options?.maxOpaquePayloadBytes });
|
|
4519
4562
|
if (!payload) break;
|
|
4520
4563
|
if (payload.replaceCanonical === true && "content" in payload) {
|
|
4521
4564
|
assertGeminiReplayContent(payload.content, "content");
|
|
@@ -4628,6 +4671,8 @@ async function* mapGeminiStream(host, providerRequest, factory, request) {
|
|
|
4628
4671
|
yield* finalizeStreamTurn(session, items, {
|
|
4629
4672
|
stopReason: reason,
|
|
4630
4673
|
rawResponseId,
|
|
4674
|
+
factory,
|
|
4675
|
+
maxOpaquePayloadBytes: host.maxOpaquePayloadBytes,
|
|
4631
4676
|
opaque: replayParts.length > 0 ? opaqueItem(OPAQUE_SOURCE.GEMINI, "replay", {
|
|
4632
4677
|
replaceCanonical: true,
|
|
4633
4678
|
content: {
|
|
@@ -4713,14 +4758,15 @@ var GeminiAdapter = class extends HttpAdapterBase {
|
|
|
4713
4758
|
super(options, { baseUrl: "https://generativelanguage.googleapis.com/v1beta" });
|
|
4714
4759
|
}
|
|
4715
4760
|
buildRequest(request) {
|
|
4716
|
-
return this.withExtraBody(buildGeminiRequest(request));
|
|
4761
|
+
return this.withExtraBody(buildGeminiRequest(request, { maxOpaquePayloadBytes: this.maxOpaquePayloadBytes }));
|
|
4717
4762
|
}
|
|
4718
4763
|
async *runStream(providerRequest, factory, request) {
|
|
4719
4764
|
yield* mapGeminiStream({
|
|
4720
4765
|
beginJsonStream: this.beginJsonStream.bind(this),
|
|
4721
4766
|
baseUrl: this.baseUrl,
|
|
4722
4767
|
apiKey: this.apiKey,
|
|
4723
|
-
mergeHeaders: this.mergeHeaders.bind(this)
|
|
4768
|
+
mergeHeaders: this.mergeHeaders.bind(this),
|
|
4769
|
+
maxOpaquePayloadBytes: this.maxOpaquePayloadBytes
|
|
4724
4770
|
}, providerRequest, factory, request);
|
|
4725
4771
|
}
|
|
4726
4772
|
};
|