@seanhogg/builderforce-memory 2026.9.29 → 2026.9.31

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 (118) hide show
  1. package/dist/bridges/AnthropicBridge.d.ts.map +1 -1
  2. package/dist/bridges/AnthropicBridge.js +24 -65
  3. package/dist/bridges/AnthropicBridge.js.map +1 -1
  4. package/dist/bridges/FetchBridge.d.ts +12 -5
  5. package/dist/bridges/FetchBridge.d.ts.map +1 -1
  6. package/dist/bridges/FetchBridge.js +6 -4
  7. package/dist/bridges/FetchBridge.js.map +1 -1
  8. package/dist/bridges/OpenAIBridge.d.ts +17 -4
  9. package/dist/bridges/OpenAIBridge.d.ts.map +1 -1
  10. package/dist/bridges/OpenAIBridge.js +71 -94
  11. package/dist/bridges/OpenAIBridge.js.map +1 -1
  12. package/dist/bridges/TransformerBridge.d.ts +6 -0
  13. package/dist/bridges/TransformerBridge.d.ts.map +1 -1
  14. package/dist/bridges/VertexAIBridge.d.ts.map +1 -1
  15. package/dist/bridges/VertexAIBridge.js +3 -34
  16. package/dist/bridges/VertexAIBridge.js.map +1 -1
  17. package/dist/distillation/DistillationEngine.d.ts +71 -54
  18. package/dist/distillation/DistillationEngine.d.ts.map +1 -1
  19. package/dist/distillation/DistillationEngine.js +112 -95
  20. package/dist/distillation/DistillationEngine.js.map +1 -1
  21. package/dist/distillation/index.d.ts +7 -1
  22. package/dist/distillation/index.d.ts.map +1 -1
  23. package/dist/distillation/index.js +5 -0
  24. package/dist/distillation/index.js.map +1 -1
  25. package/dist/distillation/ports.d.ts +43 -0
  26. package/dist/distillation/ports.d.ts.map +1 -0
  27. package/dist/distillation/ports.js +29 -0
  28. package/dist/distillation/ports.js.map +1 -0
  29. package/dist/eval/EvalHarness.d.ts +2 -1
  30. package/dist/eval/EvalHarness.d.ts.map +1 -1
  31. package/dist/eval/EvalHarness.js +13 -1
  32. package/dist/eval/EvalHarness.js.map +1 -1
  33. package/dist/eval/baseline.d.ts +33 -0
  34. package/dist/eval/baseline.d.ts.map +1 -0
  35. package/dist/eval/baseline.js +41 -0
  36. package/dist/eval/baseline.js.map +1 -0
  37. package/dist/eval/index.d.ts +1 -0
  38. package/dist/eval/index.d.ts.map +1 -1
  39. package/dist/eval/index.js +1 -0
  40. package/dist/eval/index.js.map +1 -1
  41. package/dist/eval/types.d.ts +7 -0
  42. package/dist/eval/types.d.ts.map +1 -1
  43. package/dist/index.d.ts +2 -2
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +1 -1
  46. package/dist/index.js.map +1 -1
  47. package/dist/rag/EnterpriseRetriever.d.ts.map +1 -1
  48. package/dist/rag/EnterpriseRetriever.js +2 -1
  49. package/dist/rag/EnterpriseRetriever.js.map +1 -1
  50. package/dist/retrieval/HybridRetriever.d.ts.map +1 -1
  51. package/dist/retrieval/HybridRetriever.js +2 -1
  52. package/dist/retrieval/HybridRetriever.js.map +1 -1
  53. package/dist/retrieval/decay.d.ts +24 -0
  54. package/dist/retrieval/decay.d.ts.map +1 -0
  55. package/dist/retrieval/decay.js +29 -0
  56. package/dist/retrieval/decay.js.map +1 -0
  57. package/dist/retrieval/fusion.d.ts +13 -19
  58. package/dist/retrieval/fusion.d.ts.map +1 -1
  59. package/dist/retrieval/fusion.js +17 -44
  60. package/dist/retrieval/fusion.js.map +1 -1
  61. package/dist/retrieval/index.d.ts +13 -6
  62. package/dist/retrieval/index.d.ts.map +1 -1
  63. package/dist/retrieval/index.js +10 -5
  64. package/dist/retrieval/index.js.map +1 -1
  65. package/dist/retrieval/mmr.d.ts +60 -0
  66. package/dist/retrieval/mmr.d.ts.map +1 -0
  67. package/dist/retrieval/mmr.js +94 -0
  68. package/dist/retrieval/mmr.js.map +1 -0
  69. package/dist/retrieval/weightedFusion.d.ts +64 -0
  70. package/dist/retrieval/weightedFusion.d.ts.map +1 -0
  71. package/dist/retrieval/weightedFusion.js +80 -0
  72. package/dist/retrieval/weightedFusion.js.map +1 -0
  73. package/dist/similarity/index.d.ts +6 -4
  74. package/dist/similarity/index.d.ts.map +1 -1
  75. package/dist/similarity/index.js +5 -3
  76. package/dist/similarity/index.js.map +1 -1
  77. package/dist/wire/chatClient.d.ts +100 -0
  78. package/dist/wire/chatClient.d.ts.map +1 -0
  79. package/dist/wire/chatClient.js +123 -0
  80. package/dist/wire/chatClient.js.map +1 -0
  81. package/dist/wire/index.d.ts +20 -0
  82. package/dist/wire/index.d.ts.map +1 -0
  83. package/dist/wire/index.js +18 -0
  84. package/dist/wire/index.js.map +1 -0
  85. package/dist/wire/sse.d.ts +37 -0
  86. package/dist/wire/sse.d.ts.map +1 -0
  87. package/dist/wire/sse.js +104 -0
  88. package/dist/wire/sse.js.map +1 -0
  89. package/dist/wire/usage.d.ts +46 -0
  90. package/dist/wire/usage.d.ts.map +1 -0
  91. package/dist/wire/usage.js +78 -0
  92. package/dist/wire/usage.js.map +1 -0
  93. package/package.json +11 -3
  94. package/src/bridges/AnthropicBridge.ts +24 -68
  95. package/src/bridges/FetchBridge.ts +15 -6
  96. package/src/bridges/OpenAIBridge.ts +84 -113
  97. package/src/bridges/TransformerBridge.ts +6 -0
  98. package/src/bridges/VertexAIBridge.ts +3 -32
  99. package/src/distillation/DistillationEngine.ts +176 -141
  100. package/src/distillation/index.ts +15 -1
  101. package/src/distillation/ports.ts +55 -0
  102. package/src/eval/EvalHarness.ts +12 -1
  103. package/src/eval/baseline.ts +51 -0
  104. package/src/eval/index.ts +1 -0
  105. package/src/eval/types.ts +7 -0
  106. package/src/index.ts +5 -2
  107. package/src/rag/EnterpriseRetriever.ts +2 -1
  108. package/src/retrieval/HybridRetriever.ts +2 -1
  109. package/src/retrieval/decay.ts +29 -0
  110. package/src/retrieval/fusion.ts +19 -52
  111. package/src/retrieval/index.ts +24 -6
  112. package/src/retrieval/mmr.ts +126 -0
  113. package/src/retrieval/weightedFusion.ts +101 -0
  114. package/src/similarity/index.ts +6 -4
  115. package/src/wire/chatClient.ts +196 -0
  116. package/src/wire/index.ts +20 -0
  117. package/src/wire/sse.ts +96 -0
  118. package/src/wire/usage.ts +95 -0
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Server-Sent-Events `data:` framing.
3
+ *
4
+ * Every consumer of an SSE LLM stream does the same line-level dance: trim the line,
5
+ * keep only `data:` frames, and stop at the `[DONE]` sentinel, which ends an
6
+ * OpenAI-style stream (anything after it is not part of the response). JSON streams
7
+ * then parse each payload and skip empty or malformed ones.
8
+ *
9
+ * The line rule is `slice(5).trim()`, which accepts both `data: {…}` and the
10
+ * spaceless `data:{…}` some providers emit — `slice(6)` silently drops the latter.
11
+ *
12
+ * Two levels, one rule: {@link readSseDataPayloads} yields payload TEXT (for callers
13
+ * whose frames are not all JSON, or that parse per wire shape), and
14
+ * {@link readSseDataFrames} yields parsed JSON on top of it.
15
+ *
16
+ * Pure and defensive: a malformed frame is skipped, never thrown.
17
+ */
18
+
19
+ /** The payload text of a `data:` line, or `undefined` for any other line. */
20
+ export function sseDataPayload(line: string): string | undefined {
21
+ const trimmed = line.trim();
22
+ if (!trimmed.startsWith('data:')) return undefined;
23
+ return trimmed.slice(5).trim();
24
+ }
25
+
26
+ /** True for the `data: [DONE]` line that ends an OpenAI-style stream. */
27
+ export function isSseDoneLine(line: string): boolean {
28
+ return sseDataPayload(line) === '[DONE]';
29
+ }
30
+
31
+ /**
32
+ * One SSE line's decoded JSON payload, or `undefined` when the line is not a usable
33
+ * data frame (not a `data:` line, the `[DONE]` sentinel, empty, or malformed JSON).
34
+ */
35
+ export function parseSseDataLine(line: string): unknown | undefined {
36
+ const data = sseDataPayload(line);
37
+ if (!data || data === '[DONE]') return undefined;
38
+ try {
39
+ return JSON.parse(data);
40
+ } catch {
41
+ return undefined;
42
+ }
43
+ }
44
+
45
+ /** Every parsed `data:` frame of a whole, already-buffered SSE body, up to `[DONE]`. */
46
+ export function* parseSseDataFrames(raw: string): Generator<unknown> {
47
+ for (const line of raw.split('\n')) {
48
+ if (isSseDoneLine(line)) return;
49
+ const parsed = parseSseDataLine(line);
50
+ if (parsed !== undefined) yield parsed;
51
+ }
52
+ }
53
+
54
+ /**
55
+ * Every `data:` payload of a live SSE byte stream, as text, as it arrives, up to
56
+ * `[DONE]`. A line split across chunks is held until its newline arrives; the reader
57
+ * lock is released however iteration ends. A missing body yields nothing.
58
+ */
59
+ export async function* readSseDataPayloads(body: ReadableStream<Uint8Array> | null | undefined): AsyncGenerator<string> {
60
+ if (!body) return;
61
+ const reader = body.getReader();
62
+ const decoder = new TextDecoder();
63
+ let buffer = '';
64
+ try {
65
+ while (true) {
66
+ const { done, value } = await reader.read();
67
+ if (done) break;
68
+ buffer += decoder.decode(value, { stream: true });
69
+ const lines = buffer.split('\n');
70
+ buffer = lines.pop() as string; // split() always yields ≥1 element
71
+ for (const line of lines) {
72
+ const data = sseDataPayload(line);
73
+ if (data === undefined) continue;
74
+ if (data === '[DONE]') return;
75
+ yield data;
76
+ }
77
+ }
78
+ buffer += decoder.decode();
79
+ const tail = sseDataPayload(buffer);
80
+ if (tail !== undefined && tail !== '[DONE]') yield tail;
81
+ } finally {
82
+ reader.releaseLock();
83
+ }
84
+ }
85
+
86
+ /** Every parsed JSON `data:` frame of a live SSE byte stream, up to `[DONE]`. */
87
+ export async function* readSseDataFrames(body: ReadableStream<Uint8Array> | null | undefined): AsyncGenerator<unknown> {
88
+ for await (const data of readSseDataPayloads(body)) {
89
+ if (!data) continue;
90
+ try {
91
+ yield JSON.parse(data);
92
+ } catch {
93
+ // Skip malformed SSE frames rather than failing the stream.
94
+ }
95
+ }
96
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Token-usage reading across vendor shapes.
3
+ *
4
+ * Two wire shapes reach a client: OpenAI-style `prompt_tokens`/`completion_tokens`
5
+ * (cached reads under `prompt_tokens_details.cached_tokens`, INCLUDED in
6
+ * `prompt_tokens`) and Anthropic-style `input_tokens`/`output_tokens` (cache reads
7
+ * and writes as separate top-level fields, EXCLUDED from `input_tokens`).
8
+ * {@link readUsageFields} reads either into one set of optional fields, keeping
9
+ * "absent" distinct from 0; each consumer then maps them to its own accounting.
10
+ *
11
+ * Streaming Anthropic responses split usage across events — input and cache on
12
+ * `message_start.message.usage`, output accumulating on `message_delta.usage` — and
13
+ * every count is cumulative, so {@link AnthropicStreamUsage} keeps the largest seen.
14
+ */
15
+
16
+ /** A finite number, or `undefined` for null/undefined/non-numeric input. */
17
+ export function finiteNumber(v: unknown): number | undefined {
18
+ if (v === null || v === undefined) return undefined;
19
+ const n = Number(v);
20
+ return Number.isFinite(n) ? n : undefined;
21
+ }
22
+
23
+ /** Usage as the vendor reported it. Every field is absent when the vendor omitted it. */
24
+ export interface UsageFields {
25
+ /** `prompt_tokens`, else `input_tokens`. */
26
+ promptTokens?: number;
27
+ /** `completion_tokens`, else `output_tokens`. */
28
+ completionTokens?: number;
29
+ totalTokens?: number;
30
+ /** `cache_read_input_tokens`, else `prompt_tokens_details.cached_tokens`. */
31
+ cacheReadTokens?: number;
32
+ /** `cache_creation_input_tokens`. */
33
+ cacheCreationTokens?: number;
34
+ }
35
+
36
+ /** Reads a vendor `usage` object of either shape. Anything that is not an object reads as empty. */
37
+ export function readUsageFields(u: unknown): UsageFields {
38
+ const out: UsageFields = {};
39
+ if (!u || typeof u !== 'object') return out;
40
+ const usage = u as Record<string, unknown>;
41
+ const prompt = finiteNumber(usage['prompt_tokens'] ?? usage['input_tokens']);
42
+ const completion = finiteNumber(usage['completion_tokens'] ?? usage['output_tokens']);
43
+ const total = finiteNumber(usage['total_tokens']);
44
+ if (prompt !== undefined) out.promptTokens = prompt;
45
+ if (completion !== undefined) out.completionTokens = completion;
46
+ if (total !== undefined) out.totalTokens = total;
47
+
48
+ const details = usage['prompt_tokens_details'];
49
+ const cachedFromDetails = details && typeof details === 'object'
50
+ ? finiteNumber((details as Record<string, unknown>)['cached_tokens'])
51
+ : undefined;
52
+ const cacheRead = finiteNumber(usage['cache_read_input_tokens']) ?? cachedFromDetails;
53
+ const cacheCreation = finiteNumber(usage['cache_creation_input_tokens']);
54
+ if (cacheRead !== undefined) out.cacheReadTokens = cacheRead;
55
+ if (cacheCreation !== undefined) out.cacheCreationTokens = cacheCreation;
56
+ return out;
57
+ }
58
+
59
+ /** The totals of one Anthropic stream. Input excludes both cache counts. */
60
+ export interface AnthropicUsageTotals {
61
+ inputTokens: number;
62
+ outputTokens: number;
63
+ cacheReadTokens: number;
64
+ cacheCreationTokens: number;
65
+ /** `message_start.message.model`, when the stream named it. */
66
+ model?: string;
67
+ }
68
+
69
+ /** Folds the usage events of one Anthropic Messages stream. Feed it every parsed frame. */
70
+ export class AnthropicStreamUsage {
71
+ private readonly totals: AnthropicUsageTotals = { inputTokens: 0, outputTokens: 0, cacheReadTokens: 0, cacheCreationTokens: 0 };
72
+
73
+ observe(frame: unknown): void {
74
+ if (!frame || typeof frame !== 'object') return;
75
+ const ev = frame as { type?: unknown; message?: { usage?: unknown; model?: unknown }; usage?: unknown };
76
+ let usage: unknown;
77
+ if (ev.type === 'message_start') {
78
+ usage = ev.message?.usage;
79
+ if (typeof ev.message?.model === 'string') this.totals.model = ev.message.model;
80
+ } else if (ev.type === 'message_delta') {
81
+ usage = ev.usage;
82
+ }
83
+ if (!usage || typeof usage !== 'object') return;
84
+ const u = usage as Record<string, unknown>;
85
+ const keep = (current: number, v: unknown) => Math.max(current, finiteNumber(v) ?? 0);
86
+ this.totals.inputTokens = keep(this.totals.inputTokens, u['input_tokens']);
87
+ this.totals.outputTokens = keep(this.totals.outputTokens, u['output_tokens']);
88
+ this.totals.cacheReadTokens = keep(this.totals.cacheReadTokens, u['cache_read_input_tokens']);
89
+ this.totals.cacheCreationTokens = keep(this.totals.cacheCreationTokens, u['cache_creation_input_tokens']);
90
+ }
91
+
92
+ result(): AnthropicUsageTotals {
93
+ return { ...this.totals };
94
+ }
95
+ }