@illuma-ai/agents 1.4.0-alpha.0 → 1.4.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cjs/main.cjs CHANGED
@@ -32,7 +32,6 @@ var proxyTool = require('./tools/proxyTool.cjs');
32
32
  var types = require('./providers/types.cjs');
33
33
  var capabilityNaming = require('./providers/capabilityNaming.cjs');
34
34
  var ToolsServerCapabilityProvider = require('./providers/tools-server/ToolsServerCapabilityProvider.cjs');
35
- var CompositeCapabilityProvider = require('./providers/composite/CompositeCapabilityProvider.cjs');
36
35
  var MCPCapabilityProvider = require('./providers/mcp/MCPCapabilityProvider.cjs');
37
36
  var transport = require('./providers/mcp/transport.cjs');
38
37
  var config$1 = require('./providers/mcp/config.cjs');
@@ -233,7 +232,6 @@ exports.CAPABILITY_NAME_SEPARATOR = capabilityNaming.CAPABILITY_NAME_SEPARATOR;
233
232
  exports.formatCapabilityName = capabilityNaming.formatCapabilityName;
234
233
  exports.parseCapabilityName = capabilityNaming.parseCapabilityName;
235
234
  exports.ToolsServerCapabilityProvider = ToolsServerCapabilityProvider.ToolsServerCapabilityProvider;
236
- exports.CompositeCapabilityProvider = CompositeCapabilityProvider.CompositeCapabilityProvider;
237
235
  exports.MCPCapabilityProvider = MCPCapabilityProvider.MCPCapabilityProvider;
238
236
  exports.flattenToolCallResponse = MCPCapabilityProvider.flattenToolCallResponse;
239
237
  exports.createTransport = transport.createTransport;
@@ -1 +1 @@
1
- {"version":3,"file":"main.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"main.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
package/dist/esm/main.mjs CHANGED
@@ -30,7 +30,6 @@ export { buildProxyTool } from './tools/proxyTool.mjs';
30
30
  export { AuthSource, CapabilityKind } from './providers/types.mjs';
31
31
  export { CAPABILITY_NAME_SEPARATOR, formatCapabilityName, parseCapabilityName } from './providers/capabilityNaming.mjs';
32
32
  export { ToolsServerCapabilityProvider } from './providers/tools-server/ToolsServerCapabilityProvider.mjs';
33
- export { CompositeCapabilityProvider } from './providers/composite/CompositeCapabilityProvider.mjs';
34
33
  export { MCPCapabilityProvider, flattenToolCallResponse } from './providers/mcp/MCPCapabilityProvider.mjs';
35
34
  export { createTransport } from './providers/mcp/transport.mjs';
36
35
  export { getMCPEnvDefaults, consoleLogger as mcpConsoleLogger } from './providers/mcp/config.mjs';
@@ -1 +1 @@
1
- {"version":3,"file":"main.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"main.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -6,7 +6,6 @@
6
6
  export * from './types';
7
7
  export * from './capabilityNaming';
8
8
  export * from './tools-server';
9
- export * from './composite';
10
9
  export { MCPCapabilityProvider, flattenToolCallResponse, createTransport, mcpConsoleLogger, getMCPEnvDefaults, } from './mcp';
11
10
  export type { MCPLogger, MCPProviderConfig, MCPServerSpec, MCPTransportKind, StdioSpec, SSESpec, StreamableHTTPSpec, WebSocketSpec, MCPToolDescriptor, MCPToolCallResult, MCPStructuredTool, } from './mcp';
12
11
  export { A2ACapabilityProvider, A2AClient, extractTaskText, generateRpcId, skillToCapability, coerceInputToA2AMessage, MESSAGE_INPUT_SCHEMA, a2aConsoleLogger, getA2AEnvDefaults, } from './a2a';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@illuma-ai/agents",
3
- "version": "1.4.0-alpha.0",
3
+ "version": "1.4.0-alpha.1",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -24,11 +24,6 @@
24
24
  "import": "./dist/esm/providers/a2a/A2ACapabilityProvider.mjs",
25
25
  "require": "./dist/cjs/providers/a2a/A2ACapabilityProvider.cjs",
26
26
  "types": "./dist/types/providers/a2a/A2ACapabilityProvider.d.ts"
27
- },
28
- "./providers/composite": {
29
- "import": "./dist/esm/providers/composite/CompositeCapabilityProvider.mjs",
30
- "require": "./dist/cjs/providers/composite/CompositeCapabilityProvider.cjs",
31
- "types": "./dist/types/providers/composite/CompositeCapabilityProvider.d.ts"
32
27
  }
33
28
  },
