@animalabs/membrane 0.5.42 → 0.5.44

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.
Files changed (57) hide show
  1. package/dist/formatters/completions.d.ts +7 -0
  2. package/dist/formatters/completions.d.ts.map +1 -1
  3. package/dist/formatters/completions.js +9 -0
  4. package/dist/formatters/completions.js.map +1 -1
  5. package/dist/formatters/index.d.ts +1 -0
  6. package/dist/formatters/index.js +1 -0
  7. package/dist/formatters/index.js.map +1 -1
  8. package/dist/formatters/types.d.ts +4 -0
  9. package/dist/membrane.d.ts +3 -0
  10. package/dist/membrane.d.ts.map +1 -1
  11. package/dist/membrane.js +75 -12
  12. package/dist/membrane.js.map +1 -1
  13. package/dist/providers/anthropic.d.ts.map +1 -1
  14. package/dist/providers/anthropic.js +9 -1
  15. package/dist/providers/anthropic.js.map +1 -1
  16. package/dist/providers/bedrock.js +4 -13
  17. package/dist/providers/bedrock.js.map +1 -1
  18. package/dist/providers/gemini.js +2 -11
  19. package/dist/providers/gemini.js.map +1 -1
  20. package/dist/providers/openai-compatible.js +15 -25
  21. package/dist/providers/openai-compatible.js.map +1 -1
  22. package/dist/providers/openai-completions.js +24 -48
  23. package/dist/providers/openai-completions.js.map +1 -1
  24. package/dist/providers/openai-responses.js +1 -6
  25. package/dist/providers/openai-responses.js.map +1 -1
  26. package/dist/providers/openai.js +15 -25
  27. package/dist/providers/openai.js.map +1 -1
  28. package/dist/providers/openrouter.js +16 -35
  29. package/dist/providers/openrouter.js.map +1 -1
  30. package/dist/providers/utils.d.ts +0 -38
  31. package/dist/providers/utils.d.ts.map +1 -1
  32. package/dist/providers/utils.js +0 -86
  33. package/dist/providers/utils.js.map +1 -1
  34. package/dist/registry/default-pricing.d.ts +3 -0
  35. package/dist/registry/default-pricing.d.ts.map +1 -0
  36. package/dist/registry/default-pricing.js +75 -0
  37. package/dist/registry/default-pricing.js.map +1 -0
  38. package/dist/types/request.d.ts +0 -8
  39. package/dist/types/request.d.ts.map +1 -1
  40. package/dist/types/yielding-stream.d.ts +2 -2
  41. package/dist/types/yielding-stream.d.ts.map +1 -1
  42. package/dist/utils/cost.d.ts +10 -0
  43. package/dist/utils/cost.d.ts.map +1 -0
  44. package/dist/utils/cost.js +19 -0
  45. package/dist/utils/cost.js.map +1 -0
  46. package/dist/utils/index.d.ts +2 -0
  47. package/dist/utils/index.d.ts.map +1 -1
  48. package/dist/utils/index.js +1 -0
  49. package/dist/utils/index.js.map +1 -1
  50. package/package.json +1 -1
  51. package/src/formatters/completions.ts +19 -0
  52. package/src/membrane.ts +83 -18
  53. package/src/providers/anthropic.ts +13 -1
  54. package/src/registry/default-pricing.ts +77 -0
  55. package/src/types/yielding-stream.ts +2 -2
  56. package/src/utils/cost.ts +29 -0
  57. package/src/utils/index.ts +3 -0
@@ -3,42 +3,4 @@
3
3
  * Used for tool call arguments which may be malformed from streaming.
4
4
  */
5
5
  export declare function safeParseJson(str: string | undefined): Record<string, unknown>;
