@mcp-abap-adt/llm-agent 20.7.1 → 20.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/dist/index.d.ts +8 -1
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +8 -1
  5. package/dist/index.js.map +1 -1
  6. package/dist/interfaces/assert-client-descriptors.d.ts +6 -0
  7. package/dist/interfaces/assert-client-descriptors.d.ts.map +1 -0
  8. package/dist/interfaces/assert-client-descriptors.js +27 -0
  9. package/dist/interfaces/assert-client-descriptors.js.map +1 -0
  10. package/dist/interfaces/build-namespaced-tools.d.ts +21 -0
  11. package/dist/interfaces/build-namespaced-tools.d.ts.map +1 -0
  12. package/dist/interfaces/build-namespaced-tools.js +48 -0
  13. package/dist/interfaces/build-namespaced-tools.js.map +1 -0
  14. package/dist/interfaces/builder.d.ts +17 -1
  15. package/dist/interfaces/builder.d.ts.map +1 -1
  16. package/dist/interfaces/health.d.ts +11 -0
  17. package/dist/interfaces/health.d.ts.map +1 -1
  18. package/dist/interfaces/index.d.ts +4 -2
  19. package/dist/interfaces/index.d.ts.map +1 -1
  20. package/dist/interfaces/index.js +3 -1
  21. package/dist/interfaces/index.js.map +1 -1
  22. package/dist/interfaces/mcp-connection-strategy.d.ts +14 -0
  23. package/dist/interfaces/mcp-connection-strategy.d.ts.map +1 -1
  24. package/dist/interfaces/merge-offered-tools.d.ts +8 -0
  25. package/dist/interfaces/merge-offered-tools.d.ts.map +1 -0
  26. package/dist/interfaces/merge-offered-tools.js +14 -0
  27. package/dist/interfaces/merge-offered-tools.js.map +1 -0
  28. package/dist/interfaces/pipeline-plugin.d.ts +4 -0
  29. package/dist/interfaces/pipeline-plugin.d.ts.map +1 -1
  30. package/dist/interfaces/rag.d.ts +31 -0
  31. package/dist/interfaces/rag.d.ts.map +1 -1
  32. package/dist/interfaces/rag.js +10 -0
  33. package/dist/interfaces/rag.js.map +1 -1
  34. package/dist/interfaces/tool-catalog.d.ts +35 -0
  35. package/dist/interfaces/tool-catalog.d.ts.map +1 -0
  36. package/dist/interfaces/tool-catalog.js +7 -0
  37. package/dist/interfaces/tool-catalog.js.map +1 -0
  38. package/dist/interfaces/tool-namespace.d.ts +24 -0
  39. package/dist/interfaces/tool-namespace.d.ts.map +1 -0
  40. package/dist/interfaces/tool-namespace.js +20 -0
  41. package/dist/interfaces/tool-namespace.js.map +1 -0
  42. package/dist/interfaces/tool-record-key.d.ts +59 -0
  43. package/dist/interfaces/tool-record-key.d.ts.map +1 -0
  44. package/dist/interfaces/tool-record-key.js +40 -0
  45. package/dist/interfaces/tool-record-key.js.map +1 -0
  46. package/dist/resilience/batch-chunking-embedder.d.ts +23 -0
  47. package/dist/resilience/batch-chunking-embedder.d.ts.map +1 -0
  48. package/dist/resilience/batch-chunking-embedder.js +45 -0
  49. package/dist/resilience/batch-chunking-embedder.js.map +1 -0
  50. package/dist/resilience/circuit-breaker-embedder.d.ts +23 -3
  51. package/dist/resilience/circuit-breaker-embedder.d.ts.map +1 -1
  52. package/dist/resilience/circuit-breaker-embedder.js +25 -1
  53. package/dist/resilience/circuit-breaker-embedder.js.map +1 -1
  54. package/dist/resilience/embedder-resilience.d.ts +42 -0
  55. package/dist/resilience/embedder-resilience.d.ts.map +1 -0
  56. package/dist/resilience/embedder-resilience.js +66 -0
  57. package/dist/resilience/embedder-resilience.js.map +1 -0
  58. package/dist/resilience/index.d.ts +4 -1
  59. package/dist/resilience/index.d.ts.map +1 -1
  60. package/dist/resilience/index.js +4 -1
  61. package/dist/resilience/index.js.map +1 -1
  62. package/dist/resilience/retry-embedder.d.ts +79 -0
  63. package/dist/resilience/retry-embedder.d.ts.map +1 -0
  64. package/dist/resilience/retry-embedder.js +124 -0
  65. package/dist/resilience/retry-embedder.js.map +1 -0
  66. package/package.json +1 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-catalog.d.ts","sourceRoot":"","sources":["../../src/interfaces/tool-catalog.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,wDAAwD;IACxD,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IACnB,gDAAgD;IAChD,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,2EAA2E;IAC3E,cAAc,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,+EAA+E;IAC/E,oBAAoB,IAAI,iBAAiB,GAAG,SAAS,CAAC;CACvD;AAED,uDAAuD;AACvD,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,oBAAoB,CAM3E"}
