@genesislcap/foundation-ai 14.444.1 → 14.445.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.
@@ -1,3 +1,4 @@
1
+ import { type Container } from '@microsoft/fast-foundation';
1
2
  import type { CriteriaInterpretContext } from './interactions';
2
3
  import { type AIConfig, type AIStatus, type CriteriaInterpretationResult } from './types';
3
4
  import type { ChatMessage, ChatRequestOptions, ChatStreamChunk } from './types/chat.types';
@@ -78,34 +79,144 @@ export interface ResolveAIConfigOptions {
78
79
  */
79
80
  export declare function resolveAIConfig(options?: ResolveAIConfigOptions): Promise<AIConfig | null>;
80
81
  /**
81
- * The DI token for the AIProvider interface.
82
+ * One entry in {@link (AIProviderRegistry:interface).listStatuses}. Pairs the
83
+ * registered name with a status payload (or `null` when the provider doesn't
84
+ * implement {@link AIProvider.getStatus}).
85
+ *
86
+ * @beta
87
+ */
88
+ export interface AIProviderRegistryStatusEntry {
89
+ /** The name the provider was registered under. */
90
+ name: string;
91
+ /** True when this is the registry's default provider. */
92
+ isDefault: boolean;
93
+ /** The provider's `getStatus()` result, or `null` if unavailable. */
94
+ status: AIStatus | null;
95
+ }
96
+ /**
97
+ * Registry of named AI providers. Replaces the single-provider DI token —
98
+ * hosts register one or more named providers and consumers can either ask
99
+ * for the default or resolve a specific provider by name.
100
+ *
101
+ * If no host registration happens, the DI container resolves a built-in
102
+ * empty registry — every lookup returns a no-op provider.
82
103
  *
83
104
  * @remarks
84
- * Register a provider implementation in app bootstrap (e.g. main.ts):
105
+ * Register from app bootstrap with the {@link registerAIProviders} helper:
85
106
  * ```ts
86
- * Registration.singleton(AIProvider, OpenAIProvider)
107
+ * registerAIProviders(container, { openai: provider });
108
+ * // or, for multi-provider:
109
+ * registerAIProviders(container, { openai, anthropic }, { default: 'openai' });
87
110
  * ```
88
111
  *
112
+ * @beta
113
+ */
114
+ export interface AIProviderRegistry {
115
+ /** Look up a registered provider by name. Returns `undefined` if no such name is registered. */
116
+ get(name: string): AIProvider | undefined;
117
+ /** The default provider — used when an agent doesn't specify one. */
118
+ default(): AIProvider;
119
+ /** Name of the default provider. Useful for status display. */
120
+ defaultName(): string;
121
+ /** All registered provider names, in registration order. */
122
+ names(): string[];
123
+ /**
124
+ * Returns the status payload for a single named provider, or for the
125
+ * default when `name` is omitted. Returns `null` when the provider doesn't
126
+ * implement {@link AIProvider.getStatus} or returns null.
127
+ */
128
+ getStatus(name?: string): Promise<AIStatus | null>;
129
+ /**
130
+ * Returns statuses for all registered providers in registration order.
131
+ * Each entry carries the registered name and an `isDefault` flag.
132
+ */
133
+ listStatuses(): Promise<AIProviderRegistryStatusEntry[]>;
134
+ }
135
+ /**
136
+ * Built-in fallback registry. Resolved by the DI container when no host has
137
+ * registered an {@link (AIProviderRegistry:interface)}. Holds a single
138
+ * `DefaultAIProvider` (no-op) under the name `'default'`, preserving the
139
+ * "no host registration → assistant inert" behavior.
140
+ *
141
+ * @internal
142
+ */
143
+ export declare class EmptyAIProviderRegistry implements AIProviderRegistry {
144
+ private static readonly DEFAULT_NAME;
145
+ private readonly noopProvider;
146
+ get(name: string): AIProvider | undefined;
147
+ default(): AIProvider;
148
+ defaultName(): string;
149
+ names(): string[];
150
+ getStatus(name?: string): Promise<AIStatus | null>;
151
+ listStatuses(): Promise<AIProviderRegistryStatusEntry[]>;
152
+ }
153
+ /**
154
+ * Map-backed registry built by {@link registerAIProviders}. Preserves the
155
+ * insertion order of `providers` for {@link (AIProviderRegistry:interface).names}
156
+ * and {@link (AIProviderRegistry:interface).listStatuses}.
157
+ *
89
158
  * @internal
90
159
  */
91
- export declare const AIProvider: import("@microsoft/fast-foundation").InterfaceSymbol<AIProvider>;
160
+ export declare class MapBackedAIProviderRegistry implements AIProviderRegistry {
161
+ private readonly providers;
162
+ private readonly _defaultName;
163
+ constructor(providers: Map<string, AIProvider>, defaultName: string);
164
+ get(name: string): AIProvider | undefined;
165
+ default(): AIProvider;
166
+ defaultName(): string;
167
+ names(): string[];
168
+ getStatus(name?: string): Promise<AIStatus | null>;
169
+ listStatuses(): Promise<AIProviderRegistryStatusEntry[]>;
170
+ }
171
+ /**
172
+ * The DI token for the {@link (AIProviderRegistry:interface)}. When no host
173
+ * registers a concrete registry, the container resolves the built-in empty
174
+ * registry (a single no-op provider) so consumers degrade to inert rather
175
+ * than throwing.
176
+ *
177
+ * Prefer the {@link registerAIProviders} helper over registering this token
178
+ * directly.
179
+ *
180
+ * @beta
181
+ */
182
+ export declare const AIProviderRegistry: import("@microsoft/fast-foundation").InterfaceSymbol<AIProviderRegistry>;
92
183
  /**
93
- * Gets AIProvider from the DI container.
94
- * When the AI feature flag is disabled (?feature.ai), returns DefaultAIProvider (no-op).
184
+ * Options for {@link registerAIProviders}.
185
+ *
186
+ * @beta
187
+ */
188
+ export interface RegisterAIProvidersOptions {
189
+ /**
190
+ * Name of the provider to use as the default — must be a key in the
191
+ * `providers` map. Required when more than one provider is registered;
192
+ * inferred when exactly one is registered.
193
+ */
194
+ default?: string;
195
+ }
196
+ /**
197
+ * Registers one or more named AI providers as an {@link (AIProviderRegistry:interface)}
198
+ * on the given DI container.
95
199
  *
96
200
  * @remarks
97
- * A utility method for host applications that are not using decorators or the DI container.
201
+ * - With a single provider, the default is inferred `options.default` may be omitted.
202
+ * - With multiple providers, `options.default` is required to avoid implicit ordering.
203
+ * - Throws when `providers` is empty, when the named default isn't present, or
204
+ * when multiple providers are passed without an explicit default.
98
205
  *
99
206
  * @example
100
207
  * ```ts
101
- * import { getAIProvider } from '@genesislcap/foundation-ai';
102
- * ...
103
- * private aiProvider = getAIProvider();
104
- * ...
105
- * const result = await this.aiProvider.interpretCriteria?.(input, context);
208
+ * // Single provider default inferred
209
+ * registerAIProviders(container, { openai: createAIProvider(openAiConfig) });
210
+ *
211
+ * // Multiple providers — explicit default
212
+ * registerAIProviders(
213
+ * container,
214
+ * { fast: chromeProvider, deep: anthropicProvider },
215
+ * { default: 'deep' },
216
+ * );
106
217
  * ```
107
218
  *
108
219
  * @beta
109
220
  */
110
- export declare function getAIProvider(): AIProvider;
221
+ export declare function registerAIProviders(container: Container, providers: Record<string, AIProvider>, options?: RegisterAIProvidersOptions): void;
111
222
  //# sourceMappingURL=ai-provider.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../../src/ai-provider.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAC;AAU/D,OAAO,EAGL,KAAK,QAAQ,EACb,KAAK,QAAQ,EAIb,KAAK,4BAA4B,EAIlC,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,WAAW,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAI3F;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU;IACzB,iBAAiB,CAAC,CAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,wBAAwB,GAChC,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAAC,CAAC;IAEhD;;OAEG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAEvC;;;OAGG;IACH,eAAe,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAElC;;;;;;OAMG;IACH,MAAM,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAExE;;;OAGG;IACH,IAAI,CAAC,CACH,OAAO,EAAE,WAAW,EAAE,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,WAAW,CAAC,CAAC;IAExB;;;OAGG;IACH,UAAU,CAAC,CACT,OAAO,EAAE,WAAW,EAAE,EACtB,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,aAAa,CAAC,eAAe,CAAC,CAAC;CACnC;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,UAAU,CA8CrE;AAED;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IAC7C;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,+CAA+C;IAC/C,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CACnC,OAAO,GAAE,sBAA2B,GACnC,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CA0C1B;AAED;;;;;;;;;;GAUG;AACH,eAAO,MAAM,UAAU,kEAAwE,CAAC;AAEhG;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,aAAa,IAAI,UAAU,CAM1C"}
1
+ {"version":3,"file":"ai-provider.d.ts","sourceRoot":"","sources":["../../src/ai-provider.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
- export { AIProvider, createAIProvider, getAIProvider, resolveAIConfig } from './ai-provider';
1
+ export { AIProviderRegistry, createAIProvider, registerAIProviders, resolveAIConfig, } from './ai-provider';
2
+ export type { AIProvider, AIProviderRegistryStatusEntry, RegisterAIProvidersOptions, } from './ai-provider';
2
3
  export { AnthropicProvider } from './providers/anthropic-provider';
3
4
  export { GeminiProvider } from './providers/gemini-provider';
4
5
  export { AnthropicTransport } from './transports/anthropic-transport';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACpF,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACvE,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kBAAkB,EAClB,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,GAChB,MAAM,eAAe,CAAC;AACvB,YAAY,EACV,UAAU,EACV,6BAA6B,EAC7B,0BAA0B,GAC3B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,cAAc,EAAE,MAAM,6BAA6B,CAAC;AAC7D,OAAO,EAAE,kBAAkB,EAAE,MAAM,kCAAkC,CAAC;AACtE,OAAO,EAAE,eAAe,EAAE,0BAA0B,EAAE,MAAM,+BAA+B,CAAC;AAC5F,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC5E,OAAO,EAAE,6BAA6B,EAAE,0BAA0B,EAAE,MAAM,SAAS,CAAC;AACpF,YAAY,EACV,QAAQ,EACR,QAAQ,EACR,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,eAAe,EACf,eAAe,EACf,qBAAqB,EACrB,oBAAoB,EACpB,cAAc,EACd,UAAU,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,WAAW,EACX,eAAe,EACf,kBAAkB,EAClB,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,YAAY,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,YAAY,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AACvE,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAC5D,YAAY,EAAE,wBAAwB,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EACV,oBAAoB,EACpB,mBAAmB,EACnB,4BAA4B,GAC7B,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,4BAA4B,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -9,7 +9,7 @@ import type { AIStatus, ChromeAIConfig, CriteriaInterpretationResult } from '../
9
9
  * Requires Chrome 138+
10
10
  * Configure in app bootstrap:
11
11
  * ```ts
12
- * Registration.instance(AIProvider, new ChromeProvider({ providerType: 'chrome' }))
12
+ * registerAIProviders(container, { chrome: new ChromeProvider({ providerType: 'chrome' }) });
13
13
  * ```
14
14
  *
15
15
  * @beta
@@ -1,5 +1,5 @@
1
1
  import { __awaiter } from "tslib";
2
- import { DI } from '@microsoft/fast-foundation';
2
+ import { DI, Registration } from '@microsoft/fast-foundation';
3
3
  import { AnthropicProvider } from './providers/anthropic-provider';
4
4
  import { ChromeProvider } from './providers/chrome-provider';
5
5
  import { DefaultAIProvider } from './providers/default-provider';
@@ -120,38 +120,155 @@ export function resolveAIConfig() {
120
120
  });
121
121
  }
122
122
  /**
123
- * The DI token for the AIProvider interface.
123
+ * Built-in fallback registry. Resolved by the DI container when no host has
124
+ * registered an {@link (AIProviderRegistry:interface)}. Holds a single
125
+ * `DefaultAIProvider` (no-op) under the name `'default'`, preserving the
126
+ * "no host registration → assistant inert" behavior.
124
127
  *
125
- * @remarks
126
- * Register a provider implementation in app bootstrap (e.g. main.ts):
127
- * ```ts
128
- * Registration.singleton(AIProvider, OpenAIProvider)
129
- * ```
128
+ * @internal
129
+ */
130
+ export class EmptyAIProviderRegistry {
131
+ constructor() {
132
+ this.noopProvider = new DefaultAIProvider();
133
+ }
134
+ get(name) {
135
+ return name === EmptyAIProviderRegistry.DEFAULT_NAME ? this.noopProvider : undefined;
136
+ }
137
+ default() {
138
+ return this.noopProvider;
139
+ }
140
+ defaultName() {
141
+ return EmptyAIProviderRegistry.DEFAULT_NAME;
142
+ }
143
+ names() {
144
+ return [EmptyAIProviderRegistry.DEFAULT_NAME];
145
+ }
146
+ getStatus(name) {
147
+ return __awaiter(this, void 0, void 0, function* () {
148
+ var _a, _b, _c;
149
+ if (name !== undefined && name !== EmptyAIProviderRegistry.DEFAULT_NAME)
150
+ return null;
151
+ return (_c = (yield ((_b = (_a = this.noopProvider).getStatus) === null || _b === void 0 ? void 0 : _b.call(_a)))) !== null && _c !== void 0 ? _c : null;
152
+ });
153
+ }
154
+ listStatuses() {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ var _a, _b, _c;
157
+ const status = (_c = (yield ((_b = (_a = this.noopProvider).getStatus) === null || _b === void 0 ? void 0 : _b.call(_a)))) !== null && _c !== void 0 ? _c : null;
158
+ return [{ name: EmptyAIProviderRegistry.DEFAULT_NAME, isDefault: true, status }];
159
+ });
160
+ }
161
+ }
162
+ EmptyAIProviderRegistry.DEFAULT_NAME = 'default';
163
+ /**
164
+ * Map-backed registry built by {@link registerAIProviders}. Preserves the
165
+ * insertion order of `providers` for {@link (AIProviderRegistry:interface).names}
166
+ * and {@link (AIProviderRegistry:interface).listStatuses}.
130
167
  *
131
168
  * @internal
132
169
  */
