@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.
- package/README.md +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/interfaces/assert-client-descriptors.d.ts +6 -0
- package/dist/interfaces/assert-client-descriptors.d.ts.map +1 -0
- package/dist/interfaces/assert-client-descriptors.js +27 -0
- package/dist/interfaces/assert-client-descriptors.js.map +1 -0
- package/dist/interfaces/build-namespaced-tools.d.ts +21 -0
- package/dist/interfaces/build-namespaced-tools.d.ts.map +1 -0
- package/dist/interfaces/build-namespaced-tools.js +48 -0
- package/dist/interfaces/build-namespaced-tools.js.map +1 -0
- package/dist/interfaces/builder.d.ts +17 -1
- package/dist/interfaces/builder.d.ts.map +1 -1
- package/dist/interfaces/health.d.ts +11 -0
- package/dist/interfaces/health.d.ts.map +1 -1
- package/dist/interfaces/index.d.ts +4 -2
- package/dist/interfaces/index.d.ts.map +1 -1
- package/dist/interfaces/index.js +3 -1
- package/dist/interfaces/index.js.map +1 -1
- package/dist/interfaces/mcp-connection-strategy.d.ts +14 -0
- package/dist/interfaces/mcp-connection-strategy.d.ts.map +1 -1
- package/dist/interfaces/merge-offered-tools.d.ts +8 -0
- package/dist/interfaces/merge-offered-tools.d.ts.map +1 -0
- package/dist/interfaces/merge-offered-tools.js +14 -0
- package/dist/interfaces/merge-offered-tools.js.map +1 -0
- package/dist/interfaces/pipeline-plugin.d.ts +4 -0
- package/dist/interfaces/pipeline-plugin.d.ts.map +1 -1
- package/dist/interfaces/rag.d.ts +31 -0
- package/dist/interfaces/rag.d.ts.map +1 -1
- package/dist/interfaces/rag.js +10 -0
- package/dist/interfaces/rag.js.map +1 -1
- package/dist/interfaces/tool-catalog.d.ts +35 -0
- package/dist/interfaces/tool-catalog.d.ts.map +1 -0
- package/dist/interfaces/tool-catalog.js +7 -0
- package/dist/interfaces/tool-catalog.js.map +1 -0
- package/dist/interfaces/tool-namespace.d.ts +24 -0
- package/dist/interfaces/tool-namespace.d.ts.map +1 -0
- package/dist/interfaces/tool-namespace.js +20 -0
- package/dist/interfaces/tool-namespace.js.map +1 -0
- package/dist/interfaces/tool-record-key.d.ts +59 -0
- package/dist/interfaces/tool-record-key.d.ts.map +1 -0
- package/dist/interfaces/tool-record-key.js +40 -0
- package/dist/interfaces/tool-record-key.js.map +1 -0
- package/dist/resilience/batch-chunking-embedder.d.ts +23 -0
- package/dist/resilience/batch-chunking-embedder.d.ts.map +1 -0
- package/dist/resilience/batch-chunking-embedder.js +45 -0
- package/dist/resilience/batch-chunking-embedder.js.map +1 -0
- package/dist/resilience/circuit-breaker-embedder.d.ts +23 -3
- package/dist/resilience/circuit-breaker-embedder.d.ts.map +1 -1
- package/dist/resilience/circuit-breaker-embedder.js +25 -1
- package/dist/resilience/circuit-breaker-embedder.js.map +1 -1
- package/dist/resilience/embedder-resilience.d.ts +42 -0
- package/dist/resilience/embedder-resilience.d.ts.map +1 -0
- package/dist/resilience/embedder-resilience.js +66 -0
- package/dist/resilience/embedder-resilience.js.map +1 -0
- package/dist/resilience/index.d.ts +4 -1
- package/dist/resilience/index.d.ts.map +1 -1
- package/dist/resilience/index.js +4 -1
- package/dist/resilience/index.js.map +1 -1
- package/dist/resilience/retry-embedder.d.ts +79 -0
- package/dist/resilience/retry-embedder.d.ts.map +1 -0
- package/dist/resilience/retry-embedder.js +124 -0
- package/dist/resilience/retry-embedder.js.map +1 -0
- 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 @@
|
|
|
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
|
-
|
|
10
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
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"}
|
package/dist/resilience/index.js
CHANGED
|
@@ -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,
|
|
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"}
|