@velum-labs/routekit-gateway 0.18.4 → 0.18.5
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/bedrock-source.d.ts
CHANGED
|
@@ -14,9 +14,13 @@ export type BedrockProviderSourceOptions = {
|
|
|
14
14
|
export declare const BEDROCK_OPENAI_ALLOWLIST: readonly ["openai.gpt-5.4", "openai.gpt-5.5", "openai.gpt-5.6-sol", "openai.gpt-5.6-terra", "openai.gpt-5.6-luna"];
|
|
15
15
|
export declare function isBedrockOpenAiModel(modelId: string): boolean;
|
|
16
16
|
/**
|
|
17
|
-
* Codex
|
|
18
|
-
*
|
|
19
|
-
*
|
|
17
|
+
* Codex talks to RouteKit as OpenAI-compatible, so it sends OpenAI/Codex
|
|
18
|
+
* protocol items that Bedrock mantle rejects. Native OpenAI is unchanged.
|
|
19
|
+
*
|
|
20
|
+
* - `search_content_types` on `web_search*`
|
|
21
|
+
* - `agent_message` (Codex 0.147 subagent handoff)
|
|
22
|
+
* - `encrypted_content` content parts (same 400 as `agent_message`)
|
|
23
|
+
* - `compaction` / `reasoning` encrypted blobs without `rsn_` / `smry_`
|
|
20
24
|
*/
|
|
21
25
|
export declare function sanitizeBedrockMantleRequestBody(body: unknown): unknown;
|
|
22
26
|
export declare function toBedrockConverseInput(body: unknown): ConverseCommandInput;
|
package/dist/bedrock-source.js
CHANGED
|
@@ -15,27 +15,93 @@ export function isBedrockOpenAiModel(modelId) {
|
|
|
15
15
|
return BEDROCK_OPENAI_MODEL.test(modelId);
|
|
16
16
|
}
|
|
17
17
|
/**
|
|
18
|
-
* Codex
|
|
19
|
-
*
|
|
20
|
-
*
|
|
18
|
+
* Codex talks to RouteKit as OpenAI-compatible, so it sends OpenAI/Codex
|
|
19
|
+
* protocol items that Bedrock mantle rejects. Native OpenAI is unchanged.
|
|
20
|
+
*
|
|
21
|
+
* - `search_content_types` on `web_search*`
|
|
22
|
+
* - `agent_message` (Codex 0.147 subagent handoff)
|
|
23
|
+
* - `encrypted_content` content parts (same 400 as `agent_message`)
|
|
24
|
+
* - `compaction` / `reasoning` encrypted blobs without `rsn_` / `smry_`
|
|
21
25
|
*/
|
|
22
26
|
export function sanitizeBedrockMantleRequestBody(body) {
|
|
23
27
|
const payload = record(body);
|
|
24
|
-
if (payload === undefined
|
|
28
|
+
if (payload === undefined)
|
|
25
29
|
return body;
|
|
30
|
+
let next = payload;
|
|
26
31
|
let changed = false;
|
|
27
|
-
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
if (Array.isArray(payload.tools)) {
|
|
33
|
+
const tools = payload.tools.map((tool) => {
|
|
34
|
+
const entry = record(tool);
|
|
35
|
+
if (entry === undefined)
|
|
36
|
+
return tool;
|
|
37
|
+
const type = typeof entry.type === "string" ? entry.type : "";
|
|
38
|
+
if (!type.startsWith("web_search") || !("search_content_types" in entry))
|
|
39
|
+
return tool;
|
|
40
|
+
changed = true;
|
|
41
|
+
const { search_content_types: _ignored, ...rest } = entry;
|
|
42
|
+
return rest;
|
|
43
|
+
});
|
|
44
|
+
if (changed)
|
|
45
|
+
next = { ...next, tools };
|
|
46
|
+
}
|
|
47
|
+
if (Array.isArray(payload.input)) {
|
|
48
|
+
const input = [];
|
|
49
|
+
let inputChanged = false;
|
|
50
|
+
for (const item of payload.input) {
|
|
51
|
+
const sanitized = sanitizeBedrockMantleInputItem(item);
|
|
52
|
+
if (sanitized === undefined) {
|
|
53
|
+
inputChanged = true;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (sanitized !== item)
|
|
57
|
+
inputChanged = true;
|
|
58
|
+
input.push(sanitized);
|
|
59
|
+
}
|
|
60
|
+
if (inputChanged) {
|
|
61
|
+
changed = true;
|
|
62
|
+
next = { ...next, input };
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return changed ? next : body;
|
|
66
|
+
}
|
|
67
|
+
function recognizedEncryptedPrefix(value) {
|
|
68
|
+
return typeof value === "string" && (value.startsWith("rsn_") || value.startsWith("smry_"));
|
|
69
|
+
}
|
|
70
|
+
function sanitizeBedrockMantleContent(content) {
|
|
71
|
+
if (!Array.isArray(content))
|
|
72
|
+
return { content, changed: false };
|
|
73
|
+
const parts = content.filter((part) => record(part)?.type !== "encrypted_content");
|
|
74
|
+
return { content: parts, changed: parts.length !== content.length };
|
|
75
|
+
}
|
|
76
|
+
function sanitizeBedrockMantleInputItem(item) {
|
|
77
|
+
const entry = record(item);
|
|
78
|
+
if (entry === undefined)
|
|
79
|
+
return item;
|
|
80
|
+
const type = typeof entry.type === "string" ? entry.type : "";
|
|
81
|
+
if (type === "compaction" && "encrypted_content" in entry && !recognizedEncryptedPrefix(entry.encrypted_content)) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
if (type === "agent_message") {
|
|
85
|
+
const { content } = sanitizeBedrockMantleContent(entry.content);
|
|
86
|
+
return { type: "message", role: "user", content };
|
|
87
|
+
}
|
|
88
|
+
let next = entry;
|
|
89
|
+
let changed = false;
|
|
90
|
+
if (Array.isArray(entry.content)) {
|
|
91
|
+
const sanitized = sanitizeBedrockMantleContent(entry.content);
|
|
92
|
+
if (sanitized.changed) {
|
|
93
|
+
next = { ...next, content: sanitized.content };
|
|
94
|
+
changed = true;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (type === "reasoning" &&
|
|
98
|
+
"encrypted_content" in next &&
|
|
99
|
+
!recognizedEncryptedPrefix(next.encrypted_content)) {
|
|
100
|
+
const { encrypted_content: _ignored, ...rest } = next;
|
|
101
|
+
next = rest;
|
|
34
102
|
changed = true;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
return changed ? { ...payload, tools } : body;
|
|
103
|
+
}
|
|
104
|
+
return changed ? next : item;
|
|
39
105
|
}
|
|
40
106
|
function mantleApiKey(env) {
|
|
41
107
|
const key = env.AWS_BEARER_TOKEN_BEDROCK ?? env.BEDROCK_API_KEY;
|
|
@@ -523,6 +523,48 @@ test("sanitizeBedrockMantleRequestBody strips search_content_types from web_sear
|
|
|
523
523
|
const untouched = { model: "openai.gpt-5.6-sol", tools: [{ type: "web_search" }] };
|
|
524
524
|
assert.equal(sanitizeBedrockMantleRequestBody(untouched), untouched);
|
|
525
525
|
});
|
|
526
|
+
test("sanitizeBedrockMantleRequestBody rewrites Codex agent_message and drops encrypted_content", () => {
|
|
527
|
+
const body = {
|
|
528
|
+
model: "openai.gpt-5.6-sol",
|
|
529
|
+
input: [
|
|
530
|
+
{
|
|
531
|
+
type: "agent_message",
|
|
532
|
+
author: "/root",
|
|
533
|
+
recipient: "/root/package_architecture",
|
|
534
|
+
content: [
|
|
535
|
+
{ type: "input_text", text: "Reply with exactly PONG" },
|
|
536
|
+
{ type: "encrypted_content", encrypted_content: " " }
|
|
537
|
+
]
|
|
538
|
+
},
|
|
539
|
+
{
|
|
540
|
+
type: "message",
|
|
541
|
+
role: "user",
|
|
542
|
+
content: [
|
|
543
|
+
{ type: "input_text", text: "keep" },
|
|
544
|
+
{ type: "encrypted_content", encrypted_content: " " }
|
|
545
|
+
]
|
|
546
|
+
},
|
|
547
|
+
{ type: "compaction", encrypted_content: "not-a-prefix" },
|
|
548
|
+
{ type: "reasoning", encrypted_content: "rsn_ok", summary: [] }
|
|
549
|
+
]
|
|
550
|
+
};
|
|
551
|
+
assert.deepEqual(sanitizeBedrockMantleRequestBody(body), {
|
|
552
|
+
model: "openai.gpt-5.6-sol",
|
|
553
|
+
input: [
|
|
554
|
+
{
|
|
555
|
+
type: "message",
|
|
556
|
+
role: "user",
|
|
557
|
+
content: [{ type: "input_text", text: "Reply with exactly PONG" }]
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
type: "message",
|
|
561
|
+
role: "user",
|
|
562
|
+
content: [{ type: "input_text", text: "keep" }]
|
|
563
|
+
},
|
|
564
|
+
{ type: "reasoning", encrypted_content: "rsn_ok", summary: [] }
|
|
565
|
+
]
|
|
566
|
+
});
|
|
567
|
+
});
|
|
526
568
|
test("Bedrock mantle Responses drops Codex search_content_types before egress", async () => {
|
|
527
569
|
const forwarded = [];
|
|
528
570
|
const source = new BedrockProviderSource({
|
|
@@ -551,6 +593,40 @@ test("Bedrock mantle Responses drops Codex search_content_types before egress",
|
|
|
551
593
|
}
|
|
552
594
|
]);
|
|
553
595
|
});
|
|
596
|
+
test("Bedrock mantle Responses rewrites Codex agent_message before egress", async () => {
|
|
597
|
+
const forwarded = [];
|
|
598
|
+
const source = new BedrockProviderSource({
|
|
599
|
+
env: { AWS_BEARER_TOKEN_BEDROCK: "bedrock-key", AWS_REGION: "us-east-1" },
|
|
600
|
+
controlClient: { send: async () => ({}) },
|
|
601
|
+
runtimeClient: { send: async () => ({}) },
|
|
602
|
+
mantleBackend: {
|
|
603
|
+
chat: async () => Response.json({}),
|
|
604
|
+
responses: async (body) => {
|
|
605
|
+
forwarded.push(body);
|
|
606
|
+
return Response.json({ id: "resp" });
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
const response = await source.responses({
|
|
611
|
+
model: "openai.gpt-5.6-sol",
|
|
612
|
+
input: [{
|
|
613
|
+
type: "agent_message",
|
|
614
|
+
author: "/root",
|
|
615
|
+
recipient: "/root/async_lifecycle",
|
|
616
|
+
content: [
|
|
617
|
+
{ type: "input_text", text: "hi" },
|
|
618
|
+
{ type: "encrypted_content", encrypted_content: " " }
|
|
619
|
+
]
|
|
620
|
+
}]
|
|
621
|
+
});
|
|
622
|
+
assert.equal(response.status, 200);
|
|
623
|
+
assert.deepEqual(forwarded, [
|
|
624
|
+
{
|
|
625
|
+
model: "openai.gpt-5.6-sol",
|
|
626
|
+
input: [{ type: "message", role: "user", content: [{ type: "input_text", text: "hi" }] }]
|
|
627
|
+
}
|
|
628
|
+
]);
|
|
629
|
+
});
|
|
554
630
|
test("Bedrock OpenAI chat without a mantle key returns 400 and does not call Converse", async () => {
|
|
555
631
|
const runtimeCalls = [];
|
|
556
632
|
const source = new BedrockProviderSource({
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velum-labs/routekit-gateway",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.18.
|
|
4
|
+
"version": "0.18.5",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
7
7
|
"url": "git+https://github.com/velum-labs/routekit.git",
|
|
@@ -29,10 +29,10 @@
|
|
|
29
29
|
"@aws-sdk/client-bedrock": "3.1095.0",
|
|
30
30
|
"@aws-sdk/client-bedrock-runtime": "3.1095.0",
|
|
31
31
|
"zod": "4.4.3",
|
|
32
|
-
"@velum-labs/routekit-contracts": "0.18.
|
|
33
|
-
"@velum-labs/routekit-registry": "0.18.
|
|
34
|
-
"@velum-labs/routekit-runtime": "0.18.
|
|
35
|
-
"@velum-labs/routekit-tracing": "0.18.
|
|
32
|
+
"@velum-labs/routekit-contracts": "0.18.5",
|
|
33
|
+
"@velum-labs/routekit-registry": "0.18.5",
|
|
34
|
+
"@velum-labs/routekit-runtime": "0.18.5",
|
|
35
|
+
"@velum-labs/routekit-tracing": "0.18.5"
|
|
36
36
|
},
|
|
37
37
|
"keywords": [
|
|
38
38
|
"routekit",
|