133
- export const AIProvider = DI.createInterface((x) => x.singleton(DefaultAIProvider));
170
+ export class MapBackedAIProviderRegistry {
171
+ constructor(providers, defaultName) {
172
+ if (providers.size === 0) {
173
+ throw new Error('MapBackedAIProviderRegistry: at least one provider is required.');
174
+ }
175
+ if (!providers.has(defaultName)) {
176
+ throw new Error(`MapBackedAIProviderRegistry: default name "${defaultName}" not present in providers.`);
177
+ }
178
+ this.providers = providers;
179
+ this._defaultName = defaultName;
180
+ }
181
+ get(name) {
182
+ return this.providers.get(name);
183
+ }
184
+ default() {
185
+ // Constructor guarantees this lookup succeeds.
186
+ return this.providers.get(this._defaultName);
187
+ }
188
+ defaultName() {
189
+ return this._defaultName;
190
+ }
191
+ names() {
192
+ return [...this.providers.keys()];
193
+ }
194
+ getStatus(name) {
195
+ return __awaiter(this, void 0, void 0, function* () {
196
+ var _a, _b;
197
+ const provider = name === undefined ? this.default() : this.providers.get(name);
198
+ if (!provider)
199
+ return null;
200
+ return (_b = (yield ((_a = provider.getStatus) === null || _a === void 0 ? void 0 : _a.call(provider)))) !== null && _b !== void 0 ? _b : null;
201
+ });
202
+ }
203
+ listStatuses() {
204
+ return __awaiter(this, void 0, void 0, function* () {
205
+ const entries = [...this.providers.entries()];
206
+ return Promise.all(entries.map((_a) => __awaiter(this, [_a], void 0, function* ([name, provider]) {
207
+ var _b, _c;
208
+ return ({
209
+ name,
210
+ isDefault: name === this._defaultName,
211
+ status: (_c = (yield ((_b = provider.getStatus) === null || _b === void 0 ? void 0 : _b.call(provider)))) !== null && _c !== void 0 ? _c : null,
212
+ });
213
+ })));
214
+ });
215
+ }
216
+ }
217
+ /**
218
+ * The DI token for the {@link (AIProviderRegistry:interface)}. When no host
219
+ * registers a concrete registry, the container resolves the built-in empty
220
+ * registry (a single no-op provider) so consumers degrade to inert rather
221
+ * than throwing.
222
+ *
223
+ * Prefer the {@link registerAIProviders} helper over registering this token
224
+ * directly.
225
+ *
226
+ * @beta
227
+ */
228
+ export const AIProviderRegistry = DI.createInterface((x) => x.singleton(EmptyAIProviderRegistry));
134
229
  /**
135
- * Gets AIProvider from the DI container.
136
- * When the AI feature flag is disabled (?feature.ai), returns DefaultAIProvider (no-op).
230
+ * Registers one or more named AI providers as an {@link (AIProviderRegistry:interface)}
231
+ * on the given DI container.
137
232
  *
138
233
  * @remarks
139
- * A utility method for host applications that are not using decorators or the DI container.
234
+ * - With a single provider, the default is inferred `options.default` may be omitted.
235
+ * - With multiple providers, `options.default` is required to avoid implicit ordering.
236
+ * - Throws when `providers` is empty, when the named default isn't present, or
237
+ * when multiple providers are passed without an explicit default.
140
238
  *
141
239
  * @example
142
240
  * ```ts
143
- * import { getAIProvider } from '@genesislcap/foundation-ai';
144
- * ...
145
- * private aiProvider = getAIProvider();
146
- * ...
147
- * const result = await this.aiProvider.interpretCriteria?.(input, context);
241
+ * // Single provider default inferred
242
+ * registerAIProviders(container, { openai: createAIProvider(openAiConfig) });
243
+ *
244
+ * // Multiple providers — explicit default
245
+ * registerAIProviders(
246
+ * container,
247
+ * { fast: chromeProvider, deep: anthropicProvider },
248
+ * { default: 'deep' },
249
+ * );
148
250
  * ```
149
251
  *
150
252
  * @beta
151
253
  */