6
- /**
7
- * Create a combined AbortSignal that fires on either the caller's signal
8
- * or a timeout (whichever comes first).
9
- *
10
- * The returned `cleanup` function MUST be called in a `finally` block to
11
- * clear the timeout and remove the event listener, preventing leaks.
12
- *
13
- * Timeout aborts with `DOMException('Request timed out', 'AbortError')`
14
- * so it classifies identically to user-initiated aborts.
15
- */
16
- export declare function createCombinedSignal(signal?: AbortSignal, timeoutMs?: number): {
17
- signal?: AbortSignal;
18
- cleanup?: () => void;
19
- };
20
- /**
21
- * SSE (Server-Sent Events) line parser that correctly handles events
22
- * split across multiple TCP chunks.
23
- *
24
- * The naive approach of `chunk.split('\n').filter(l => l.startsWith('data: '))`
25
- * silently drops events when an SSE line spans two chunks:
26
- * Chunk 1: `data: {"choices":[{"delta":{"content":"don'` (no newline — incomplete)
27
- * Chunk 2: `t do that"}}]}\n` (doesn't start with `data: `)
28
- * Result: the entire event is lost, causing "skipped words" in output.
29
- *
30
- * This parser buffers partial lines and only yields complete `data: ...` lines.
31
- */
32
- export declare class SSELineParser {
33
- private buffer;
34
- /**
35
- * Feed a raw chunk from the stream reader and get back complete SSE data lines.
36
- * Each returned string is the content after `data: ` (e.g. the JSON payload or `[DONE]`).
37
- */
38
- feed(chunk: string): string[];
39
- /**
40
- * Flush any remaining buffered content (call when stream ends).
41
- */
42
- flush(): string[];
43
- }
44
6
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,CAAC,EAAE,WAAW,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB;IAAE,MAAM,CAAC,EAAE,WAAW,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CAAE,CA8BhD;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAc;IAE5B;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE;IAmB7B;;OAEG;IACH,KAAK,IAAI,MAAM,EAAE;CASlB"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO9E"}
@@ -11,90 +11,4 @@ export function safeParseJson(str) {
11
11
  return {};
12
12
  }
13
13
  }