@@ -0,0 +1,7 @@
1
+ /** Type guard: does `x` report tool-catalog status? */
2
+ export function isToolCatalogReporter(x) {
3
+ return (typeof x === 'object' &&
4
+ x !== null &&
5
+ typeof x.getToolCatalogStatus === 'function');
6
+ }
7
+ //# sourceMappingURL=tool-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-catalog.js","sourceRoot":"","sources":["../../src/interfaces/tool-catalog.ts"],"names":[],"mappings":"AAkCA,uDAAuD;AACvD,MAAM,UAAU,qBAAqB,CAAC,CAAU;IAC9C,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,OAAQ,CAA0B,CAAC,oBAAoB,KAAK,UAAU,CACvE,CAAC;AACJ,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { IMcpClient } from './mcp-client.js';
2
+ export interface ToolNamespaceContext {
3
+ /** Original tool name the server exposes. */
4
+ toolName: string;
5
+ /** Prefix source resolved by the builder: the server's config `name`, else `s${slotIndex}`. */
6
+ prefix: string;
7
+ /** True when this tool name is exposed by more than one currently-active client. */
8
+ colliding: boolean;
9
+ }
10
+ export interface IToolNamespace {
11
+ /** Name the LLM sees / RAG stores. Must be non-empty, `^[a-zA-Z0-9_-]+$`, <= 64 chars.
12
+ * The builder validates this output — an invalid name fails fast. */
13
+ expose(ctx: ToolNamespaceContext): string;
14
+ }
15
+ /** Bare when unique; `${prefix}__${toolName}` on a collision. */
16
+ export declare const defaultToolNamespace: IToolNamespace;
17
+ /**
18
+ * Wrap an MCP client so `callTool` always targets `originalName`, whatever
19
+ * (exposed) name the caller passes. All other IMcpClient methods proxy straight
20
+ * through. This encapsulates the namespace strip in the tool→client map value,
21
+ * so no executor call site needs to know about namespacing.
22
+ */
23
+ export declare function bindToolCallName(client: IMcpClient, originalName: string): IMcpClient;
24
+ //# sourceMappingURL=tool-namespace.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-namespace.d.ts","sourceRoot":"","sources":["../../src/interfaces/tool-namespace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,oBAAoB;IACnC,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,+FAA+F;IAC/F,MAAM,EAAE,MAAM,CAAC;IACf,oFAAoF;IACpF,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B;0EACsE;IACtE,MAAM,CAAC,GAAG,EAAE,oBAAoB,GAAG,MAAM,CAAC;CAC3C;AAED,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,EAAE,cAGlC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,UAAU,EAClB,YAAY,EAAE,MAAM,GACnB,UAAU,CASZ"}
@@ -0,0 +1,20 @@
1
+ /** Bare when unique; `${prefix}__${toolName}` on a collision. */
2
+ export const defaultToolNamespace = {
3
+ expose: ({ toolName, prefix, colliding }) => colliding ? `${prefix}__${toolName}` : toolName,
4
+ };
5
+ /**
6
+ * Wrap an MCP client so `callTool` always targets `originalName`, whatever
7
+ * (exposed) name the caller passes. All other IMcpClient methods proxy straight
8
+ * through. This encapsulates the namespace strip in the tool→client map value,
9
+ * so no executor call site needs to know about namespacing.
10
+ */
11
+ export function bindToolCallName(client, originalName) {
12
+ return {
13
+ listTools: (options) => client.listTools(options),
14
+ callTool: (_exposedName, args, options) => client.callTool(originalName, args, options),
15
+ ...(client.healthCheck
16
+ ? { healthCheck: (options) => client.healthCheck?.(options) }
17
+ : {}),
18
+ };
19
+ }
20
+ //# sourceMappingURL=tool-namespace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-namespace.js","sourceRoot":"","sources":["../../src/interfaces/tool-namespace.ts"],"names":[],"mappings":"AAiBA,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAmB;IAClD,MAAM,EAAE,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,EAAU,EAAE,CAClD,SAAS,CAAC,CAAC,CAAC,GAAG,MAAM,KAAK,QAAQ,EAAE,CAAC,CAAC,CAAC,QAAQ;CAClD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAC9B,MAAkB,EAClB,YAAoB;IAEpB,OAAO;QACL,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC;QACjD,QAAQ,EAAE,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CACxC,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,IAAI,EAAE,OAAO,CAAC;QAC9C,GAAG,CAAC,MAAM,CAAC,WAAW;YACpB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,OAAO,CAAC,EAAE;YAC7D,CAAC,CAAC,EAAE,CAAC;KACM,CAAC;AAClB,CAAC"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Strategy for the RAG record id under which an MCP tool is stored.
3
+ *
4
+ * A variation point the consumer owns: the default gives a working,
5
+ * collision-free *storage* key, and a consumer who knows its servers (real
6
+ * names, a per-server collection layout, or a faster-but-conflicting scheme)
7
+ * swaps in its own — provided the id keeps the `tool:` prefix (see `key`). The
8
+ * engine stays MCP-agnostic — it never assumes a fixed server set.
9
+ *
10
+ * Scope: this disambiguates records in the tools RAG store (so same-named tools
11
+ * from different servers both survive, improving recall). It does NOT route a
12
+ * call to a specific server — tool selection deduplicates by name because LLM
13
+ * tool-calling needs unique names, so a colliding name resolves to the first
14
+ * client. Per-server call routing needs tool-name namespacing, tracked apart.
15
+ */
16
+ export interface ToolKeyContext {
17
+ /** The tool's own name, as exposed by its MCP server. */
18
+ toolName: string;
19
+ /**
20
+ * Zero-based index of the client this tool came from. One MCP server maps to
21
+ * exactly one client, so within a boot this identifies the server. Stable for
22
+ * the run; not durable across restarts if the configured order changes.
23
+ */
24
+ clientIndex: number;
25
+ /** Total number of connected MCP clients this run. */
26
+ clientCount: number;
27
+ }
28
+ export interface IToolRecordKey {
29
+ /**
30
+ * The record id for a tool. Must be stable for a given (name, server), and
31
+ * must start with `tool:` — retrieval uses that prefix to tell tool records
32
+ * apart from skill records (`skill:`) in the same store. The tool name is
33
+ * stored in metadata separately, so anything after `tool:` is free.
34
+ */
35
+ key(ctx: ToolKeyContext): string;
36
+ }
37
+ /**
38
+ * Default: a single MCP server keeps the historical `tool:${name}` key, so
39
+ * existing single-server collections are unchanged. With two or more servers
40
+ * the client index disambiguates, so identically named tools from different
41
+ * servers no longer overwrite each other.
42
+ */
43
+ export declare const defaultToolRecordKey: IToolRecordKey;
44
+ /**
45
+ * Recover a tool's name from a stored record, independent of the key scheme.
46
+ *
47
+ * The name is written into record metadata at vectorization time, so this
48
+ * works for ANY {@link IToolRecordKey} — including a consumer's custom scheme —
49
+ * without parsing the id. The id parse is a fallback for records written before
50
+ * the name was stored, and it understands both default forms (`tool:name` and
51
+ * `tool:<index>:name`).
52
+ *
53
+ * Returns `undefined` for a record that is not a tool (no `tool:` id).
54
+ */
55
+ export declare function toolNameFromRecord(meta: {
56
+ id?: unknown;
57
+ name?: unknown;
58
+ }): string | undefined;
59
+ //# sourceMappingURL=tool-record-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-record-key.d.ts","sourceRoot":"","sources":["../../src/interfaces/tool-record-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,sDAAsD;IACtD,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,GAAG,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,CAAC;CAClC;AAED;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,EAAE,cAMlC,CAAC;AAEF;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IACvC,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB,GAAG,MAAM,GAAG,SAAS,CAWrB"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Default: a single MCP server keeps the historical `tool:${name}` key, so
3
+ * existing single-server collections are unchanged. With two or more servers
4
+ * the client index disambiguates, so identically named tools from different
5
+ * servers no longer overwrite each other.
6
+ */
7
+ export const defaultToolRecordKey = {
8
+ key({ toolName, clientIndex, clientCount }) {
9
+ return clientCount <= 1
10
+ ? `tool:${toolName}`
11
+ : `tool:${clientIndex}:${toolName}`;
12
+ },
13
+ };
14
+ /**
15
+ * Recover a tool's name from a stored record, independent of the key scheme.
16
+ *
17
+ * The name is written into record metadata at vectorization time, so this
18
+ * works for ANY {@link IToolRecordKey} — including a consumer's custom scheme —
19
+ * without parsing the id. The id parse is a fallback for records written before
20
+ * the name was stored, and it understands both default forms (`tool:name` and
21
+ * `tool:<index>:name`).
22
+ *
23
+ * Returns `undefined` for a record that is not a tool (no `tool:` id).
24
+ */
25
+ export function toolNameFromRecord(meta) {
26
+ const id = meta?.id;
27
+ if (typeof id !== 'string' || !id.startsWith('tool:'))
28
+ return undefined;
29
+ if (typeof meta.name === 'string' && meta.name.length > 0)
30
+ return meta.name;
31
+ const rest = id.slice(5);
32
+ // Default multi-server form `tool:<index>:<name>` — a numeric first segment is
33
+ // the client index, so the name follows it.
34
+ const indexed = /^\d+:(.*)$/.exec(rest);
35
+ if (indexed)
36
+ return indexed[1];
37
+ // Otherwise the historical `tool:<name>[:<suffix>]` form — name comes first.
38
+ return rest.replace(/:.*$/, '');
39
+ }
40
+ //# sourceMappingURL=tool-record-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-record-key.js","sourceRoot":"","sources":["../../src/interfaces/tool-record-key.ts"],"names":[],"mappings":"AAsCA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAmB;IAClD,GAAG,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,EAAE;QACxC,OAAO,WAAW,IAAI,CAAC;YACrB,CAAC,CAAC,QAAQ,QAAQ,EAAE;YACpB,CAAC,CAAC,QAAQ,WAAW,IAAI,QAAQ,EAAE,CAAC;IACxC,CAAC;CACF,CAAC;AAEF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,IAGlC;IACC,MAAM,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC;IACpB,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACxE,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IAC5E,MAAM,IAAI,GAAG,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACzB,+EAA+E;IAC/E,4CAA4C;IAC5C,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxC,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;IAC/B,6EAA6E;IAC7E,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAClC,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * BatchChunkingEmbedder — splits embedBatch input into provider-safe chunks.
3
+ *
4
+ * Applied ONLY over a batch-capable inner (see composeResilientEmbedder): a
5
+ * decorator exposing embedBatch unconditionally would make a non-batch embedder
6
+ * look batch-capable to isBatchEmbedder.
7
+ */
8
+ import type { IEmbedderBatch, IEmbedResult } from '../interfaces/rag.js';
9
+ import type { CallOptions } from '../interfaces/types.js';
10
+ /**
11
+ * Used when neither YAML nor the provider declares a cap. Comfortably below the
12
+ * only hard cap we have confirmed (Vertex 250), and large enough that a
13
+ * 356-tool catalog costs 4 requests.
14
+ */
15
+ export declare const DEFAULT_MAX_BATCH_SIZE = 100;
16
+ export declare class BatchChunkingEmbedder implements IEmbedderBatch {
17
+ private readonly inner;
18
+ private readonly maxBatchSize;
19
+ constructor(inner: IEmbedderBatch, maxBatchSize: number);
20
+ embed(text: string, options?: CallOptions): Promise<IEmbedResult>;
21
+ embedBatch(texts: string[], options?: CallOptions): Promise<IEmbedResult[]>;
22
+ }
23
+ //# sourceMappingURL=batch-chunking-embedder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-chunking-embedder.d.ts","sourceRoot":"","sources":["../../src/resilience/batch-chunking-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAG1D;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C,qBAAa,qBAAsB,YAAW,cAAc;IAExD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,KAAK,EAAE,cAAc,EACrB,YAAY,EAAE,MAAM;IAUvC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAI3D,UAAU,CACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC;CAkB3B"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * BatchChunkingEmbedder — splits embedBatch input into provider-safe chunks.
3
+ *
4
+ * Applied ONLY over a batch-capable inner (see composeResilientEmbedder): a
5
+ * decorator exposing embedBatch unconditionally would make a non-batch embedder
6
+ * look batch-capable to isBatchEmbedder.
7
+ */
8
+ import { RagError } from '../interfaces/types.js';
9
+ /**
10
+ * Used when neither YAML nor the provider declares a cap. Comfortably below the
11
+ * only hard cap we have confirmed (Vertex 250), and large enough that a
12
+ * 356-tool catalog costs 4 requests.
13
+ */
14
+ export const DEFAULT_MAX_BATCH_SIZE = 100;
15
+ export class BatchChunkingEmbedder {
16
+ inner;
17
+ maxBatchSize;
18
+ constructor(inner, maxBatchSize) {
19
+ this.inner = inner;
20
+ this.maxBatchSize = maxBatchSize;
21
+ if (!Number.isSafeInteger(maxBatchSize) || maxBatchSize < 1) {
22
+ throw new RagError(`maxBatchSize must be a positive safe integer, got ${String(maxBatchSize)}`, 'CONFIG_ERROR');
23
+ }
24
+ }
25
+ embed(text, options) {
26
+ return this.inner.embed(text, options);
27
+ }
28
+ async embedBatch(texts, options) {
29
+ if (texts.length === 0)
30
+ return [];
31
+ const out = [];
32
+ // Sequential on purpose: concurrent chunks would reintroduce the rate
33
+ // limiting that chunking exists to avoid.
34
+ for (let i = 0; i < texts.length; i += this.maxBatchSize) {
35
+ const chunk = texts.slice(i, i + this.maxBatchSize);
36
+ const res = await this.inner.embedBatch(chunk, options);
37
+ if (res.length !== chunk.length) {
38
+ throw new RagError(`Batch embedding returned ${res.length} embeddings, expected ${chunk.length}`, 'EMBED_ERROR');
39
+ }
40
+ out.push(...res);
41
+ }
42
+ return out;
43
+ }
44
+ }
45
+ //# sourceMappingURL=batch-chunking-embedder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch-chunking-embedder.js","sourceRoot":"","sources":["../../src/resilience/batch-chunking-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD;;;;GAIG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,GAAG,CAAC;AAE1C,MAAM,OAAO,qBAAqB;IAEb;IACA;IAFnB,YACmB,KAAqB,EACrB,YAAoB;QADpB,UAAK,GAAL,KAAK,CAAgB;QACrB,iBAAY,GAAZ,YAAY,CAAQ;QAErC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YAC5D,MAAM,IAAI,QAAQ,CAChB,qDAAqD,MAAM,CAAC,YAAY,CAAC,EAAE,EAC3E,cAAc,CACf,CAAC;QACJ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,IAAY,EAAE,OAAqB;QACvC,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC;IAED,KAAK,CAAC,UAAU,CACd,KAAe,EACf,OAAqB;QAErB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAClC,MAAM,GAAG,GAAmB,EAAE,CAAC;QAC/B,sEAAsE;QACtE,0CAA0C;QAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC;YACpD,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YACxD,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,IAAI,QAAQ,CAChB,4BAA4B,GAAG,CAAC,MAAM,yBAAyB,KAAK,CAAC,MAAM,EAAE,EAC7E,aAAa,CACd,CAAC;YACJ,CAAC;YACD,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC;QACnB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;CACF"}
@@ -3,14 +3,34 @@
3
3
  *