152
- export function getAIProvider() {
153
- if (!isAIFeatureEnabled()) {
154
- return new DefaultAIProvider();
254
+ export function registerAIProviders(container, providers, options = {}) {
255
+ const entries = Object.entries(providers);
256
+ if (entries.length === 0) {
257
+ throw new Error('registerAIProviders: at least one provider is required.');
258
+ }
259
+ let defaultName;
260
+ if (options.default !== undefined) {
261
+ if (!Object.prototype.hasOwnProperty.call(providers, options.default)) {
262
+ throw new Error(`registerAIProviders: default "${options.default}" is not one of the registered providers (${entries.map(([k]) => k).join(', ')}).`);
263
+ }
264
+ defaultName = options.default;
265
+ }
266
+ else if (entries.length === 1) {
267
+ defaultName = entries[0][0];
268
+ }
269
+ else {
270
+ throw new Error(`registerAIProviders: multiple providers registered (${entries.map(([k]) => k).join(', ')}) — must specify { default } to disambiguate.`);
155
271
  }
156
- return DI.getOrCreateDOMContainer().get(AIProvider);
272
+ const registry = new MapBackedAIProviderRegistry(new Map(entries), defaultName);
273
+ container.register(Registration.instance(AIProviderRegistry, registry));
157
274
  }
package/dist/esm/index.js CHANGED
@@ -1,4 +1,4 @@
1
- export { AIProvider, createAIProvider, getAIProvider, resolveAIConfig } from './ai-provider';
1
+ export { AIProviderRegistry, createAIProvider, registerAIProviders, resolveAIConfig, } from './ai-provider';
2
2
  export { AnthropicProvider } from './providers/anthropic-provider';
3
3
  export { GeminiProvider } from './providers/gemini-provider';
4
4
  export { AnthropicTransport } from './transports/anthropic-transport';
@@ -11,7 +11,7 @@ const CHROME_MODEL_NAME = 'Gemini Nano';
11
11
  * Requires Chrome 138+
12
12
  * Configure in app bootstrap:
13
13
  * ```ts
14
- * Registration.instance(AIProvider, new ChromeProvider({ providerType: 'chrome' }))
14
+ * registerAIProviders(container, { chrome: new ChromeProvider({ providerType: 'chrome' }) });
15
15
  * ```
16
16
  *
17
17
  * @beta
@@ -709,6 +709,405 @@
709
709
  ],
710
710
  "extendsTokenRanges": []
711
711
  },
