@node-llm/core 1.6.2 → 1.8.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/README.md +9 -8
- package/dist/aliases.d.ts +215 -0
- package/dist/aliases.d.ts.map +1 -1
- package/dist/aliases.js +241 -26
- package/dist/chat/Chat.d.ts +12 -3
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +35 -5
- package/dist/chat/ChatOptions.d.ts +2 -1
- package/dist/chat/ChatOptions.d.ts.map +1 -1
- package/dist/chat/ChatResponse.d.ts +9 -2
- package/dist/chat/ChatResponse.d.ts.map +1 -1
- package/dist/chat/ChatResponse.js +12 -3
- package/dist/chat/ChatStream.d.ts.map +1 -1
- package/dist/chat/ChatStream.js +15 -1
- package/dist/chat/Content.d.ts +7 -0
- package/dist/chat/Content.d.ts.map +1 -1
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +50 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/llm.d.ts.map +1 -1
- package/dist/llm.js +3 -2
- package/dist/models/models.d.ts +321 -76
- package/dist/models/models.d.ts.map +1 -1
- package/dist/models/models.js +7804 -2885
- package/dist/providers/Provider.d.ts +37 -0
- package/dist/providers/Provider.d.ts.map +1 -1
- package/dist/providers/anthropic/Capabilities.d.ts +1 -0
- package/dist/providers/anthropic/Capabilities.d.ts.map +1 -1
- package/dist/providers/anthropic/Capabilities.js +8 -5
- package/dist/providers/anthropic/Chat.d.ts.map +1 -1
- package/dist/providers/anthropic/Chat.js +23 -1
- package/dist/providers/anthropic/Streaming.d.ts.map +1 -1
- package/dist/providers/anthropic/Streaming.js +15 -0
- package/dist/providers/anthropic/types.d.ts +7 -1
- package/dist/providers/anthropic/types.d.ts.map +1 -1
- package/dist/providers/bedrock/BedrockProvider.d.ts +53 -0
- package/dist/providers/bedrock/BedrockProvider.d.ts.map +1 -0
- package/dist/providers/bedrock/BedrockProvider.js +107 -0
- package/dist/providers/bedrock/Capabilities.d.ts +50 -0
- package/dist/providers/bedrock/Capabilities.d.ts.map +1 -0
- package/dist/providers/bedrock/Capabilities.js +233 -0
- package/dist/providers/bedrock/Chat.d.ts +26 -0
- package/dist/providers/bedrock/Chat.d.ts.map +1 -0
- package/dist/providers/bedrock/Chat.js +170 -0
- package/dist/providers/bedrock/Embeddings.d.ts +22 -0
- package/dist/providers/bedrock/Embeddings.d.ts.map +1 -0
- package/dist/providers/bedrock/Embeddings.js +100 -0
- package/dist/providers/bedrock/Image.d.ts +33 -0
- package/dist/providers/bedrock/Image.d.ts.map +1 -0
- package/dist/providers/bedrock/Image.js +154 -0
- package/dist/providers/bedrock/Models.d.ts +34 -0
- package/dist/providers/bedrock/Models.d.ts.map +1 -0
- package/dist/providers/bedrock/Models.js +131 -0
- package/dist/providers/bedrock/Moderation.d.ts +23 -0
- package/dist/providers/bedrock/Moderation.d.ts.map +1 -0
- package/dist/providers/bedrock/Moderation.js +138 -0
- package/dist/providers/bedrock/Streaming.d.ts +21 -0
- package/dist/providers/bedrock/Streaming.d.ts.map +1 -0
- package/dist/providers/bedrock/Streaming.js +240 -0
- package/dist/providers/bedrock/config.d.ts +57 -0
- package/dist/providers/bedrock/config.d.ts.map +1 -0
- package/dist/providers/bedrock/config.js +33 -0
- package/dist/providers/bedrock/index.d.ts +8 -0
- package/dist/providers/bedrock/index.d.ts.map +1 -0
- package/dist/providers/bedrock/index.js +30 -0
- package/dist/providers/bedrock/mapper.d.ts +37 -0
- package/dist/providers/bedrock/mapper.d.ts.map +1 -0
- package/dist/providers/bedrock/mapper.js +204 -0
- package/dist/providers/bedrock/types.d.ts +179 -0
- package/dist/providers/bedrock/types.d.ts.map +1 -0
- package/dist/providers/bedrock/types.js +7 -0
- package/dist/providers/deepseek/Capabilities.d.ts +3 -2
- package/dist/providers/deepseek/Capabilities.d.ts.map +1 -1
- package/dist/providers/deepseek/Capabilities.js +19 -5
- package/dist/providers/deepseek/Chat.d.ts.map +1 -1
- package/dist/providers/deepseek/Chat.js +9 -2
- package/dist/providers/deepseek/Streaming.d.ts.map +1 -1
- package/dist/providers/deepseek/Streaming.js +3 -2
- package/dist/providers/gemini/Capabilities.d.ts +1 -0
- package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
- package/dist/providers/gemini/Capabilities.js +9 -6
- package/dist/providers/gemini/Chat.d.ts.map +1 -1
- package/dist/providers/gemini/Chat.js +4 -5
- package/dist/providers/gemini/Streaming.d.ts.map +1 -1
- package/dist/providers/gemini/Streaming.js +17 -2
- package/dist/providers/gemini/types.d.ts +4 -0
- package/dist/providers/gemini/types.d.ts.map +1 -1
- package/dist/providers/ollama/Capabilities.d.ts.map +1 -1
- package/dist/providers/ollama/Capabilities.js +4 -1
- package/dist/providers/openai/Capabilities.d.ts +1 -0
- package/dist/providers/openai/Capabilities.d.ts.map +1 -1
- package/dist/providers/openai/Capabilities.js +14 -11
- package/dist/providers/openai/Chat.d.ts.map +1 -1
- package/dist/providers/openai/Chat.js +18 -3
- package/dist/providers/openai/Streaming.d.ts.map +1 -1
- package/dist/providers/openai/Streaming.js +11 -3
- package/dist/providers/registry.d.ts +2 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +2 -1
- package/dist/utils/AwsSigV4.d.ts +51 -0
- package/dist/utils/AwsSigV4.d.ts.map +1 -0
- package/dist/utils/AwsSigV4.js +209 -0
- package/package.json +1 -1
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bedrock Streaming Handler
|
|
3
|
+
*
|
|
4
|
+
* Handles streaming responses from Bedrock ConverseStream API.
|
|
5
|
+
* Parses the AWS EventStream binary format to extract JSON chunks.
|
|
6
|
+
*/
|
|
7
|
+
import { validateBedrockConfig, getBedrockEndpoint } from "./config.js";
|
|
8
|
+
import { signRequest } from "../../utils/AwsSigV4.js";
|
|
9
|
+
import { fetchWithTimeout } from "../../utils/fetch.js";
|
|
10
|
+
import { logger } from "../../utils/logger.js";
|
|
11
|
+
import { buildConverseRequest } from "./mapper.js";
|
|
12
|
+
import { ModelRegistry } from "../../models/ModelRegistry.js";
|
|
13
|
+
export class BedrockStreaming {
|
|
14
|
+
config;
|
|
15
|
+
authMode;
|
|
16
|
+
baseUrl;
|
|
17
|
+
constructor(config) {
|
|
18
|
+
this.config = config;
|
|
19
|
+
this.authMode = validateBedrockConfig(config);
|
|
20
|
+
this.baseUrl = getBedrockEndpoint(config.region);
|
|
21
|
+
}
|
|
22
|
+
async *execute(request, controller) {
|
|
23
|
+
const internalController = new AbortController();
|
|
24
|
+
const abortController = controller || internalController;
|
|
25
|
+
const signal = request.signal ? request.signal : abortController.signal;
|
|
26
|
+
const currentToolCalls = new Map();
|
|
27
|
+
let currentReasoning = "";
|
|
28
|
+
const modelId = request.model;
|
|
29
|
+
const url = `${this.baseUrl}/model/${modelId}/converse-stream`;
|
|
30
|
+
const guardrail = this.config.guardrailIdentifier && this.config.guardrailVersion
|
|
31
|
+
? {
|
|
32
|
+
guardrailIdentifier: this.config.guardrailIdentifier,
|
|
33
|
+
guardrailVersion: this.config.guardrailVersion
|
|
34
|
+
}
|
|
35
|
+
: undefined;
|
|
36
|
+
const body = buildConverseRequest(request.messages, request.tools, {
|
|
37
|
+
maxTokens: request.max_tokens,
|
|
38
|
+
temperature: request.temperature,
|
|
39
|
+
thinking: request.thinking,
|
|
40
|
+
guardrail,
|
|
41
|
+
additionalModelRequestFields: request.additionalModelRequestFields
|
|
42
|
+
});
|
|
43
|
+
const bodyJson = JSON.stringify(body);
|
|
44
|
+
const headers = this.buildHeaders(url, bodyJson, request.headers);
|
|
45
|
+
logger.logRequest("Bedrock", "POST", url, body);
|
|
46
|
+
const response = await fetchWithTimeout(url, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers,
|
|
49
|
+
body: bodyJson,
|
|
50
|
+
signal
|
|
51
|
+
}, request.requestTimeout ?? this.config.requestTimeout);
|
|
52
|
+
if (!response.ok) {
|
|
53
|
+
const errorText = await response.text();
|
|
54
|
+
logger.logResponse("Bedrock", response.status, response.statusText, errorText);
|
|
55
|
+
throw new Error(`Bedrock Streaming Error (${response.status}): ${errorText}`);
|
|
56
|
+
}
|
|
57
|
+
if (!response.body) {
|
|
58
|
+
throw new Error("No response body from Bedrock streaming");
|
|
59
|
+
}
|
|
60
|
+
const reader = response.body.getReader();
|
|
61
|
+
const decoder = new TextDecoder();
|
|
62
|
+
let buffer = new Uint8Array(0);
|
|
63
|
+
try {
|
|
64
|
+
while (true) {
|
|
65
|
+
const { value, done } = await reader.read();
|
|
66
|
+
if (done)
|
|
67
|
+
break;
|
|
68
|
+
// Append new data to buffer
|
|
69
|
+
const newBuffer = new Uint8Array(buffer.length + value.length);
|
|
70
|
+
newBuffer.set(buffer);
|
|
71
|
+
newBuffer.set(value, buffer.length);
|
|
72
|
+
buffer = newBuffer;
|
|
73
|
+
// Parse messages from buffer
|
|
74
|
+
while (buffer.length >= 12) {
|
|
75
|
+
const totalLength = new DataView(buffer.buffer, buffer.byteOffset, 4).getUint32(0);
|
|
76
|
+
if (totalLength < 16 || totalLength > 1024 * 1024) {
|
|
77
|
+
// Safety check: skip if total length is unreasonable
|
|
78
|
+
logger.error(`Bedrock stream: invalid total length ${totalLength}`);
|
|
79
|
+
buffer = buffer.slice(4);
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (buffer.length < totalLength) {
|
|
83
|
+
break; // Wait for more data
|
|
84
|
+
}
|
|
85
|
+
const headersLength = new DataView(buffer.buffer, buffer.byteOffset + 4, 4).getUint32(0);
|
|
86
|
+
if (headersLength + 16 > totalLength) {
|
|
87
|
+
logger.error(`Bedrock stream: invalid headers length ${headersLength} for total length ${totalLength}`);
|
|
88
|
+
buffer = buffer.slice(totalLength);
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
const payloadLength = totalLength - headersLength - 16;
|
|
92
|
+
const payloadOffset = 12 + headersLength;
|
|
93
|
+
const payload = buffer.slice(payloadOffset, payloadOffset + payloadLength);
|
|
94
|
+
const chunkJson = decoder.decode(payload);
|
|
95
|
+
try {
|
|
96
|
+
const event = JSON.parse(chunkJson);
|
|
97
|
+
const chatChunk = this.parseEvent(event, currentToolCalls, (text) => {
|
|
98
|
+
currentReasoning += text;
|
|
99
|
+
}, modelId);
|
|
100
|
+
if (chatChunk) {
|
|
101
|
+
yield chatChunk;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
catch (e) {
|
|
105
|
+
// Might be a binary event or malformed JSON (though Bedrock uses JSON in payload)
|
|
106
|
+
logger.debug("Failed to parse Bedrock event payload", { chunkJson, error: e });
|
|
107
|
+
}
|
|
108
|
+
// Advance buffer
|
|
109
|
+
buffer = buffer.slice(totalLength);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
reader.releaseLock();
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Parse a Bedrock ConverseStream event into a NodeLLM ChatChunk.
|
|
119
|
+
*/
|
|
120
|
+
parseEvent(event, toolCalls, onReasoning, modelId) {
|
|
121
|
+
// Bedrock ConverseStream events can be wrapped or unwrapped depending on model/service version
|
|
122
|
+
const contentBlockStart = event.contentBlockStart;
|
|
123
|
+
const contentBlockDelta = event.contentBlockDelta || (event.delta ? event : null);
|
|
124
|
+
const contentBlockStop = event.contentBlockStop;
|
|
125
|
+
const messageStop = event.messageStop || (event.stopReason ? event : null);
|
|
126
|
+
const metadata = event.metadata || (event.usage ? event : null);
|
|
127
|
+
// 1. Content Block Start (Initialize tools or reasoning)
|
|
128
|
+
if (contentBlockStart) {
|
|
129
|
+
const { contentBlockIndex, start } = contentBlockStart;
|
|
130
|
+
if (start?.toolUse) {
|
|
131
|
+
toolCalls.set(contentBlockIndex, {
|
|
132
|
+
id: start.toolUse.toolUseId,
|
|
133
|
+
name: start.toolUse.name,
|
|
134
|
+
input: ""
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
if (start?.reasoningContent) {
|
|
138
|
+
return { content: "", thinking: { text: "" }, reasoning: "" };
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
// 2. Content Block Delta (Accumulate text, tools, or reasoning)
|
|
142
|
+
if (contentBlockDelta) {
|
|
143
|
+
const delta = contentBlockDelta.delta || contentBlockDelta;
|
|
144
|
+
const contentBlockIndex = contentBlockDelta.contentBlockIndex ?? 0;
|
|
145
|
+
if (delta.text) {
|
|
146
|
+
return { content: delta.text };
|
|
147
|
+
}
|
|
148
|
+
if (delta.reasoningContent?.text) {
|
|
149
|
+
onReasoning(delta.reasoningContent.text);
|
|
150
|
+
return {
|
|
151
|
+
content: "",
|
|
152
|
+
thinking: { text: delta.reasoningContent.text },
|
|
153
|
+
reasoning: delta.reasoningContent.text
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (delta.toolUse) {
|
|
157
|
+
const toolCall = toolCalls.get(contentBlockIndex);
|
|
158
|
+
if (toolCall) {
|
|
159
|
+
toolCall.input += delta.toolUse.input;
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
// 3. Content Block Stop (Finalize tool calls)
|
|
165
|
+
if (contentBlockStop) {
|
|
166
|
+
const { contentBlockIndex } = contentBlockStop;
|
|
167
|
+
const toolCall = toolCalls.get(contentBlockIndex);
|
|
168
|
+
if (toolCall) {
|
|
169
|
+
toolCalls.delete(contentBlockIndex);
|
|
170
|
+
return {
|
|
171
|
+
content: "",
|
|
172
|
+
tool_calls: [
|
|
173
|
+
{
|
|
174
|
+
id: toolCall.id,
|
|
175
|
+
type: "function",
|
|
176
|
+
function: {
|
|
177
|
+
name: toolCall.name,
|
|
178
|
+
arguments: toolCall.input
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 4. Message Stop
|
|
186
|
+
if (event.messageStop) {
|
|
187
|
+
return {
|
|
188
|
+
content: "",
|
|
189
|
+
done: true,
|
|
190
|
+
finish_reason: event.messageStop.stopReason
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
// 5. Metadata (Usage)
|
|
194
|
+
if (event.metadata && event.metadata.usage) {
|
|
195
|
+
const rawUsage = {
|
|
196
|
+
input_tokens: event.metadata.usage.inputTokens,
|
|
197
|
+
output_tokens: event.metadata.usage.outputTokens,
|
|
198
|
+
total_tokens: event.metadata.usage.totalTokens,
|
|
199
|
+
cached_tokens: event.metadata.usage.cacheReadInputTokens,
|
|
200
|
+
cache_creation_tokens: event.metadata.usage.cacheWriteInputTokens
|
|
201
|
+
};
|
|
202
|
+
const usage = ModelRegistry.calculateCost(rawUsage, modelId, "bedrock");
|
|
203
|
+
const metadata = event.metadata.trace ? { trace: event.metadata.trace } : undefined;
|
|
204
|
+
return { content: "", usage, done: true, metadata };
|
|
205
|
+
}
|
|
206
|
+
return null;
|
|
207
|
+
}
|
|
208
|
+
buildHeaders(url, body, additionalHeaders) {
|
|
209
|
+
const headers = {
|
|
210
|
+
"Content-Type": "application/json",
|
|
211
|
+
Accept: "application/json",
|
|
212
|
+
...additionalHeaders
|
|
213
|
+
};
|
|
214
|
+
if (this.authMode === "apiKey") {
|
|
215
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
216
|
+
}
|
|
217
|
+
else {
|
|
218
|
+
const signedHeaders = signRequest({
|
|
219
|
+
method: "POST",
|
|
220
|
+
url,
|
|
221
|
+
body,
|
|
222
|
+
credentials: {
|
|
223
|
+
accessKeyId: this.config.accessKeyId,
|
|
224
|
+
secretAccessKey: this.config.secretAccessKey,
|
|
225
|
+
sessionToken: this.config.sessionToken
|
|
226
|
+
},
|
|
227
|
+
region: this.config.region,
|
|
228
|
+
service: "bedrock"
|
|
229
|
+
});
|
|
230
|
+
headers["host"] = signedHeaders.host;
|
|
231
|
+
headers["x-amz-date"] = signedHeaders["x-amz-date"];
|
|
232
|
+
headers["x-amz-content-sha256"] = signedHeaders["x-amz-content-sha256"];
|
|
233
|
+
headers["Authorization"] = signedHeaders.authorization;
|
|
234
|
+
if (signedHeaders["x-amz-security-token"]) {
|
|
235
|
+
headers["x-amz-security-token"] = signedHeaders["x-amz-security-token"];
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return headers;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Bedrock Provider Configuration
|
|
3
|
+
*
|
|
4
|
+
* Supports two authentication modes:
|
|
5
|
+
* 1. API Key (Bearer token) - Simplest, for long-term API keys
|
|
6
|
+
* 2. SigV4 (IAM credentials) - For EC2/ECS/Lambda with IAM roles
|
|
7
|
+
*/
|
|
8
|
+
export interface BedrockConfig {
|
|
9
|
+
/**
|
|
10
|
+
* AWS Region where Bedrock is enabled.
|
|
11
|
+
* Example: "us-east-1", "us-west-2"
|
|
12
|
+
*/
|
|
13
|
+
region: string;
|
|
14
|
+
/**
|
|
15
|
+
* Long-term API key generated from AWS Bedrock console.
|
|
16
|
+
* When provided, uses simple Bearer token authentication.
|
|
17
|
+
* Mutually exclusive with accessKeyId/secretAccessKey.
|
|
18
|
+
*/
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
/**
|
|
21
|
+
* AWS Access Key ID.
|
|
22
|
+
* Required when using SigV4 authentication (no apiKey).
|
|
23
|
+
*/
|
|
24
|
+
accessKeyId?: string;
|
|
25
|
+
/**
|
|
26
|
+
* AWS Secret Access Key.
|
|
27
|
+
* Required when using SigV4 authentication (no apiKey).
|
|
28
|
+
*/
|
|
29
|
+
secretAccessKey?: string;
|
|
30
|
+
/**
|
|
31
|
+
* AWS Session Token (optional).
|
|
32
|
+
* Required for temporary credentials from STS, SSO, or assumed roles.
|
|
33
|
+
*/
|
|
34
|
+
sessionToken?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Request timeout in milliseconds.
|
|
37
|
+
* Default: 120000 (2 minutes)
|
|
38
|
+
*/
|
|
39
|
+
requestTimeout?: number;
|
|
40
|
+
/**
|
|
41
|
+
* Default Bedrock Guardrail identifier (ID or ARN).
|
|
42
|
+
*/
|
|
43
|
+
guardrailIdentifier?: string;
|
|
44
|
+
/**
|
|
45
|
+
* Default Bedrock Guardrail version (e.g., "1", "DRAFT").
|
|
46
|
+
*/
|
|
47
|
+
guardrailVersion?: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Validates the configuration and determines the auth mode.
|
|
51
|
+
*/
|
|
52
|
+
export declare function validateBedrockConfig(config: BedrockConfig): "apiKey" | "sigv4";
|
|
53
|
+
/**
|
|
54
|
+
* Build the Bedrock Runtime endpoint URL for a given region.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getBedrockEndpoint(region: string): string;
|
|
57
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/providers/bedrock/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IAKf;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAKhB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAKtB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,GAAG,OAAO,CAuB/E;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEzD"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AWS Bedrock Provider Configuration
|
|
3
|
+
*
|
|
4
|
+
* Supports two authentication modes:
|
|
5
|
+
* 1. API Key (Bearer token) - Simplest, for long-term API keys
|
|
6
|
+
* 2. SigV4 (IAM credentials) - For EC2/ECS/Lambda with IAM roles
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Validates the configuration and determines the auth mode.
|
|
10
|
+
*/
|
|
11
|
+
export function validateBedrockConfig(config) {
|
|
12
|
+
if (!config.region) {
|
|
13
|
+
throw new Error("BedrockConfig: region is required");
|
|
14
|
+
}
|
|
15
|
+
const hasApiKey = !!config.apiKey;
|
|
16
|
+
const hasSigV4 = !!(config.accessKeyId && config.secretAccessKey);
|
|
17
|
+
if (hasApiKey && hasSigV4) {
|
|
18
|
+
throw new Error("BedrockConfig: provide either apiKey OR accessKeyId/secretAccessKey, not both");
|
|
19
|
+
}
|
|
20
|
+
if (hasApiKey) {
|
|
21
|
+
return "apiKey";
|
|
22
|
+
}
|
|
23
|
+
if (hasSigV4) {
|
|
24
|
+
return "sigv4";
|
|
25
|
+
}
|
|
26
|
+
throw new Error("BedrockConfig: provide either apiKey OR accessKeyId/secretAccessKey");
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Build the Bedrock Runtime endpoint URL for a given region.
|
|
30
|
+
*/
|
|
31
|
+
export function getBedrockEndpoint(region) {
|
|
32
|
+
return `https://bedrock-runtime.${region}.amazonaws.com`;
|
|
33
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bedrock Provider - Public Exports
|
|
3
|
+
*/
|
|
4
|
+
export declare function registerBedrockProvider(): void;
|
|
5
|
+
export { BedrockProvider, BedrockConfig } from "./BedrockProvider.js";
|
|
6
|
+
export { BedrockChat } from "./Chat.js";
|
|
7
|
+
export * from "./types.js";
|
|
8
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/bedrock/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,wBAAgB,uBAAuB,SAuBtC;AAED,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,cAAc,YAAY,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bedrock Provider - Public Exports
|
|
3
|
+
*/
|
|
4
|
+
import { config as globalConfig } from "../../config.js";
|
|
5
|
+
import { providerRegistry } from "../registry.js";
|
|
6
|
+
import { BedrockProvider } from "./BedrockProvider.js";
|
|
7
|
+
export function registerBedrockProvider() {
|
|
8
|
+
providerRegistry.register("bedrock", (config) => {
|
|
9
|
+
const cfg = config || globalConfig;
|
|
10
|
+
const region = cfg.bedrockRegion;
|
|
11
|
+
if (!region) {
|
|
12
|
+
throw new Error("bedrockRegion is not set in config or AWS_REGION environment variable");
|
|
13
|
+
}
|
|
14
|
+
// Pass all available credentials to the provider.
|
|
15
|
+
// BedrockProvider.validateBedrockConfig will ensure they are mutually exclusive.
|
|
16
|
+
const bedrockConfig = {
|
|
17
|
+
region,
|
|
18
|
+
apiKey: cfg.bedrockApiKey,
|
|
19
|
+
accessKeyId: cfg.bedrockAccessKeyId,
|
|
20
|
+
secretAccessKey: cfg.bedrockSecretAccessKey,
|
|
21
|
+
sessionToken: cfg.bedrockSessionToken,
|
|
22
|
+
guardrailIdentifier: cfg.bedrockGuardrailIdentifier,
|
|
23
|
+
guardrailVersion: cfg.bedrockGuardrailVersion
|
|
24
|
+
};
|
|
25
|
+
return new BedrockProvider(bedrockConfig);
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export { BedrockProvider } from "./BedrockProvider.js";
|
|
29
|
+
export { BedrockChat } from "./Chat.js";
|
|
30
|
+
export * from "./types.js";
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bedrock Message Mapper
|
|
3
|
+
*
|
|
4
|
+
* Converts NodeLLM messages to Bedrock Converse API format.
|
|
5
|
+
* Handles system messages, tool calls, and content blocks.
|
|
6
|
+
*/
|
|
7
|
+
import { Message } from "../../chat/Message.js";
|
|
8
|
+
import { ToolDefinition } from "../../chat/Tool.js";
|
|
9
|
+
import { BedrockMessage, BedrockContentBlock, BedrockConverseRequest, BedrockToolConfig } from "./types.js";
|
|
10
|
+
import { ThinkingConfig } from "../../providers/Provider.js";
|
|
11
|
+
/**
|
|
12
|
+
* Convert NodeLLM messages to Bedrock Converse format.
|
|
13
|
+
* Extracts system messages to the top-level system field.
|
|
14
|
+
*/
|
|
15
|
+
export declare function convertMessages(messages: Message[]): {
|
|
16
|
+
messages: BedrockMessage[];
|
|
17
|
+
system?: BedrockContentBlock[];
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Convert NodeLLM tool definitions to Bedrock tool config.
|
|
21
|
+
*/
|
|
22
|
+
export declare function convertTools(tools?: ToolDefinition[]): BedrockToolConfig | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* Build a complete Bedrock Converse request from NodeLLM ChatRequest.
|
|
25
|
+
*/
|
|
26
|
+
export declare function buildConverseRequest(messages: Message[], tools?: ToolDefinition[], options?: {
|
|
27
|
+
maxTokens?: number;
|
|
28
|
+
temperature?: number;
|
|
29
|
+
thinking?: ThinkingConfig;
|
|
30
|
+
guardrail?: {
|
|
31
|
+
guardrailIdentifier: string;
|
|
32
|
+
guardrailVersion: string;
|
|
33
|
+
trace?: "enabled" | "disabled";
|
|
34
|
+
};
|
|
35
|
+
additionalModelRequestFields?: Record<string, any>;
|
|
36
|
+
}): BedrockConverseRequest;
|
|
37
|
+
//# sourceMappingURL=mapper.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mapper.d.ts","sourceRoot":"","sources":["../../../src/providers/bedrock/mapper.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,sBAAsB,EACtB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAiD7D;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG;IACpD,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,MAAM,CAAC,EAAE,mBAAmB,EAAE,CAAC;CAChC,CAuFA;AAMD;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,CAAC,EAAE,cAAc,EAAE,GAAG,iBAAiB,GAAG,SAAS,CAgBpF;AAMD;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,CAAC,EAAE,cAAc,EAAE,EACxB,OAAO,CAAC,EAAE;IACR,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,SAAS,CAAC,EAAE;QACV,mBAAmB,EAAE,MAAM,CAAC;QAC5B,gBAAgB,EAAE,MAAM,CAAC;QACzB,KAAK,CAAC,EAAE,SAAS,GAAG,UAAU,CAAC;KAChC,CAAC;IACF,4BAA4B,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CACpD,GACA,sBAAsB,CAmDxB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bedrock Message Mapper
|
|
3
|
+
*
|
|
4
|
+
* Converts NodeLLM messages to Bedrock Converse API format.
|
|
5
|
+
* Handles system messages, tool calls, and content blocks.
|
|
6
|
+
*/
|
|
7
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
8
|
+
// Message Conversion
|
|
9
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
10
|
+
/**
|
|
11
|
+
* Convert a NodeLLM message to Bedrock content blocks.
|
|
12
|
+
*/
|
|
13
|
+
function messageContentToBlocks(content) {
|
|
14
|
+
if (typeof content === "string") {
|
|
15
|
+
return content ? [{ text: content }] : [];
|
|
16
|
+
}
|
|
17
|
+
if (Array.isArray(content)) {
|
|
18
|
+
const blocks = [];
|
|
19
|
+
for (const part of content) {
|
|
20
|
+
if (part.type === "text") {
|
|
21
|
+
const block = { text: part.text };
|
|
22
|
+
blocks.push(block);
|
|
23
|
+
if (part.cache_control?.type === "ephemeral") {
|
|
24
|
+
blocks.push({ cachePoint: { type: "default" } });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
else if (part.type === "image_url" && part.image_url) {
|
|
28
|
+
// Extract base64 data from data URL
|
|
29
|
+
const match = part.image_url.url.match(/^data:image\/(\w+);base64,(.+)$/);
|
|
30
|
+
if (match && match[1] && match[2]) {
|
|
31
|
+
blocks.push({
|
|
32
|
+
image: {
|
|
33
|
+
format: match[1].replace("jpg", "jpeg"),
|
|
34
|
+
source: { bytes: match[2] }
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
// Fallback if not a data URL or missing base64
|
|
40
|
+
blocks.push({ text: `[Image: ${part.image_url.url}]` });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
// Default to empty text for unsupported types
|
|
45
|
+
blocks.push({ text: "" });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return blocks.filter((b) => b.text !== "");
|
|
49
|
+
}
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Convert NodeLLM messages to Bedrock Converse format.
|
|
54
|
+
* Extracts system messages to the top-level system field.
|
|
55
|
+
*/
|
|
56
|
+
export function convertMessages(messages) {
|
|
57
|
+
const systemBlocks = [];
|
|
58
|
+
const bedrockMessages = [];
|
|
59
|
+
let currentToolResults = [];
|
|
60
|
+
const flushToolResults = () => {
|
|
61
|
+
if (currentToolResults.length > 0) {
|
|
62
|
+
bedrockMessages.push({
|
|
63
|
+
role: "user",
|
|
64
|
+
content: currentToolResults
|
|
65
|
+
});
|
|
66
|
+
currentToolResults = [];
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
for (const msg of messages) {
|
|
70
|
+
if (msg.role !== "tool") {
|
|
71
|
+
flushToolResults();
|
|
72
|
+
}
|
|
73
|
+
// System messages go to the top-level system field
|
|
74
|
+
if (msg.role === "system") {
|
|
75
|
+
const blocks = messageContentToBlocks(msg.content);
|
|
76
|
+
systemBlocks.push(...blocks);
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
// User messages
|
|
80
|
+
if (msg.role === "user") {
|
|
81
|
+
bedrockMessages.push({
|
|
82
|
+
role: "user",
|
|
83
|
+
content: messageContentToBlocks(msg.content)
|
|
84
|
+
});
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
// Assistant messages (may include tool calls and reasoning)
|
|
88
|
+
if (msg.role === "assistant") {
|
|
89
|
+
const contentBlocks = messageContentToBlocks(msg.content);
|
|
90
|
+
// Add reasoning content if present
|
|
91
|
+
if (msg.reasoning) {
|
|
92
|
+
contentBlocks.unshift({
|
|
93
|
+
reasoningContent: {
|
|
94
|
+
text: msg.reasoning
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
// Add tool use blocks if present
|
|
99
|
+
if (msg.tool_calls) {
|
|
100
|
+
for (const toolCall of msg.tool_calls) {
|
|
101
|
+
contentBlocks.push({
|
|
102
|
+
toolUse: {
|
|
103
|
+
toolUseId: toolCall.id,
|
|
104
|
+
name: toolCall.function.name,
|
|
105
|
+
input: JSON.parse(toolCall.function.arguments || "{}")
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
bedrockMessages.push({
|
|
111
|
+
role: "assistant",
|
|
112
|
+
content: contentBlocks
|
|
113
|
+
});
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
// Tool result messages
|
|
117
|
+
if (msg.role === "tool") {
|
|
118
|
+
currentToolResults.push({
|
|
119
|
+
toolResult: {
|
|
120
|
+
toolUseId: msg.tool_call_id || "",
|
|
121
|
+
content: [{ text: typeof msg.content === "string" ? msg.content : "" }],
|
|
122
|
+
status: msg.isError ? "error" : "success"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
flushToolResults();
|
|
128
|
+
return {
|
|
129
|
+
messages: bedrockMessages,
|
|
130
|
+
system: systemBlocks.length > 0 ? systemBlocks : undefined
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
134
|
+
// Tool Conversion
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
/**
|
|
137
|
+
* Convert NodeLLM tool definitions to Bedrock tool config.
|
|
138
|
+
*/
|
|
139
|
+
export function convertTools(tools) {
|
|
140
|
+
if (!tools || tools.length === 0) {
|
|
141
|
+
return undefined;
|
|
142
|
+
}
|
|
143
|
+
return {
|
|
144
|
+
tools: tools.map((tool) => ({
|
|
145
|
+
toolSpec: {
|
|
146
|
+
name: tool.function.name,
|
|
147
|
+
description: tool.function.description,
|
|
148
|
+
inputSchema: {
|
|
149
|
+
json: tool.function.parameters || {}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}))
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
156
|
+
// Request Builder
|
|
157
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
158
|
+
/**
|
|
159
|
+
* Build a complete Bedrock Converse request from NodeLLM ChatRequest.
|
|
160
|
+
*/
|
|
161
|
+
export function buildConverseRequest(messages, tools, options) {
|
|
162
|
+
const { messages: bedrockMessages, system } = convertMessages(messages);
|
|
163
|
+
const request = {
|
|
164
|
+
messages: bedrockMessages
|
|
165
|
+
};
|
|
166
|
+
if (system) {
|
|
167
|
+
request.system = system;
|
|
168
|
+
}
|
|
169
|
+
const toolConfig = convertTools(tools);
|
|
170
|
+
if (toolConfig) {
|
|
171
|
+
request.toolConfig = toolConfig;
|
|
172
|
+
}
|
|
173
|
+
if (options?.guardrail) {
|
|
174
|
+
request.guardrailConfig = options.guardrail;
|
|
175
|
+
}
|
|
176
|
+
// Inference config (only add if we have values)
|
|
177
|
+
if (options?.maxTokens || options?.temperature !== undefined) {
|
|
178
|
+
request.inferenceConfig = {};
|
|
179
|
+
if (options.maxTokens) {
|
|
180
|
+
request.inferenceConfig.maxTokens = options.maxTokens;
|
|
181
|
+
}
|
|
182
|
+
if (options.temperature !== undefined) {
|
|
183
|
+
request.inferenceConfig.temperature = options.temperature;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
// Thinking config for Claude 3.7+
|
|
187
|
+
if (options?.thinking?.budget) {
|
|
188
|
+
request.additionalModelRequestFields = {
|
|
189
|
+
...request.additionalModelRequestFields,
|
|
190
|
+
thinking: {
|
|
191
|
+
type: "enabled",
|
|
192
|
+
budget_tokens: options.thinking.budget
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
// Merge any other additional fields
|
|
197
|
+
if (options?.additionalModelRequestFields) {
|
|
198
|
+
request.additionalModelRequestFields = {
|
|
199
|
+
...request.additionalModelRequestFields,
|
|
200
|
+
...options.additionalModelRequestFields
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return request;
|
|
204
|
+
}
|