4
4
  * When the circuit is open, calls throw an error rather than hitting the
5
5
  * underlying embedding service.
6
+ *
7
+ * Prefer the {@link withCircuitBreaker} factory: it selects a non-batch or
8
+ * batch class by inspecting the inner embedder, so it preserves batch
9
+ * capability rather than fabricating it. The exported classes are kept for
10
+ * direct construction and backward compatibility.
6
11
  */
7
- import type { CallOptions, IEmbedder, IEmbedResult } from '@mcp-abap-adt/llm-agent';
12
+ import type { CallOptions, IEmbedder, IEmbedderBatch, IEmbedResult } from '@mcp-abap-adt/llm-agent';
8
13
  import type { CircuitBreaker } from './circuit-breaker.js';
9
- export declare class CircuitBreakerEmbedder implements IEmbedder {
10
- private readonly inner;
14
+ /** Non-batch breaker decorator exposes only `embed()`. */
15
+ export declare class CircuitBreakerEmbedderBase implements IEmbedder {
16
+ protected readonly inner: IEmbedder;
11
17
  readonly breaker: CircuitBreaker;
12
18
  constructor(inner: IEmbedder, breaker: CircuitBreaker);
13
19
  embed(text: string, options?: CallOptions): Promise<IEmbedResult>;
20
+ }
21
+ /**
22
+ * Batch breaker decorator. Unchanged public shape: it always exposes
23
+ * `embedBatch`, so `new CircuitBreakerEmbedder(nonBatchInner, ...)` still
24
+ * reports batch capability it lacks (and throws at call time). Construct via
25
+ * {@link withCircuitBreaker} to avoid that.
26
+ */
27
+ export declare class CircuitBreakerEmbedder extends CircuitBreakerEmbedderBase implements IEmbedderBatch {
14
28
  embedBatch(texts: string[], options?: CallOptions): Promise<IEmbedResult[]>;
15
29
  }
30
+ /**
31
+ * Wrap an embedder with a circuit breaker, preserving batch capability: a
32
+ * batch-capable inner gets the batch class, a non-batch inner the base class.
33
+ * The same two-class-behind-a-factory shape as `wrapEmbedder` / `withRetry`.
34
+ */
35
+ export declare function withCircuitBreaker(inner: IEmbedder, breaker: CircuitBreaker): IEmbedder;
16
36
  //# sourceMappingURL=circuit-breaker-embedder.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"circuit-breaker-embedder.d.ts","sourceRoot":"","sources":["../../src/resilience/circuit-breaker-embedder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,qBAAa,sBAAuB,YAAW,SAAS;IAEpD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,QAAQ,CAAC,OAAO,EAAE,cAAc;gBADf,KAAK,EAAE,SAAS,EACxB,OAAO,EAAE,cAAc;IAG5B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAcjE,UAAU,CACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC;CAmB3B"}
1
+ {"version":3,"file":"circuit-breaker-embedder.d.ts","sourceRoot":"","sources":["../../src/resilience/circuit-breaker-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,WAAW,EACX,SAAS,EACT,cAAc,EACd,YAAY,EACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE3D,4DAA4D;AAC5D,qBAAa,0BAA2B,YAAW,SAAS;IAExD,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS;IACnC,QAAQ,CAAC,OAAO,EAAE,cAAc;gBADb,KAAK,EAAE,SAAS,EAC1B,OAAO,EAAE,cAAc;IAG5B,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAaxE;AAED;;;;;GAKG;AACH,qBAAa,sBACX,SAAQ,0BACR,YAAW,cAAc;IAEnB,UAAU,CACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC;CAmB3B;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,cAAc,GACtB,SAAS,CAIX"}
@@ -3,9 +3,15 @@
3
3
  *
4
4
  * When the circuit is open, calls throw an error rather than hitting the
5
5
  * underlying embedding service.
6
+ *
7
+ * Prefer the {@link withCircuitBreaker} factory: it selects a non-batch or
8
+ * batch class by inspecting the inner embedder, so it preserves batch
9
+ * capability rather than fabricating it. The exported classes are kept for
10
+ * direct construction and backward compatibility.
6
11
  */
7
12
  import { isBatchEmbedder, RagError } from '@mcp-abap-adt/llm-agent';
8
- export class CircuitBreakerEmbedder {
13
+ /** Non-batch breaker decorator — exposes only `embed()`. */
14
+ export class CircuitBreakerEmbedderBase {
9
15
  inner;
10
16
  breaker;
11
17
  constructor(inner, breaker) {
@@ -26,6 +32,14 @@ export class CircuitBreakerEmbedder {
26
32
  throw err;
27
33
  }
28
34
  }
35
+ }
36
+ /**
37
+ * Batch breaker decorator. Unchanged public shape: it always exposes
38
+ * `embedBatch`, so `new CircuitBreakerEmbedder(nonBatchInner, ...)` still
39
+ * reports batch capability it lacks (and throws at call time). Construct via
40
+ * {@link withCircuitBreaker} to avoid that.
41
+ */
42
+ export class CircuitBreakerEmbedder extends CircuitBreakerEmbedderBase {
29
43
  async embedBatch(texts, options) {
30
44
  if (!this.breaker.isCallPermitted) {
31
45
  throw new RagError('Embedder circuit breaker is open', 'CIRCUIT_OPEN');
@@ -44,4 +58,14 @@ export class CircuitBreakerEmbedder {
44
58
  }
45
59
  }
46
60
  }
61
+ /**
62
+ * Wrap an embedder with a circuit breaker, preserving batch capability: a
63
+ * batch-capable inner gets the batch class, a non-batch inner the base class.
64
+ * The same two-class-behind-a-factory shape as `wrapEmbedder` / `withRetry`.
65
+ */
66
+ export function withCircuitBreaker(inner, breaker) {
67
+ return isBatchEmbedder(inner)
68
+ ? new CircuitBreakerEmbedder(inner, breaker)
69
+ : new CircuitBreakerEmbedderBase(inner, breaker);
70
+ }
47
71
  //# sourceMappingURL=circuit-breaker-embedder.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"circuit-breaker-embedder.js","sourceRoot":"","sources":["../../src/resilience/circuit-breaker-embedder.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGpE,MAAM,OAAO,sBAAsB;IAEd;IACR;IAFX,YACmB,KAAgB,EACxB,OAAuB;QADf,UAAK,GAAL,KAAK,CAAW;QACxB,YAAO,GAAP,OAAO,CAAgB;IAC/B,CAAC;IAEJ,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,OAAqB;QAC7C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAClC,MAAM,IAAI,QAAQ,CAAC,kCAAkC,EAAE,cAAc,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,UAAU,CACd,KAAe,EACf,OAAqB;QAErB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAClC,MAAM,IAAI,QAAQ,CAAC,kCAAkC,EAAE,cAAc,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,QAAQ,CAChB,iDAAiD,EACjD,aAAa,CACd,CAAC;QACJ,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"circuit-breaker-embedder.js","sourceRoot":"","sources":["../../src/resilience/circuit-breaker-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAQH,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGpE,4DAA4D;AAC5D,MAAM,OAAO,0BAA0B;IAEhB;IACV;IAFX,YACqB,KAAgB,EAC1B,OAAuB;QADb,UAAK,GAAL,KAAK,CAAW;QAC1B,YAAO,GAAP,OAAO,CAAgB;IAC/B,CAAC;IAEJ,KAAK,CAAC,KAAK,CAAC,IAAY,EAAE,OAAqB;QAC7C,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAClC,MAAM,IAAI,QAAQ,CAAC,kCAAkC,EAAE,cAAc,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,OAAO,sBACX,SAAQ,0BAA0B;IAGlC,KAAK,CAAC,UAAU,CACd,KAAe,EACf,OAAqB;QAErB,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,CAAC;YAClC,MAAM,IAAI,QAAQ,CAAC,kCAAkC,EAAE,cAAc,CAAC,CAAC;QACzE,CAAC;QACD,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACjC,MAAM,IAAI,QAAQ,CAChB,iDAAiD,EACjD,aAAa,CACd,CAAC;QACJ,CAAC;QACD,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;YAC3D,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,OAAO,MAAM,CAAC;QAChB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,CAAC;YAC7B,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAgB,EAChB,OAAuB;IAEvB,OAAO,eAAe,CAAC,KAAK,CAAC;QAC3B,CAAC,CAAC,IAAI,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC;QAC5C,CAAC,CAAC,IAAI,0BAA0B,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Composition of the embedder resilience chain, and the metadata that travels
3
+ * with it.
4
+ *
5
+ * wrapEmbedder( BatchChunkingEmbedder( RetryBatchEmbedder( provider ) ) )
6
+ *
7
+ * Retry sits INSIDE chunking so each chunk retries independently: a failure on
8
+ * chunk 20 must not re-issue chunks 1-19.
9
+ *
10
+ * The metadata is keyed by a registered symbol, not a string property: a string
11
+ * key could be matched structurally by an unrelated consumer embedder, and the
12
+ * guard would then read a foreign object as ours.
13
+ */
14
+ import type { IEmbedder } from '../interfaces/rag.js';
15
+ import type { ILogger } from '../logger/types.js';
16
+ import type { EmbedderRetryOptions } from './retry-embedder.js';
17
+ export declare const RESILIENCE_META: unique symbol;
18
+ export interface EmbedderResilienceMetadata {
19
+ /** Absent for a non-batch embedder: retry applies, chunking does not. */
20
+ maxBatchSize?: number;
21
+ }
22
+ /** Undefined iff the embedder has no resilience layer. */
23
+ export declare function getResilienceMetadata(e: IEmbedder): EmbedderResilienceMetadata | undefined;
24
+ /**
25
+ * Attach metadata to an instance without making it enumerable.
26
+ *
27
+ * Also used by `wrapEmbedder` (llm-agent-libs) to propagate the metadata onto
28
+ * its own wrapper: that decorator's `inner` is `protected`, so a caller holding
29
+ * the wrapper could not otherwise see a brand sitting on a layer below, and
30
+ * re-resolution would compose the decorators a second time.
31
+ */
32
+ export declare function brandResilient(e: IEmbedder, meta: EmbedderResilienceMetadata): void;
33
+ export interface ComposeResilienceOptions {
34
+ /** A cap a human configured. ONLY this may trigger the conflict check. */
35
+ explicitMaxBatchSize?: number;
36
+ /** Provider-derived or default cap; never triggers the conflict check. */
37
+ fallbackMaxBatchSize?: number;
38
+ retry?: Partial<EmbedderRetryOptions>;
39
+ logger?: ILogger;
40
+ }
41
+ export declare function composeResilientEmbedder(inner: IEmbedder, options?: ComposeResilienceOptions): IEmbedder;
42
+ //# sourceMappingURL=embedder-resilience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder-resilience.d.ts","sourceRoot":"","sources":["../../src/resilience/embedder-resilience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAKlD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,eAAO,MAAM,eAAe,eAAkD,CAAC;AAE/E,MAAM,WAAW,0BAA0B;IACzC,yEAAyE;IACzE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,0DAA0D;AAC1D,wBAAgB,qBAAqB,CACnC,CAAC,EAAE,SAAS,GACX,0BAA0B,GAAG,SAAS,CAIxC;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,CAAC,EAAE,SAAS,EACZ,IAAI,EAAE,0BAA0B,GAC/B,IAAI,CAON;AAED,MAAM,WAAW,wBAAwB;IACvC,0EAA0E;IAC1E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,0EAA0E;IAC1E,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,KAAK,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,wBAAwB,GACjC,SAAS,CAgCX"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Composition of the embedder resilience chain, and the metadata that travels
3
+ * with it.
4
+ *
5
+ * wrapEmbedder( BatchChunkingEmbedder( RetryBatchEmbedder( provider ) ) )
6
+ *
7
+ * Retry sits INSIDE chunking so each chunk retries independently: a failure on
8
+ * chunk 20 must not re-issue chunks 1-19.
9
+ *
10
+ * The metadata is keyed by a registered symbol, not a string property: a string
11
+ * key could be matched structurally by an unrelated consumer embedder, and the
12
+ * guard would then read a foreign object as ours.
13
+ */
14
+ import { isBatchEmbedder, isBatchSizeLimited } from '../interfaces/rag.js';
15
+ import { BatchChunkingEmbedder, DEFAULT_MAX_BATCH_SIZE, } from './batch-chunking-embedder.js';
16
+ import { withRetry } from './retry-embedder.js';
17
+ export const RESILIENCE_META = Symbol.for('@mcp-abap-adt/embedder-resilience');
18
+ /** Undefined iff the embedder has no resilience layer. */
19
+ export function getResilienceMetadata(e) {
20
+ return e[RESILIENCE_META];
21
+ }
22
+ /**
23
+ * Attach metadata to an instance without making it enumerable.
24
+ *
25
+ * Also used by `wrapEmbedder` (llm-agent-libs) to propagate the metadata onto
26
+ * its own wrapper: that decorator's `inner` is `protected`, so a caller holding
27
+ * the wrapper could not otherwise see a brand sitting on a layer below, and
28
+ * re-resolution would compose the decorators a second time.
29
+ */
30
+ export function brandResilient(e, meta) {
31
+ Object.defineProperty(e, RESILIENCE_META, {
32
+ value: meta,
33
+ enumerable: false,
34
+ configurable: false,
35
+ writable: false,
36
+ });
37
+ }
38
+ export function composeResilientEmbedder(inner, options) {
39
+ const existing = getResilienceMetadata(inner);
40
+ if (existing) {
41
+ const requested = options?.explicitMaxBatchSize;
42
+ // Re-deriving the cap here would fire on every normal boot: wrapEmbedder
43
+ // hides the provider, so a derived value falls to the default and would
44
+ // look like a conflict nobody configured. Only an explicit request counts.
45
+ if (requested !== undefined && requested !== existing.maxBatchSize) {
46
+ options?.logger?.log({
47
+ type: 'warning',
48
+ traceId: 'embedder-resolution',
49
+ message: `Embedder is already composed with maxBatchSize ${String(existing.maxBatchSize)}; ` +
50
+ `ignoring the requested ${requested}. One shared embedder has one cap.`,
51
+ });
52
+ }
53
+ return inner;
54
+ }
55
+ const cap = options?.explicitMaxBatchSize ??
56
+ options?.fallbackMaxBatchSize ??
57
+ (isBatchSizeLimited(inner) ? inner.maxBatchSize : DEFAULT_MAX_BATCH_SIZE);
58
+ const retried = withRetry(inner, options?.retry);
59
+ const batchCapable = isBatchEmbedder(retried);
60
+ const composed = batchCapable
61
+ ? new BatchChunkingEmbedder(retried, cap)
62
+ : retried;
63
+ brandResilient(composed, batchCapable ? { maxBatchSize: cap } : {});
64
+ return composed;
65
+ }
66
+ //# sourceMappingURL=embedder-resilience.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"embedder-resilience.js","sourceRoot":"","sources":["../../src/resilience/embedder-resilience.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,CAAC,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;AAO/E,0DAA0D;AAC1D,MAAM,UAAU,qBAAqB,CACnC,CAAY;IAEZ,OAAQ,CAAwD,CAC9D,eAAe,CAChB,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAC5B,CAAY,EACZ,IAAgC;IAEhC,MAAM,CAAC,cAAc,CAAC,CAAC,EAAE,eAAe,EAAE;QACxC,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,KAAK;QACjB,YAAY,EAAE,KAAK;QACnB,QAAQ,EAAE,KAAK;KAChB,CAAC,CAAC;AACL,CAAC;AAWD,MAAM,UAAU,wBAAwB,CACtC,KAAgB,EAChB,OAAkC;IAElC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC9C,IAAI,QAAQ,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,OAAO,EAAE,oBAAoB,CAAC;QAChD,yEAAyE;QACzE,wEAAwE;QACxE,2EAA2E;QAC3E,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,QAAQ,CAAC,YAAY,EAAE,CAAC;YACnE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC;gBACnB,IAAI,EAAE,SAAS;gBACf,OAAO,EAAE,qBAAqB;gBAC9B,OAAO,EACL,kDAAkD,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI;oBACnF,0BAA0B,SAAS,oCAAoC;aAC1E,CAAC,CAAC;QACL,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,GAAG,GACP,OAAO,EAAE,oBAAoB;QAC7B,OAAO,EAAE,oBAAoB;QAC7B,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC;IAE5E,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,CAAC,CAAC;IACjD,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAC9C,MAAM,QAAQ,GAAG,YAAY;QAC3B,CAAC,CAAC,IAAI,qBAAqB,CAAC,OAAO,EAAE,GAAG,CAAC;QACzC,CAAC,CAAC,OAAO,CAAC;IAEZ,cAAc,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpE,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -1,5 +1,8 @@
1
+ export { BatchChunkingEmbedder, DEFAULT_MAX_BATCH_SIZE, } from './batch-chunking-embedder.js';
1
2
  export { CircuitBreaker, type CircuitBreakerConfig, type CircuitState, } from './circuit-breaker.js';
2
- export { CircuitBreakerEmbedder } from './circuit-breaker-embedder.js';
3
+ export { CircuitBreakerEmbedder, CircuitBreakerEmbedderBase, withCircuitBreaker, } from './circuit-breaker-embedder.js';
3
4
  export { CircuitBreakerLlm } from './circuit-breaker-llm.js';
5
+ export { brandResilient, type ComposeResilienceOptions, composeResilientEmbedder, type EmbedderResilienceMetadata, getResilienceMetadata, RESILIENCE_META, } from './embedder-resilience.js';
4
6
  export { FallbackRag } from './fallback-rag.js';
7
+ export { type EmbedderRetryOptions, extractStatusCode, isRetryableStatus, RetryBatchEmbedder, RetryEmbedder, withRetry, } from './retry-embedder.js';
5
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,YAAY,GAClB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,cAAc,EACd,KAAK,wBAAwB,EAC7B,wBAAwB,EACxB,KAAK,0BAA0B,EAC/B,qBAAqB,EACrB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EACL,KAAK,oBAAoB,EACzB,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,SAAS,GACV,MAAM,qBAAqB,CAAC"}
@@ -1,5 +1,8 @@
1
+ export { BatchChunkingEmbedder, DEFAULT_MAX_BATCH_SIZE, } from './batch-chunking-embedder.js';
1
2
  export { CircuitBreaker, } from './circuit-breaker.js';
2
- export { CircuitBreakerEmbedder } from './circuit-breaker-embedder.js';
3
+ export { CircuitBreakerEmbedder, CircuitBreakerEmbedderBase, withCircuitBreaker, } from './circuit-breaker-embedder.js';
3
4
  export { CircuitBreakerLlm } from './circuit-breaker-llm.js';
5
+ export { brandResilient, composeResilientEmbedder, getResilienceMetadata, RESILIENCE_META, } from './embedder-resilience.js';
4
6
  export { FallbackRag } from './fallback-rag.js';
7
+ export { extractStatusCode, isRetryableStatus, RetryBatchEmbedder, RetryEmbedder, withRetry, } from './retry-embedder.js';
5
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/resilience/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EACL,cAAc,GAGf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,GACnB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EACL,cAAc,EAEd,wBAAwB,EAExB,qBAAqB,EACrB,eAAe,GAChB,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAEL,iBAAiB,EACjB,iBAAiB,EACjB,kBAAkB,EAClB,aAAa,EACb,SAAS,GACV,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * RetryEmbedder — IEmbedder decorators that retry transient failures with
3
+ * exponential backoff. Ported from RetryLlm (llm-agent-libs) onto IEmbedder,
4
+ * which throws instead of returning a Result.
5
+ *
6
+ * Two classes behind a factory, following wrapEmbedder: a single class exposing
7
+ * embedBatch unconditionally would make every non-batch embedder look
8
+ * batch-capable to isBatchEmbedder.
9
+ */
10
+ import type { IEmbedder, IEmbedderBatch, IEmbedResult } from '../interfaces/rag.js';
11
+ import type { CallOptions } from '../interfaces/types.js';
12
+ import type { IWaitStrategy } from '../interfaces/wait-strategy.js';
13
+ export interface EmbedderRetryOptions {
14
+ /** Maximum number of retries (total calls = maxAttempts + 1). Default: 3. */
15
+ maxAttempts: number;
16
+ /** Initial backoff delay in ms. Doubles each attempt. Default: 2000. */
17
+ backoffMs: number;
18
+ /** HTTP status codes that trigger a retry. Default: [429, 500, 502, 503]. */
19
+ retryOn: number[];
20
+ /**
21
+ * Mechanism for the backoff sleep. Default: `DefaultWaitStrategy`.
22
+ *
23
+ * The same seam the controller's `wait` step uses: a deployment can replace
24
+ * a blocking timer with jitter, its own scheduler, or suspend/resume.
25
+ *
26
+ * Optional, unlike the scalar knobs beside it: this is a collaborator, not a
27
+ * setting. A consumer assembling a full options literal should not have to
28
+ * name an internal mechanism, and the type stays expressible as plain data.
29
+ */
30
+ waitStrategy?: IWaitStrategy;
31
+ }
32
+ /** Internal shape after defaults are applied — every field is present. */
33
+ type ResolvedRetryOptions = Omit<EmbedderRetryOptions, 'waitStrategy'> & {
34
+ waitStrategy: IWaitStrategy;
35
+ };
36
+ /**
37
+ * Resolve an HTTP status from an unknown thrown value: own status/statusCode,
38
+ * then the same walking `cause`, bounded by depth and a visited set so a cyclic
39
+ * chain cannot hang. Returns undefined when no numeric status is present.
40
+ */
41
+ export declare function extractStatusCode(err: unknown): number | undefined;
42
+ /**
43
+ * Whether a thrown value should be retried against a set of HTTP status codes.
44
+ *
45
+ * A structured status (own `status`/`statusCode`, or the same on `cause`) is
46
+ * authoritative. Only when none is present does it fall back to the message,
47
+ * and there it matches on **word boundaries** — a bare `includes('429')` also
48
+ * fires on `4290`, an id, or a byte count, turning a hard error into a
49
+ * multi-second backoff stall.
50
+ *
51
+ * Shared by both retry decorators (embedder and LLM) so the classification
52
+ * cannot drift between them.
53
+ */
54
+ export declare function isRetryableStatus(err: unknown, retryOn: number[]): boolean;
55
+ export declare class RetryEmbedder implements IEmbedder {
56
+ protected readonly inner: IEmbedder;
57
+ protected readonly opts: ResolvedRetryOptions;
58
+ constructor(inner: IEmbedder, options?: Partial<EmbedderRetryOptions>);
59
+ embed(text: string, options?: CallOptions): Promise<IEmbedResult>;
60
+ protected run<T>(call: () => Promise<T>, options?: CallOptions): Promise<T>;
61
+ protected isRetryable(err: unknown): boolean;
62
+ /**
63
+ * Delegated to IWaitStrategy rather than hand-rolled: honouring the signal is
64
+ * part of that contract — an already-aborted signal returns immediately
65
+ * (addEventListener never fires for an event that already dispatched), and
66
+ * the listener is removed when the timer wins so a request- or session-scoped
67
+ * signal does not accumulate one per retry.
68
+ */
69
+ protected backoff(attempt: number, signal?: AbortSignal): Promise<void>;
70
+ }
71
+ export declare class RetryBatchEmbedder extends RetryEmbedder implements IEmbedderBatch {
72
+ protected readonly inner: IEmbedderBatch;
73
+ constructor(inner: IEmbedderBatch, options?: Partial<EmbedderRetryOptions>);
74
+ embedBatch(texts: string[], options?: CallOptions): Promise<IEmbedResult[]>;
75
+ }
76
+ /** Preserves batch capability: never turns a non-batch embedder into one. */
77
+ export declare function withRetry(inner: IEmbedder, options?: Partial<EmbedderRetryOptions>): IEmbedder;
78
+ export {};
79
+ //# sourceMappingURL=retry-embedder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry-embedder.d.ts","sourceRoot":"","sources":["../../src/resilience/retry-embedder.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,YAAY,EACb,MAAM,sBAAsB,CAAC;AAG9B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAE1D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAGpE,MAAM,WAAW,oBAAoB;IACnC,6EAA6E;IAC7E,WAAW,EAAE,MAAM,CAAC;IACpB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,aAAa,CAAC;CAC9B;AAED,0EAA0E;AAC1E,KAAK,oBAAoB,GAAG,IAAI,CAAC,oBAAoB,EAAE,cAAc,CAAC,GAAG;IACvE,YAAY,EAAE,aAAa,CAAC;CAC7B,CAAC;AAYF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAgBlE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAK1E;AAED,qBAAa,aAAc,YAAW,SAAS;IAI3C,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS;IAHrC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC;gBAGzB,KAAK,EAAE,SAAS,EACnC,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAYnC,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;cAIvD,GAAG,CAAC,CAAC,EACnB,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACtB,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,CAAC,CAAC;IAeb,SAAS,CAAC,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAI5C;;;;;;OAMG;cACa,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC;CAIjB;AAED,qBAAa,kBACX,SAAQ,aACR,YAAW,cAAc;IAGvB,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,cAAc;gBAArB,KAAK,EAAE,cAAc,EACxC,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC;IAKnC,UAAU,CACd,KAAK,EAAE,MAAM,EAAE,EACf,OAAO,CAAC,EAAE,WAAW,GACpB,OAAO,CAAC,YAAY,EAAE,CAAC;CAG3B;AAED,6EAA6E;AAC7E,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,GACtC,SAAS,CAIX"}