712
+ {
713
+ "kind": "Interface",
714
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry:interface",
715
+ "docComment": "/**\n * Registry of named AI providers. Replaces the single-provider DI token — hosts register one or more named providers and consumers can either ask for the default or resolve a specific provider by name.\n *\n * If no host registration happens, the DI container resolves a built-in empty registry — every lookup returns a no-op provider.\n *\n * @remarks\n *\n * Register from app bootstrap with the {@link registerAIProviders} helper:\n * ```ts\n * registerAIProviders(container, { openai: provider });\n * // or, for multi-provider:\n * registerAIProviders(container, { openai, anthropic }, { default: 'openai' });\n * ```\n *\n * @beta\n */\n",
716
+ "excerptTokens": [
717
+ {
718
+ "kind": "Content",
719
+ "text": "export interface AIProviderRegistry "
720
+ }
721
+ ],
722
+ "fileUrlPath": "src/ai-provider.ts",
723
+ "releaseTag": "Beta",
724
+ "name": "AIProviderRegistry",
725
+ "preserveMemberOrder": false,
726
+ "members": [
727
+ {
728
+ "kind": "MethodSignature",
729
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#default:member(1)",
730
+ "docComment": "/**\n * The default provider — used when an agent doesn't specify one.\n */\n",
731
+ "excerptTokens": [
732
+ {
733
+ "kind": "Content",
734
+ "text": "default(): "
735
+ },
736
+ {
737
+ "kind": "Reference",
738
+ "text": "AIProvider",
739
+ "canonicalReference": "@genesislcap/foundation-ai!AIProvider:interface"
740
+ },
741
+ {
742
+ "kind": "Content",
743
+ "text": ";"
744
+ }
745
+ ],
746
+ "isOptional": false,
747
+ "returnTypeTokenRange": {
748
+ "startIndex": 1,
749
+ "endIndex": 2
750
+ },
751
+ "releaseTag": "Beta",
752
+ "overloadIndex": 1,
753
+ "parameters": [],
754
+ "name": "default"
755
+ },
756
+ {
757
+ "kind": "MethodSignature",
758
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#defaultName:member(1)",
759
+ "docComment": "/**\n * Name of the default provider. Useful for status display.\n */\n",
760
+ "excerptTokens": [
761
+ {
762
+ "kind": "Content",
763
+ "text": "defaultName(): "
764
+ },
765
+ {
766
+ "kind": "Content",
767
+ "text": "string"
768
+ },
769
+ {
770
+ "kind": "Content",
771
+ "text": ";"
772
+ }
773
+ ],
774
+ "isOptional": false,
775
+ "returnTypeTokenRange": {
776
+ "startIndex": 1,
777
+ "endIndex": 2
778
+ },
779
+ "releaseTag": "Beta",
780
+ "overloadIndex": 1,
781
+ "parameters": [],
782
+ "name": "defaultName"
783
+ },
784
+ {
785
+ "kind": "MethodSignature",
786
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#get:member(1)",
787
+ "docComment": "/**\n * Look up a registered provider by name. Returns `undefined` if no such name is registered.\n */\n",
788
+ "excerptTokens": [
789
+ {
790
+ "kind": "Content",
791
+ "text": "get(name: "
792
+ },
793
+ {
794
+ "kind": "Content",
795
+ "text": "string"
796
+ },
797
+ {
798
+ "kind": "Content",
799
+ "text": "): "
800
+ },
801
+ {
802
+ "kind": "Reference",
803
+ "text": "AIProvider",
804
+ "canonicalReference": "@genesislcap/foundation-ai!AIProvider:interface"
805
+ },
806
+ {
807
+ "kind": "Content",
808
+ "text": " | undefined"
809
+ },
810
+ {
811
+ "kind": "Content",
812
+ "text": ";"
813
+ }
814
+ ],
815
+ "isOptional": false,
816
+ "returnTypeTokenRange": {
817
+ "startIndex": 3,
818
+ "endIndex": 5
819
+ },
820
+ "releaseTag": "Beta",
821
+ "overloadIndex": 1,
822
+ "parameters": [
823
+ {
824
+ "parameterName": "name",
825
+ "parameterTypeTokenRange": {
826
+ "startIndex": 1,
827
+ "endIndex": 2
828
+ },
829
+ "isOptional": false
830
+ }
831
+ ],
832
+ "name": "get"
833
+ },
834
+ {
835
+ "kind": "MethodSignature",
836
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#getStatus:member(1)",
837
+ "docComment": "/**\n * Returns the status payload for a single named provider, or for the default when `name` is omitted. Returns `null` when the provider doesn't implement {@link AIProvider.getStatus} or returns null.\n */\n",
838
+ "excerptTokens": [
839
+ {
840
+ "kind": "Content",
841
+ "text": "getStatus(name?: "
842
+ },
843
+ {
844
+ "kind": "Content",
845
+ "text": "string"
846
+ },
847
+ {
848
+ "kind": "Content",
849
+ "text": "): "
850
+ },
851
+ {
852
+ "kind": "Reference",
853
+ "text": "Promise",
854
+ "canonicalReference": "!Promise:interface"
855
+ },
856
+ {
857
+ "kind": "Content",
858
+ "text": "<"
859
+ },
860
+ {
861
+ "kind": "Reference",
862
+ "text": "AIStatus",
863
+ "canonicalReference": "@genesislcap/foundation-ai!AIStatus:interface"
864
+ },
865
+ {
866
+ "kind": "Content",
867
+ "text": " | null>"
868
+ },
869
+ {
870
+ "kind": "Content",
871
+ "text": ";"
872
+ }
873
+ ],
874
+ "isOptional": false,
875
+ "returnTypeTokenRange": {
876
+ "startIndex": 3,
877
+ "endIndex": 7
878
+ },
879
+ "releaseTag": "Beta",
880
+ "overloadIndex": 1,
881
+ "parameters": [
882
+ {
883
+ "parameterName": "name",
884
+ "parameterTypeTokenRange": {
885
+ "startIndex": 1,
886
+ "endIndex": 2
887
+ },
888
+ "isOptional": true
889
+ }
890
+ ],
891
+ "name": "getStatus"
892
+ },
893
+ {
894
+ "kind": "MethodSignature",
895
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#listStatuses:member(1)",
896
+ "docComment": "/**\n * Returns statuses for all registered providers in registration order. Each entry carries the registered name and an `isDefault` flag.\n */\n",
897
+ "excerptTokens": [
898
+ {
899
+ "kind": "Content",
900
+ "text": "listStatuses(): "
901
+ },
902
+ {
903
+ "kind": "Reference",
904
+ "text": "Promise",
905
+ "canonicalReference": "!Promise:interface"
906
+ },
907
+ {
908
+ "kind": "Content",
909
+ "text": "<"
910
+ },
911
+ {
912
+ "kind": "Reference",
913
+ "text": "AIProviderRegistryStatusEntry",
914
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistryStatusEntry:interface"
915
+ },
916
+ {
917
+ "kind": "Content",
918
+ "text": "[]>"
919
+ },
920
+ {
921
+ "kind": "Content",
922
+ "text": ";"
923
+ }
924
+ ],
925
+ "isOptional": false,
926
+ "returnTypeTokenRange": {
927
+ "startIndex": 1,
928
+ "endIndex": 5
929
+ },
930
+ "releaseTag": "Beta",
931
+ "overloadIndex": 1,
932
+ "parameters": [],
933
+ "name": "listStatuses"
934
+ },
935
+ {
936
+ "kind": "MethodSignature",
937
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry#names:member(1)",
938
+ "docComment": "/**\n * All registered provider names, in registration order.\n */\n",
939
+ "excerptTokens": [
940
+ {
941
+ "kind": "Content",
942
+ "text": "names(): "
943
+ },
944
+ {
945
+ "kind": "Content",
946
+ "text": "string[]"
947
+ },
948
+ {
949
+ "kind": "Content",
950
+ "text": ";"
951
+ }
952
+ ],
953
+ "isOptional": false,
954
+ "returnTypeTokenRange": {
955
+ "startIndex": 1,
956
+ "endIndex": 2
957
+ },
958
+ "releaseTag": "Beta",
959
+ "overloadIndex": 1,
960
+ "parameters": [],
961
+ "name": "names"
962
+ }
963
+ ],
964
+ "extendsTokenRanges": []
965
+ },
966
+ {
967
+ "kind": "Variable",
968
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry:var",
969
+ "docComment": "/**\n * The DI token for the {@link (AIProviderRegistry:interface)}. When no host registers a concrete registry, the container resolves the built-in empty registry (a single no-op provider) so consumers degrade to inert rather than throwing.\n *\n * Prefer the {@link registerAIProviders} helper over registering this token directly.\n *\n * @beta\n */\n",
970
+ "excerptTokens": [
971
+ {
972
+ "kind": "Content",
973
+ "text": "AIProviderRegistry: "
974
+ },
975
+ {
976
+ "kind": "Content",
977
+ "text": "import(\"@microsoft/fast-foundation\")."
978
+ },
979
+ {
980
+ "kind": "Reference",
981
+ "text": "InterfaceSymbol",
982
+ "canonicalReference": "@microsoft/fast-foundation!InterfaceSymbol:type"
983
+ },
984
+ {
985
+ "kind": "Content",
986
+ "text": "<"
987
+ },
988
+ {
989
+ "kind": "Reference",
990
+ "text": "AIProviderRegistry",
991
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistry:interface"
992
+ },
993
+ {
994
+ "kind": "Content",
995
+ "text": ">"
996
+ }
997
+ ],
998
+ "fileUrlPath": "src/ai-provider.ts",
999
+ "isReadonly": true,
1000
+ "releaseTag": "Beta",
1001
+ "name": "AIProviderRegistry",
1002
+ "variableTypeTokenRange": {
1003
+ "startIndex": 1,
1004
+ "endIndex": 6
1005
+ }
1006
+ },
1007
+ {
1008
+ "kind": "Interface",
1009
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistryStatusEntry:interface",
1010
+ "docComment": "/**\n * One entry in {@link (AIProviderRegistry:interface).listStatuses}. Pairs the registered name with a status payload (or `null` when the provider doesn't implement {@link AIProvider.getStatus}).\n *\n * @beta\n */\n",
1011
+ "excerptTokens": [
1012
+ {
1013
+ "kind": "Content",
1014
+ "text": "export interface AIProviderRegistryStatusEntry "
1015
+ }
1016
+ ],
1017
+ "fileUrlPath": "src/ai-provider.ts",
1018
+ "releaseTag": "Beta",
1019
+ "name": "AIProviderRegistryStatusEntry",
1020
+ "preserveMemberOrder": false,
1021
+ "members": [
1022
+ {
1023
+ "kind": "PropertySignature",
1024
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistryStatusEntry#isDefault:member",
1025
+ "docComment": "/**\n * True when this is the registry's default provider.\n */\n",
1026
+ "excerptTokens": [
1027
+ {
1028
+ "kind": "Content",
1029
+ "text": "isDefault: "
1030
+ },
1031
+ {
1032
+ "kind": "Content",
1033
+ "text": "boolean"
1034
+ },
1035
+ {
1036
+ "kind": "Content",
1037
+ "text": ";"
1038
+ }
1039
+ ],
1040
+ "isReadonly": false,
1041
+ "isOptional": false,
1042
+ "releaseTag": "Beta",
1043
+ "name": "isDefault",
1044
+ "propertyTypeTokenRange": {
1045
+ "startIndex": 1,
1046
+ "endIndex": 2
1047
+ }
1048
+ },
1049
+ {
1050
+ "kind": "PropertySignature",
1051
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistryStatusEntry#name:member",
1052
+ "docComment": "/**\n * The name the provider was registered under.\n */\n",
1053
+ "excerptTokens": [
1054
+ {
1055
+ "kind": "Content",
1056
+ "text": "name: "
1057
+ },
1058
+ {
1059
+ "kind": "Content",
1060
+ "text": "string"
1061
+ },
1062
+ {
1063
+ "kind": "Content",
1064
+ "text": ";"
1065
+ }
1066
+ ],
1067
+ "isReadonly": false,
1068
+ "isOptional": false,
1069
+ "releaseTag": "Beta",
1070
+ "name": "name",
1071
+ "propertyTypeTokenRange": {
1072
+ "startIndex": 1,
1073
+ "endIndex": 2
1074
+ }
1075
+ },
1076
+ {
1077
+ "kind": "PropertySignature",
1078
+ "canonicalReference": "@genesislcap/foundation-ai!AIProviderRegistryStatusEntry#status:member",
1079
+ "docComment": "/**\n * The provider's `getStatus()` result, or `null` if unavailable.\n */\n",
1080
+ "excerptTokens": [
1081
+ {
1082
+ "kind": "Content",
1083
+ "text": "status: "
1084
+ },
1085
+ {
1086
+ "kind": "Reference",
1087
+ "text": "AIStatus",
1088
+ "canonicalReference": "@genesislcap/foundation-ai!AIStatus:interface"
1089
+ },
1090
+ {
1091
+ "kind": "Content",
1092
+ "text": " | null"
1093
+ },
1094
+ {
1095
+ "kind": "Content",
1096
+ "text": ";"
1097
+ }
1098
+ ],
1099
+ "isReadonly": false,
1100
+ "isOptional": false,
1101
+ "releaseTag": "Beta",
1102
+ "name": "status",
1103
+ "propertyTypeTokenRange": {
1104
+ "startIndex": 1,
1105
+ "endIndex": 3
1106
+ }
1107
+ }
1108
+ ],
1109
+ "extendsTokenRanges": []
1110
+ },
712
1111
  {
713
1112
  "kind": "TypeAlias",
714
1113
  "canonicalReference": "@genesislcap/foundation-ai!AIProviderType:type",
@@ -5791,35 +6190,6 @@
5791
6190
  }
