@animalabs/membrane 0.5.4 → 0.5.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.
@@ -0,0 +1,43 @@
1
+ /**
2
+ * AWS Bedrock provider adapter for Anthropic Claude models
3
+ *
4
+ * Uses the Anthropic Messages API format through AWS Bedrock.
5
+ */
6
+ import type { ProviderAdapter, ProviderRequest, ProviderRequestOptions, ProviderResponse, StreamCallbacks } from '../types/index.js';
7
+ export interface BedrockAdapterConfig {
8
+ /** AWS access key ID */
9
+ accessKeyId?: string;
10
+ /** AWS secret access key */
11
+ secretAccessKey?: string;
12
+ /** AWS region (defaults to us-west-2) */
13
+ region?: string;
14
+ /** AWS session token (for temporary credentials) */
15
+ sessionToken?: string;
16
+ /** Default max tokens */
17
+ defaultMaxTokens?: number;
18
+ /** Anthropic API version header (defaults to 2023-06-01) */
19
+ anthropicVersion?: string;
20
+ }
21
+ export declare class BedrockAdapter implements ProviderAdapter {
22
+ readonly name = "bedrock";
23
+ private accessKeyId;
24
+ private secretAccessKey;
25
+ private sessionToken?;
26
+ private region;
27
+ private defaultMaxTokens;
28
+ private anthropicVersion;
29
+ constructor(config?: BedrockAdapterConfig);
30
+ supportsModel(modelId: string): boolean;
31
+ /**
32
+ * Convert a standard Claude model ID to Bedrock format if needed
33
+ */
34
+ private toBedrockModelId;
35
+ complete(request: ProviderRequest, options?: ProviderRequestOptions): Promise<ProviderResponse>;
36
+ stream(request: ProviderRequest, callbacks: StreamCallbacks, options?: ProviderRequestOptions): Promise<ProviderResponse>;
37
+ private buildRequest;
38
+ private invokeModel;
39
+ private invokeModelWithStream;
40
+ private parseResponse;
41
+ private handleError;
42
+ }
43
+ //# sourceMappingURL=bedrock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bedrock.d.ts","sourceRoot":"","sources":["../../src/providers/bedrock.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,eAAe,EAEhB,MAAM,mBAAmB,CAAC;AAc3B,MAAM,WAAW,oBAAoB;IACnC,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,4BAA4B;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,yCAAyC;IACzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB,yBAAyB;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA8LD,qBAAa,cAAe,YAAW,eAAe;IACpD,QAAQ,CAAC,IAAI,aAAa;IAE1B,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,eAAe,CAAS;IAChC,OAAO,CAAC,YAAY,CAAC,CAAS;IAC9B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,gBAAgB,CAAS;gBAErB,MAAM,GAAE,oBAAyB;IAa7C,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKvC;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAwBlB,QAAQ,CACZ,OAAO,EAAE,eAAe,EACxB,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;IActB,MAAM,CACV,OAAO,EAAE,eAAe,EACxB,SAAS,EAAE,eAAe,EAC1B,OAAO,CAAC,EAAE,sBAAsB,GAC/B,OAAO,CAAC,gBAAgB,CAAC;IAa5B,OAAO,CAAC,YAAY;YAsCN,WAAW;YA0CX,qBAAqB;IAwLnC,OAAO,CAAC,aAAa;IAsCrB,OAAO,CAAC,WAAW;CAkCpB"}
@@ -0,0 +1,443 @@
1
+ /**
2
+ * AWS Bedrock provider adapter for Anthropic Claude models
3
+ *
4
+ * Uses the Anthropic Messages API format through AWS Bedrock.
5
+ */
6
+ import { MembraneError, rateLimitError, contextLengthError, authError, serverError, abortError, } from '../types/index.js';
7
+ // ============================================================================
8
+ // AWS Signature V4 Implementation
9
+ // ============================================================================
10
+ async function hmacSha256(key, data) {
11
+ const cryptoKey = await crypto.subtle.importKey('raw', key, { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
12
+ return crypto.subtle.sign('HMAC', cryptoKey, new TextEncoder().encode(data));
13
+ }
14
+ async function sha256(data) {
15
+ const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
16
+ return Array.from(new Uint8Array(hash))
17
+ .map(b => b.toString(16).padStart(2, '0'))
18
+ .join('');
19
+ }
20
+ async function getSignatureKey(secretKey, dateStamp, region, service) {
21
+ const kDate = await hmacSha256(new TextEncoder().encode('AWS4' + secretKey), dateStamp);
22
+ const kRegion = await hmacSha256(kDate, region);
23
+ const kService = await hmacSha256(kRegion, service);
24
+ return hmacSha256(kService, 'aws4_request');
25
+ }
26
+ function getAmzDate() {
27
+ const now = new Date();
28
+ const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
29
+ const dateStamp = amzDate.slice(0, 8);
30
+ return { amzDate, dateStamp };
31
+ }
32
+ async function signRequest(method, url, headers, body, accessKeyId, secretAccessKey, sessionToken, region, service) {
33
+ const { amzDate, dateStamp } = getAmzDate();
34
+ // Prepare headers for signing
35
+ const signedHeaders = {
36
+ ...headers,
37
+ host: url.host,
38
+ 'x-amz-date': amzDate,
39
+ };
40
+ if (sessionToken) {
41
+ signedHeaders['x-amz-security-token'] = sessionToken;
42
+ }
43
+ // Create canonical request
44
+ const sortedHeaderKeys = Object.keys(signedHeaders).sort();
45
+ const canonicalHeaders = sortedHeaderKeys
46
+ .map(k => `${k.toLowerCase()}:${signedHeaders[k]?.trim()}`)
47
+ .join('\n') + '\n';
48
+ const signedHeadersList = sortedHeaderKeys.map(k => k.toLowerCase()).join(';');
49
+ const payloadHash = await sha256(body);
50
+ // URI-encode path components for canonical request (AWS SigV4 requirement)
51
+ // AWS requires double-encoding: %3A in the URL becomes %253A in the canonical request
52
+ // We encode each segment without decoding first to achieve double-encoding
53
+ const canonicalUri = url.pathname
54
+ .split('/')
55
+ .map(segment => encodeURIComponent(segment))
56
+ .join('/');
57
+ const canonicalRequest = [
58
+ method,
59
+ canonicalUri,
60
+ url.search.slice(1), // Remove leading '?'
61
+ canonicalHeaders,
62
+ signedHeadersList,
63
+ payloadHash,
64
+ ].join('\n');
65
+ // Create string to sign
66
+ const algorithm = 'AWS4-HMAC-SHA256';
67
+ const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
68
+ const stringToSign = [
69
+ algorithm,
70
+ amzDate,
71
+ credentialScope,
72
+ await sha256(canonicalRequest),
73
+ ].join('\n');
74
+ // Calculate signature
75
+ const signingKey = await getSignatureKey(secretAccessKey, dateStamp, region, service);
76
+ const signatureBuffer = await hmacSha256(signingKey, stringToSign);
77
+ const signature = Array.from(new Uint8Array(signatureBuffer))
78
+ .map(b => b.toString(16).padStart(2, '0'))
79
+ .join('');
80
+ // Create authorization header
81
+ const authorization = `${algorithm} Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeadersList}, Signature=${signature}`;
82
+ return {
83
+ ...signedHeaders,
84
+ authorization,
85
+ };
86
+ }
87
+ // ============================================================================
88
+ // Bedrock Adapter
89
+ // ============================================================================
90
+ export class BedrockAdapter {
91
+ name = 'bedrock';
92
+ accessKeyId;
93
+ secretAccessKey;
94
+ sessionToken;
95
+ region;
96
+ defaultMaxTokens;
97
+ anthropicVersion;
98
+ constructor(config = {}) {
99
+ this.accessKeyId = config.accessKeyId ?? process.env.AWS_ACCESS_KEY_ID ?? '';
100
+ this.secretAccessKey = config.secretAccessKey ?? process.env.AWS_SECRET_ACCESS_KEY ?? '';
101
+ this.sessionToken = config.sessionToken ?? process.env.AWS_SESSION_TOKEN;
102
+ this.region = config.region ?? process.env.AWS_REGION ?? 'us-west-2';
103
+ this.defaultMaxTokens = config.defaultMaxTokens ?? 4096;
104
+ this.anthropicVersion = config.anthropicVersion ?? 'bedrock-2023-05-31';
105
+ if (!this.accessKeyId || !this.secretAccessKey) {
106
+ throw new Error('AWS credentials required: accessKeyId and secretAccessKey');
107
+ }
108
+ }
109
+ supportsModel(modelId) {
110
+ // Support both Bedrock model IDs and standard Claude model IDs
111
+ return modelId.includes('claude') || modelId.startsWith('anthropic.');
112
+ }
113
+ /**
114
+ * Convert a standard Claude model ID to Bedrock format if needed
115
+ */
116
+ toBedrockModelId(modelId) {
117
+ // If already in Bedrock format, use as-is
118
+ if (modelId.startsWith('anthropic.')) {
119
+ return modelId;
120
+ }
121
+ // Map common Claude model IDs to Bedrock format
122
+ const modelMap = {
123
+ 'claude-3-5-sonnet-20241022': 'anthropic.claude-3-5-sonnet-20241022-v2:0',
124
+ 'claude-3-5-sonnet-latest': 'anthropic.claude-3-5-sonnet-20241022-v2:0',
125
+ 'claude-3-5-haiku-20241022': 'anthropic.claude-3-5-haiku-20241022-v1:0',
126
+ 'claude-3-5-haiku-latest': 'anthropic.claude-3-5-haiku-20241022-v1:0',
127
+ 'claude-3-opus-20240229': 'anthropic.claude-3-opus-20240229-v1:0',
128
+ 'claude-3-sonnet-20240229': 'anthropic.claude-3-sonnet-20240229-v1:0',
129
+ 'claude-3-haiku-20240307': 'anthropic.claude-3-haiku-20240307-v1:0',
130
+ 'claude-sonnet-4-20250514': 'anthropic.claude-sonnet-4-20250514-v1:0',
131
+ 'claude-opus-4-20250514': 'anthropic.claude-opus-4-20250514-v1:0',
132
+ // Haiku 4.5 aliases
133
+ 'claude-haiku-4-5-20251001': 'anthropic.claude-3-5-haiku-20241022-v1:0',
134
+ };
135
+ return modelMap[modelId] ?? `anthropic.${modelId}-v1:0`;
136
+ }
137
+ async complete(request, options) {
138
+ const bedrockModelId = this.toBedrockModelId(request.model);
139
+ const bedrockRequest = this.buildRequest(request);
140
+ const fullRequest = { modelId: bedrockModelId, ...bedrockRequest };
141
+ options?.onRequest?.(fullRequest);
142
+ try {
143
+ const response = await this.invokeModel(bedrockModelId, bedrockRequest, options?.signal);
144
+ return this.parseResponse(response, fullRequest);
145
+ }
146
+ catch (error) {
147
+ throw this.handleError(error, fullRequest);
148
+ }
149
+ }
150
+ async stream(request, callbacks, options) {
151
+ const bedrockModelId = this.toBedrockModelId(request.model);
152
+ const bedrockRequest = this.buildRequest(request);
153
+ const fullRequest = { modelId: bedrockModelId, ...bedrockRequest, stream: true };
154
+ options?.onRequest?.(fullRequest);
155
+ try {
156
+ return await this.invokeModelWithStream(bedrockModelId, bedrockRequest, callbacks, options?.signal);
157
+ }
158
+ catch (error) {
159
+ throw this.handleError(error, fullRequest);
160
+ }
161
+ }
162
+ buildRequest(request) {
163
+ const params = {
164
+ anthropic_version: this.anthropicVersion,
165
+ max_tokens: request.maxTokens || this.defaultMaxTokens,
166
+ messages: request.messages,
167
+ };
168
+ // Handle system prompt
169
+ if (request.system) {
170
+ params.system = request.system;
171
+ }
172
+ if (request.temperature !== undefined) {
173
+ params.temperature = request.temperature;
174
+ }
175
+ if (request.stopSequences && request.stopSequences.length > 0) {
176
+ params.stop_sequences = request.stopSequences;
177
+ }
178
+ if (request.tools && request.tools.length > 0) {
179
+ params.tools = request.tools;
180
+ }
181
+ // Handle extended thinking
182
+ if (request.thinking) {
183
+ params.thinking = request.thinking;
184
+ }
185
+ // Apply extra params, excluding internal membrane fields
186
+ if (request.extra) {
187
+ const { normalizedMessages, prompt, ...rest } = request.extra;
188
+ Object.assign(params, rest);
189
+ }
190
+ return params;
191
+ }
192
+ async invokeModel(modelId, request, signal) {
193
+ const url = new URL(`https://bedrock-runtime.${this.region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`);
194
+ const body = JSON.stringify(request);
195
+ const headers = {
196
+ 'content-type': 'application/json',
197
+ accept: 'application/json',
198
+ };
199
+ const signedHeaders = await signRequest('POST', url, headers, body, this.accessKeyId, this.secretAccessKey, this.sessionToken, this.region, 'bedrock');
200
+ const response = await fetch(url.toString(), {
201
+ method: 'POST',
202
+ headers: signedHeaders,
203
+ body,
204
+ signal,
205
+ });
206
+ if (!response.ok) {
207
+ const errorText = await response.text();
208
+ throw new BedrockError(response.status, errorText);
209
+ }
210
+ return response.json();
211
+ }
212
+ async invokeModelWithStream(modelId, request, callbacks, signal) {
213
+ const url = new URL(`https://bedrock-runtime.${this.region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke-with-response-stream`);
214
+ const body = JSON.stringify(request);
215
+ const headers = {
216
+ 'content-type': 'application/json',
217
+ accept: 'application/vnd.amazon.eventstream',
218
+ };
219
+ const signedHeaders = await signRequest('POST', url, headers, body, this.accessKeyId, this.secretAccessKey, this.sessionToken, this.region, 'bedrock');
220
+ const response = await fetch(url.toString(), {
221
+ method: 'POST',
222
+ headers: signedHeaders,
223
+ body,
224
+ signal,
225
+ });
226
+ if (!response.ok) {
227
+ const errorText = await response.text();
228
+ throw new BedrockError(response.status, errorText);
229
+ }
230
+ // Parse the binary event stream
231
+ const contentBlocks = [];
232
+ let currentBlockIndex = -1;
233
+ let finalMessage;
234
+ let inputTokens = 0;
235
+ let outputTokens = 0;
236
+ let stopReason = 'end_turn';
237
+ let fullText = '';
238
+ const reader = response.body?.getReader();
239
+ if (!reader) {
240
+ throw new Error('No response body');
241
+ }
242
+ let buffer = new Uint8Array(0);
243
+ try {
244
+ while (true) {
245
+ const { done, value } = await reader.read();
246
+ if (done)
247
+ break;
248
+ // Append new data to buffer
249
+ const newBuffer = new Uint8Array(buffer.length + value.length);
250
+ newBuffer.set(buffer);
251
+ newBuffer.set(value, buffer.length);
252
+ buffer = newBuffer;
253
+ // Parse complete events from buffer
254
+ while (buffer.length >= 16) {
255
+ // AWS event stream format:
256
+ // 4 bytes: total byte length (big-endian)
257
+ // 4 bytes: headers length (big-endian)
258
+ // 4 bytes: prelude CRC
259
+ // headers
260
+ // payload
261
+ // 4 bytes: message CRC
262
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
263
+ const totalLength = view.getUint32(0, false);
264
+ const headersLength = view.getUint32(4, false);
265
+ if (buffer.length < totalLength) {
266
+ // Incomplete message, wait for more data
267
+ break;
268
+ }
269
+ // Extract payload (skip prelude, headers, and CRCs)
270
+ const payloadStart = 12 + headersLength;
271
+ const payloadEnd = totalLength - 4;
272
+ const payloadBytes = buffer.slice(payloadStart, payloadEnd);
273
+ // Parse headers to find event type
274
+ let eventType = '';
275
+ let headerOffset = 12;
276
+ const headerEnd = 12 + headersLength;
277
+ while (headerOffset < headerEnd) {
278
+ const nameLength = buffer[headerOffset];
279
+ headerOffset += 1;
280
+ const name = new TextDecoder().decode(buffer.slice(headerOffset, headerOffset + nameLength));
281
+ headerOffset += nameLength;
282
+ const valueType = buffer[headerOffset];
283
+ headerOffset += 1;
284
+ if (valueType === 7) {
285
+ // String type
286
+ const valueLength = new DataView(buffer.buffer, buffer.byteOffset + headerOffset, 2).getUint16(0, false);
287
+ headerOffset += 2;
288
+ const value = new TextDecoder().decode(buffer.slice(headerOffset, headerOffset + valueLength));
289
+ headerOffset += valueLength;
290
+ if (name === ':event-type') {
291
+ eventType = value;
292
+ }
293
+ }
294
+ else {
295
+ // Skip other header types
296
+ break;
297
+ }
298
+ }
299
+ // Parse the JSON payload
300
+ if (eventType === 'chunk' && payloadBytes.length > 0) {
301
+ try {
302
+ const payloadJson = JSON.parse(new TextDecoder().decode(payloadBytes));
303
+ if (payloadJson.bytes) {
304
+ // Decode base64 payload
305
+ const eventData = JSON.parse(atob(payloadJson.bytes));
306
+ if (eventData.type === 'message_start' && eventData.message) {
307
+ inputTokens = eventData.message.usage?.input_tokens ?? 0;
308
+ }
309
+ else if (eventData.type === 'content_block_start') {
310
+ currentBlockIndex = eventData.index ?? 0;
311
+ contentBlocks[currentBlockIndex] = eventData.content_block;
312
+ callbacks.onContentBlock?.(currentBlockIndex, eventData.content_block);
313
+ }
314
+ else if (eventData.type === 'content_block_delta') {
315
+ if (eventData.delta?.type === 'text_delta' && eventData.delta.text) {
316
+ fullText += eventData.delta.text;
317
+ callbacks.onChunk(eventData.delta.text);
318
+ if (contentBlocks[currentBlockIndex]) {
319
+ contentBlocks[currentBlockIndex].text = (contentBlocks[currentBlockIndex].text ?? '') + eventData.delta.text;
320
+ }
321
+ }
322
+ else if (eventData.delta?.type === 'thinking_delta' && eventData.delta.thinking) {
323
+ callbacks.onChunk(eventData.delta.thinking);
324
+ }
325
+ }
326
+ else if (eventData.type === 'message_delta') {
327
+ if (eventData.usage) {
328
+ outputTokens = eventData.usage.output_tokens;
329
+ }
330
+ if (eventData.delta?.stop_reason) {
331
+ stopReason = eventData.delta.stop_reason;
332
+ }
333
+ }
334
+ }
335
+ }
336
+ catch {
337
+ // Skip malformed events
338
+ }
339
+ }
340
+ // Remove processed message from buffer
341
+ buffer = buffer.slice(totalLength);
342
+ }
343
+ }
344
+ }
345
+ finally {
346
+ reader.releaseLock();
347
+ }
348
+ // Build response from accumulated data
349
+ finalMessage = {
350
+ id: 'msg_stream',
351
+ type: 'message',
352
+ role: 'assistant',
353
+ content: contentBlocks.map(b => ({
354
+ type: b.type,
355
+ text: b.text,
356
+ })),
357
+ model: modelId,
358
+ stop_reason: stopReason,
359
+ usage: {
360
+ input_tokens: inputTokens,
361
+ output_tokens: outputTokens,
362
+ },
363
+ };
364
+ return this.parseResponse(finalMessage, { modelId, ...request, stream: true });
365
+ }
366
+ parseResponse(response, rawRequest) {
367
+ const content = [];
368
+ for (const block of response.content) {
369
+ if (block.type === 'text' && block.text) {
370
+ content.push({ type: 'text', text: block.text });
371
+ }
372
+ else if (block.type === 'tool_use' && block.id && block.name) {
373
+ content.push({
374
+ type: 'tool_use',
375
+ id: block.id,
376
+ name: block.name,
377
+ input: block.input,
378
+ });
379
+ }
380
+ else if (block.type === 'thinking' && block.thinking) {
381
+ content.push({
382
+ type: 'thinking',
383
+ thinking: block.thinking,
384
+ signature: block.signature,
385
+ });
386
+ }
387
+ }
388
+ return {
389
+ content,
390
+ stopReason: response.stop_reason ?? 'end_turn',
391
+ stopSequence: response.stop_sequence ?? undefined,
392
+ usage: {
393
+ inputTokens: response.usage.input_tokens,
394
+ outputTokens: response.usage.output_tokens,
395
+ cacheCreationTokens: response.usage.cache_creation_input_tokens,
396
+ cacheReadTokens: response.usage.cache_read_input_tokens,
397
+ },
398
+ model: response.model,
399
+ rawRequest,
400
+ raw: response,
401
+ };
402
+ }
403
+ handleError(error, rawRequest) {
404
+ if (error instanceof BedrockError) {
405
+ const status = error.status;
406
+ const message = error.message;
407
+ if (status === 429) {
408
+ return rateLimitError(message, undefined, error, rawRequest);
409
+ }
410
+ if (status === 401 || status === 403) {
411
+ return authError(message, error, rawRequest);
412
+ }
413
+ if (message.includes('context') || message.includes('too long') || message.includes('token')) {
414
+ return contextLengthError(message, error, rawRequest);
415
+ }
416
+ if (status >= 500) {
417
+ return serverError(message, status, error, rawRequest);
418
+ }
419
+ }
420
+ if (error instanceof Error && error.name === 'AbortError') {
421
+ return abortError(undefined, rawRequest);
422
+ }
423
+ return new MembraneError({
424
+ type: 'unknown',
425
+ message: error instanceof Error ? error.message : String(error),
426
+ retryable: false,
427
+ rawError: error,
428
+ rawRequest,
429
+ });
430
+ }
431
+ }
432
+ // ============================================================================
433
+ // Error Class
434
+ // ============================================================================
435
+ class BedrockError extends Error {
436
+ status;
437
+ constructor(status, message) {
438
+ super(message);
439
+ this.status = status;
440
+ this.name = 'BedrockError';
441
+ }
442
+ }
443
+ //# sourceMappingURL=bedrock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bedrock.js","sourceRoot":"","sources":["../../src/providers/bedrock.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,5 @@ export { OpenAIAdapter, toOpenAIContent, fromOpenAIContent, type OpenAIAdapterCo
7
7
  export { OpenAICompatibleAdapter, toOpenAIMessages, fromOpenAIMessage, type OpenAICompatibleAdapterConfig, } from './openai-compatible.js';
8
8
  export { OpenAICompletionsAdapter, type OpenAICompletionsAdapterConfig, } from './openai-completions.js';
9
9
  export { MockAdapter, createEchoAdapter, createCannedAdapter, type MockAdapterConfig, } from './mock.js';
10
+ export { BedrockAdapter, type BedrockAdapterConfig, } from './bedrock.js';
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,6BAA6B,GACnC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,wBAAwB,EACxB,KAAK,8BAA8B,GACpC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,sBAAsB,GAC5B,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,EACrB,KAAK,uBAAuB,GAC7B,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,KAAK,mBAAmB,GACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,EACjB,KAAK,6BAA6B,GACnC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,wBAAwB,EACxB,KAAK,8BAA8B,GACpC,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,iBAAiB,GACvB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,EACd,KAAK,oBAAoB,GAC1B,MAAM,cAAc,CAAC"}
@@ -7,4 +7,5 @@ export { OpenAIAdapter, toOpenAIContent, fromOpenAIContent, } from './openai.js'
7
7
  export { OpenAICompatibleAdapter, toOpenAIMessages, fromOpenAIMessage, } from './openai-compatible.js';
8
8
  export { OpenAICompletionsAdapter, } from './openai-completions.js';
9
9
  export { MockAdapter, createEchoAdapter, createCannedAdapter, } from './mock.js';
10
+ export { BedrockAdapter, } from './bedrock.js';
10
11
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GAEtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,GAElB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,GAElB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,wBAAwB,GAEzB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GAEpB,MAAM,WAAW,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/providers/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,oBAAoB,GAErB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EACL,iBAAiB,EACjB,oBAAoB,EACpB,qBAAqB,GAEtB,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EACL,aAAa,EACb,eAAe,EACf,iBAAiB,GAElB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,uBAAuB,EACvB,gBAAgB,EAChB,iBAAiB,GAElB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EACL,wBAAwB,GAEzB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GAEpB,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,cAAc,GAEf,MAAM,cAAc,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animalabs/membrane",
3
- "version": "0.5.4",
3
+ "version": "0.5.5",
4
4
  "description": "LLM middleware - a selective boundary that transforms what passes through",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -0,0 +1,675 @@
1
+ /**
2
+ * AWS Bedrock provider adapter for Anthropic Claude models
3
+ *
4
+ * Uses the Anthropic Messages API format through AWS Bedrock.
5
+ */
6
+
7
+ import type {
8
+ ProviderAdapter,
9
+ ProviderRequest,
10
+ ProviderRequestOptions,
11
+ ProviderResponse,
12
+ StreamCallbacks,
13
+ ContentBlock,
14
+ } from '../types/index.js';
15
+ import {
16
+ MembraneError,
17
+ rateLimitError,
18
+ contextLengthError,
19
+ authError,
20
+ serverError,
21
+ abortError,
22
+ } from '../types/index.js';
23
+
24
+ // ============================================================================
25
+ // Adapter Configuration
26
+ // ============================================================================
27
+
28
+ export interface BedrockAdapterConfig {
29
+ /** AWS access key ID */
30
+ accessKeyId?: string;
31
+
32
+ /** AWS secret access key */
33
+ secretAccessKey?: string;
34
+
35
+ /** AWS region (defaults to us-west-2) */
36
+ region?: string;
37
+
38
+ /** AWS session token (for temporary credentials) */
39
+ sessionToken?: string;
40
+
41
+ /** Default max tokens */
42
+ defaultMaxTokens?: number;
43
+
44
+ /** Anthropic API version header (defaults to 2023-06-01) */
45
+ anthropicVersion?: string;
46
+ }
47
+
48
+ // ============================================================================
49
+ // Bedrock Request/Response Types
50
+ // ============================================================================
51
+
52
+ interface BedrockMessageRequest {
53
+ anthropic_version: string;
54
+ max_tokens: number;
55
+ messages: Array<{
56
+ role: 'user' | 'assistant';
57
+ content: unknown;
58
+ }>;
59
+ system?: string | Array<{ type: 'text'; text: string; cache_control?: { type: 'ephemeral' } }>;
60
+ temperature?: number;
61
+ stop_sequences?: string[];
62
+ tools?: unknown[];
63
+ thinking?: { type: 'enabled'; budget_tokens: number };
64
+ }
65
+
66
+ interface BedrockMessageResponse {
67
+ id: string;
68
+ type: 'message';
69
+ role: 'assistant';
70
+ content: Array<{
71
+ type: 'text' | 'tool_use' | 'thinking';
72
+ text?: string;
73
+ thinking?: string;
74
+ signature?: string;
75
+ id?: string;
76
+ name?: string;
77
+ input?: unknown;
78
+ }>;
79
+ model: string;
80
+ stop_reason: 'end_turn' | 'max_tokens' | 'stop_sequence' | 'tool_use' | null;
81
+ stop_sequence?: string | null;
82
+ usage: {
83
+ input_tokens: number;
84
+ output_tokens: number;
85
+ cache_creation_input_tokens?: number;
86
+ cache_read_input_tokens?: number;
87
+ };
88
+ }
89
+
90
+ interface BedrockStreamEvent {
91
+ type: string;
92
+ index?: number;
93
+ content_block?: {
94
+ type: string;
95
+ text?: string;
96
+ thinking?: string;
97
+ id?: string;
98
+ name?: string;
99
+ input?: unknown;
100
+ };
101
+ delta?: {
102
+ type: string;
103
+ text?: string;
104
+ thinking?: string;
105
+ partial_json?: string;
106
+ stop_reason?: string;
107
+ stop_sequence?: string;
108
+ };
109
+ message?: BedrockMessageResponse;
110
+ usage?: {
111
+ input_tokens: number;
112
+ output_tokens: number;
113
+ };
114
+ }
115
+
116
+ // ============================================================================
117
+ // AWS Signature V4 Implementation
118
+ // ============================================================================
119
+
120
+ async function hmacSha256(key: ArrayBuffer | Uint8Array, data: string): Promise<ArrayBuffer> {
121
+ const cryptoKey = await crypto.subtle.importKey(
122
+ 'raw',
123
+ key,
124
+ { name: 'HMAC', hash: 'SHA-256' },
125
+ false,
126
+ ['sign']
127
+ );
128
+ return crypto.subtle.sign('HMAC', cryptoKey, new TextEncoder().encode(data));
129
+ }
130
+
131
+ async function sha256(data: string): Promise<string> {
132
+ const hash = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(data));
133
+ return Array.from(new Uint8Array(hash))
134
+ .map(b => b.toString(16).padStart(2, '0'))
135
+ .join('');
136
+ }
137
+
138
+ async function getSignatureKey(
139
+ secretKey: string,
140
+ dateStamp: string,
141
+ region: string,
142
+ service: string
143
+ ): Promise<ArrayBuffer> {
144
+ const kDate = await hmacSha256(new TextEncoder().encode('AWS4' + secretKey), dateStamp);
145
+ const kRegion = await hmacSha256(kDate, region);
146
+ const kService = await hmacSha256(kRegion, service);
147
+ return hmacSha256(kService, 'aws4_request');
148
+ }
149
+
150
+ function getAmzDate(): { amzDate: string; dateStamp: string } {
151
+ const now = new Date();
152
+ const amzDate = now.toISOString().replace(/[:-]|\.\d{3}/g, '');
153
+ const dateStamp = amzDate.slice(0, 8);
154
+ return { amzDate, dateStamp };
155
+ }
156
+
157
+ async function signRequest(
158
+ method: string,
159
+ url: URL,
160
+ headers: Record<string, string>,
161
+ body: string,
162
+ accessKeyId: string,
163
+ secretAccessKey: string,
164
+ sessionToken: string | undefined,
165
+ region: string,
166
+ service: string
167
+ ): Promise<Record<string, string>> {
168
+ const { amzDate, dateStamp } = getAmzDate();
169
+
170
+ // Prepare headers for signing
171
+ const signedHeaders: Record<string, string> = {
172
+ ...headers,
173
+ host: url.host,
174
+ 'x-amz-date': amzDate,
175
+ };
176
+
177
+ if (sessionToken) {
178
+ signedHeaders['x-amz-security-token'] = sessionToken;
179
+ }
180
+
181
+ // Create canonical request
182
+ const sortedHeaderKeys = Object.keys(signedHeaders).sort();
183
+ const canonicalHeaders = sortedHeaderKeys
184
+ .map(k => `${k.toLowerCase()}:${signedHeaders[k]?.trim()}`)
185
+ .join('\n') + '\n';
186
+ const signedHeadersList = sortedHeaderKeys.map(k => k.toLowerCase()).join(';');
187
+ const payloadHash = await sha256(body);
188
+
189
+ // URI-encode path components for canonical request (AWS SigV4 requirement)
190
+ // AWS requires double-encoding: %3A in the URL becomes %253A in the canonical request
191
+ // We encode each segment without decoding first to achieve double-encoding
192
+ const canonicalUri = url.pathname
193
+ .split('/')
194
+ .map(segment => encodeURIComponent(segment))
195
+ .join('/');
196
+
197
+ const canonicalRequest = [
198
+ method,
199
+ canonicalUri,
200
+ url.search.slice(1), // Remove leading '?'
201
+ canonicalHeaders,
202
+ signedHeadersList,
203
+ payloadHash,
204
+ ].join('\n');
205
+
206
+ // Create string to sign
207
+ const algorithm = 'AWS4-HMAC-SHA256';
208
+ const credentialScope = `${dateStamp}/${region}/${service}/aws4_request`;
209
+ const stringToSign = [
210
+ algorithm,
211
+ amzDate,
212
+ credentialScope,
213
+ await sha256(canonicalRequest),
214
+ ].join('\n');
215
+
216
+ // Calculate signature
217
+ const signingKey = await getSignatureKey(secretAccessKey, dateStamp, region, service);
218
+ const signatureBuffer = await hmacSha256(signingKey, stringToSign);
219
+ const signature = Array.from(new Uint8Array(signatureBuffer))
220
+ .map(b => b.toString(16).padStart(2, '0'))
221
+ .join('');
222
+
223
+ // Create authorization header
224
+ const authorization = `${algorithm} Credential=${accessKeyId}/${credentialScope}, SignedHeaders=${signedHeadersList}, Signature=${signature}`;
225
+
226
+ return {
227
+ ...signedHeaders,
228
+ authorization,
229
+ };
230
+ }
231
+
232
+ // ============================================================================
233
+ // Bedrock Adapter
234
+ // ============================================================================
235
+
236
+ export class BedrockAdapter implements ProviderAdapter {
237
+ readonly name = 'bedrock';
238
+
239
+ private accessKeyId: string;
240
+ private secretAccessKey: string;
241
+ private sessionToken?: string;
242
+ private region: string;
243
+ private defaultMaxTokens: number;
244
+ private anthropicVersion: string;
245
+
246
+ constructor(config: BedrockAdapterConfig = {}) {
247
+ this.accessKeyId = config.accessKeyId ?? process.env.AWS_ACCESS_KEY_ID ?? '';
248
+ this.secretAccessKey = config.secretAccessKey ?? process.env.AWS_SECRET_ACCESS_KEY ?? '';
249
+ this.sessionToken = config.sessionToken ?? process.env.AWS_SESSION_TOKEN;
250
+ this.region = config.region ?? process.env.AWS_REGION ?? 'us-west-2';
251
+ this.defaultMaxTokens = config.defaultMaxTokens ?? 4096;
252
+ this.anthropicVersion = config.anthropicVersion ?? 'bedrock-2023-05-31';
253
+
254
+ if (!this.accessKeyId || !this.secretAccessKey) {
255
+ throw new Error('AWS credentials required: accessKeyId and secretAccessKey');
256
+ }
257
+ }
258
+
259
+ supportsModel(modelId: string): boolean {
260
+ // Support both Bedrock model IDs and standard Claude model IDs
261
+ return modelId.includes('claude') || modelId.startsWith('anthropic.');
262
+ }
263
+
264
+ /**
265
+ * Convert a standard Claude model ID to Bedrock format if needed
266
+ */
267
+ private toBedrockModelId(modelId: string): string {
268
+ // If already in Bedrock format, use as-is
269
+ if (modelId.startsWith('anthropic.')) {
270
+ return modelId;
271
+ }
272
+
273
+ // Map common Claude model IDs to Bedrock format
274
+ const modelMap: Record<string, string> = {
275
+ 'claude-3-5-sonnet-20241022': 'anthropic.claude-3-5-sonnet-20241022-v2:0',
276
+ 'claude-3-5-sonnet-latest': 'anthropic.claude-3-5-sonnet-20241022-v2:0',
277
+ 'claude-3-5-haiku-20241022': 'anthropic.claude-3-5-haiku-20241022-v1:0',
278
+ 'claude-3-5-haiku-latest': 'anthropic.claude-3-5-haiku-20241022-v1:0',
279
+ 'claude-3-opus-20240229': 'anthropic.claude-3-opus-20240229-v1:0',
280
+ 'claude-3-sonnet-20240229': 'anthropic.claude-3-sonnet-20240229-v1:0',
281
+ 'claude-3-haiku-20240307': 'anthropic.claude-3-haiku-20240307-v1:0',
282
+ 'claude-sonnet-4-20250514': 'anthropic.claude-sonnet-4-20250514-v1:0',
283
+ 'claude-opus-4-20250514': 'anthropic.claude-opus-4-20250514-v1:0',
284
+ // Haiku 4.5 aliases
285
+ 'claude-haiku-4-5-20251001': 'anthropic.claude-3-5-haiku-20241022-v1:0',
286
+ };
287
+
288
+ return modelMap[modelId] ?? `anthropic.${modelId}-v1:0`;
289
+ }
290
+
291
+ async complete(
292
+ request: ProviderRequest,
293
+ options?: ProviderRequestOptions
294
+ ): Promise<ProviderResponse> {
295
+ const bedrockModelId = this.toBedrockModelId(request.model);
296
+ const bedrockRequest = this.buildRequest(request);
297
+ const fullRequest = { modelId: bedrockModelId, ...bedrockRequest };
298
+ options?.onRequest?.(fullRequest);
299
+
300
+ try {
301
+ const response = await this.invokeModel(bedrockModelId, bedrockRequest, options?.signal);
302
+ return this.parseResponse(response, fullRequest);
303
+ } catch (error) {
304
+ throw this.handleError(error, fullRequest);
305
+ }
306
+ }
307
+
308
+ async stream(
309
+ request: ProviderRequest,
310
+ callbacks: StreamCallbacks,
311
+ options?: ProviderRequestOptions
312
+ ): Promise<ProviderResponse> {
313
+ const bedrockModelId = this.toBedrockModelId(request.model);
314
+ const bedrockRequest = this.buildRequest(request);
315
+ const fullRequest = { modelId: bedrockModelId, ...bedrockRequest, stream: true };
316
+ options?.onRequest?.(fullRequest);
317
+
318
+ try {
319
+ return await this.invokeModelWithStream(bedrockModelId, bedrockRequest, callbacks, options?.signal);
320
+ } catch (error) {
321
+ throw this.handleError(error, fullRequest);
322
+ }
323
+ }
324
+
325
+ private buildRequest(request: ProviderRequest): BedrockMessageRequest {
326
+ const params: BedrockMessageRequest = {
327
+ anthropic_version: this.anthropicVersion,
328
+ max_tokens: request.maxTokens || this.defaultMaxTokens,
329
+ messages: request.messages as BedrockMessageRequest['messages'],
330
+ };
331
+
332
+ // Handle system prompt
333
+ if (request.system) {
334
+ params.system = request.system as BedrockMessageRequest['system'];
335
+ }
336
+
337
+ if (request.temperature !== undefined) {
338
+ params.temperature = request.temperature;
339
+ }
340
+
341
+ if (request.stopSequences && request.stopSequences.length > 0) {
342
+ params.stop_sequences = request.stopSequences;
343
+ }
344
+
345
+ if (request.tools && request.tools.length > 0) {
346
+ params.tools = request.tools;
347
+ }
348
+
349
+ // Handle extended thinking
350
+ if ((request as any).thinking) {
351
+ params.thinking = (request as any).thinking;
352
+ }
353
+
354
+ // Apply extra params, excluding internal membrane fields
355
+ if (request.extra) {
356
+ const { normalizedMessages, prompt, ...rest } = request.extra as Record<string, unknown>;
357
+ Object.assign(params, rest);
358
+ }
359
+
360
+ return params;
361
+ }
362
+
363
+ private async invokeModel(
364
+ modelId: string,
365
+ request: BedrockMessageRequest,
366
+ signal?: AbortSignal
367
+ ): Promise<BedrockMessageResponse> {
368
+ const url = new URL(
369
+ `https://bedrock-runtime.${this.region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke`
370
+ );
371
+
372
+ const body = JSON.stringify(request);
373
+ const headers: Record<string, string> = {
374
+ 'content-type': 'application/json',
375
+ accept: 'application/json',
376
+ };
377
+
378
+ const signedHeaders = await signRequest(
379
+ 'POST',
380
+ url,
381
+ headers,
382
+ body,
383
+ this.accessKeyId,
384
+ this.secretAccessKey,
385
+ this.sessionToken,
386
+ this.region,
387
+ 'bedrock'
388
+ );
389
+
390
+ const response = await fetch(url.toString(), {
391
+ method: 'POST',
392
+ headers: signedHeaders,
393
+ body,
394
+ signal,
395
+ });
396
+
397
+ if (!response.ok) {
398
+ const errorText = await response.text();
399
+ throw new BedrockError(response.status, errorText);
400
+ }
401
+
402
+ return response.json() as Promise<BedrockMessageResponse>;
403
+ }
404
+
405
+ private async invokeModelWithStream(
406
+ modelId: string,
407
+ request: BedrockMessageRequest,
408
+ callbacks: StreamCallbacks,
409
+ signal?: AbortSignal
410
+ ): Promise<ProviderResponse> {
411
+ const url = new URL(
412
+ `https://bedrock-runtime.${this.region}.amazonaws.com/model/${encodeURIComponent(modelId)}/invoke-with-response-stream`
413
+ );
414
+
415
+ const body = JSON.stringify(request);
416
+ const headers: Record<string, string> = {
417
+ 'content-type': 'application/json',
418
+ accept: 'application/vnd.amazon.eventstream',
419
+ };
420
+
421
+ const signedHeaders = await signRequest(
422
+ 'POST',
423
+ url,
424
+ headers,
425
+ body,
426
+ this.accessKeyId,
427
+ this.secretAccessKey,
428
+ this.sessionToken,
429
+ this.region,
430
+ 'bedrock'
431
+ );
432
+
433
+ const response = await fetch(url.toString(), {
434
+ method: 'POST',
435
+ headers: signedHeaders,
436
+ body,
437
+ signal,
438
+ });
439
+
440
+ if (!response.ok) {
441
+ const errorText = await response.text();
442
+ throw new BedrockError(response.status, errorText);
443
+ }
444
+
445
+ // Parse the binary event stream
446
+ const contentBlocks: Array<{ type: string; text?: string }> = [];
447
+ let currentBlockIndex = -1;
448
+ let finalMessage: BedrockMessageResponse | undefined;
449
+ let inputTokens = 0;
450
+ let outputTokens = 0;
451
+ let stopReason: string = 'end_turn';
452
+ let fullText = '';
453
+
454
+ const reader = response.body?.getReader();
455
+ if (!reader) {
456
+ throw new Error('No response body');
457
+ }
458
+
459
+ let buffer = new Uint8Array(0);
460
+
461
+ try {
462
+ while (true) {
463
+ const { done, value } = await reader.read();
464
+ if (done) break;
465
+
466
+ // Append new data to buffer
467
+ const newBuffer = new Uint8Array(buffer.length + value.length);
468
+ newBuffer.set(buffer);
469
+ newBuffer.set(value, buffer.length);
470
+ buffer = newBuffer;
471
+
472
+ // Parse complete events from buffer
473
+ while (buffer.length >= 16) {
474
+ // AWS event stream format:
475
+ // 4 bytes: total byte length (big-endian)
476
+ // 4 bytes: headers length (big-endian)
477
+ // 4 bytes: prelude CRC
478
+ // headers
479
+ // payload
480
+ // 4 bytes: message CRC
481
+ const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
482
+ const totalLength = view.getUint32(0, false);
483
+ const headersLength = view.getUint32(4, false);
484
+
485
+ if (buffer.length < totalLength) {
486
+ // Incomplete message, wait for more data
487
+ break;
488
+ }
489
+
490
+ // Extract payload (skip prelude, headers, and CRCs)
491
+ const payloadStart = 12 + headersLength;
492
+ const payloadEnd = totalLength - 4;
493
+ const payloadBytes = buffer.slice(payloadStart, payloadEnd);
494
+
495
+ // Parse headers to find event type
496
+ let eventType = '';
497
+ let headerOffset = 12;
498
+ const headerEnd = 12 + headersLength;
499
+ while (headerOffset < headerEnd) {
500
+ const nameLength = buffer[headerOffset]!;
501
+ headerOffset += 1;
502
+ const name = new TextDecoder().decode(buffer.slice(headerOffset, headerOffset + nameLength));
503
+ headerOffset += nameLength;
504
+ const valueType = buffer[headerOffset]!;
505
+ headerOffset += 1;
506
+
507
+ if (valueType === 7) {
508
+ // String type
509
+ const valueLength = new DataView(buffer.buffer, buffer.byteOffset + headerOffset, 2).getUint16(0, false);
510
+ headerOffset += 2;
511
+ const value = new TextDecoder().decode(buffer.slice(headerOffset, headerOffset + valueLength));
512
+ headerOffset += valueLength;
513
+
514
+ if (name === ':event-type') {
515
+ eventType = value;
516
+ }
517
+ } else {
518
+ // Skip other header types
519
+ break;
520
+ }
521
+ }
522
+
523
+ // Parse the JSON payload
524
+ if (eventType === 'chunk' && payloadBytes.length > 0) {
525
+ try {
526
+ const payloadJson = JSON.parse(new TextDecoder().decode(payloadBytes));
527
+ if (payloadJson.bytes) {
528
+ // Decode base64 payload
529
+ const eventData = JSON.parse(atob(payloadJson.bytes)) as BedrockStreamEvent;
530
+
531
+ if (eventData.type === 'message_start' && eventData.message) {
532
+ inputTokens = eventData.message.usage?.input_tokens ?? 0;
533
+ } else if (eventData.type === 'content_block_start') {
534
+ currentBlockIndex = eventData.index ?? 0;
535
+ contentBlocks[currentBlockIndex] = eventData.content_block as { type: string };
536
+ callbacks.onContentBlock?.(currentBlockIndex, eventData.content_block);
537
+ } else if (eventData.type === 'content_block_delta') {
538
+ if (eventData.delta?.type === 'text_delta' && eventData.delta.text) {
539
+ fullText += eventData.delta.text;
540
+ callbacks.onChunk(eventData.delta.text);
541
+ if (contentBlocks[currentBlockIndex]) {
542
+ contentBlocks[currentBlockIndex]!.text = (contentBlocks[currentBlockIndex]!.text ?? '') + eventData.delta.text;
543
+ }
544
+ } else if (eventData.delta?.type === 'thinking_delta' && eventData.delta.thinking) {
545
+ callbacks.onChunk(eventData.delta.thinking);
546
+ }
547
+ } else if (eventData.type === 'message_delta') {
548
+ if (eventData.usage) {
549
+ outputTokens = eventData.usage.output_tokens;
550
+ }
551
+ if (eventData.delta?.stop_reason) {
552
+ stopReason = eventData.delta.stop_reason;
553
+ }
554
+ }
555
+ }
556
+ } catch {
557
+ // Skip malformed events
558
+ }
559
+ }
560
+
561
+ // Remove processed message from buffer
562
+ buffer = buffer.slice(totalLength);
563
+ }
564
+ }
565
+ } finally {
566
+ reader.releaseLock();
567
+ }
568
+
569
+ // Build response from accumulated data
570
+ finalMessage = {
571
+ id: 'msg_stream',
572
+ type: 'message',
573
+ role: 'assistant',
574
+ content: contentBlocks.map(b => ({
575
+ type: b.type as 'text',
576
+ text: b.text,
577
+ })),
578
+ model: modelId,
579
+ stop_reason: stopReason as BedrockMessageResponse['stop_reason'],
580
+ usage: {
581
+ input_tokens: inputTokens,
582
+ output_tokens: outputTokens,
583
+ },
584
+ };
585
+
586
+ return this.parseResponse(finalMessage, { modelId, ...request, stream: true });
587
+ }
588
+
589
+ private parseResponse(response: BedrockMessageResponse, rawRequest: unknown): ProviderResponse {
590
+ const content: ContentBlock[] = [];
591
+
592
+ for (const block of response.content) {
593
+ if (block.type === 'text' && block.text) {
594
+ content.push({ type: 'text', text: block.text });
595
+ } else if (block.type === 'tool_use' && block.id && block.name) {
596
+ content.push({
597
+ type: 'tool_use',
598
+ id: block.id,
599
+ name: block.name,
600
+ input: block.input as Record<string, unknown>,
601
+ });
602
+ } else if (block.type === 'thinking' && block.thinking) {
603
+ content.push({
604
+ type: 'thinking',
605
+ thinking: block.thinking,
606
+ signature: block.signature,
607
+ });
608
+ }
609
+ }
610
+
611
+ return {
612
+ content,
613
+ stopReason: response.stop_reason ?? 'end_turn',
614
+ stopSequence: response.stop_sequence ?? undefined,
615
+ usage: {
616
+ inputTokens: response.usage.input_tokens,
617
+ outputTokens: response.usage.output_tokens,
618
+ cacheCreationTokens: response.usage.cache_creation_input_tokens,
619
+ cacheReadTokens: response.usage.cache_read_input_tokens,
620
+ },
621
+ model: response.model,
622
+ rawRequest,
623
+ raw: response,
624
+ };
625
+ }
626
+
627
+ private handleError(error: unknown, rawRequest?: unknown): MembraneError {
628
+ if (error instanceof BedrockError) {
629
+ const status = error.status;
630
+ const message = error.message;
631
+
632
+ if (status === 429) {
633
+ return rateLimitError(message, undefined, error, rawRequest);
634
+ }
635
+
636
+ if (status === 401 || status === 403) {
637
+ return authError(message, error, rawRequest);
638
+ }
639
+
640
+ if (message.includes('context') || message.includes('too long') || message.includes('token')) {
641
+ return contextLengthError(message, error, rawRequest);
642
+ }
643
+
644
+ if (status >= 500) {
645
+ return serverError(message, status, error, rawRequest);
646
+ }
647
+ }
648
+
649
+ if (error instanceof Error && error.name === 'AbortError') {
650
+ return abortError(undefined, rawRequest);
651
+ }
652
+
653
+ return new MembraneError({
654
+ type: 'unknown',
655
+ message: error instanceof Error ? error.message : String(error),
656
+ retryable: false,
657
+ rawError: error,
658
+ rawRequest,
659
+ });
660
+ }
661
+ }
662
+
663
+ // ============================================================================
664
+ // Error Class
665
+ // ============================================================================
666
+
667
+ class BedrockError extends Error {
668
+ constructor(
669
+ public status: number,
670
+ message: string
671
+ ) {
672
+ super(message);
673
+ this.name = 'BedrockError';
674
+ }
675
+ }
@@ -41,3 +41,8 @@ export {
41
41
  createCannedAdapter,
42
42
  type MockAdapterConfig,
43
43
  } from './mock.js';
44
+
45
+ export {
46
+ BedrockAdapter,
47
+ type BedrockAdapterConfig,
48
+ } from './bedrock.js';