34
29
  "type": "module",
@@ -9,7 +9,10 @@ export * from './types';
9
9
  // A2A consumers get the same encoding without re-export duplication.
10
10
  export * from './capabilityNaming';
11
11
  export * from './tools-server';
12
- export * from './composite';
12
+ // Hosts compose multiple providers by iterating a plain array and
13
+ // concatenating tools — see docs/capability-providers.md. No wrapper
14
+ // class is provided because the loop is trivial and keeps host code
15
+ // transparent.
13
16
  // MCP + A2A barrels intentionally namespaced to avoid re-exporting
14
17
  // `CAPABILITY_NAME_SEPARATOR` / `formatCapabilityName` twice (each
15
18
  // provider module re-exports them internally; the canonical export
@@ -1,80 +0,0 @@
1
- 'use strict';
2
-
3
- /**
4
- * CompositeCapabilityProvider — fans out to multiple CapabilityProviders
5
- * and merges their manifests + runnables into one.
6
- *
7
- * Use case: an agent that consumes tools from tools-server AND MCP servers
8
- * AND (future) skills. The composite exposes a single CapabilityProvider
9
- * interface to the agent runtime so it doesn't know or care how many
10
- * backing sources exist.
11
- *
12
- * Precedence: later providers do NOT override earlier ones on name
13
- * collision — collisions are logged and the first-registered capability
14
- * wins. Callers should ensure providers expose disjoint name spaces.
15
- */
16
- class CompositeCapabilityProvider {
17
- providerId;
18
- providers;
19
- constructor(providers) {
20
- if (!providers.length) {
21
- throw new Error('CompositeCapabilityProvider: at least one provider is required');
22
- }
23
- this.providers = providers;
24
- this.providerId = `composite:${providers.map((p) => p.providerId).join(',')}`;
25
- }
26
- async fetchManifest(filter) {
27
- // Fetch all providers in parallel. One provider failing should not
28
- // prevent others from contributing — log and continue.
29
- const results = await Promise.allSettled(this.providers.map((p) => p.fetchManifest(filter)));
30
- const merged = [];
31
- const seen = new Set();
32
- for (let i = 0; i < results.length; i++) {
33
- const result = results[i];
34
- const provider = this.providers[i];
35
- if (result.status === 'rejected') {
36
- // DEBUG
37
- // eslint-disable-next-line no-console
38
- console.debug(`[composite] provider ${provider.providerId} fetchManifest failed — ${String(result.reason)}`);
39
- continue;
40
- }
41
- for (const cap of result.value) {
42
- if (seen.has(cap.name)) {
43
- // DEBUG
44
- // eslint-disable-next-line no-console
45
- console.debug(`[composite] name collision on "${cap.name}" from ${provider.providerId} — keeping first`);
46
- continue;
47
- }
48
- seen.add(cap.name);
49
- merged.push(cap);
50
- }
51
- }
52
- // DEBUG
53
- // eslint-disable-next-line no-console
54
- console.debug(`[composite] merged manifest: ${merged.length} caps from ${this.providers.length} providers`);
55
- return merged;
56
- }
57
- async createRunnables(capabilities, credentials) {
58
- // Determine which capabilities belong to which provider by refetching
59
- // each provider's manifest and intersecting with the requested set.
60
- // This keeps providers stateless — we don't require Capability to
61
- // carry a back-reference to its provider.
62
- const capabilityNames = new Set(capabilities.map((c) => c.name));
63
- const perProviderCaps = await Promise.all(this.providers.map(async (p) => {
64
- const manifest = await p.fetchManifest();
65
- return manifest.filter((c) => capabilityNames.has(c.name));
66
- }));
67
- const allRunnables = [];
68
- for (let i = 0; i < this.providers.length; i++) {
69
- const providerCaps = perProviderCaps[i];
70
- if (!providerCaps.length)
71
- continue;
72
- const runnables = await this.providers[i].createRunnables(providerCaps, credentials);
73
- allRunnables.push(...runnables);
74
- }
75
- return allRunnables;
76
- }
77
- }
78
-
79
- exports.CompositeCapabilityProvider = CompositeCapabilityProvider;
80
- //# sourceMappingURL=CompositeCapabilityProvider.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CompositeCapabilityProvider.cjs","sources":["../../../../src/providers/composite/CompositeCapabilityProvider.ts"],"sourcesContent":["/**\n * CompositeCapabilityProvider — fans out to multiple CapabilityProviders\n * and merges their manifests + runnables into one.\n *\n * Use case: an agent that consumes tools from tools-server AND MCP servers\n * AND (future) skills. The composite exposes a single CapabilityProvider\n * interface to the agent runtime so it doesn't know or care how many\n * backing sources exist.\n *\n * Precedence: later providers do NOT override earlier ones on name\n * collision — collisions are logged and the first-registered capability\n * wins. Callers should ensure providers expose disjoint name spaces.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type {\n Capability,\n CapabilityFilter,\n CapabilityProvider,\n CredentialMap,\n} from '@/providers/types';\n\nexport class CompositeCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly providers: CapabilityProvider[];\n\n constructor(providers: CapabilityProvider[]) {\n if (!providers.length) {\n throw new Error(\n 'CompositeCapabilityProvider: at least one provider is required'\n );\n }\n this.providers = providers;\n this.providerId = `composite:${providers.map((p) => p.providerId).join(',')}`;\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n // Fetch all providers in parallel. One provider failing should not\n // prevent others from contributing — log and continue.\n const results = await Promise.allSettled(\n this.providers.map((p) => p.fetchManifest(filter))\n );\n\n const merged: Capability[] = [];\n const seen = new Set<string>();\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const provider = this.providers[i];\n\n if (result.status === 'rejected') {\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] provider ${provider.providerId} fetchManifest failed — ${String(result.reason)}`\n );\n continue;\n }\n\n for (const cap of result.value) {\n if (seen.has(cap.name)) {\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] name collision on \"${cap.name}\" from ${provider.providerId} — keeping first`\n );\n continue;\n }\n seen.add(cap.name);\n merged.push(cap);\n }\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] merged manifest: ${merged.length} caps from ${this.providers.length} providers`\n );\n\n return merged;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n // Determine which capabilities belong to which provider by refetching\n // each provider's manifest and intersecting with the requested set.\n // This keeps providers stateless — we don't require Capability to\n // carry a back-reference to its provider.\n const capabilityNames = new Set(capabilities.map((c) => c.name));\n const perProviderCaps = await Promise.all(\n this.providers.map(async (p) => {\n const manifest = await p.fetchManifest();\n return manifest.filter((c) => capabilityNames.has(c.name));\n })\n );\n\n const allRunnables: StructuredToolInterface[] = [];\n for (let i = 0; i < this.providers.length; i++) {\n const providerCaps = perProviderCaps[i];\n if (!providerCaps.length) continue;\n const runnables = await this.providers[i].createRunnables(\n providerCaps,\n credentials\n );\n allRunnables.push(...runnables);\n }\n\n return allRunnables;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,78 +0,0 @@
1
- /**
2
- * CompositeCapabilityProvider — fans out to multiple CapabilityProviders
3
- * and merges their manifests + runnables into one.
4
- *
5
- * Use case: an agent that consumes tools from tools-server AND MCP servers
6
- * AND (future) skills. The composite exposes a single CapabilityProvider
7
- * interface to the agent runtime so it doesn't know or care how many
8
- * backing sources exist.
9
- *
10
- * Precedence: later providers do NOT override earlier ones on name
11
- * collision — collisions are logged and the first-registered capability
12
- * wins. Callers should ensure providers expose disjoint name spaces.
13
- */
14
- class CompositeCapabilityProvider {
15
- providerId;
16
- providers;
17
- constructor(providers) {
18
- if (!providers.length) {
19
- throw new Error('CompositeCapabilityProvider: at least one provider is required');
20
- }
21
- this.providers = providers;
22
- this.providerId = `composite:${providers.map((p) => p.providerId).join(',')}`;
23
- }
24
- async fetchManifest(filter) {
25
- // Fetch all providers in parallel. One provider failing should not
26
- // prevent others from contributing — log and continue.
27
- const results = await Promise.allSettled(this.providers.map((p) => p.fetchManifest(filter)));
28
- const merged = [];
29
- const seen = new Set();
30
- for (let i = 0; i < results.length; i++) {
31
- const result = results[i];
32
- const provider = this.providers[i];
33
- if (result.status === 'rejected') {
34
- // DEBUG
35
- // eslint-disable-next-line no-console
36
- console.debug(`[composite] provider ${provider.providerId} fetchManifest failed — ${String(result.reason)}`);
37
- continue;
38
- }
39
- for (const cap of result.value) {
40
- if (seen.has(cap.name)) {
41
- // DEBUG
42
- // eslint-disable-next-line no-console
43
- console.debug(`[composite] name collision on "${cap.name}" from ${provider.providerId} — keeping first`);
44
- continue;
45
- }
46
- seen.add(cap.name);
47
- merged.push(cap);
48
- }
49
- }
50
- // DEBUG
51
- // eslint-disable-next-line no-console
52
- console.debug(`[composite] merged manifest: ${merged.length} caps from ${this.providers.length} providers`);
53
- return merged;
54
- }
55
- async createRunnables(capabilities, credentials) {
56
- // Determine which capabilities belong to which provider by refetching
57
- // each provider's manifest and intersecting with the requested set.
58
- // This keeps providers stateless — we don't require Capability to
59
- // carry a back-reference to its provider.
60
- const capabilityNames = new Set(capabilities.map((c) => c.name));
61
- const perProviderCaps = await Promise.all(this.providers.map(async (p) => {
62
- const manifest = await p.fetchManifest();
63
- return manifest.filter((c) => capabilityNames.has(c.name));
64
- }));
65
- const allRunnables = [];
66
- for (let i = 0; i < this.providers.length; i++) {
67
- const providerCaps = perProviderCaps[i];
68
- if (!providerCaps.length)
69
- continue;
70
- const runnables = await this.providers[i].createRunnables(providerCaps, credentials);
71
- allRunnables.push(...runnables);
72
- }
73
- return allRunnables;
74
- }
75
- }
76
-
77
- export { CompositeCapabilityProvider };
78
- //# sourceMappingURL=CompositeCapabilityProvider.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CompositeCapabilityProvider.mjs","sources":["../../../../src/providers/composite/CompositeCapabilityProvider.ts"],"sourcesContent":["/**\n * CompositeCapabilityProvider — fans out to multiple CapabilityProviders\n * and merges their manifests + runnables into one.\n *\n * Use case: an agent that consumes tools from tools-server AND MCP servers\n * AND (future) skills. The composite exposes a single CapabilityProvider\n * interface to the agent runtime so it doesn't know or care how many\n * backing sources exist.\n *\n * Precedence: later providers do NOT override earlier ones on name\n * collision — collisions are logged and the first-registered capability\n * wins. Callers should ensure providers expose disjoint name spaces.\n */\n\nimport type { StructuredToolInterface } from '@langchain/core/tools';\nimport type {\n Capability,\n CapabilityFilter,\n CapabilityProvider,\n CredentialMap,\n} from '@/providers/types';\n\nexport class CompositeCapabilityProvider implements CapabilityProvider {\n readonly providerId: string;\n private readonly providers: CapabilityProvider[];\n\n constructor(providers: CapabilityProvider[]) {\n if (!providers.length) {\n throw new Error(\n 'CompositeCapabilityProvider: at least one provider is required'\n );\n }\n this.providers = providers;\n this.providerId = `composite:${providers.map((p) => p.providerId).join(',')}`;\n }\n\n async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {\n // Fetch all providers in parallel. One provider failing should not\n // prevent others from contributing — log and continue.\n const results = await Promise.allSettled(\n this.providers.map((p) => p.fetchManifest(filter))\n );\n\n const merged: Capability[] = [];\n const seen = new Set<string>();\n\n for (let i = 0; i < results.length; i++) {\n const result = results[i];\n const provider = this.providers[i];\n\n if (result.status === 'rejected') {\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] provider ${provider.providerId} fetchManifest failed — ${String(result.reason)}`\n );\n continue;\n }\n\n for (const cap of result.value) {\n if (seen.has(cap.name)) {\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] name collision on \"${cap.name}\" from ${provider.providerId} — keeping first`\n );\n continue;\n }\n seen.add(cap.name);\n merged.push(cap);\n }\n }\n\n // DEBUG\n // eslint-disable-next-line no-console\n console.debug(\n `[composite] merged manifest: ${merged.length} caps from ${this.providers.length} providers`\n );\n\n return merged;\n }\n\n async createRunnables(\n capabilities: Capability[],\n credentials: CredentialMap\n ): Promise<StructuredToolInterface[]> {\n // Determine which capabilities belong to which provider by refetching\n // each provider's manifest and intersecting with the requested set.\n // This keeps providers stateless — we don't require Capability to\n // carry a back-reference to its provider.\n const capabilityNames = new Set(capabilities.map((c) => c.name));\n const perProviderCaps = await Promise.all(\n this.providers.map(async (p) => {\n const manifest = await p.fetchManifest();\n return manifest.filter((c) => capabilityNames.has(c.name));\n })\n );\n\n const allRunnables: StructuredToolInterface[] = [];\n for (let i = 0; i < this.providers.length; i++) {\n const providerCaps = perProviderCaps[i];\n if (!providerCaps.length) continue;\n const runnables = await this.providers[i].createRunnables(\n providerCaps,\n credentials\n );\n allRunnables.push(...runnables);\n }\n\n return allRunnables;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,22 +0,0 @@
1
- /**
2
- * CompositeCapabilityProvider — fans out to multiple CapabilityProviders
3
- * and merges their manifests + runnables into one.
4
- *
5
- * Use case: an agent that consumes tools from tools-server AND MCP servers
6
- * AND (future) skills. The composite exposes a single CapabilityProvider
7
- * interface to the agent runtime so it doesn't know or care how many
8
- * backing sources exist.
9
- *
10
- * Precedence: later providers do NOT override earlier ones on name
11
- * collision — collisions are logged and the first-registered capability
12
- * wins. Callers should ensure providers expose disjoint name spaces.
13
- */
14
- import type { StructuredToolInterface } from '@langchain/core/tools';
15
- import type { Capability, CapabilityFilter, CapabilityProvider, CredentialMap } from '@/providers/types';
16
- export declare class CompositeCapabilityProvider implements CapabilityProvider {
17
- readonly providerId: string;
18
- private readonly providers;
19
- constructor(providers: CapabilityProvider[]);
20
- fetchManifest(filter?: CapabilityFilter): Promise<Capability[]>;
21
- createRunnables(capabilities: Capability[], credentials: CredentialMap): Promise<StructuredToolInterface[]>;
22
- }
@@ -1 +0,0 @@
1
- export * from './CompositeCapabilityProvider';
@@ -1,93 +0,0 @@
1
- import { CompositeCapabilityProvider } from '../composite/CompositeCapabilityProvider';
2
- import {
3
- CapabilityKind,
4
- type Capability,
5
- type CapabilityProvider,
6
- type CredentialMap,
7
- } from '../types';
8
-
9
- const makeCap = (
10
- name: string,
11
- kind: CapabilityKind = CapabilityKind.TOOL
12
- ): Capability => ({
13
- kind,
14
- name,
15
- description: `${name} cap`,
16
- authConfig: [],
17
- metadata: {},
18
- });
19
-
20
- class FakeProvider implements CapabilityProvider {
21
- readonly providerId: string;
22
- manifestCallCount = 0;
23
- createCallCount = 0;
24
-
25
- constructor(
26
- id: string,
27
- private readonly manifest: Capability[],
28
- private readonly failOnFetch = false
29
- ) {
30
- this.providerId = id;
31
- }
32
- async fetchManifest(): Promise<Capability[]> {
33
- this.manifestCallCount++;
34
- if (this.failOnFetch) throw new Error('simulated failure');
35
- return this.manifest;
36
- }
37
- async createRunnables(capabilities: Capability[], _creds: CredentialMap) {
38
- this.createCallCount++;
39
- // Return one fake tool per capability name — we can't import StructuredToolInterface here cleanly,
40
- // so cast. The test only checks length + name.
41
- return capabilities.map((c) => ({ name: c.name }) as unknown as never);
42
- }
43
- }
44
-
45
- describe('CompositeCapabilityProvider', () => {
46
- it('throws on empty provider list', () => {
47
- expect(() => new CompositeCapabilityProvider([])).toThrow(/at least one/);
48
- });
49
-
50
- it('providerId reflects composed providers', () => {
51
- const composite = new CompositeCapabilityProvider([
52
- new FakeProvider('p1', []),
53
- new FakeProvider('p2', []),
54
- ]);
55
- expect(composite.providerId).toBe('composite:p1,p2');
56
- });
57
-
58
- it('merges manifests from all providers', async () => {
59
- const p1 = new FakeProvider('p1', [makeCap('a'), makeCap('b')]);
60
- const p2 = new FakeProvider('p2', [makeCap('c')]);
61
- const composite = new CompositeCapabilityProvider([p1, p2]);
62
- const caps = await composite.fetchManifest();
63
- expect(caps.map((c) => c.name).sort()).toEqual(['a', 'b', 'c']);
64
- });
65
-
66
- it('deduplicates on name collision, first provider wins', async () => {
67
- const p1 = new FakeProvider('p1', [makeCap('dup'), makeCap('a')]);
68
- const p2 = new FakeProvider('p2', [makeCap('dup'), makeCap('b')]);
69
- const composite = new CompositeCapabilityProvider([p1, p2]);
70
- const caps = await composite.fetchManifest();
71
- expect(caps.map((c) => c.name).sort()).toEqual(['a', 'b', 'dup']);
72
- });
73
-
74
- it('continues when one provider fails', async () => {
75
- const p1 = new FakeProvider('p1', [], true);
76
- const p2 = new FakeProvider('p2', [makeCap('x')]);
77
- const composite = new CompositeCapabilityProvider([p1, p2]);
78
- const caps = await composite.fetchManifest();
79
- expect(caps).toHaveLength(1);
80
- expect(caps[0].name).toBe('x');
81
- });
82
-
83
- it('createRunnables routes each capability to its owning provider', async () => {
84
- const p1 = new FakeProvider('p1', [makeCap('a'), makeCap('b')]);
85
- const p2 = new FakeProvider('p2', [makeCap('c')]);
86
- const composite = new CompositeCapabilityProvider([p1, p2]);
87
- const manifest = await composite.fetchManifest();
88
- const runnables = await composite.createRunnables(manifest, {});
89
- expect(runnables).toHaveLength(3);
90
- expect(p1.createCallCount).toBe(1);
91
- expect(p2.createCallCount).toBe(1);
92
- });
93
- });
@@ -1,112 +0,0 @@
1
- /**
2
- * CompositeCapabilityProvider — fans out to multiple CapabilityProviders
3
- * and merges their manifests + runnables into one.
4
- *
5
- * Use case: an agent that consumes tools from tools-server AND MCP servers
6
- * AND (future) skills. The composite exposes a single CapabilityProvider
7
- * interface to the agent runtime so it doesn't know or care how many
8
- * backing sources exist.
9
- *
10
- * Precedence: later providers do NOT override earlier ones on name
11
- * collision — collisions are logged and the first-registered capability
12
- * wins. Callers should ensure providers expose disjoint name spaces.
13
- */
14
-
15
- import type { StructuredToolInterface } from '@langchain/core/tools';
16
- import type {
17
- Capability,
18
- CapabilityFilter,
19
- CapabilityProvider,
20
- CredentialMap,
21
- } from '@/providers/types';
22
-
23
- export class CompositeCapabilityProvider implements CapabilityProvider {
24
- readonly providerId: string;
25
- private readonly providers: CapabilityProvider[];
26
-
27
- constructor(providers: CapabilityProvider[]) {
28
- if (!providers.length) {
29
- throw new Error(
30
- 'CompositeCapabilityProvider: at least one provider is required'
31
- );
32
- }
33
- this.providers = providers;
34
- this.providerId = `composite:${providers.map((p) => p.providerId).join(',')}`;
35
- }
36
-
37
- async fetchManifest(filter?: CapabilityFilter): Promise<Capability[]> {
38
- // Fetch all providers in parallel. One provider failing should not
39
- // prevent others from contributing — log and continue.
40
- const results = await Promise.allSettled(
41
- this.providers.map((p) => p.fetchManifest(filter))
42
- );
43
-
44
- const merged: Capability[] = [];
45
- const seen = new Set<string>();
46
-
47
- for (let i = 0; i < results.length; i++) {
48
- const result = results[i];
49
- const provider = this.providers[i];
50
-
51
- if (result.status === 'rejected') {
52
- // DEBUG
53
- // eslint-disable-next-line no-console
54
- console.debug(
55
- `[composite] provider ${provider.providerId} fetchManifest failed — ${String(result.reason)}`
56
- );
57
- continue;
58
- }
59
-
60
- for (const cap of result.value) {
61
- if (seen.has(cap.name)) {
62
- // DEBUG
63
- // eslint-disable-next-line no-console
64
- console.debug(
65
- `[composite] name collision on "${cap.name}" from ${provider.providerId} — keeping first`
66
- );
67
- continue;
68
- }
69
- seen.add(cap.name);
70
- merged.push(cap);
71
- }
72
- }
73
-
74
- // DEBUG
75
- // eslint-disable-next-line no-console
76
- console.debug(
77
- `[composite] merged manifest: ${merged.length} caps from ${this.providers.length} providers`
78
- );
79
-
80
- return merged;
81
- }
82
-
83
- async createRunnables(
84
- capabilities: Capability[],
85
- credentials: CredentialMap
86
- ): Promise<StructuredToolInterface[]> {
87
- // Determine which capabilities belong to which provider by refetching
88
- // each provider's manifest and intersecting with the requested set.
89
- // This keeps providers stateless — we don't require Capability to
90
- // carry a back-reference to its provider.
91
- const capabilityNames = new Set(capabilities.map((c) => c.name));
92
- const perProviderCaps = await Promise.all(
93
- this.providers.map(async (p) => {
94
- const manifest = await p.fetchManifest();
95
- return manifest.filter((c) => capabilityNames.has(c.name));
96
- })
97
- );
98
-
99
- const allRunnables: StructuredToolInterface[] = [];
100
- for (let i = 0; i < this.providers.length; i++) {
101
- const providerCaps = perProviderCaps[i];
102
- if (!providerCaps.length) continue;
103
- const runnables = await this.providers[i].createRunnables(
104
- providerCaps,
105
- credentials
106
- );
107
- allRunnables.push(...runnables);
108
- }
109
-
110
- return allRunnables;
111
- }
112
- }
@@ -1 +0,0 @@
1
- export * from './CompositeCapabilityProvider';