5792
6191
  ]
5793
6192
  },
5794
- {
5795
- "kind": "Function",
5796
- "canonicalReference": "@genesislcap/foundation-ai!getAIProvider:function(1)",
5797
- "docComment": "/**\n * Gets AIProvider from the DI container. When the AI feature flag is disabled (?feature.ai), returns DefaultAIProvider (no-op).\n *\n * @remarks\n *\n * A utility method for host applications that are not using decorators or the DI container.\n *\n * @example\n * ```ts\n * import { getAIProvider } from '@genesislcap/foundation-ai';\n * ...\n * private aiProvider = getAIProvider();\n * ...\n * const result = await this.aiProvider.interpretCriteria?.(input, context);\n * ```\n *\n * @beta\n */\n",
5798
- "excerptTokens": [
5799
- {
5800
- "kind": "Content",
5801
- "text": "export declare function getAIProvider(): "
5802
- },
5803
- {
5804
- "kind": "Reference",
5805
- "text": "AIProvider",
5806
- "canonicalReference": "@genesislcap/foundation-ai!AIProvider:interface"
5807
- },
5808
- {
5809
- "kind": "Content",
5810
- "text": ";"
5811
- }
5812
- ],
5813
- "fileUrlPath": "src/ai-provider.ts",
5814
- "returnTypeTokenRange": {
5815
- "startIndex": 1,
5816
- "endIndex": 2
5817
- },
5818
- "releaseTag": "Beta",
5819
- "overloadIndex": 1,
5820
- "parameters": [],
5821
- "name": "getAIProvider"
5822
- },
5823
6193
  {
5824
6194
  "kind": "Interface",
5825
6195
  "canonicalReference": "@genesislcap/foundation-ai!InteractionRequestOptions:interface",
@@ -6115,6 +6485,144 @@
6115
6485
  },