14
- /**
15
- * Create a combined AbortSignal that fires on either the caller's signal
16
- * or a timeout (whichever comes first).
17
- *
18
- * The returned `cleanup` function MUST be called in a `finally` block to
19
- * clear the timeout and remove the event listener, preventing leaks.
20
- *
21
- * Timeout aborts with `DOMException('Request timed out', 'AbortError')`
22
- * so it classifies identically to user-initiated aborts.
23
- */
24
- export function createCombinedSignal(signal, timeoutMs) {
25
- if (!signal && !timeoutMs)
26
- return {};
27
- if (signal && !timeoutMs)
28
- return { signal };
29
- const controller = new AbortController();
30
- let timeoutId;
31
- if (timeoutMs) {
32
- timeoutId = setTimeout(() => controller.abort(new DOMException('Request timed out', 'AbortError')), timeoutMs);
33
- }
34
- const onAbort = () => controller.abort(signal.reason);
35
- if (signal) {
36
- if (signal.aborted) {
37
- controller.abort(signal.reason);
38
- }
39
- else {
40
- signal.addEventListener('abort', onAbort, { once: true });
41
- }
42
- }
43
- return {
44
- signal: controller.signal,
45
- cleanup: () => {
46
- if (timeoutId)
47
- clearTimeout(timeoutId);
48
- if (signal)
49
- signal.removeEventListener('abort', onAbort);
50
- },
51
- };
52
- }
53
- /**
54
- * SSE (Server-Sent Events) line parser that correctly handles events
55
- * split across multiple TCP chunks.
56
- *
57
- * The naive approach of `chunk.split('\n').filter(l => l.startsWith('data: '))`
58
- * silently drops events when an SSE line spans two chunks:
59
- * Chunk 1: `data: {"choices":[{"delta":{"content":"don'` (no newline — incomplete)
60
- * Chunk 2: `t do that"}}]}\n` (doesn't start with `data: `)
61
- * Result: the entire event is lost, causing "skipped words" in output.
62
- *
63
- * This parser buffers partial lines and only yields complete `data: ...` lines.
64
- */
65
- export class SSELineParser {
66
- buffer = '';
67
- /**
68
- * Feed a raw chunk from the stream reader and get back complete SSE data lines.
69
- * Each returned string is the content after `data: ` (e.g. the JSON payload or `[DONE]`).
70
- */
71
- feed(chunk) {
72
- this.buffer += chunk;
73
- const results = [];
74
- // Split on newlines, keeping the last (potentially incomplete) segment in the buffer
75
- const lines = this.buffer.split('\n');
76
- this.buffer = lines.pop() || '';
77
- for (const line of lines) {
78
- const trimmed = line.trim();
79
- if (trimmed.startsWith('data: ')) {
80
- results.push(trimmed.slice(6));
81
- }
82
- // Skip empty lines, comments (`:...`), and other SSE fields (event:, id:, retry:)
83
- }
84
- return results;
85
- }
86
- /**
87
- * Flush any remaining buffered content (call when stream ends).
88
- */
89
- flush() {
90
- if (!this.buffer.trim())
91
- return [];
92
- const trimmed = this.buffer.trim();
93
- this.buffer = '';
94
- if (trimmed.startsWith('data: ')) {
95
- return [trimmed.slice(6)];
96
- }
97
- return [];
98
- }
99
- }
100
14
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/providers/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,GAAuB;IACnD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,IAAI,CAAC,iDAAiD,EAAE,CAAC,CAAC,CAAC;QACnE,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ModelPricing } from '../types/provider.js';
2
+ export declare function getDefaultPricing(modelId: string): ModelPricing | undefined;
3
+ //# sourceMappingURL=default-pricing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-pricing.d.ts","sourceRoot":"","sources":["../../src/registry/default-pricing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAkEzD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAU3E"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Built-in pricing table for known models.
3
+ * Prices in USD per million tokens. Last updated: 2025-07.
4
+ *
5
+ * Used as fallback when no ModelRegistry is configured.
6
+ * Registry pricing (if available) takes precedence.
7
+ */
8
+ const PRICING_TABLE = [
9
+ // Anthropic — Claude 4.6
10
+ {
11
+ prefix: 'claude-opus-4-6',
12
+ pricing: { inputPerMillion: 15, outputPerMillion: 75, cacheWritePerMillion: 18.75, cacheReadPerMillion: 1.50, currency: 'USD' },
13
+ },
14
+ {
15
+ prefix: 'claude-sonnet-4-6',
16
+ pricing: { inputPerMillion: 3, outputPerMillion: 15, cacheWritePerMillion: 3.75, cacheReadPerMillion: 0.30, currency: 'USD' },
17
+ },
18
+ // Anthropic — Claude 4.5
19
+ {
20
+ prefix: 'claude-haiku-4-5',
21
+ pricing: { inputPerMillion: 0.80, outputPerMillion: 4, cacheWritePerMillion: 1.00, cacheReadPerMillion: 0.08, currency: 'USD' },
22
+ },
23
+ // Anthropic — Claude 4
24
+ {
25
+ prefix: 'claude-opus-4',
26
+ pricing: { inputPerMillion: 15, outputPerMillion: 75, cacheWritePerMillion: 18.75, cacheReadPerMillion: 1.50, currency: 'USD' },
27
+ },
28
+ {
29
+ prefix: 'claude-sonnet-4',
30
+ pricing: { inputPerMillion: 3, outputPerMillion: 15, cacheWritePerMillion: 3.75, cacheReadPerMillion: 0.30, currency: 'USD' },
31
+ },
32
+ // Anthropic — Claude 3.5
33
+ {
34
+ prefix: 'claude-3-5-sonnet',
35
+ pricing: { inputPerMillion: 3, outputPerMillion: 15, cacheWritePerMillion: 3.75, cacheReadPerMillion: 0.30, currency: 'USD' },
36
+ },
37
+ {
38
+ prefix: 'claude-3-5-haiku',
39
+ pricing: { inputPerMillion: 0.80, outputPerMillion: 4, cacheWritePerMillion: 1.00, cacheReadPerMillion: 0.08, currency: 'USD' },
40
+ },
41
+ // OpenAI — GPT-4o
42
+ {
43
+ prefix: 'gpt-4o-2024',
44
+ pricing: { inputPerMillion: 2.50, outputPerMillion: 10, cacheReadPerMillion: 1.25, currency: 'USD' },
45
+ },
46
+ {
47
+ prefix: 'gpt-4o',
48
+ pricing: { inputPerMillion: 2.50, outputPerMillion: 10, cacheReadPerMillion: 1.25, currency: 'USD' },
49
+ },
50
+ {
51
+ prefix: 'gpt-4o-mini',
52
+ pricing: { inputPerMillion: 0.15, outputPerMillion: 0.60, cacheReadPerMillion: 0.075, currency: 'USD' },
53
+ },
54
+ // Google — Gemini 2.5
55
+ {
56
+ prefix: 'gemini-2.5-pro',
57
+ pricing: { inputPerMillion: 1.25, outputPerMillion: 10, currency: 'USD' },
58
+ },
59
+ {
60
+ prefix: 'gemini-2.5-flash',
61
+ pricing: { inputPerMillion: 0.15, outputPerMillion: 0.60, currency: 'USD' },
62
+ },
63
+ ];
64
+ export function getDefaultPricing(modelId) {
65
+ let best;
66
+ let bestLen = 0;
67
+ for (const entry of PRICING_TABLE) {
68
+ if (modelId.startsWith(entry.prefix) && entry.prefix.length > bestLen) {
69
+ best = entry.pricing;
70
+ bestLen = entry.prefix.length;
71
+ }
72
+ }
73
+ return best;
74
+ }
75
+ //# sourceMappingURL=default-pricing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"default-pricing.js","sourceRoot":"","sources":["../../src/registry/default-pricing.ts"],"names":[],"mappings":"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"}
@@ -102,14 +102,6 @@ export interface NormalizedRequest {
102
102
  * Default: 'Claude'
103
103
  */
104
104
  assistantParticipant?: string;
105
- /**
106
- * Control streaming behavior when calling membrane.stream().
107
- * - true or undefined: use streaming (default)
108
- * - false: force non-streaming — membrane.stream() will internally use
109
- * complete() and synthesize streaming callbacks from the full response.
110
- * Useful for working around provider streaming bugs.
111
- */
112
- streaming?: boolean;
113
105
  /** Provider-specific parameters (pass-through) */
114
106
  providerParams?: Record<string, unknown>;
115
107
  }
