@skaile/transform-proxy 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.md +22 -0
- package/dist/cli.mjs +1 -1
- package/dist/{config-BKD-ILIz.mjs → config-DQPsbYLi.mjs} +708 -51
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -1
- package/dist/omp/index.d.mts +89 -0
- package/dist/omp/index.mjs +345 -0
- package/package.json +24 -3
|
@@ -304,60 +304,60 @@ var UnsupportedContentError = class extends Error {
|
|
|
304
304
|
}
|
|
305
305
|
};
|
|
306
306
|
// src/wire/anthropic.ts
|
|
307
|
-
const isObj = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
307
|
+
const isObj$2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
308
308
|
/** Block types that carry attachments the proxy cannot pseudonymize. */
|
|
309
309
|
const REFUSED_BLOCKS = {
|
|
310
310
|
image: true,
|
|
311
311
|
document: true,
|
|
312
312
|
search_result: true
|
|
313
313
|
};
|
|
314
|
-
const signatureKey = (signature) => `anthropic:${signature}`;
|
|
315
|
-
function refuse(block) {
|
|
314
|
+
const signatureKey$1 = (signature) => `anthropic:${signature}`;
|
|
315
|
+
function refuse$1(block) {
|
|
316
316
|
if (typeof block.type === "string" && REFUSED_BLOCKS[block.type] === true) throw new UnsupportedContentError(`Anthropic ${block.type} content cannot be transformed`);
|
|
317
317
|
}
|
|
318
|
-
async function outbound(transform, text, leaf) {
|
|
318
|
+
async function outbound$2(transform, text, leaf) {
|
|
319
319
|
return text === "" ? text : transform.outbound(text, leaf);
|
|
320
320
|
}
|
|
321
321
|
/** A string, or an array of blocks whose `text` blocks are rewritten. */
|
|
322
322
|
async function rewriteText(content, leaf, transform) {
|
|
323
|
-
if (typeof content === "string") return outbound(transform, content, leaf);
|
|
323
|
+
if (typeof content === "string") return outbound$2(transform, content, leaf);
|
|
324
324
|
if (!Array.isArray(content)) return content;
|
|
325
325
|
const out = [];
|
|
326
326
|
for (const block of content) {
|
|
327
|
-
if (!isObj(block)) {
|
|
327
|
+
if (!isObj$2(block)) {
|
|
328
328
|
out.push(block);
|
|
329
329
|
continue;
|
|
330
330
|
}
|
|
331
|
-
refuse(block);
|
|
331
|
+
refuse$1(block);
|
|
332
332
|
out.push(block.type === "text" && typeof block.text === "string" ? {
|
|
333
333
|
...block,
|
|
334
|
-
text: await outbound(transform, block.text, leaf)
|
|
334
|
+
text: await outbound$2(transform, block.text, leaf)
|
|
335
335
|
} : block);
|
|
336
336
|
}
|
|
337
337
|
return out;
|
|
338
338
|
}
|
|
339
339
|
/** Every string leaf of a JSON value (tool-call input); keys stay as they are. */
|
|
340
|
-
async function rewriteStrings(value, leaf, transform) {
|
|
341
|
-
if (typeof value === "string") return outbound(transform, value, leaf);
|
|
340
|
+
async function rewriteStrings$2(value, leaf, transform) {
|
|
341
|
+
if (typeof value === "string") return outbound$2(transform, value, leaf);
|
|
342
342
|
if (Array.isArray(value)) {
|
|
343
343
|
const out = [];
|
|
344
|
-
for (const item of value) out.push(await rewriteStrings(item, leaf, transform));
|
|
344
|
+
for (const item of value) out.push(await rewriteStrings$2(item, leaf, transform));
|
|
345
345
|
return out;
|
|
346
346
|
}
|
|
347
|
-
if (isObj(value)) {
|
|
347
|
+
if (isObj$2(value)) {
|
|
348
348
|
const out = {};
|
|
349
|
-
for (const [key, item] of Object.entries(value)) out[key] = await rewriteStrings(item, leaf, transform);
|
|
349
|
+
for (const [key, item] of Object.entries(value)) out[key] = await rewriteStrings$2(item, leaf, transform);
|
|
350
350
|
return out;
|
|
351
351
|
}
|
|
352
352
|
return value;
|
|
353
353
|
}
|
|
354
354
|
/** Every string leaf of a JSON value, restored inbound. */
|
|
355
|
-
function restoreStrings(value, transform) {
|
|
355
|
+
function restoreStrings$1(value, transform) {
|
|
356
356
|
if (typeof value === "string") return transform.inbound(value);
|
|
357
|
-
if (Array.isArray(value)) return value.map((item) => restoreStrings(item, transform));
|
|
358
|
-
if (isObj(value)) {
|
|
357
|
+
if (Array.isArray(value)) return value.map((item) => restoreStrings$1(item, transform));
|
|
358
|
+
if (isObj$2(value)) {
|
|
359
359
|
const out = {};
|
|
360
|
-
for (const [key, item] of Object.entries(value)) out[key] = restoreStrings(item, transform);
|
|
360
|
+
for (const [key, item] of Object.entries(value)) out[key] = restoreStrings$1(item, transform);
|
|
361
361
|
return out;
|
|
362
362
|
}
|
|
363
363
|
return value;
|
|
@@ -365,7 +365,7 @@ function restoreStrings(value, transform) {
|
|
|
365
365
|
/** A thinking block: swaps in the cached model text when its signature is known, else rewrites it. */
|
|
366
366
|
async function rewriteThinking(block, ctx) {
|
|
367
367
|
if (typeof block.signature === "string") {
|
|
368
|
-
const cached = ctx.signatures.get(signatureKey(block.signature));
|
|
368
|
+
const cached = ctx.signatures.get(signatureKey$1(block.signature));
|
|
369
369
|
if (cached !== void 0) return {
|
|
370
370
|
...block,
|
|
371
371
|
thinking: cached
|
|
@@ -374,25 +374,25 @@ async function rewriteThinking(block, ctx) {
|
|
|
374
374
|
if (typeof block.thinking !== "string") return block;
|
|
375
375
|
return {
|
|
376
376
|
...block,
|
|
377
|
-
thinking: await outbound(ctx.transform, block.thinking, { kind: "thinking" })
|
|
377
|
+
thinking: await outbound$2(ctx.transform, block.thinking, { kind: "thinking" })
|
|
378
378
|
};
|
|
379
379
|
}
|
|
380
|
-
async function rewriteContent(content, role, toolNames, ctx) {
|
|
380
|
+
async function rewriteContent$2(content, role, toolNames, ctx) {
|
|
381
381
|
const textKind = role === "assistant" ? "assistant" : "user";
|
|
382
|
-
if (typeof content === "string") return outbound(ctx.transform, content, { kind: textKind });
|
|
382
|
+
if (typeof content === "string") return outbound$2(ctx.transform, content, { kind: textKind });
|
|
383
383
|
if (!Array.isArray(content)) return content;
|
|
384
384
|
const out = [];
|
|
385
385
|
for (const block of content) {
|
|
386
|
-
if (!isObj(block)) {
|
|
386
|
+
if (!isObj$2(block)) {
|
|
387
387
|
out.push(block);
|
|
388
388
|
continue;
|
|
389
389
|
}
|
|
390
|
-
refuse(block);
|
|
390
|
+
refuse$1(block);
|
|
391
391
|
switch (block.type) {
|
|
392
392
|
case "text":
|
|
393
393
|
out.push(typeof block.text === "string" ? {
|
|
394
394
|
...block,
|
|
395
|
-
text: await outbound(ctx.transform, block.text, { kind: textKind })
|
|
395
|
+
text: await outbound$2(ctx.transform, block.text, { kind: textKind })
|
|
396
396
|
} : block);
|
|
397
397
|
break;
|
|
398
398
|
case "thinking":
|
|
@@ -402,7 +402,7 @@ async function rewriteContent(content, role, toolNames, ctx) {
|
|
|
402
402
|
const toolName = typeof block.name === "string" ? block.name : void 0;
|
|
403
403
|
out.push({
|
|
404
404
|
...block,
|
|
405
|
-
input: await rewriteStrings(block.input, {
|
|
405
|
+
input: await rewriteStrings$2(block.input, {
|
|
406
406
|
kind: "toolCall",
|
|
407
407
|
toolName
|
|
408
408
|
}, ctx.transform)
|
|
@@ -429,8 +429,8 @@ async function rewriteContent(content, role, toolNames, ctx) {
|
|
|
429
429
|
function toolNamesById(messages) {
|
|
430
430
|
const names = /* @__PURE__ */ new Map();
|
|
431
431
|
for (const message of messages) {
|
|
432
|
-
if (!isObj(message) || !Array.isArray(message.content)) continue;
|
|
433
|
-
for (const block of message.content) if (isObj(block) && block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") names.set(block.id, block.name);
|
|
432
|
+
if (!isObj$2(message) || !Array.isArray(message.content)) continue;
|
|
433
|
+
for (const block of message.content) if (isObj$2(block) && block.type === "tool_use" && typeof block.id === "string" && typeof block.name === "string") names.set(block.id, block.name);
|
|
434
434
|
}
|
|
435
435
|
return names;
|
|
436
436
|
}
|
|
@@ -465,7 +465,7 @@ function tailDelta(kind, tail) {
|
|
|
465
465
|
partial_json: tail
|
|
466
466
|
};
|
|
467
467
|
}
|
|
468
|
-
function createStreamTransformer(ctx) {
|
|
468
|
+
function createStreamTransformer$2(ctx) {
|
|
469
469
|
const blocks = /* @__PURE__ */ new Map();
|
|
470
470
|
const handle = (block) => {
|
|
471
471
|
let payload;
|
|
@@ -474,12 +474,12 @@ function createStreamTransformer(ctx) {
|
|
|
474
474
|
} catch {
|
|
475
475
|
return block.raw;
|
|
476
476
|
}
|
|
477
|
-
if (!isObj(payload)) return block.raw;
|
|
477
|
+
if (!isObj$2(payload)) return block.raw;
|
|
478
478
|
const index = typeof payload.index === "number" ? payload.index : void 0;
|
|
479
479
|
switch (payload.type) {
|
|
480
480
|
case "content_block_start": {
|
|
481
481
|
const content = payload.content_block;
|
|
482
|
-
if (index === void 0 || !isObj(content)) return block.raw;
|
|
482
|
+
if (index === void 0 || !isObj$2(content)) return block.raw;
|
|
483
483
|
if (content.type === "text" || content.type === "thinking" || content.type === "tool_use") {
|
|
484
484
|
const kind = content.type === "tool_use" ? "tool" : content.type;
|
|
485
485
|
blocks.set(index, newBlockState(kind, ctx.transform));
|
|
@@ -489,7 +489,7 @@ function createStreamTransformer(ctx) {
|
|
|
489
489
|
case "content_block_delta": {
|
|
490
490
|
const state = index === void 0 ? void 0 : blocks.get(index);
|
|
491
491
|
const delta = payload.delta;
|
|
492
|
-
if (state === void 0 || !isObj(delta)) return block.raw;
|
|
492
|
+
if (state === void 0 || !isObj$2(delta)) return block.raw;
|
|
493
493
|
if (state.kind === "text" && delta.type === "text_delta" && typeof delta.text === "string") return formatSseEvent(block.event, {
|
|
494
494
|
...payload,
|
|
495
495
|
delta: {
|
|
@@ -508,7 +508,7 @@ function createStreamTransformer(ctx) {
|
|
|
508
508
|
});
|
|
509
509
|
}
|
|
510
510
|
if (state.kind === "thinking" && delta.type === "signature_delta" && typeof delta.signature === "string") {
|
|
511
|
-
ctx.signatures.set(signatureKey(delta.signature), state.raw);
|
|
511
|
+
ctx.signatures.set(signatureKey$1(delta.signature), state.raw);
|
|
512
512
|
return block.raw;
|
|
513
513
|
}
|
|
514
514
|
if (state.kind === "tool" && delta.type === "input_json_delta" && typeof delta.partial_json === "string") return formatSseEvent(block.event, {
|
|
@@ -552,31 +552,31 @@ function createStreamTransformer(ctx) {
|
|
|
552
552
|
}
|
|
553
553
|
const anthropicWalker = {
|
|
554
554
|
async request(body, ctx) {
|
|
555
|
-
if (!isObj(body)) return body;
|
|
555
|
+
if (!isObj$2(body)) return body;
|
|
556
556
|
const out = { ...body };
|
|
557
557
|
if (body.system !== void 0) out.system = await rewriteText(body.system, { kind: "system" }, ctx.transform);
|
|
558
558
|
if (ctx.transform.instruction !== void 0) out.system = withInstruction(out.system, ctx.transform.instruction);
|
|
559
559
|
if (Array.isArray(body.messages)) {
|
|
560
560
|
const toolNames = toolNamesById(body.messages);
|
|
561
561
|
const messages = [];
|
|
562
|
-
for (const message of body.messages) messages.push(isObj(message) ? {
|
|
562
|
+
for (const message of body.messages) messages.push(isObj$2(message) ? {
|
|
563
563
|
...message,
|
|
564
|
-
content: await rewriteContent(message.content, message.role, toolNames, ctx)
|
|
564
|
+
content: await rewriteContent$2(message.content, message.role, toolNames, ctx)
|
|
565
565
|
} : message);
|
|
566
566
|
out.messages = messages;
|
|
567
567
|
}
|
|
568
568
|
return out;
|
|
569
569
|
},
|
|
570
570
|
response(body, ctx) {
|
|
571
|
-
if (!isObj(body) || !Array.isArray(body.content)) return body;
|
|
571
|
+
if (!isObj$2(body) || !Array.isArray(body.content)) return body;
|
|
572
572
|
const content = body.content.map((block) => {
|
|
573
|
-
if (!isObj(block)) return block;
|
|
573
|
+
if (!isObj$2(block)) return block;
|
|
574
574
|
if (block.type === "text" && typeof block.text === "string") return {
|
|
575
575
|
...block,
|
|
576
576
|
text: ctx.transform.inbound(block.text)
|
|
577
577
|
};
|
|
578
578
|
if (block.type === "thinking" && typeof block.thinking === "string") {
|
|
579
|
-
if (typeof block.signature === "string") ctx.signatures.set(signatureKey(block.signature), block.thinking);
|
|
579
|
+
if (typeof block.signature === "string") ctx.signatures.set(signatureKey$1(block.signature), block.thinking);
|
|
580
580
|
return {
|
|
581
581
|
...block,
|
|
582
582
|
thinking: ctx.transform.inbound(block.thinking)
|
|
@@ -584,7 +584,7 @@ const anthropicWalker = {
|
|
|
584
584
|
}
|
|
585
585
|
if (block.type === "tool_use") return {
|
|
586
586
|
...block,
|
|
587
|
-
input: restoreStrings(block.input, ctx.transform)
|
|
587
|
+
input: restoreStrings$1(block.input, ctx.transform)
|
|
588
588
|
};
|
|
589
589
|
return block;
|
|
590
590
|
});
|
|
@@ -593,6 +593,651 @@ const anthropicWalker = {
|
|
|
593
593
|
content
|
|
594
594
|
};
|
|
595
595
|
},
|
|
596
|
+
stream(ctx) {
|
|
597
|
+
return createStreamTransformer$2(ctx);
|
|
598
|
+
}
|
|
599
|
+
};
|
|
600
|
+
// src/wire/openai-chat.ts
|
|
601
|
+
const isObj$1 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
602
|
+
/** Content part types that carry attachments the proxy cannot pseudonymize. */
|
|
603
|
+
const REFUSED_PARTS$1 = {
|
|
604
|
+
image_url: true,
|
|
605
|
+
input_audio: true,
|
|
606
|
+
file: true
|
|
607
|
+
};
|
|
608
|
+
/** Reasoning fields used by OpenAI-compatible providers. */
|
|
609
|
+
const REASONING_FIELDS = ["reasoning_content", "reasoning"];
|
|
610
|
+
async function outbound$1(transform, text, leaf) {
|
|
611
|
+
return text === "" ? text : transform.outbound(text, leaf);
|
|
612
|
+
}
|
|
613
|
+
/** A string, or an array of parts whose `text` parts are rewritten. */
|
|
614
|
+
async function rewriteContent$1(content, leaf, transform) {
|
|
615
|
+
if (typeof content === "string") return outbound$1(transform, content, leaf);
|
|
616
|
+
if (!Array.isArray(content)) return content;
|
|
617
|
+
const out = [];
|
|
618
|
+
for (const part of content) {
|
|
619
|
+
if (!isObj$1(part)) {
|
|
620
|
+
out.push(part);
|
|
621
|
+
continue;
|
|
622
|
+
}
|
|
623
|
+
if (typeof part.type === "string" && REFUSED_PARTS$1[part.type] === true) throw new UnsupportedContentError(`OpenAI chat ${part.type} content cannot be transformed`);
|
|
624
|
+
out.push(part.type === "text" && typeof part.text === "string" ? {
|
|
625
|
+
...part,
|
|
626
|
+
text: await outbound$1(transform, part.text, leaf)
|
|
627
|
+
} : part);
|
|
628
|
+
}
|
|
629
|
+
return out;
|
|
630
|
+
}
|
|
631
|
+
async function rewriteStrings$1(value, leaf, transform) {
|
|
632
|
+
if (typeof value === "string") return outbound$1(transform, value, leaf);
|
|
633
|
+
if (Array.isArray(value)) {
|
|
634
|
+
const out = [];
|
|
635
|
+
for (const item of value) out.push(await rewriteStrings$1(item, leaf, transform));
|
|
636
|
+
return out;
|
|
637
|
+
}
|
|
638
|
+
if (isObj$1(value)) {
|
|
639
|
+
const out = {};
|
|
640
|
+
for (const [key, item] of Object.entries(value)) out[key] = await rewriteStrings$1(item, leaf, transform);
|
|
641
|
+
return out;
|
|
642
|
+
}
|
|
643
|
+
return value;
|
|
644
|
+
}
|
|
645
|
+
function restoreStrings(value, transform) {
|
|
646
|
+
if (typeof value === "string") return transform.inbound(value);
|
|
647
|
+
if (Array.isArray(value)) return value.map((item) => restoreStrings(item, transform));
|
|
648
|
+
if (isObj$1(value)) {
|
|
649
|
+
const out = {};
|
|
650
|
+
for (const [key, item] of Object.entries(value)) out[key] = restoreStrings(item, transform);
|
|
651
|
+
return out;
|
|
652
|
+
}
|
|
653
|
+
return value;
|
|
654
|
+
}
|
|
655
|
+
/** Tool-call arguments are a JSON string: rewrite its string leaves, or the raw text when it is not JSON. */
|
|
656
|
+
async function rewriteArguments$1(args, leaf, transform) {
|
|
657
|
+
let parsed;
|
|
658
|
+
try {
|
|
659
|
+
parsed = JSON.parse(args);
|
|
660
|
+
} catch {
|
|
661
|
+
return outbound$1(transform, args, leaf);
|
|
662
|
+
}
|
|
663
|
+
return JSON.stringify(await rewriteStrings$1(parsed, leaf, transform));
|
|
664
|
+
}
|
|
665
|
+
function restoreArguments$1(args, transform) {
|
|
666
|
+
let parsed;
|
|
667
|
+
try {
|
|
668
|
+
parsed = JSON.parse(args);
|
|
669
|
+
} catch {
|
|
670
|
+
return transform.inbound(args);
|
|
671
|
+
}
|
|
672
|
+
return JSON.stringify(restoreStrings(parsed, transform));
|
|
673
|
+
}
|
|
674
|
+
async function rewriteToolCalls(calls, transform, names) {
|
|
675
|
+
if (!Array.isArray(calls)) return calls;
|
|
676
|
+
const out = [];
|
|
677
|
+
for (const call of calls) {
|
|
678
|
+
if (!isObj$1(call) || !isObj$1(call.function)) {
|
|
679
|
+
out.push(call);
|
|
680
|
+
continue;
|
|
681
|
+
}
|
|
682
|
+
const fn = call.function;
|
|
683
|
+
const toolName = typeof fn.name === "string" ? fn.name : void 0;
|
|
684
|
+
if (typeof call.id === "string" && toolName !== void 0) names.set(call.id, toolName);
|
|
685
|
+
out.push(typeof fn.arguments === "string" ? {
|
|
686
|
+
...call,
|
|
687
|
+
function: {
|
|
688
|
+
...fn,
|
|
689
|
+
arguments: await rewriteArguments$1(fn.arguments, {
|
|
690
|
+
kind: "toolCall",
|
|
691
|
+
toolName
|
|
692
|
+
}, transform)
|
|
693
|
+
}
|
|
694
|
+
} : call);
|
|
695
|
+
}
|
|
696
|
+
return out;
|
|
697
|
+
}
|
|
698
|
+
async function rewriteMessage(message, transform, names) {
|
|
699
|
+
const out = { ...message };
|
|
700
|
+
switch (message.role) {
|
|
701
|
+
case "system":
|
|
702
|
+
case "developer":
|
|
703
|
+
out.content = await rewriteContent$1(message.content, { kind: "system" }, transform);
|
|
704
|
+
break;
|
|
705
|
+
case "user":
|
|
706
|
+
out.content = await rewriteContent$1(message.content, { kind: "user" }, transform);
|
|
707
|
+
break;
|
|
708
|
+
case "assistant":
|
|
709
|
+
for (const field of REASONING_FIELDS) {
|
|
710
|
+
const value = message[field];
|
|
711
|
+
if (typeof value === "string") out[field] = await outbound$1(transform, value, { kind: "thinking" });
|
|
712
|
+
}
|
|
713
|
+
out.content = await rewriteContent$1(message.content, { kind: "assistant" }, transform);
|
|
714
|
+
out.tool_calls = await rewriteToolCalls(message.tool_calls, transform, names);
|
|
715
|
+
if (message.tool_calls === void 0) delete out.tool_calls;
|
|
716
|
+
break;
|
|
717
|
+
case "tool": {
|
|
718
|
+
const toolName = typeof message.tool_call_id === "string" ? names.get(message.tool_call_id) : void 0;
|
|
719
|
+
out.content = await rewriteContent$1(message.content, {
|
|
720
|
+
kind: "toolResult",
|
|
721
|
+
toolName
|
|
722
|
+
}, transform);
|
|
723
|
+
break;
|
|
724
|
+
}
|
|
725
|
+
default: return message;
|
|
726
|
+
}
|
|
727
|
+
if (message.content === void 0) delete out.content;
|
|
728
|
+
return out;
|
|
729
|
+
}
|
|
730
|
+
/** The delta carrying every held tail of one choice, or undefined when nothing is held. */
|
|
731
|
+
function flushChoice(state) {
|
|
732
|
+
const delta = {};
|
|
733
|
+
if (state.content !== void 0) {
|
|
734
|
+
const tail = state.content.flush();
|
|
735
|
+
if (tail !== "") delta.content = tail;
|
|
736
|
+
}
|
|
737
|
+
for (const [field, restore] of state.reasoning) {
|
|
738
|
+
const tail = restore.flush();
|
|
739
|
+
if (tail !== "") delta[field] = tail;
|
|
740
|
+
}
|
|
741
|
+
const tools = [];
|
|
742
|
+
for (const [index, restore] of state.tools) {
|
|
743
|
+
const tail = restore.flush();
|
|
744
|
+
if (tail !== "") tools.push({
|
|
745
|
+
index,
|
|
746
|
+
function: { arguments: tail }
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
if (tools.length > 0) delta.tool_calls = tools;
|
|
750
|
+
state.content = void 0;
|
|
751
|
+
state.reasoning.clear();
|
|
752
|
+
state.tools.clear();
|
|
753
|
+
return Object.keys(delta).length === 0 ? void 0 : delta;
|
|
754
|
+
}
|
|
755
|
+
function createStreamTransformer$1(ctx) {
|
|
756
|
+
const choices = /* @__PURE__ */ new Map();
|
|
757
|
+
/** The latest chunk's envelope (id, model, ...), reused for tail chunks. */
|
|
758
|
+
let envelope = { object: "chat.completion.chunk" };
|
|
759
|
+
const choiceState = (index) => {
|
|
760
|
+
let state = choices.get(index);
|
|
761
|
+
if (state === void 0) {
|
|
762
|
+
state = {
|
|
763
|
+
reasoning: /* @__PURE__ */ new Map(),
|
|
764
|
+
tools: /* @__PURE__ */ new Map()
|
|
765
|
+
};
|
|
766
|
+
choices.set(index, state);
|
|
767
|
+
}
|
|
768
|
+
return state;
|
|
769
|
+
};
|
|
770
|
+
const tailEvent = (event, index, delta) => formatSseEvent(event, {
|
|
771
|
+
...envelope,
|
|
772
|
+
choices: [{
|
|
773
|
+
index,
|
|
774
|
+
delta,
|
|
775
|
+
finish_reason: null
|
|
776
|
+
}]
|
|
777
|
+
});
|
|
778
|
+
const flushAll = (event) => {
|
|
779
|
+
let out = "";
|
|
780
|
+
for (const [index, state] of choices) {
|
|
781
|
+
const delta = flushChoice(state);
|
|
782
|
+
if (delta !== void 0) out += tailEvent(event, index, delta);
|
|
783
|
+
}
|
|
784
|
+
choices.clear();
|
|
785
|
+
return out;
|
|
786
|
+
};
|
|
787
|
+
const rewriteDelta = (delta, state) => {
|
|
788
|
+
const out = { ...delta };
|
|
789
|
+
let changed = false;
|
|
790
|
+
if (typeof delta.content === "string") {
|
|
791
|
+
state.content ??= ctx.transform.inboundStream();
|
|
792
|
+
out.content = state.content.push(delta.content);
|
|
793
|
+
changed = true;
|
|
794
|
+
}
|
|
795
|
+
for (const field of REASONING_FIELDS) {
|
|
796
|
+
const value = delta[field];
|
|
797
|
+
if (typeof value !== "string") continue;
|
|
798
|
+
let restore = state.reasoning.get(field);
|
|
799
|
+
if (restore === void 0) {
|
|
800
|
+
restore = ctx.transform.inboundStream();
|
|
801
|
+
state.reasoning.set(field, restore);
|
|
802
|
+
}
|
|
803
|
+
out[field] = restore.push(value);
|
|
804
|
+
changed = true;
|
|
805
|
+
}
|
|
806
|
+
if (Array.isArray(delta.tool_calls)) out.tool_calls = delta.tool_calls.map((call) => {
|
|
807
|
+
if (!isObj$1(call) || !isObj$1(call.function) || typeof call.function.arguments !== "string") return call;
|
|
808
|
+
const index = typeof call.index === "number" ? call.index : 0;
|
|
809
|
+
let restore = state.tools.get(index);
|
|
810
|
+
if (restore === void 0) {
|
|
811
|
+
restore = createJsonArgRestorer(() => ctx.transform.inboundStream());
|
|
812
|
+
state.tools.set(index, restore);
|
|
813
|
+
}
|
|
814
|
+
changed = true;
|
|
815
|
+
return {
|
|
816
|
+
...call,
|
|
817
|
+
function: {
|
|
818
|
+
...call.function,
|
|
819
|
+
arguments: restore.push(call.function.arguments)
|
|
820
|
+
}
|
|
821
|
+
};
|
|
822
|
+
});
|
|
823
|
+
return {
|
|
824
|
+
delta: out,
|
|
825
|
+
changed
|
|
826
|
+
};
|
|
827
|
+
};
|
|
828
|
+
const handle = (block) => {
|
|
829
|
+
if (block.data.trim() === "[DONE]") return flushAll(block.event) + block.raw;
|
|
830
|
+
let payload;
|
|
831
|
+
try {
|
|
832
|
+
payload = JSON.parse(block.data);
|
|
833
|
+
} catch {
|
|
834
|
+
return block.raw;
|
|
835
|
+
}
|
|
836
|
+
if (!isObj$1(payload) || !Array.isArray(payload.choices)) return block.raw;
|
|
837
|
+
const { choices: _choices, ...rest } = payload;
|
|
838
|
+
envelope = rest;
|
|
839
|
+
let changed = false;
|
|
840
|
+
let before = "";
|
|
841
|
+
const rewritten = payload.choices.map((choice) => {
|
|
842
|
+
if (!isObj$1(choice)) return choice;
|
|
843
|
+
const index = typeof choice.index === "number" ? choice.index : 0;
|
|
844
|
+
const state = choiceState(index);
|
|
845
|
+
let next = choice;
|
|
846
|
+
if (isObj$1(choice.delta)) {
|
|
847
|
+
const result = rewriteDelta(choice.delta, state);
|
|
848
|
+
if (result.changed) {
|
|
849
|
+
next = {
|
|
850
|
+
...choice,
|
|
851
|
+
delta: result.delta
|
|
852
|
+
};
|
|
853
|
+
changed = true;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
if (choice.finish_reason !== null && choice.finish_reason !== void 0) {
|
|
857
|
+
const tail = flushChoice(state);
|
|
858
|
+
choices.delete(index);
|
|
859
|
+
if (tail !== void 0) before += tailEvent(block.event, index, tail);
|
|
860
|
+
}
|
|
861
|
+
return next;
|
|
862
|
+
});
|
|
863
|
+
return before + (changed ? formatSseEvent(block.event, {
|
|
864
|
+
...payload,
|
|
865
|
+
choices: rewritten
|
|
866
|
+
}) : block.raw);
|
|
867
|
+
};
|
|
868
|
+
return createSseFramer(handle, () => flushAll(void 0));
|
|
869
|
+
}
|
|
870
|
+
const openaiChatWalker = {
|
|
871
|
+
async request(body, ctx) {
|
|
872
|
+
if (!isObj$1(body)) return body;
|
|
873
|
+
const out = { ...body };
|
|
874
|
+
if (Array.isArray(body.messages)) {
|
|
875
|
+
const names = /* @__PURE__ */ new Map();
|
|
876
|
+
const messages = [];
|
|
877
|
+
for (const message of body.messages) messages.push(isObj$1(message) ? await rewriteMessage(message, ctx.transform, names) : message);
|
|
878
|
+
if (ctx.transform.instruction !== void 0) messages.unshift({
|
|
879
|
+
role: "system",
|
|
880
|
+
content: ctx.transform.instruction
|
|
881
|
+
});
|
|
882
|
+
out.messages = messages;
|
|
883
|
+
}
|
|
884
|
+
return out;
|
|
885
|
+
},
|
|
886
|
+
response(body, ctx) {
|
|
887
|
+
if (!isObj$1(body) || !Array.isArray(body.choices)) return body;
|
|
888
|
+
const choices = body.choices.map((choice) => {
|
|
889
|
+
if (!isObj$1(choice) || !isObj$1(choice.message)) return choice;
|
|
890
|
+
const message = { ...choice.message };
|
|
891
|
+
if (typeof message.content === "string") message.content = ctx.transform.inbound(message.content);
|
|
892
|
+
for (const field of REASONING_FIELDS) {
|
|
893
|
+
const value = message[field];
|
|
894
|
+
if (typeof value === "string") message[field] = ctx.transform.inbound(value);
|
|
895
|
+
}
|
|
896
|
+
if (Array.isArray(message.tool_calls)) message.tool_calls = message.tool_calls.map((call) => {
|
|
897
|
+
if (!isObj$1(call) || !isObj$1(call.function) || typeof call.function.arguments !== "string") return call;
|
|
898
|
+
return {
|
|
899
|
+
...call,
|
|
900
|
+
function: {
|
|
901
|
+
...call.function,
|
|
902
|
+
arguments: restoreArguments$1(call.function.arguments, ctx.transform)
|
|
903
|
+
}
|
|
904
|
+
};
|
|
905
|
+
});
|
|
906
|
+
return {
|
|
907
|
+
...choice,
|
|
908
|
+
message
|
|
909
|
+
};
|
|
910
|
+
});
|
|
911
|
+
return {
|
|
912
|
+
...body,
|
|
913
|
+
choices
|
|
914
|
+
};
|
|
915
|
+
},
|
|
916
|
+
stream(ctx) {
|
|
917
|
+
return createStreamTransformer$1(ctx);
|
|
918
|
+
}
|
|
919
|
+
};
|
|
920
|
+
// src/wire/openai-responses.ts
|
|
921
|
+
const isObj = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
922
|
+
/** Part types that carry attachments the proxy cannot pseudonymize. */
|
|
923
|
+
const REFUSED_PARTS = {
|
|
924
|
+
input_image: true,
|
|
925
|
+
input_file: true,
|
|
926
|
+
input_audio: true
|
|
927
|
+
};
|
|
928
|
+
const signatureKey = (itemId) => `responses:${itemId}`;
|
|
929
|
+
function refuse(part) {
|
|
930
|
+
if (typeof part.type === "string" && REFUSED_PARTS[part.type] === true) throw new UnsupportedContentError(`OpenAI responses ${part.type} content cannot be transformed`);
|
|
931
|
+
}
|
|
932
|
+
async function outbound(transform, text, leaf) {
|
|
933
|
+
return text === "" ? text : transform.outbound(text, leaf);
|
|
934
|
+
}
|
|
935
|
+
/** A string, or an array of parts whose `input_text`/`output_text` parts are rewritten. */
|
|
936
|
+
async function rewriteContent(content, leaf, transform) {
|
|
937
|
+
if (typeof content === "string") return outbound(transform, content, leaf);
|
|
938
|
+
if (!Array.isArray(content)) return content;
|
|
939
|
+
const out = [];
|
|
940
|
+
for (const part of content) {
|
|
941
|
+
if (!isObj(part)) {
|
|
942
|
+
out.push(part);
|
|
943
|
+
continue;
|
|
944
|
+
}
|
|
945
|
+
refuse(part);
|
|
946
|
+
out.push((part.type === "input_text" || part.type === "output_text") && typeof part.text === "string" ? {
|
|
947
|
+
...part,
|
|
948
|
+
text: await outbound(transform, part.text, leaf)
|
|
949
|
+
} : part);
|
|
950
|
+
}
|
|
951
|
+
return out;
|
|
952
|
+
}
|
|
953
|
+
async function rewriteStrings(value, leaf, transform) {
|
|
954
|
+
if (typeof value === "string") return outbound(transform, value, leaf);
|
|
955
|
+
if (Array.isArray(value)) {
|
|
956
|
+
const out = [];
|
|
957
|
+
for (const item of value) out.push(await rewriteStrings(item, leaf, transform));
|
|
958
|
+
return out;
|
|
959
|
+
}
|
|
960
|
+
if (isObj(value)) {
|
|
961
|
+
const out = {};
|
|
962
|
+
for (const [key, item] of Object.entries(value)) out[key] = await rewriteStrings(item, leaf, transform);
|
|
963
|
+
return out;
|
|
964
|
+
}
|
|
965
|
+
return value;
|
|
966
|
+
}
|
|
967
|
+
/** Tool-call arguments: a JSON string whose string leaves are rewritten; raw text when it is not JSON. */
|
|
968
|
+
async function rewriteArguments(args, leaf, transform) {
|
|
969
|
+
let parsed;
|
|
970
|
+
try {
|
|
971
|
+
parsed = JSON.parse(args);
|
|
972
|
+
} catch {
|
|
973
|
+
return outbound(transform, args, leaf);
|
|
974
|
+
}
|
|
975
|
+
return JSON.stringify(await rewriteStrings(parsed, leaf, transform));
|
|
976
|
+
}
|
|
977
|
+
/** Restores the string values of a JSON text, keeping its formatting; restored originals are JSON-escaped. */
|
|
978
|
+
function restoreArguments(args, transform) {
|
|
979
|
+
const restorer = createJsonArgRestorer(() => transform.inboundStream());
|
|
980
|
+
return restorer.push(args) + restorer.flush();
|
|
981
|
+
}
|
|
982
|
+
function summaryTexts(item) {
|
|
983
|
+
if (!Array.isArray(item.summary)) return void 0;
|
|
984
|
+
const texts = [];
|
|
985
|
+
for (const part of item.summary) {
|
|
986
|
+
if (!isObj(part) || typeof part.text !== "string") return void 0;
|
|
987
|
+
texts.push(part.text);
|
|
988
|
+
}
|
|
989
|
+
return texts;
|
|
990
|
+
}
|
|
991
|
+
function cachedSummary(item, ctx) {
|
|
992
|
+
if (typeof item.id !== "string") return void 0;
|
|
993
|
+
const cached = ctx.signatures.get(signatureKey(item.id));
|
|
994
|
+
if (cached === void 0) return void 0;
|
|
995
|
+
const texts = JSON.parse(cached);
|
|
996
|
+
if (!Array.isArray(texts) || !Array.isArray(item.summary) || texts.length !== item.summary.length) return void 0;
|
|
997
|
+
return texts;
|
|
998
|
+
}
|
|
999
|
+
async function rewriteReasoning(item, ctx) {
|
|
1000
|
+
if (!Array.isArray(item.summary)) return item;
|
|
1001
|
+
const cached = cachedSummary(item, ctx);
|
|
1002
|
+
const summary = [];
|
|
1003
|
+
for (const [i, part] of item.summary.entries()) if (!isObj(part) || typeof part.text !== "string") summary.push(part);
|
|
1004
|
+
else if (cached !== void 0) summary.push({
|
|
1005
|
+
...part,
|
|
1006
|
+
text: cached[i]
|
|
1007
|
+
});
|
|
1008
|
+
else summary.push({
|
|
1009
|
+
...part,
|
|
1010
|
+
text: await outbound(ctx.transform, part.text, { kind: "thinking" })
|
|
1011
|
+
});
|
|
1012
|
+
return {
|
|
1013
|
+
...item,
|
|
1014
|
+
summary
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
function roleKind(role) {
|
|
1018
|
+
if (role === "developer" || role === "system") return "system";
|
|
1019
|
+
if (role === "user") return "user";
|
|
1020
|
+
if (role === "assistant") return "assistant";
|
|
1021
|
+
}
|
|
1022
|
+
function toolNamesByCallId(items) {
|
|
1023
|
+
const names = /* @__PURE__ */ new Map();
|
|
1024
|
+
for (const item of items) if (isObj(item) && item.type === "function_call" && typeof item.call_id === "string" && typeof item.name === "string") names.set(item.call_id, item.name);
|
|
1025
|
+
return names;
|
|
1026
|
+
}
|
|
1027
|
+
async function rewriteItem(item, toolNames, ctx) {
|
|
1028
|
+
if (item.type === "message" || item.type === void 0 && item.role !== void 0) {
|
|
1029
|
+
const kind = roleKind(item.role);
|
|
1030
|
+
if (kind === void 0) return item;
|
|
1031
|
+
return {
|
|
1032
|
+
...item,
|
|
1033
|
+
content: await rewriteContent(item.content, { kind }, ctx.transform)
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
switch (item.type) {
|
|
1037
|
+
case "function_call": {
|
|
1038
|
+
if (typeof item.arguments !== "string") return item;
|
|
1039
|
+
const toolName = typeof item.name === "string" ? item.name : void 0;
|
|
1040
|
+
return {
|
|
1041
|
+
...item,
|
|
1042
|
+
arguments: await rewriteArguments(item.arguments, {
|
|
1043
|
+
kind: "toolCall",
|
|
1044
|
+
toolName
|
|
1045
|
+
}, ctx.transform)
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
case "function_call_output": {
|
|
1049
|
+
const toolName = typeof item.call_id === "string" ? toolNames.get(item.call_id) : void 0;
|
|
1050
|
+
return {
|
|
1051
|
+
...item,
|
|
1052
|
+
output: await rewriteContent(item.output, {
|
|
1053
|
+
kind: "toolResult",
|
|
1054
|
+
toolName
|
|
1055
|
+
}, ctx.transform)
|
|
1056
|
+
};
|
|
1057
|
+
}
|
|
1058
|
+
case "reasoning": return rewriteReasoning(item, ctx);
|
|
1059
|
+
default: return item;
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
/** Restores one output item; reasoning items store their raw summary in the signature cache first. */
|
|
1063
|
+
function restoreItem(item, ctx) {
|
|
1064
|
+
if (!isObj(item)) return item;
|
|
1065
|
+
const transform = ctx.transform;
|
|
1066
|
+
switch (item.type) {
|
|
1067
|
+
case "message":
|
|
1068
|
+
if (!Array.isArray(item.content)) return item;
|
|
1069
|
+
return {
|
|
1070
|
+
...item,
|
|
1071
|
+
content: item.content.map((part) => restorePart(part, transform))
|
|
1072
|
+
};
|
|
1073
|
+
case "reasoning": {
|
|
1074
|
+
const texts = summaryTexts(item);
|
|
1075
|
+
if (texts === void 0) return item;
|
|
1076
|
+
if (typeof item.id === "string") ctx.signatures.set(signatureKey(item.id), JSON.stringify(texts));
|
|
1077
|
+
return {
|
|
1078
|
+
...item,
|
|
1079
|
+
summary: item.summary.map((part) => ({
|
|
1080
|
+
...part,
|
|
1081
|
+
text: transform.inbound(part.text)
|
|
1082
|
+
}))
|
|
1083
|
+
};
|
|
1084
|
+
}
|
|
1085
|
+
case "function_call": return typeof item.arguments === "string" ? {
|
|
1086
|
+
...item,
|
|
1087
|
+
arguments: restoreArguments(item.arguments, transform)
|
|
1088
|
+
} : item;
|
|
1089
|
+
default: return item;
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function restorePart(part, transform) {
|
|
1093
|
+
return isObj(part) && part.type === "output_text" && typeof part.text === "string" ? {
|
|
1094
|
+
...part,
|
|
1095
|
+
text: transform.inbound(part.text)
|
|
1096
|
+
} : part;
|
|
1097
|
+
}
|
|
1098
|
+
function restoreResponse(body, ctx) {
|
|
1099
|
+
const out = { ...body };
|
|
1100
|
+
if (Array.isArray(body.output)) out.output = body.output.map((item) => restoreItem(item, ctx));
|
|
1101
|
+
if (typeof body.output_text === "string") out.output_text = ctx.transform.inbound(body.output_text);
|
|
1102
|
+
return out;
|
|
1103
|
+
}
|
|
1104
|
+
function createStreamTransformer(ctx) {
|
|
1105
|
+
const streams = /* @__PURE__ */ new Map();
|
|
1106
|
+
const open = (key, factory) => {
|
|
1107
|
+
let state = streams.get(key);
|
|
1108
|
+
if (state === void 0) {
|
|
1109
|
+
state = { restore: factory() };
|
|
1110
|
+
streams.set(key, state);
|
|
1111
|
+
}
|
|
1112
|
+
return state;
|
|
1113
|
+
};
|
|
1114
|
+
/** Emits the tail delta (if any) followed by the rewritten `.done` event. */
|
|
1115
|
+
const closeWith = (block, payload, key, deltaType, done) => {
|
|
1116
|
+
const state = streams.get(key);
|
|
1117
|
+
streams.delete(key);
|
|
1118
|
+
let out = "";
|
|
1119
|
+
const tail = state?.restore.flush() ?? "";
|
|
1120
|
+
if (tail !== "") {
|
|
1121
|
+
const { text: _text, arguments: _args, ...rest } = payload;
|
|
1122
|
+
out += formatSseEvent(block.event === void 0 ? void 0 : deltaType, {
|
|
1123
|
+
...rest,
|
|
1124
|
+
type: deltaType,
|
|
1125
|
+
delta: tail
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
return out + formatSseEvent(block.event, done);
|
|
1129
|
+
};
|
|
1130
|
+
const handle = (block) => {
|
|
1131
|
+
let payload;
|
|
1132
|
+
try {
|
|
1133
|
+
payload = JSON.parse(block.data);
|
|
1134
|
+
} catch {
|
|
1135
|
+
return block.raw;
|
|
1136
|
+
}
|
|
1137
|
+
if (!isObj(payload)) return block.raw;
|
|
1138
|
+
const itemId = typeof payload.item_id === "string" ? payload.item_id : void 0;
|
|
1139
|
+
const textKey = `text:${itemId}:${String(payload.content_index)}`;
|
|
1140
|
+
const summaryKey = `summary:${itemId}:${String(payload.summary_index)}`;
|
|
1141
|
+
const argsKey = `args:${itemId}`;
|
|
1142
|
+
const textStream = () => ctx.transform.inboundStream();
|
|
1143
|
+
const argStream = () => createJsonArgRestorer(() => ctx.transform.inboundStream());
|
|
1144
|
+
switch (payload.type) {
|
|
1145
|
+
case "response.output_text.delta":
|
|
1146
|
+
if (itemId === void 0 || typeof payload.delta !== "string") return block.raw;
|
|
1147
|
+
return formatSseEvent(block.event, {
|
|
1148
|
+
...payload,
|
|
1149
|
+
delta: open(textKey, textStream).restore.push(payload.delta)
|
|
1150
|
+
});
|
|
1151
|
+
case "response.reasoning_summary_text.delta":
|
|
1152
|
+
if (itemId === void 0 || typeof payload.delta !== "string") return block.raw;
|
|
1153
|
+
return formatSseEvent(block.event, {
|
|
1154
|
+
...payload,
|
|
1155
|
+
delta: open(summaryKey, textStream).restore.push(payload.delta)
|
|
1156
|
+
});
|
|
1157
|
+
case "response.function_call_arguments.delta":
|
|
1158
|
+
if (itemId === void 0 || typeof payload.delta !== "string") return block.raw;
|
|
1159
|
+
return formatSseEvent(block.event, {
|
|
1160
|
+
...payload,
|
|
1161
|
+
delta: open(argsKey, argStream).restore.push(payload.delta)
|
|
1162
|
+
});
|
|
1163
|
+
case "response.output_text.done":
|
|
1164
|
+
if (itemId === void 0 || typeof payload.text !== "string") return block.raw;
|
|
1165
|
+
return closeWith(block, payload, textKey, "response.output_text.delta", {
|
|
1166
|
+
...payload,
|
|
1167
|
+
text: ctx.transform.inbound(payload.text)
|
|
1168
|
+
});
|
|
1169
|
+
case "response.reasoning_summary_text.done":
|
|
1170
|
+
if (itemId === void 0 || typeof payload.text !== "string") return block.raw;
|
|
1171
|
+
return closeWith(block, payload, summaryKey, "response.reasoning_summary_text.delta", {
|
|
1172
|
+
...payload,
|
|
1173
|
+
text: ctx.transform.inbound(payload.text)
|
|
1174
|
+
});
|
|
1175
|
+
case "response.function_call_arguments.done":
|
|
1176
|
+
if (itemId === void 0 || typeof payload.arguments !== "string") return block.raw;
|
|
1177
|
+
return closeWith(block, payload, argsKey, "response.function_call_arguments.delta", {
|
|
1178
|
+
...payload,
|
|
1179
|
+
arguments: restoreArguments(payload.arguments, ctx.transform)
|
|
1180
|
+
});
|
|
1181
|
+
case "response.content_part.done": return isObj(payload.part) ? formatSseEvent(block.event, {
|
|
1182
|
+
...payload,
|
|
1183
|
+
part: restorePart(payload.part, ctx.transform)
|
|
1184
|
+
}) : block.raw;
|
|
1185
|
+
case "response.reasoning_summary_part.done": return isObj(payload.part) && typeof payload.part.text === "string" ? formatSseEvent(block.event, {
|
|
1186
|
+
...payload,
|
|
1187
|
+
part: {
|
|
1188
|
+
...payload.part,
|
|
1189
|
+
text: ctx.transform.inbound(payload.part.text)
|
|
1190
|
+
}
|
|
1191
|
+
}) : block.raw;
|
|
1192
|
+
case "response.output_item.done": return isObj(payload.item) ? formatSseEvent(block.event, {
|
|
1193
|
+
...payload,
|
|
1194
|
+
item: restoreItem(payload.item, ctx)
|
|
1195
|
+
}) : block.raw;
|
|
1196
|
+
case "response.completed":
|
|
1197
|
+
case "response.incomplete": return isObj(payload.response) ? formatSseEvent(block.event, {
|
|
1198
|
+
...payload,
|
|
1199
|
+
response: restoreResponse(payload.response, ctx)
|
|
1200
|
+
}) : block.raw;
|
|
1201
|
+
default: return block.raw;
|
|
1202
|
+
}
|
|
1203
|
+
};
|
|
1204
|
+
const finish = () => {
|
|
1205
|
+
let out = "";
|
|
1206
|
+
for (const [key, state] of streams) {
|
|
1207
|
+
const tail = state.restore.flush();
|
|
1208
|
+
if (tail === "") continue;
|
|
1209
|
+
const [kind, itemId] = key.split(":");
|
|
1210
|
+
const type = kind === "text" ? "response.output_text.delta" : kind === "summary" ? "response.reasoning_summary_text.delta" : "response.function_call_arguments.delta";
|
|
1211
|
+
out += formatSseEvent(type, {
|
|
1212
|
+
type,
|
|
1213
|
+
item_id: itemId,
|
|
1214
|
+
delta: tail
|
|
1215
|
+
});
|
|
1216
|
+
}
|
|
1217
|
+
streams.clear();
|
|
1218
|
+
return out;
|
|
1219
|
+
};
|
|
1220
|
+
return createSseFramer(handle, finish);
|
|
1221
|
+
}
|
|
1222
|
+
const openaiResponsesWalker = {
|
|
1223
|
+
async request(body, ctx) {
|
|
1224
|
+
if (!isObj(body)) return body;
|
|
1225
|
+
const out = { ...body };
|
|
1226
|
+
if (typeof body.instructions === "string") out.instructions = await outbound(ctx.transform, body.instructions, { kind: "system" });
|
|
1227
|
+
const instruction = ctx.transform.instruction;
|
|
1228
|
+
if (instruction !== void 0) out.instructions = typeof out.instructions === "string" && out.instructions !== "" ? `${instruction}\n\n${out.instructions}` : instruction;
|
|
1229
|
+
if (typeof body.input === "string") out.input = await outbound(ctx.transform, body.input, { kind: "user" });
|
|
1230
|
+
else if (Array.isArray(body.input)) {
|
|
1231
|
+
const toolNames = toolNamesByCallId(body.input);
|
|
1232
|
+
const input = [];
|
|
1233
|
+
for (const item of body.input) input.push(isObj(item) ? await rewriteItem(item, toolNames, ctx) : item);
|
|
1234
|
+
out.input = input;
|
|
1235
|
+
}
|
|
1236
|
+
return out;
|
|
1237
|
+
},
|
|
1238
|
+
response(body, ctx) {
|
|
1239
|
+
return isObj(body) ? restoreResponse(body, ctx) : body;
|
|
1240
|
+
},
|
|
596
1241
|
stream(ctx) {
|
|
597
1242
|
return createStreamTransformer(ctx);
|
|
598
1243
|
}
|
|
@@ -600,18 +1245,30 @@ const anthropicWalker = {
|
|
|
600
1245
|
// src/routes.ts
|
|
601
1246
|
/**
|
|
602
1247
|
* The route table. Routes are matched in order, so longer suffixes come first.
|
|
603
|
-
*
|
|
604
|
-
* those paths, and embeddings, answer 404 `unsupported_route`.
|
|
1248
|
+
* Any other path, embeddings included, answers 404 `unsupported_route`.
|
|
605
1249
|
*/
|
|
606
|
-
const WIRE_ROUTES = [
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
1250
|
+
const WIRE_ROUTES = [
|
|
1251
|
+
{
|
|
1252
|
+
suffix: "/messages/count_tokens",
|
|
1253
|
+
wire: anthropicWalker,
|
|
1254
|
+
rewriteResponse: false
|
|
1255
|
+
},
|
|
1256
|
+
{
|
|
1257
|
+
suffix: "/messages",
|
|
1258
|
+
wire: anthropicWalker,
|
|
1259
|
+
rewriteResponse: true
|
|
1260
|
+
},
|
|
1261
|
+
{
|
|
1262
|
+
suffix: "/chat/completions",
|
|
1263
|
+
wire: openaiChatWalker,
|
|
1264
|
+
rewriteResponse: true
|
|
1265
|
+
},
|
|
1266
|
+
{
|
|
1267
|
+
suffix: "/responses",
|
|
1268
|
+
wire: openaiResponsesWalker,
|
|
1269
|
+
rewriteResponse: true
|
|
1270
|
+
}
|
|
1271
|
+
];
|
|
615
1272
|
/** Classifies a request by method and path. `undefined` means the route is unsupported. */
|
|
616
1273
|
function classify(method, pathname) {
|
|
617
1274
|
if (method === "GET" && pathname.endsWith("/models")) return { kind: "passthrough" };
|
|
@@ -1057,4 +1714,4 @@ function requireStringList(value, field) {
|
|
|
1057
1714
|
function isRecord(value) {
|
|
1058
1715
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1059
1716
|
}
|
|
1060
|
-
export {
|
|
1717
|
+
export { composeTransforms as _, parseProxyConfig as a, SESSION_HEADER as c, createTransformProxy as d, openaiResponsesWalker as f, createSessionFacts as g, UnsupportedContentError as h, loadProxyConfig as i, TOKEN_HEADER as l, anthropicWalker as m, configCandidates as n, resolveProxyConfig as o, openaiChatWalker as p, findProxyConfig as r, PIPELINE_HEADER as s, CONFIG_FILE_NAME as t, UPSTREAM_HEADER as u, errorMessage as v, silentLogger as y };
|