6116
6486
  "implementsTokenRanges": []
6117
6487
  },
6488
+ {
6489
+ "kind": "Function",
6490
+ "canonicalReference": "@genesislcap/foundation-ai!registerAIProviders:function(1)",
6491
+ "docComment": "/**\n * Registers one or more named AI providers as an {@link (AIProviderRegistry:interface)} on the given DI container.\n *\n * @remarks\n *\n * - With a single provider, the default is inferred — `options.default` may be omitted. - With multiple providers, `options.default` is required to avoid implicit ordering. - Throws when `providers` is empty, when the named default isn't present, or when multiple providers are passed without an explicit default.\n *\n * @example\n * ```ts\n * // Single provider — default inferred\n * registerAIProviders(container, { openai: createAIProvider(openAiConfig) });\n *\n * // Multiple providers — explicit default\n * registerAIProviders(\n * container,\n * { fast: chromeProvider, deep: anthropicProvider },\n * { default: 'deep' },\n * );\n * ```\n *\n * @beta\n */\n",
6492
+ "excerptTokens": [
6493
+ {
6494
+ "kind": "Content",
6495
+ "text": "export declare function registerAIProviders(container: "
6496
+ },
6497
+ {
6498
+ "kind": "Reference",
6499
+ "text": "Container",
6500
+ "canonicalReference": "@microsoft/fast-foundation!Container:interface"
6501
+ },
6502
+ {
6503
+ "kind": "Content",
6504
+ "text": ", providers: "
6505
+ },
6506
+ {
6507
+ "kind": "Reference",
6508
+ "text": "Record",
6509
+ "canonicalReference": "!Record:type"
6510
+ },
6511
+ {
6512
+ "kind": "Content",
6513
+ "text": "<string, "
6514
+ },
6515
+ {
6516
+ "kind": "Reference",
6517
+ "text": "AIProvider",
6518
+ "canonicalReference": "@genesislcap/foundation-ai!AIProvider:interface"
6519
+ },
6520
+ {
6521
+ "kind": "Content",
6522
+ "text": ">"
6523
+ },
6524
+ {
6525
+ "kind": "Content",
6526
+ "text": ", options?: "
6527
+ },
6528
+ {
6529
+ "kind": "Reference",
6530
+ "text": "RegisterAIProvidersOptions",
6531
+ "canonicalReference": "@genesislcap/foundation-ai!RegisterAIProvidersOptions:interface"
6532
+ },
6533
+ {
6534
+ "kind": "Content",
6535
+ "text": "): "
6536
+ },
6537
+ {
6538
+ "kind": "Content",
6539
+ "text": "void"
6540
+ },
6541
+ {
6542
+ "kind": "Content",
6543
+ "text": ";"
6544
+ }
6545
+ ],
6546
+ "fileUrlPath": "src/ai-provider.ts",
6547
+ "returnTypeTokenRange": {
6548
+ "startIndex": 10,
6549
+ "endIndex": 11
6550
+ },
6551
+ "releaseTag": "Beta",
6552
+ "overloadIndex": 1,
6553
+ "parameters": [
6554
+ {
6555
+ "parameterName": "container",
6556
+ "parameterTypeTokenRange": {
6557
+ "startIndex": 1,
6558
+ "endIndex": 2
6559
+ },
6560
+ "isOptional": false
6561
+ },
6562
+ {
6563
+ "parameterName": "providers",
6564
+ "parameterTypeTokenRange": {
6565
+ "startIndex": 3,
6566
+ "endIndex": 7
6567
+ },
6568
+ "isOptional": false
6569
+ },
6570
+ {
6571
+ "parameterName": "options",
6572
+ "parameterTypeTokenRange": {
6573
+ "startIndex": 8,
6574
+ "endIndex": 9
6575
+ },
6576
+ "isOptional": true
6577
+ }
6578
+ ],
6579
+ "name": "registerAIProviders"
6580
+ },
6581
+ {
6582
+ "kind": "Interface",
6583
+ "canonicalReference": "@genesislcap/foundation-ai!RegisterAIProvidersOptions:interface",
6584
+ "docComment": "/**\n * Options for {@link registerAIProviders}.\n *\n * @beta\n */\n",
6585
+ "excerptTokens": [
6586
+ {
6587
+ "kind": "Content",
6588
+ "text": "export interface RegisterAIProvidersOptions "
6589
+ }
6590
+ ],
6591
+ "fileUrlPath": "src/ai-provider.ts",
6592
+ "releaseTag": "Beta",
6593
+ "name": "RegisterAIProvidersOptions",
6594
+ "preserveMemberOrder": false,
6595
+ "members": [
6596
+ {
6597
+ "kind": "PropertySignature",
6598
+ "canonicalReference": "@genesislcap/foundation-ai!RegisterAIProvidersOptions#default:member",
6599
+ "docComment": "/**\n * Name of the provider to use as the default — must be a key in the `providers` map. Required when more than one provider is registered; inferred when exactly one is registered.\n */\n",
6600
+ "excerptTokens": [
6601
+ {
6602
+ "kind": "Content",
6603
+ "text": "default?: "
6604
+ },
6605
+ {
6606
+ "kind": "Content",
6607
+ "text": "string"
6608
+ },
6609
+ {
6610
+ "kind": "Content",
6611
+ "text": ";"
6612
+ }
6613
+ ],
6614
+ "isReadonly": false,
6615
+ "isOptional": true,
6616
+ "releaseTag": "Beta",
6617
+ "name": "default",
6618
+ "propertyTypeTokenRange": {
6619
+ "startIndex": 1,
6620
+ "endIndex": 2
6621
+ }
6622
+ }
6623
+ ],
6624
+ "extendsTokenRanges": []
6625
+ },
6118
6626
  {
6119
6627
  "kind": "Function",
6120
6628
  "canonicalReference": "@genesislcap/foundation-ai!resolveAIConfig:function(1)",
@@ -1,3 +1,4 @@
1
+ import { Container } from '@microsoft/fast-foundation';
1
2
  import { InterfaceSymbol } from '@microsoft/fast-foundation';
2
3
 
3
4
  /**
@@ -69,19 +70,6 @@ export declare interface AIProvider {
69
70
  streamChat?(history: ChatMessage[], userMessage: string, options?: ChatRequestOptions): AsyncIterable<ChatStreamChunk>;
70
71
  }
71
72
 
72
- /**
73
- * The DI token for the AIProvider interface.
74
- *
75
- * @remarks
76
- * Register a provider implementation in app bootstrap (e.g. main.ts):
77
- * ```ts
78
- * Registration.singleton(AIProvider, OpenAIProvider)
79
- * ```
80
- *
81
- * @internal
82
- */
83
- export declare const AIProvider: InterfaceSymbol<AIProvider>;
84
-
85
73
  /**
86
74
  * Base provider-level configuration.
87
75
  *
@@ -98,6 +86,75 @@ declare interface AIProviderConfig {
98
86
  criteriaInstructions?: string;
99
87
  }
100
88
 
89
+ /**
90
+ * Registry of named AI providers. Replaces the single-provider DI token —
91
+ * hosts register one or more named providers and consumers can either ask
92
+ * for the default or resolve a specific provider by name.
93
+ *
94
+ * If no host registration happens, the DI container resolves a built-in
95
+ * empty registry — every lookup returns a no-op provider.
96
+ *
97
+ * @remarks
98
+ * Register from app bootstrap with the {@link registerAIProviders} helper:
99
+ * ```ts
100
+ * registerAIProviders(container, { openai: provider });
101
+ * // or, for multi-provider:
102
+ * registerAIProviders(container, { openai, anthropic }, { default: 'openai' });
103
+ * ```
104
+ *
105
+ * @beta
106
+ */
107
+ export declare interface AIProviderRegistry {
108
+ /** Look up a registered provider by name. Returns `undefined` if no such name is registered. */
109
+ get(name: string): AIProvider | undefined;
110
+ /** The default provider — used when an agent doesn't specify one. */
111
+ default(): AIProvider;
112
+ /** Name of the default provider. Useful for status display. */
113
+ defaultName(): string;
114
+ /** All registered provider names, in registration order. */
115
+ names(): string[];
116
+ /**
117
+ * Returns the status payload for a single named provider, or for the
118
+ * default when `name` is omitted. Returns `null` when the provider doesn't
119
+ * implement {@link AIProvider.getStatus} or returns null.
120
+ */
121
+ getStatus(name?: string): Promise<AIStatus | null>;
122
+ /**
123
+ * Returns statuses for all registered providers in registration order.
124
+ * Each entry carries the registered name and an `isDefault` flag.
125
+ */
126
+ listStatuses(): Promise<AIProviderRegistryStatusEntry[]>;
127
+ }
128
+
129
+ /**
130
+ * The DI token for the {@link (AIProviderRegistry:interface)}. When no host
131
+ * registers a concrete registry, the container resolves the built-in empty
132
+ * registry (a single no-op provider) so consumers degrade to inert rather
133
+ * than throwing.
134
+ *
135
+ * Prefer the {@link registerAIProviders} helper over registering this token
136
+ * directly.
137
+ *
138
+ * @beta
139
+ */
140
+ export declare const AIProviderRegistry: InterfaceSymbol<AIProviderRegistry>;
141
+
142
+ /**
143
+ * One entry in {@link (AIProviderRegistry:interface).listStatuses}. Pairs the
144
+ * registered name with a status payload (or `null` when the provider doesn't
145
+ * implement {@link AIProvider.getStatus}).
146
+ *
147
+ * @beta
148
+ */
149
+ export declare interface AIProviderRegistryStatusEntry {
150
+ /** The name the provider was registered under. */
151
+ name: string;
152
+ /** True when this is the registry's default provider. */
153
+ isDefault: boolean;
154
+ /** The provider's `getStatus()` result, or `null` if unavailable. */
155
+ status: AIStatus | null;
156
+ }
157
+
101
158
  /**
102
159
  * All AI provider identifiers (server, client, unconfigured).
103
160
  *
@@ -941,26 +998,6 @@ declare interface GeminiTransportConfig {
941
998
  serverEndpoint?: string;
942
999
  }
943
1000
 
944
- /**
945
- * Gets AIProvider from the DI container.
946
- * When the AI feature flag is disabled (?feature.ai), returns DefaultAIProvider (no-op).
947
- *
948
- * @remarks
949
- * A utility method for host applications that are not using decorators or the DI container.
950
- *
951
- * @example
952
- * ```ts
953
- * import { getAIProvider } from '@genesislcap/foundation-ai';
954
- * ...
955
- * private aiProvider = getAIProvider();
956
- * ...
957
- * const result = await this.aiProvider.interpretCriteria?.(input, context);
958
- * ```
959
- *
960
- * @beta
961
- */
962
- export declare function getAIProvider(): AIProvider;
963
-
964
1001
  /**
965
1002
  * Options passed to `requestInteraction` at call time.
966
1003
  *
@@ -1024,6 +1061,47 @@ export declare class MalformedFunctionCallError extends Error {
1024
1061
  constructor(finishMessage?: string);
1025
1062
  }
1026
1063
 
1064
+ /**
1065
+ * Registers one or more named AI providers as an {@link (AIProviderRegistry:interface)}
1066
+ * on the given DI container.
1067
+ *
1068
+ * @remarks
1069
+ * - With a single provider, the default is inferred — `options.default` may be omitted.
1070
+ * - With multiple providers, `options.default` is required to avoid implicit ordering.
1071
+ * - Throws when `providers` is empty, when the named default isn't present, or
1072
+ * when multiple providers are passed without an explicit default.
1073
+ *
1074
+ * @example
1075
+ * ```ts
1076
+ * // Single provider — default inferred
1077
+ * registerAIProviders(container, { openai: createAIProvider(openAiConfig) });
1078
+ *
1079
+ * // Multiple providers — explicit default
1080
+ * registerAIProviders(
1081
+ * container,
1082
+ * { fast: chromeProvider, deep: anthropicProvider },
1083
+ * { default: 'deep' },
1084
+ * );
1085
+ * ```
1086
+ *
1087
+ * @beta
1088
+ */
1089
+ export declare function registerAIProviders(container: Container, providers: Record<string, AIProvider>, options?: RegisterAIProvidersOptions): void;
1090
+
1091
+ /**
1092
+ * Options for {@link registerAIProviders}.
1093
+ *
1094
+ * @beta
1095
+ */
1096
+ export declare interface RegisterAIProvidersOptions {
1097
+ /**
1098
+ * Name of the provider to use as the default — must be a key in the
1099
+ * `providers` map. Required when more than one provider is registered;
1100
+ * inferred when exactly one is registered.
1101
+ */
1102
+ default?: string;
1103
+ }
1104
+
1027
1105
  /**
1028
1106
  * Resolves AI config, optionally preferring Chrome when available.
1029
1107
  * Use before registering AIProvider. Server URL is derived from API_HOST.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/foundation-ai",
3
3
  "description": "Genesis Foundation AI - Provider-agnostic AI configuration and shared utilities",
4
- "version": "14.444.1",
4
+ "version": "14.445.1",
5
5
  "sideEffects": false,
6
6
  "license": "SEE LICENSE IN license.txt",
7
7
  "main": "dist/esm/index.js",
@@ -51,17 +51,17 @@
51
51
  }
52
52
  },
53
53
  "devDependencies": {
54
- "@genesislcap/foundation-testing": "14.444.1",
55
- "@genesislcap/genx": "14.444.1",
56
- "@genesislcap/rollup-builder": "14.444.1",
57
- "@genesislcap/ts-builder": "14.444.1",
58
- "@genesislcap/uvu-playwright-builder": "14.444.1",
59
- "@genesislcap/vite-builder": "14.444.1",
60
- "@genesislcap/webpack-builder": "14.444.1"
54
+ "@genesislcap/foundation-testing": "14.445.1",
55
+ "@genesislcap/genx": "14.445.1",
56
+ "@genesislcap/rollup-builder": "14.445.1",
57
+ "@genesislcap/ts-builder": "14.445.1",
58
+ "@genesislcap/uvu-playwright-builder": "14.445.1",
59
+ "@genesislcap/vite-builder": "14.445.1",
60
+ "@genesislcap/webpack-builder": "14.445.1"
61
61
  },
62
62
  "dependencies": {
63
- "@genesislcap/foundation-logger": "14.444.1",
64
- "@genesislcap/foundation-utils": "14.444.1",
63
+ "@genesislcap/foundation-logger": "14.445.1",
64
+ "@genesislcap/foundation-utils": "14.445.1",
65
65
  "@microsoft/fast-foundation": "2.50.0"
66
66
  },
67
67
  "repository": {
@@ -72,5 +72,5 @@
72
72
  "publishConfig": {
73
73
  "access": "public"
74
74
  },
75
- "gitHead": "837befe80b4972686cb48fe7d86334c5d819ced6"
75
+ "gitHead": "893e8b2ffadacaedb39f1935c1979278191b6730"
76
76
  }