@@ -1 +1 @@
1
- {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/types/request.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"request.d.ts","sourceRoot":"","sources":["../../src/types/request.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAMjD,MAAM,WAAW,gBAAgB;IAC/B,uBAAuB;IACvB,KAAK,EAAE,MAAM,CAAC;IAEd,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAElB,wBAAwB;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,yCAAyC;IACzC,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd,2CAA2C;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IAEzB,4CAA4C;IAC5C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE;QACT,OAAO,EAAE,OAAO,CAAC;QACjB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,CAAC;IAEF,uCAAuC;IACvC,eAAe,CAAC,EAAE;QAChB,OAAO,EAAE,OAAO,CAAC;QACjB,UAAU,EAAE,CAAC,MAAM,GAAG,OAAO,CAAC,EAAE,CAAC;QACjC,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,GAAG,KAAK,CAAC;QACtD,SAAS,CAAC,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;KAC1C,CAAC;CACH;AAMD,MAAM,MAAM,oBAAoB,GAC5B,MAAM,GACN,YAAY,GACZ,oBAAoB,CAAC;AAEzB,MAAM,WAAW,kBAAkB;IACjC,4BAA4B;IAC5B,SAAS,EAAE,MAAM,EAAE,CAAC;IAEpB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAEhC,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAMD,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,MAAM,CAAC,EAAE,WAAW,CAAC;IAErB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,iCAAiC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAMD,MAAM,MAAM,QAAQ,GAChB,KAAK,GACL,QAAQ,GACR,MAAM,CAAC;AAMX,MAAM,WAAW,iBAAiB;IAChC,4BAA4B;IAC5B,QAAQ,EAAE,iBAAiB,EAAE,CAAC;IAE9B,oBAAoB;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,+BAA+B;IAC/B,MAAM,EAAE,gBAAgB,CAAC;IAEzB,uBAAuB;IACvB,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IAEzB,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAEpB,kCAAkC;IAClC,aAAa,CAAC,EAAE,kBAAkB,GAAG,MAAM,EAAE,CAAC;IAE9C;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IAEvB;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAE5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B,kDAAkD;IAClD,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC1C"}
@@ -9,7 +9,7 @@
9
9
  */
10
10
  import type { ContentBlock } from './content.js';
11
11
  import type { ToolCall, ToolResult, ToolContext } from './tools.js';
12
- import type { BasicUsage, NormalizedResponse } from './response.js';
12
+ import type { DetailedUsage, NormalizedResponse } from './response.js';
13
13
  import type { ChunkMeta, BlockEvent } from './streaming.js';
14
14
  /**
15
15
  * Token/chunk event - raw text as it arrives from the LLM.
@@ -40,7 +40,7 @@ export interface ToolCallsEvent {
40
40
  */
41
41
  export interface UsageEvent {
42
42
  type: 'usage';
43
- usage: BasicUsage;
43
+ usage: DetailedUsage;
44
44
  }
45
45
  /**
46
46
  * Complete event - inference cycle finished successfully.
@@ -1 +1 @@
1
- {"version":3,"file":"yielding-stream.d.ts","sourceRoot":"","sources":["../../src/types/yielding-stream.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"yielding-stream.d.ts","sourceRoot":"","sources":["../../src/types/yielding-stream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { CostBreakdown } from '../types/response.js';
2
+ import type { ModelPricing } from '../types/provider.js';
3
+ export interface CostableUsage {
4
+ inputTokens: number;
5
+ outputTokens: number;
6
+ cacheCreationTokens?: number;
7
+ cacheReadTokens?: number;
8
+ }
9
+ export declare function calculateCost(usage: CostableUsage, pricing: ModelPricing): CostBreakdown;
10
+ //# sourceMappingURL=cost.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.d.ts","sourceRoot":"","sources":["../../src/utils/cost.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,GAAG,aAAa,CAkBxF"}
@@ -0,0 +1,19 @@
1
+ export function calculateCost(usage, pricing) {
2
+ const input = usage.inputTokens * pricing.inputPerMillion / 1_000_000;
3
+ const output = usage.outputTokens * pricing.outputPerMillion / 1_000_000;
4
+ const cacheWrite = pricing.cacheWritePerMillion != null
5
+ ? (usage.cacheCreationTokens ?? 0) * pricing.cacheWritePerMillion / 1_000_000
6
+ : undefined;
7
+ const cacheRead = pricing.cacheReadPerMillion != null
8
+ ? (usage.cacheReadTokens ?? 0) * pricing.cacheReadPerMillion / 1_000_000
9
+ : undefined;
10
+ return {
11
+ input,
12
+ output,
13
+ cacheWrite,
14
+ cacheRead,
15
+ total: input + output + (cacheWrite ?? 0) + (cacheRead ?? 0),
16
+ currency: pricing.currency,
17
+ };
18
+ }
19
+ //# sourceMappingURL=cost.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/utils/cost.ts"],"names":[],"mappings":"AAUA,MAAM,UAAU,aAAa,CAAC,KAAoB,EAAE,OAAqB;IACvE,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,GAAG,OAAO,CAAC,eAAe,GAAG,SAAS,CAAC;IACtE,MAAM,MAAM,GAAG,KAAK,CAAC,YAAY,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC;IACzE,MAAM,UAAU,GAAG,OAAO,CAAC,oBAAoB,IAAI,IAAI;QACrD,CAAC,CAAC,CAAC,KAAK,CAAC,mBAAmB,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,oBAAoB,GAAG,SAAS;QAC7E,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,SAAS,GAAG,OAAO,CAAC,mBAAmB,IAAI,IAAI;QACnD,CAAC,CAAC,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,CAAC,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS;QACxE,CAAC,CAAC,SAAS,CAAC;IAEd,OAAO;QACL,KAAK;QACL,MAAM;QACN,UAAU;QACV,SAAS;QACT,KAAK,EAAE,KAAK,GAAG,MAAM,GAAG,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,CAAC;QAC5D,QAAQ,EAAE,OAAO,CAAC,QAAQ;KAC3B,CAAC;AACJ,CAAC"}
@@ -2,4 +2,6 @@
2
2
  * Utility exports
3
3
  */
4
4
  export { parseToolCalls, formatToolResults, formatToolResult, formatToolDefinitions, getToolInstructions, hasUnclosedToolBlock, endsWithPartialToolBlock, unescapeXml, type ToolDefinitionForPrompt, } from './tool-parser.js';
5
+ export { calculateCost } from './cost.js';
6
+ export type { CostableUsage } from './cost.js';
5
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,EACX,KAAK,uBAAuB,GAC7B,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
@@ -2,4 +2,5 @@
2
2
  * Utility exports
3
3
  */
4
4
  export { parseToolCalls, formatToolResults, formatToolResult, formatToolDefinitions, getToolInstructions, hasUnclosedToolBlock, endsWithPartialToolBlock, unescapeXml, } from './tool-parser.js';
5
+ export { calculateCost } from './cost.js';
5
6
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,GAEZ,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,wBAAwB,EACxB,WAAW,GAEZ,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@animalabs/membrane",
3
- "version": "0.5.42",
3
+ "version": "0.5.44",
4
4
  "description": "LLM middleware - a selective boundary that transforms what passes through",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -63,6 +63,14 @@ export interface CompletionsFormatterConfig extends FormatterConfig {
63
63
  */
64
64
  maxParticipantsForStop?: number;
65
65
 
66
+ /**
67
+ * Add lowercased variants of participant stop sequences.
68
+ * Useful for models whose tokenizer doesn't normalize casing,
69
+ * allowing simmed names with different casing to still trigger stops.
70
+ * Default: false
71
+ */
72
+ caseInsensitiveStops?: boolean;
73
+
66
74
  /**
67
75
  * Whether to warn when images are stripped.
68
76
  * Default: true
@@ -187,6 +195,7 @@ export class CompletionsFormatter implements PrefillFormatter {
187
195
  nameFormat: config.nameFormat ?? '{name}: ',
188
196
  messageSeparator: config.messageSeparator ?? '\n\n',
189
197
  maxParticipantsForStop: config.maxParticipantsForStop ?? 10,
198
+ caseInsensitiveStops: config.caseInsensitiveStops ?? false,
190
199
  warnOnImageStrip: config.warnOnImageStrip ?? true,
191
200
  // Completions models don't support images - always strip
192
201
  unsupportedMedia: 'strip',
@@ -364,6 +373,16 @@ export class CompletionsFormatter implements PrefillFormatter {
364
373
  const prefix = this.config.nameFormat.replace('{name}', participant).trimEnd();
365
374
  stops.push(`\n\n${prefix}`);
366
375
  stops.push(`\n${prefix}`);
376
+
377
+ // Add lowercased variants if casing differs (for models that generate mixed-case names)
378
+ if (this.config.caseInsensitiveStops) {
379
+ const lower = this.config.nameFormat.replace('{name}', participant.toLowerCase()).trimEnd();
380
+ if (lower !== prefix) {
381
+ stops.push(`\n\n${lower}`);
382
+ stops.push(`\n${lower}`);
383
+ }
384
+ }
385
+
367
386
  count++;
368
387
  }
369
388
 
package/src/membrane.ts CHANGED
@@ -53,6 +53,8 @@ import type {
53
53
  import type { PrefillFormatter, StreamParser } from './formatters/types.js';
54
54
  import { AnthropicXmlFormatter } from './formatters/anthropic-xml.js';
55
55
  import { YieldingStreamImpl } from './yielding-stream.js';
56
+ import { calculateCost } from './utils/cost.js';
57
+ import { getDefaultPricing } from './registry/default-pricing.js';
56
58
 
57
59
  // ============================================================================
58
60
  // Membrane Class
@@ -273,6 +275,7 @@ export class Membrane {
273
275
  const parser = formatter.createStreamParser();
274
276
  let toolDepth = 0;
275
277
  let totalUsage: DetailedUsage = { inputTokens: 0, outputTokens: 0 };
278
+ const pricing = this.resolvePricing(request.config.model);
276
279
  const contentBlocks: ContentBlock[] = [];
277
280
  let lastStopReason: StopReason = 'end_turn';
278
281
  let lastStopSequence: string | undefined;
@@ -425,6 +428,7 @@ export class Membrane {
425
428
  if (streamResult.usage.cacheReadTokens) {
426
429
  totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + streamResult.usage.cacheReadTokens;
427
430
  }
431
+ if (pricing) totalUsage.estimatedCost = calculateCost(totalUsage, pricing);
428
432
  onUsage?.(totalUsage);
429
433
 
430
434
  // Flush the parser to complete any in-progress streaming block
@@ -737,6 +741,7 @@ export class Membrane {
737
741
 
738
742
  let toolDepth = 0;
739
743
  let totalUsage: DetailedUsage = { inputTokens: 0, outputTokens: 0 };
744
+ const pricing = this.resolvePricing(request.config.model);
740
745
  let lastStopReason: StopReason = 'end_turn';
741
746
  let lastStopSequence: string | undefined;
742
747
  let rawRequest: unknown;
@@ -807,6 +812,7 @@ export class Membrane {
807
812
  if (streamResult.usage.cacheReadTokens) {
808
813
  totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + streamResult.usage.cacheReadTokens;
809
814
  }
815
+ if (pricing) totalUsage.estimatedCost = calculateCost(totalUsage, pricing);
810
816
  onUsage?.(totalUsage);
811
817
 
812
818
  // Parse content blocks from response
@@ -960,15 +966,23 @@ export class Membrane {
960
966
  const assistantName = request.assistantParticipant
961
967
  ?? this.config.assistantParticipant ?? 'Claude';
962
968
 
969
+ const promptCaching = request.promptCaching ?? true;
970
+ const cacheControl = promptCaching ? { type: 'ephemeral' as const, ...(request.cacheTtl ? { ttl: request.cacheTtl } : {}) } : undefined;
971
+
963
972
  for (const msg of messages) {
964
973
  const isAssistant = msg.participant === assistantName;
965
974
  const role = isAssistant ? 'assistant' : 'user';
966
-
975
+
967
976
  // Convert content blocks
968
977
  const content: any[] = [];
978
+ const includeNamePrefix = !isAssistant;
969
979
  for (const block of msg.content) {
970
980
  if (block.type === 'text') {
971
- const textBlock: Record<string, unknown> = { type: 'text', text: block.text };
981
+ let text = block.text;
982
+ if (includeNamePrefix && msg.participant) {
983
+ text = `${msg.participant}: ${text}`;
984
+ }
985
+ const textBlock: Record<string, unknown> = { type: 'text', text };
972
986
  if ((block as any).cache_control) {
973
987
  textBlock.cache_control = (block as any).cache_control;
974
988
  }
@@ -1005,19 +1019,42 @@ export class Membrane {
1005
1019
  }
1006
1020
  }
1007
1021
  }
1008
-
1022
+
1023
+ // Apply cache_control to last block of messages with cacheBreakpoint
1024
+ if (msg.cacheBreakpoint && cacheControl && content.length > 0) {
1025
+ content[content.length - 1].cache_control = cacheControl;
1026
+ }
1027
+
1009
1028
  providerMessages.push({ role, content });
1010
1029
  }
1011
1030
 
1012
1031
  // Convert tools to provider format.
1013
1032
  // Native tool names must match ^[a-zA-Z0-9_-]{1,128}$ — sanitize colons
1014
1033
  // from the module:tool namespace convention. Reversed in parseProviderContent.
1015
- const tools = request.tools?.map(tool => ({
1016
- name: sanitizeToolName(tool.name),
1017
- description: tool.description,
1018
- input_schema: tool.inputSchema,
1019
- }));
1020
-
1034
+ const tools = request.tools?.map((tool, idx) => {
1035
+ const t: Record<string, unknown> = {
1036
+ name: sanitizeToolName(tool.name),
1037
+ description: tool.description,
1038
+ input_schema: tool.inputSchema,
1039
+ };
1040
+ // Cache the tool list — mark the last tool with cache_control
1041
+ if (cacheControl && request.tools && idx === request.tools.length - 1) {
1042
+ t.cache_control = cacheControl;
1043
+ }
1044
+ return t;
1045
+ });
1046
+
1047
+ // Wrap system prompt with cache_control if prompt caching is enabled
1048
+ let system: unknown = request.system;
1049
+ if (cacheControl && typeof system === 'string' && system.length > 0) {
1050
+ system = [{ type: 'text', text: system, cache_control: cacheControl }];
1051
+ } else if (cacheControl && Array.isArray(system) && system.length > 0) {
1052
+ const blocks = system as Record<string, unknown>[];
1053
+ system = blocks.map((block, idx) =>
1054
+ idx === blocks.length - 1 ? { ...block, cache_control: cacheControl } : block
1055
+ );
1056
+ }
1057
+
1021
1058
  // Build thinking config for native extended thinking
1022
1059
  const thinking = request.config.thinking?.enabled
1023
1060
  ? {
@@ -1034,7 +1071,7 @@ export class Membrane {
1034
1071
  maxTokens: request.config.maxTokens,
1035
1072
  temperature,
1036
1073
  messages: providerMessages,
1037
- system: request.system,
1074
+ system,
1038
1075
  tools,
1039
1076
  thinking,
1040
1077
  extra: request.providerParams,
@@ -1377,6 +1414,7 @@ export class Membrane {
1377
1414
  outputTokens: providerResponse.usage.outputTokens,
1378
1415
  cacheCreationTokens: providerResponse.usage.cacheCreationTokens,
1379
1416
  cacheReadTokens: providerResponse.usage.cacheReadTokens,
1417
+ estimatedCost: this.estimateCost(providerResponse.usage, request.config.model),
1380
1418
  },
1381
1419
  timing: {
1382
1420
  totalDurationMs: durationMs,
@@ -1458,6 +1496,7 @@ export class Membrane {
1458
1496
  },
1459
1497
  usage: {
1460
1498
  ...usage,
1499
+ estimatedCost: usage.estimatedCost ?? this.estimateCost(usage, request.config.model),
1461
1500
  },
1462
1501
  timing: {
1463
1502
  totalDurationMs: durationMs,
@@ -1497,13 +1536,23 @@ export class Membrane {
1497
1536
  }
1498
1537
  }
1499
1538
 
1500
- private calculateCacheHitRatio(usage: any): number {
1539
+ private calculateCacheHitRatio(usage: Pick<DetailedUsage, 'inputTokens' | 'cacheReadTokens'>): number {
1501
1540
  const cacheRead = usage.cacheReadTokens ?? 0;
1502
1541
  const total = usage.inputTokens ?? 0;
1503
1542
  if (total === 0) return 0;
1504
1543
  return cacheRead / total;
1505
1544
  }
1506
1545
 
1546
+ private resolvePricing(model: string): import('./types/provider.js').ModelPricing | undefined {
1547
+ return this.registry?.getPricing(model) ?? getDefaultPricing(model);
1548
+ }
1549
+
1550
+ /** Resolve pricing + calculate cost in one call (for one-shot use outside loops). */
1551
+ private estimateCost(usage: import('./utils/cost.js').CostableUsage, model: string): import('./types/response.js').CostBreakdown | undefined {
1552
+ const pricing = this.resolvePricing(model);
1553
+ return pricing ? calculateCost(usage, pricing) : undefined;
1554
+ }
1555
+
1507
1556
  private calculateRetryDelay(attempt: number): number {
1508
1557
  const { retryDelayMs, backoffMultiplier, maxRetryDelayMs } = this.retryConfig;
1509
1558
  const delay = retryDelayMs * Math.pow(backoffMultiplier, attempt - 1);
@@ -1639,7 +1688,8 @@ export class Membrane {
1639
1688
  const formatter = this.formatter;
1640
1689
  const parser = formatter.createStreamParser();
1641
1690
  let toolDepth = 0;
1642
- let totalUsage: BasicUsage = { inputTokens: 0, outputTokens: 0 };
1691
+ let totalUsage: DetailedUsage = { inputTokens: 0, outputTokens: 0 };
1692
+ const pricing = this.resolvePricing(request.config.model);
1643
1693
  const contentBlocks: ContentBlock[] = [];
1644
1694
  let lastStopReason: StopReason = 'end_turn';
1645
1695
  let lastStopSequence: string | undefined;
@@ -1768,9 +1818,16 @@ export class Membrane {
1768
1818
  lastStopReason = this.mapStopReason(streamResult.stopReason);
1769
1819
  lastStopSequence = streamResult.stopSequence ?? undefined;
1770
1820
 
1771
- // Accumulate usage
1821
+ // Accumulate usage (including cache metrics)
1772
1822
  totalUsage.inputTokens += streamResult.usage.inputTokens;
1773
1823
  totalUsage.outputTokens += streamResult.usage.outputTokens;
1824
+ if (streamResult.usage.cacheCreationTokens) {
1825
+ totalUsage.cacheCreationTokens = (totalUsage.cacheCreationTokens ?? 0) + streamResult.usage.cacheCreationTokens;
1826
+ }
1827
+ if (streamResult.usage.cacheReadTokens) {
1828
+ totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + streamResult.usage.cacheReadTokens;
1829
+ }
1830
+ if (pricing) totalUsage.estimatedCost = calculateCost(totalUsage, pricing);
1774
1831
  if (emitUsage) {
1775
1832
  stream.emit({ type: 'usage', usage: { ...totalUsage } });
1776
1833
  }
@@ -2075,7 +2132,8 @@ export class Membrane {
2075
2132
  } = options;
2076
2133
 
2077
2134
  let toolDepth = 0;
2078
- let totalUsage: BasicUsage = { inputTokens: 0, outputTokens: 0 };
2135
+ let totalUsage: DetailedUsage = { inputTokens: 0, outputTokens: 0 };
2136
+ const pricing = this.resolvePricing(request.config.model);
2079
2137
  let lastStopReason: StopReason = 'end_turn';
2080
2138
  let lastStopSequence: string | undefined;
2081
2139
  let rawRequest: unknown;
@@ -2141,9 +2199,16 @@ export class Membrane {
2141
2199
  lastStopReason = this.mapStopReason(streamResult.stopReason);
2142
2200
  lastStopSequence = streamResult.stopSequence ?? undefined;
2143
2201
 
2144
- // Accumulate usage
2202
+ // Accumulate usage (including cache metrics)
2145
2203
  totalUsage.inputTokens += streamResult.usage.inputTokens;
2146
2204
  totalUsage.outputTokens += streamResult.usage.outputTokens;
2205
+ if (streamResult.usage.cacheCreationTokens) {
2206
+ totalUsage.cacheCreationTokens = (totalUsage.cacheCreationTokens ?? 0) + streamResult.usage.cacheCreationTokens;
2207
+ }
2208
+ if (streamResult.usage.cacheReadTokens) {
2209
+ totalUsage.cacheReadTokens = (totalUsage.cacheReadTokens ?? 0) + streamResult.usage.cacheReadTokens;
2210
+ }
2211
+ if (pricing) totalUsage.estimatedCost = calculateCost(totalUsage, pricing);
2147
2212
  if (emitUsage) {
2148
2213
  stream.emit({ type: 'usage', usage: { ...totalUsage } });
2149
2214
  }
@@ -2252,9 +2317,9 @@ export class Membrane {
2252
2317
  },
2253
2318
  cache: {
2254
2319
  markersInRequest: 0,
2255
- tokensCreated: 0,
2256
- tokensRead: 0,
2257
- hitRatio: 0,
2320
+ tokensCreated: totalUsage.cacheCreationTokens ?? 0,
2321
+ tokensRead: totalUsage.cacheReadTokens ?? 0,
2322
+ hitRatio: this.calculateCacheHitRatio(totalUsage),
2258
2323
  },
2259
2324
  },
2260
2325
  raw: {