@animalabs/membrane 0.5.73 → 0.5.75
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/formatters/anthropic-xml.d.ts +21 -0
- package/dist/formatters/anthropic-xml.d.ts.map +1 -1
- package/dist/formatters/anthropic-xml.js +134 -6
- package/dist/formatters/anthropic-xml.js.map +1 -1
- package/dist/membrane.js +2 -2
- package/dist/membrane.js.map +1 -1
- package/dist/providers/anthropic.d.ts +33 -0
- package/dist/providers/anthropic.d.ts.map +1 -1
- package/dist/providers/anthropic.js +113 -8
- package/dist/providers/anthropic.js.map +1 -1
- package/dist/providers/bedrock.d.ts.map +1 -1
- package/dist/providers/bedrock.js +45 -0
- package/dist/providers/bedrock.js.map +1 -1
- package/dist/types/config.d.ts +7 -0
- package/dist/types/config.d.ts.map +1 -1
- package/dist/types/config.js.map +1 -1
- package/dist/types/content.d.ts +18 -0
- package/dist/types/content.d.ts.map +1 -1
- package/dist/types/content.js.map +1 -1
- package/dist/types/provider.d.ts +6 -0
- package/dist/types/provider.d.ts.map +1 -1
- package/dist/utils/tool-parser.d.ts.map +1 -1
- package/dist/utils/tool-parser.js +11 -0
- package/dist/utils/tool-parser.js.map +1 -1
- package/package.json +1 -1
- package/src/formatters/anthropic-xml.ts +142 -6
- package/src/membrane.ts +2 -2
- package/src/providers/anthropic.ts +121 -8
- package/src/providers/bedrock.ts +45 -0
- package/src/types/config.ts +8 -0
- package/src/types/content.ts +18 -0
- package/src/types/provider.ts +6 -0
- package/src/utils/tool-parser.ts +11 -0
package/src/providers/bedrock.ts
CHANGED
|
@@ -21,6 +21,11 @@ import {
|
|
|
21
21
|
abortError,
|
|
22
22
|
} from '../types/index.js';
|
|
23
23
|
import { createCombinedSignal } from './utils.js';
|
|
24
|
+
import {
|
|
25
|
+
INTERLEAVED_THINKING_BETA,
|
|
26
|
+
needsInterleavedThinkingBeta,
|
|
27
|
+
thinkingEnabled,
|
|
28
|
+
} from './anthropic.js';
|
|
24
29
|
|
|
25
30
|
// ============================================================================
|
|
26
31
|
// Adapter Configuration
|
|
@@ -64,6 +69,8 @@ interface BedrockMessageRequest {
|
|
|
64
69
|
stop_sequences?: string[];
|
|
65
70
|
tools?: unknown[];
|
|
66
71
|
thinking?: { type: 'enabled'; budget_tokens: number };
|
|
72
|
+
/** Beta flags. On bedrock-runtime these ride in the body, not a header. */
|
|
73
|
+
anthropic_beta?: string[];
|
|
67
74
|
}
|
|
68
75
|
|
|
69
76
|
interface BedrockMessageResponse {
|
|
@@ -407,6 +414,17 @@ export class BedrockAdapter implements ProviderAdapter {
|
|
|
407
414
|
Object.assign(params, rest);
|
|
408
415
|
}
|
|
409
416
|
|
|
417
|
+
// Interleaved thinking on pre-4.6 Claude 4: same gate as the Anthropic
|
|
418
|
+
// adapter, but bedrock-runtime takes betas as the `anthropic_beta` body
|
|
419
|
+
// field rather than an HTTP header. Runs after the extra-assign so a
|
|
420
|
+
// consumer-supplied anthropic_beta is merged (Set-deduped), not clobbered.
|
|
421
|
+
// The gate only matches Claude 4 <4.6 ids, so legacy 3.x models (which
|
|
422
|
+
// reject unknown beta flags) never receive the field.
|
|
423
|
+
if (thinkingEnabled(request) && needsInterleavedThinkingBeta(request.model)) {
|
|
424
|
+
const existing = Array.isArray(params.anthropic_beta) ? params.anthropic_beta : [];
|
|
425
|
+
params.anthropic_beta = [...new Set([...existing, INTERLEAVED_THINKING_BETA])];
|
|
426
|
+
}
|
|
427
|
+
|
|
410
428
|
return params;
|
|
411
429
|
}
|
|
412
430
|
|
|
@@ -632,6 +650,15 @@ export class BedrockAdapter implements ProviderAdapter {
|
|
|
632
650
|
if (contentBlocks[currentBlockIndex]) {
|
|
633
651
|
contentBlocks[currentBlockIndex]!.signature = (contentBlocks[currentBlockIndex]!.signature ?? '') + (eventData.delta as any).signature;
|
|
634
652
|
}
|
|
653
|
+
} else if (eventData.delta?.type === 'input_json_delta' && (eventData.delta as any).partial_json !== undefined) {
|
|
654
|
+
// Tool-call arguments stream as input_json_delta fragments.
|
|
655
|
+
// Dropping these (pre-2026-07-21 behavior) gutted every
|
|
656
|
+
// tool_use block: stop_reason said tool_use but the block
|
|
657
|
+
// lost its input — and then its id/name in final assembly.
|
|
658
|
+
const blk = contentBlocks[currentBlockIndex] as (typeof contentBlocks)[number] & { partialJson?: string };
|
|
659
|
+
if (blk) {
|
|
660
|
+
blk.partialJson = (blk.partialJson ?? '') + (eventData.delta as any).partial_json;
|
|
661
|
+
}
|
|
635
662
|
}
|
|
636
663
|
} else if (eventData.type === 'content_block_stop') {
|
|
637
664
|
// Mirror the Anthropic adapter: fire onContentBlock a second
|
|
@@ -640,6 +667,13 @@ export class BedrockAdapter implements ProviderAdapter {
|
|
|
640
667
|
// on the dual-fire convention (e.g. membrane's native
|
|
641
668
|
// yielding path) silently drops block_complete on Bedrock.
|
|
642
669
|
const blockIdx = (eventData as { index?: number }).index ?? currentBlockIndex;
|
|
670
|
+
// Finalize tool_use blocks: parse accumulated argument JSON
|
|
671
|
+
// into `input` before the block_complete fire, so consumers
|
|
672
|
+
// of the dual-fire convention see a complete tool call.
|
|
673
|
+
const stoppedBlk = contentBlocks[blockIdx] as ((typeof contentBlocks)[number] & { partialJson?: string; input?: unknown }) | undefined;
|
|
674
|
+
if (stoppedBlk?.type === 'tool_use' && stoppedBlk.partialJson !== undefined) {
|
|
675
|
+
try { stoppedBlk.input = JSON.parse(stoppedBlk.partialJson || '{}'); } catch { /* keep prior input */ }
|
|
676
|
+
}
|
|
643
677
|
callbacks.onContentBlock?.(blockIdx, contentBlocks[blockIdx]);
|
|
644
678
|
} else if (eventData.type === 'message_delta') {
|
|
645
679
|
if (eventData.usage) {
|
|
@@ -687,6 +721,17 @@ export class BedrockAdapter implements ProviderAdapter {
|
|
|
687
721
|
// Pass through verbatim — carries the encrypted `data` payload
|
|
688
722
|
return { ...b } as unknown as { type: 'text'; text?: string };
|
|
689
723
|
}
|
|
724
|
+
if (b.type === 'tool_use') {
|
|
725
|
+
// Preserve id/name and the input accumulated from input_json_delta
|
|
726
|
+
// fragments — the generic text mapping below would strip them and
|
|
727
|
+
// parseResponse would then drop the block (requires id && name).
|
|
728
|
+
const tb = b as { type: string; id?: string; name?: string; input?: unknown; partialJson?: string };
|
|
729
|
+
let input: unknown = tb.input ?? {};
|
|
730
|
+
if (tb.partialJson) {
|
|
731
|
+
try { input = JSON.parse(tb.partialJson); } catch { /* keep prior input */ }
|
|
732
|
+
}
|
|
733
|
+
return { type: 'tool_use', id: tb.id, name: tb.name, input } as unknown as { type: 'text'; text?: string };
|
|
734
|
+
}
|
|
690
735
|
return { type: b.type as 'text', text: b.text };
|
|
691
736
|
}),
|
|
692
737
|
model: modelId,
|
package/src/types/config.ts
CHANGED
|
@@ -136,6 +136,14 @@ export interface MembraneConfig {
|
|
|
136
136
|
*/
|
|
137
137
|
maxParticipantsForStop?: number;
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Default for request.promptCaching when the request doesn't set it.
|
|
141
|
+
* Historical default is true (Anthropic API). Set false for transports
|
|
142
|
+
* that reject cache_control (e.g. Bedrock legacy Claude models, which 400
|
|
143
|
+
* with "your request did not allow prompt caching").
|
|
144
|
+
*/
|
|
145
|
+
defaultPromptCaching?: boolean;
|
|
146
|
+
|
|
139
147
|
/**
|
|
140
148
|
* Prefill formatter for message serialization and response parsing.
|
|
141
149
|
* Controls how messages are formatted for the API and how responses are parsed.
|
package/src/types/content.ts
CHANGED
|
@@ -110,6 +110,17 @@ export interface ToolUseContent {
|
|
|
110
110
|
id: string;
|
|
111
111
|
name: string;
|
|
112
112
|
input: Record<string, unknown>;
|
|
113
|
+
/**
|
|
114
|
+
* Verbatim document text this call was parsed from in prefill/XML mode:
|
|
115
|
+
* the full `<function_calls>…</function_calls>` block, shared by every
|
|
116
|
+
* invoke parsed from that block. Prefill formatters replay it exactly
|
|
117
|
+
* instead of synthesizing a rendering — in prefill mode the context IS
|
|
118
|
+
* the document the agent authored, and a paraphrase of its own action
|
|
119
|
+
* both corrupts the record and teaches the model a syntax the parser
|
|
120
|
+
* does not accept (membrane#36). Analogous to `signature` on a thinking
|
|
121
|
+
* block. Absent on native-tools blocks and on legacy stored blocks.
|
|
122
|
+
*/
|
|
123
|
+
rawXml?: string;
|
|
113
124
|
/** See {@link TextContent.rawItem}. */
|
|
114
125
|
rawItem?: unknown;
|
|
115
126
|
}
|
|
@@ -119,6 +130,13 @@ export interface ToolResultContent {
|
|
|
119
130
|
toolUseId: string;
|
|
120
131
|
content: string | ContentBlock[];
|
|
121
132
|
isError?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Verbatim document text this result was parsed from in prefill/XML mode:
|
|
135
|
+
* the full `<function_results>…</function_results>` block as the harness
|
|
136
|
+
* originally placed it in the document, shared by every result parsed
|
|
137
|
+
* from that block. Replayed exactly on the prefill path (membrane#36).
|
|
138
|
+
*/
|
|
139
|
+
rawXml?: string;
|
|
122
140
|
/** See {@link TextContent.rawItem}. */
|
|
123
141
|
rawItem?: unknown;
|
|
124
142
|
}
|
package/src/types/provider.ts
CHANGED
|
@@ -239,6 +239,12 @@ export interface ProviderRequestOptions {
|
|
|
239
239
|
timeoutMs?: number;
|
|
240
240
|
/** Abort if no SSE event arrives within this many ms (default: 120000) */
|
|
241
241
|
idleTimeoutMs?: number;
|
|
242
|
+
/**
|
|
243
|
+
* Deadline for the FIRST stream event (TTFT). Large contexts on a cache
|
|
244
|
+
* miss legitimately take minutes before message_start while the SDK
|
|
245
|
+
* swallows ping keepalives (default: max(idleTimeoutMs, 600000)).
|
|
246
|
+
*/
|
|
247
|
+
firstEventTimeoutMs?: number;
|
|
242
248
|
/** Called with the raw API request body right before fetch */
|
|
243
249
|
onRequest?: (rawRequest: unknown) => void;
|
|
244
250
|
/**
|
package/src/utils/tool-parser.ts
CHANGED
|
@@ -350,6 +350,10 @@ export function parseAccumulatedIntoBlocks(
|
|
|
350
350
|
let funcMatch: RegExpExecArray | null;
|
|
351
351
|
while ((funcMatch = FUNCTION_BLOCK_WITH_CONTENT_REGEX.exec(processedText)) !== null) {
|
|
352
352
|
const innerContent = funcMatch[2] ?? '';
|
|
353
|
+
// Verbatim document text of the whole block — carried on each parsed
|
|
354
|
+
// tool_use so prefill replay reproduces the generation exactly instead
|
|
355
|
+
// of synthesizing a paraphrase (membrane#36).
|
|
356
|
+
const rawXml = funcMatch[0];
|
|
353
357
|
const blockToolCalls: ContentBlock[] = [];
|
|
354
358
|
|
|
355
359
|
// Parse invoke tags in this block
|
|
@@ -378,6 +382,7 @@ export function parseAccumulatedIntoBlocks(
|
|
|
378
382
|
id,
|
|
379
383
|
name: toolName,
|
|
380
384
|
input,
|
|
385
|
+
rawXml,
|
|
381
386
|
});
|
|
382
387
|
}
|
|
383
388
|
|
|
@@ -394,6 +399,7 @@ export function parseAccumulatedIntoBlocks(
|
|
|
394
399
|
id,
|
|
395
400
|
name: toolName,
|
|
396
401
|
input: {},
|
|
402
|
+
rawXml,
|
|
397
403
|
});
|
|
398
404
|
}
|
|
399
405
|
|
|
@@ -411,6 +417,9 @@ export function parseAccumulatedIntoBlocks(
|
|
|
411
417
|
let resultsMatch: RegExpExecArray | null;
|
|
412
418
|
while ((resultsMatch = FUNCTION_RESULTS_BLOCK_REGEX.exec(processedText)) !== null) {
|
|
413
419
|
const innerContent = resultsMatch[2] ?? '';
|
|
420
|
+
// Verbatim document text the harness placed — carried for exact replay
|
|
421
|
+
// on the prefill path (membrane#36).
|
|
422
|
+
const rawXml = resultsMatch[0];
|
|
414
423
|
const blockResults: ContentBlock[] = [];
|
|
415
424
|
|
|
416
425
|
// Parse result tags
|
|
@@ -426,6 +435,7 @@ export function parseAccumulatedIntoBlocks(
|
|
|
426
435
|
toolUseId,
|
|
427
436
|
content,
|
|
428
437
|
isError: false,
|
|
438
|
+
rawXml,
|
|
429
439
|
});
|
|
430
440
|
}
|
|
431
441
|
|
|
@@ -442,6 +452,7 @@ export function parseAccumulatedIntoBlocks(
|
|
|
442
452
|
toolUseId,
|
|
443
453
|
content,
|
|
444
454
|
isError: true,
|
|
455
|
+
rawXml,
|
|
445
456
|
});
|
|
446
457
|
}
|
|
447
458
|
|