@genesislcap/ai-assistant 14.444.1 → 14.445.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/dist/ai-assistant.api.json +312 -41
- package/dist/ai-assistant.d.ts +105 -8
- package/dist/dts/components/ai-driver/ai-driver.d.ts +7 -0
- package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts +37 -3
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +5 -3
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/config/config.d.ts +31 -0
- package/dist/dts/config/config.d.ts.map +1 -1
- package/dist/dts/config/define-stateful-agent.d.ts +9 -0
- package/dist/dts/config/define-stateful-agent.d.ts.map +1 -1
- package/dist/dts/config/validate-providers.d.ts +25 -0
- package/dist/dts/config/validate-providers.d.ts.map +1 -0
- package/dist/dts/config/validate-providers.test.d.ts +2 -0
- package/dist/dts/config/validate-providers.test.d.ts.map +1 -0
- package/dist/dts/main/main.d.ts +17 -5
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/main/main.styles.d.ts.map +1 -1
- package/dist/dts/main/main.template.d.ts.map +1 -1
- package/dist/dts/state/ai-assistant-slice.d.ts +14 -1
- package/dist/dts/state/ai-assistant-slice.d.ts.map +1 -1
- package/dist/dts/state/session-store.d.ts +2 -0
- package/dist/dts/state/session-store.d.ts.map +1 -1
- package/dist/esm/components/chat-driver/chat-driver.js +84 -15
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +23 -4
- package/dist/esm/config/define-stateful-agent.js +12 -0
- package/dist/esm/config/validate-providers.js +47 -0
- package/dist/esm/config/validate-providers.test.js +100 -0
- package/dist/esm/main/main.js +57 -10
- package/dist/esm/main/main.styles.js +52 -0
- package/dist/esm/main/main.template.js +36 -1
- package/dist/esm/state/ai-assistant-slice.js +8 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/migration-GENC-1262.md +219 -0
- package/package.json +16 -16
- package/src/components/ai-driver/ai-driver.ts +8 -0
- package/src/components/chat-driver/chat-driver.ts +96 -14
- package/src/components/orchestrating-driver/orchestrating-driver.ts +29 -4
- package/src/config/config.ts +32 -0
- package/src/config/define-stateful-agent.ts +28 -0
- package/src/config/validate-providers.test.ts +148 -0
- package/src/config/validate-providers.ts +58 -0
- package/src/main/main.styles.ts +52 -0
- package/src/main/main.template.ts +50 -2
- package/src/main/main.ts +51 -7
- package/src/state/ai-assistant-slice.ts +24 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatInputDuringExecutionMode, ChatMessage } from '@genesislcap/foundation-ai';
|
|
1
|
+
import type { AIProviderRegistryStatusEntry, ChatInputDuringExecutionMode, ChatMessage } from '@genesislcap/foundation-ai';
|
|
2
2
|
import type { PayloadAction } from '@genesislcap/foundation-redux';
|
|
3
3
|
import type { AgentConfig } from '../config/config';
|
|
4
4
|
import type { AiAssistantAnimation, AiAssistantState, SuggestionsState } from '../main/main.types';
|
|
@@ -36,6 +36,17 @@ export interface AiAssistantSessionState {
|
|
|
36
36
|
sessionCostUsd: number;
|
|
37
37
|
/** Active model id (e.g. `claude-sonnet-4-6`), resolved on connect. */
|
|
38
38
|
activeModel: string | undefined;
|
|
39
|
+
/**
|
|
40
|
+
* Name of the AI provider used on the most recent turn — drives "current"
|
|
41
|
+
* marker in the settings panel. `undefined` until the first turn runs.
|
|
42
|
+
*/
|
|
43
|
+
activeProviderName: string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Snapshot of every registered provider's status, in registration order.
|
|
46
|
+
* Populated on connect (or on settings-open if not yet loaded) and reused
|
|
47
|
+
* for the lifetime of the session — provider registration is static.
|
|
48
|
+
*/
|
|
49
|
+
providerStatuses: AIProviderRegistryStatusEntry[];
|
|
39
50
|
activeAgent: Omit<AgentConfig, 'toolHandlers'> | undefined;
|
|
40
51
|
/**
|
|
41
52
|
* Name of the agent the user has pinned via the picker. `null` means the
|
|
@@ -87,6 +98,8 @@ export declare const aiAssistantSlice: import("@reduxjs/toolkit").Slice<AiAssist
|
|
|
87
98
|
setContextLimit(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<number | undefined>): void;
|
|
88
99
|
setSessionCostUsd(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<number>): void;
|
|
89
100
|
setActiveModel(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | undefined>): void;
|
|
101
|
+
setActiveProviderName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | undefined>): void;
|
|
102
|
+
setProviderStatuses(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<AIProviderRegistryStatusEntry[]>): void;
|
|
90
103
|
setActiveAgent(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<Omit<AgentConfig, "toolHandlers"> | undefined>): void;
|
|
91
104
|
setPinnedAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | null>): void;
|
|
92
105
|
setFlowOwnerAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: PayloadAction<string | null>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ai-assistant-slice.d.ts","sourceRoot":"","sources":["../../../src/state/ai-assistant-slice.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ai-assistant-slice.d.ts","sourceRoot":"","sources":["../../../src/state/ai-assistant-slice.ts"],"names":[],"mappings":"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"}
|
|
@@ -12,6 +12,8 @@ declare function makeStore(devTools: boolean | undefined): import("@genesislcap/
|
|
|
12
12
|
setContextLimit(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<number | undefined>): void;
|
|
13
13
|
setSessionCostUsd(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<number>): void;
|
|
14
14
|
setActiveModel(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | undefined>): void;
|
|
15
|
+
setActiveProviderName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | undefined>): void;
|
|
16
|
+
setProviderStatuses(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<import("@genesislcap/foundation-ai").AIProviderRegistryStatusEntry[]>): void;
|
|
15
17
|
setActiveAgent(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<Omit<import("..").AgentConfig, "toolHandlers"> | undefined>): void;
|
|
16
18
|
setPinnedAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | null>): void;
|
|
17
19
|
setFlowOwnerAgentName(state: import("immer").WritableDraft<AiAssistantSessionState>, action: import("@reduxjs/toolkit").PayloadAction<string | null>): void;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../../src/state/session-store.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAIvD,iBAAS,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS
|
|
1
|
+
{"version":3,"file":"session-store.d.ts","sourceRoot":"","sources":["../../../src/state/session-store.ts"],"names":[],"mappings":"AACA,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,sBAAsB,CAAC;AAE9B,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC;AAIvD,iBAAS,SAAS,CAAC,QAAQ,EAAE,OAAO,GAAG,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;wCAM/C;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,GAAG,kBAAkB,CAMnF;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEpD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C;AAED,YAAY,EAAE,kBAAkB,EAAE,uBAAuB,EAAE,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
2
|
import { MalformedFunctionCallError } from '@genesislcap/foundation-ai';
|
|
3
3
|
import { agenticActivityBus } from '../../channel/ai-activity-bus';
|
|
4
|
+
import { resolveChatProvider } from '../../config/validate-providers';
|
|
4
5
|
import { applyHistoryCap } from '../../utils/history-transform';
|
|
5
6
|
import { logger } from '../../utils/logger';
|
|
6
7
|
import { TOOL_FOLD_SYMBOL } from '../../utils/tool-fold';
|
|
@@ -26,9 +27,9 @@ const HANDOFF_TOOL_RESULT_PLACEHOLDER = 'Handoff to another specialist — routi
|
|
|
26
27
|
* @beta
|
|
27
28
|
*/
|
|
28
29
|
export class ChatDriver extends EventTarget {
|
|
29
|
-
constructor(
|
|
30
|
+
constructor(providerRegistry, toolHandlers = {}, toolDefinitions = [], systemPrompt, primerHistory, maxToolIterations = DEFAULT_MAX_TOOL_ITERATIONS, maxFoldOperations = DEFAULT_MAX_FOLD_OPERATIONS, maxTurnSnapshots = DEFAULT_MAX_TURN_SNAPSHOTS) {
|
|
30
31
|
super();
|
|
31
|
-
this.
|
|
32
|
+
this.providerRegistry = providerRegistry;
|
|
32
33
|
this.maxToolIterations = maxToolIterations;
|
|
33
34
|
this.history = [];
|
|
34
35
|
this.busy = false;
|
|
@@ -59,6 +60,12 @@ export class ChatDriver extends EventTarget {
|
|
|
59
60
|
this.turnSnapshots = [];
|
|
60
61
|
/** Monotonic counter that survives agent swaps — useful for cross-referencing with history. */
|
|
61
62
|
this.globalTurnIndex = 0;
|
|
63
|
+
/**
|
|
64
|
+
* Caches validated provider lookups per name within the current agent. Cleared
|
|
65
|
+
* by `applyAgent` so each new agent's static/function-resolved names are
|
|
66
|
+
* validated fresh.
|
|
67
|
+
*/
|
|
68
|
+
this.resolvedProviderCache = new Map();
|
|
62
69
|
if (typeof toolHandlers === 'function') {
|
|
63
70
|
this.toolHandlersFactory = toolHandlers;
|
|
64
71
|
this.toolHandlers = {};
|
|
@@ -117,10 +124,71 @@ export class ChatDriver extends EventTarget {
|
|
|
117
124
|
typeof config.displayName === 'string' ? config.displayName : config.name;
|
|
118
125
|
this.debugSnapshotter = config.getDebugSnapshot;
|
|
119
126
|
this.subAgentsMap = new Map(((_c = config.subAgents) !== null && _c !== void 0 ? _c : []).map((s) => [s.name, s]));
|
|
127
|
+
this.activeProviderInput = config.provider;
|
|
128
|
+
this.resolvedProviderCache.clear();
|
|
129
|
+
this.lastResolvedProviderName = undefined;
|
|
130
|
+
// Static validation: resolve the name now so unknown-provider and missing-
|
|
131
|
+
// capability errors fire at agent swap rather than on the first LLM call.
|
|
132
|
+
// Function-form `provider` is validated lazily inside `resolveProviderForTurn`.
|
|
133
|
+
if (typeof config.provider === 'string') {
|
|
134
|
+
this.resolveProviderByName(config.provider, config.name);
|
|
135
|
+
}
|
|
120
136
|
// Reset fold state when agent changes — each specialist starts fresh
|
|
121
137
|
this.foldStack = [];
|
|
122
138
|
this.consecutiveFoldOps = 0;
|
|
123
139
|
}
|
|
140
|
+
/**
|
|
141
|
+
* Returns the most recently resolved provider name. Falls back to the
|
|
142
|
+
* registry's default when no per-turn resolution has happened yet.
|
|
143
|
+
*/
|
|
144
|
+
getActiveProviderName() {
|
|
145
|
+
var _a;
|
|
146
|
+
return (_a = this.lastResolvedProviderName) !== null && _a !== void 0 ? _a : this.providerRegistry.defaultName();
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Resolve a named provider against the registry. Cached per-agent so
|
|
150
|
+
* repeated lookups during one agent's lifetime don't re-validate.
|
|
151
|
+
* Validation lives in `resolveChatProvider`; this wrapper just adds the
|
|
152
|
+
* cache.
|
|
153
|
+
*/
|
|
154
|
+
resolveProviderByName(name, agentName) {
|
|
155
|
+
const cached = this.resolvedProviderCache.get(name);
|
|
156
|
+
if (cached)
|
|
157
|
+
return cached;
|
|
158
|
+
const provider = resolveChatProvider(this.providerRegistry, name, agentName);
|
|
159
|
+
this.resolvedProviderCache.set(name, provider);
|
|
160
|
+
return provider;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Resolve the provider to use for the current turn. Walks the agent's
|
|
164
|
+
* `provider` selector (static or function form) or falls back to the
|
|
165
|
+
* registry default. Dispatches `provider-changed` when the resolved name
|
|
166
|
+
* differs from the last dispatched value.
|
|
167
|
+
*/
|
|
168
|
+
resolveProviderForTurn(ctx) {
|
|
169
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
170
|
+
var _a;
|
|
171
|
+
let provider;
|
|
172
|
+
let resolvedName;
|
|
173
|
+
if (this.activeProviderInput === undefined) {
|
|
174
|
+
provider = this.providerRegistry.default();
|
|
175
|
+
resolvedName = this.providerRegistry.defaultName();
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
const name = typeof this.activeProviderInput === 'function'
|
|
179
|
+
? yield this.activeProviderInput(ctx)
|
|
180
|
+
: this.activeProviderInput;
|
|
181
|
+
provider = this.resolveProviderByName(name, (_a = this.activeAgentName) !== null && _a !== void 0 ? _a : '<unknown>');
|
|
182
|
+
resolvedName = name;
|
|
183
|
+
}
|
|
184
|
+
this.lastResolvedProviderName = resolvedName;
|
|
185
|
+
if (resolvedName !== this.lastDispatchedProviderName) {
|
|
186
|
+
this.lastDispatchedProviderName = resolvedName;
|
|
187
|
+
this.dispatchEvent(new CustomEvent('provider-changed', { detail: { name: resolvedName } }));
|
|
188
|
+
}
|
|
189
|
+
return provider;
|
|
190
|
+
});
|
|
191
|
+
}
|
|
124
192
|
/**
|
|
125
193
|
* Returns the early-stop result set by `completeSubAgent`, if any.
|
|
126
194
|
* Called by a parent `ChatDriver` after running this instance as a sub-agent.
|
|
@@ -197,8 +265,12 @@ export class ChatDriver extends EventTarget {
|
|
|
197
265
|
}
|
|
198
266
|
getSuggestions(history, prompt, count, allAgentInfo) {
|
|
199
267
|
return __awaiter(this, void 0, void 0, function* () {
|
|
200
|
-
|
|
201
|
-
|
|
268
|
+
// Suggestions are an out-of-turn UI helper, not bound to any single agent —
|
|
269
|
+
// always run against the registry default. Best-effort: a default with no
|
|
270
|
+
// `prompt()` just means no suggestions, not a hard error.
|
|
271
|
+
const defaultProvider = this.providerRegistry.default();
|
|
272
|
+
if (!defaultProvider.prompt) {
|
|
273
|
+
logger.warn('ChatDriver: default AI provider does not implement prompt()');
|
|
202
274
|
return [];
|
|
203
275
|
}
|
|
204
276
|
let agentContext = '';
|
|
@@ -275,7 +347,7 @@ export class ChatDriver extends EventTarget {
|
|
|
275
347
|
`- No numbering, bullets, markdown, emojis, code blocks, or quotes around the suggestion.\n` +
|
|
276
348
|
`- No preamble, headings, summary, or commentary before or after the list.`;
|
|
277
349
|
}
|
|
278
|
-
const text = yield
|
|
350
|
+
const text = yield defaultProvider.prompt(userMessage, { systemPrompt });
|
|
279
351
|
// Lenient parsing as a defensive backstop: even with the strict prompt,
|
|
280
352
|
// models occasionally slip in numbering, bullets, or surrounding markdown.
|
|
281
353
|
return (text
|
|
@@ -391,10 +463,6 @@ export class ChatDriver extends EventTarget {
|
|
|
391
463
|
return __awaiter(this, void 0, void 0, function* () {
|
|
392
464
|
if (this.busy || (!userInput.trim() && !(attachments === null || attachments === void 0 ? void 0 : attachments.length)))
|
|
393
465
|
return { reason: 'done' };
|
|
394
|
-
if (!this.aiProvider.chat) {
|
|
395
|
-
logger.warn('ChatDriver: AIProvider does not implement chat()');
|
|
396
|
-
return { reason: 'done' };
|
|
397
|
-
}
|
|
398
466
|
this.busy = true;
|
|
399
467
|
this.subAgentCompletion = undefined;
|
|
400
468
|
this.agentReleaseRequested = false;
|
|
@@ -477,7 +545,7 @@ export class ChatDriver extends EventTarget {
|
|
|
477
545
|
...contextMessages,
|
|
478
546
|
...((_b = subConfig.primerHistory) !== null && _b !== void 0 ? _b : []),
|
|
479
547
|
];
|
|
480
|
-
const child = new ChatDriver(this.
|
|
548
|
+
const child = new ChatDriver(this.providerRegistry);
|
|
481
549
|
child.applyAgent(Object.assign(Object.assign({}, subConfig), { primerHistory: effectivePrimer }));
|
|
482
550
|
// Route interactions back through this driver so widgets render in the
|
|
483
551
|
// parent's (ultimately the root's) history and resolve via the same
|
|
@@ -522,10 +590,6 @@ export class ChatDriver extends EventTarget {
|
|
|
522
590
|
return __awaiter(this, void 0, void 0, function* () {
|
|
523
591
|
if (this.busy)
|
|
524
592
|
return { reason: 'done' };
|
|
525
|
-
if (!this.aiProvider.chat) {
|
|
526
|
-
logger.warn('ChatDriver: AIProvider does not implement chat()');
|
|
527
|
-
return { reason: 'done' };
|
|
528
|
-
}
|
|
529
593
|
this.busy = true;
|
|
530
594
|
this.subAgentCompletion = undefined;
|
|
531
595
|
agenticActivityBus.publish('tool-loop-start', undefined);
|
|
@@ -762,10 +826,15 @@ export class ChatDriver extends EventTarget {
|
|
|
762
826
|
tools: this.toolDefinitions.length ? this.toolDefinitions : undefined,
|
|
763
827
|
attachments: attachmentsForCall,
|
|
764
828
|
};
|
|
829
|
+
// Resolve the active provider for this turn. Static names were validated
|
|
830
|
+
// in `applyAgent`; function-form names are validated on first resolution
|
|
831
|
+
// here and cached for the agent's lifetime.
|
|
832
|
+
// oxlint-disable-next-line no-await-in-loop
|
|
833
|
+
const activeProvider = yield this.resolveProviderForTurn(promptCtx);
|
|
765
834
|
let response;
|
|
766
835
|
try {
|
|
767
836
|
// oxlint-disable-next-line no-await-in-loop
|
|
768
|
-
response = yield
|
|
837
|
+
response = yield activeProvider.chat(historyForCall, userInputForCall, options);
|
|
769
838
|
}
|
|
770
839
|
catch (e) {
|
|
771
840
|
if (e instanceof MalformedFunctionCallError) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { __awaiter } from "tslib";
|
|
2
|
+
import { validateStaticAgentProviders } from '../../config/validate-providers';
|
|
2
3
|
import { transformHistoryForAgent } from '../../utils/history-transform';
|
|
3
4
|
import { logger } from '../../utils/logger';
|
|
4
5
|
import { ChatDriver, REQUEST_CONTINUATION_TOOL, } from '../chat-driver/chat-driver';
|
|
@@ -50,10 +51,10 @@ function buildFallbackSystemPrompt(fallback, specialists) {
|
|
|
50
51
|
* @beta
|
|
51
52
|
*/
|
|
52
53
|
export class OrchestratingDriver extends EventTarget {
|
|
53
|
-
constructor(
|
|
54
|
+
constructor(providerRegistry, agents, options = {}) {
|
|
54
55
|
var _a, _b, _c, _d;
|
|
55
56
|
super();
|
|
56
|
-
this.
|
|
57
|
+
this.providerRegistry = providerRegistry;
|
|
57
58
|
this.agents = agents;
|
|
58
59
|
/**
|
|
59
60
|
* Aborted on driver disposal. Threaded into `AgentLifecycleContext.signal`
|
|
@@ -80,6 +81,10 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
80
81
|
this.classifierHistoryLength =
|
|
81
82
|
(_c = options.classifierHistoryLength) !== null && _c !== void 0 ? _c : DEFAULT_CLASSIFIER_HISTORY_LENGTH;
|
|
82
83
|
this.classifierRetries = (_d = options.classifierRetries) !== null && _d !== void 0 ? _d : DEFAULT_CLASSIFIER_RETRIES;
|
|
84
|
+
// Static-name validation: walk every agent (and nested sub-agents). Any
|
|
85
|
+
// `provider: '<name>'` that isn't registered, or resolves to a provider
|
|
86
|
+
// without `chat()`, throws now rather than at first turn.
|
|
87
|
+
validateStaticAgentProviders(agents, providerRegistry);
|
|
83
88
|
// Specialists drive the classifier. `excludeFromClassifier` agents are still
|
|
84
89
|
// resolvable by name (so manual pinning works) but never auto-routed.
|
|
85
90
|
this.specialists = agents.filter(isSpecialist).filter((a) => !a.excludeFromClassifier);
|
|
@@ -90,7 +95,7 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
90
95
|
const rawFallback = fallbacks[0];
|
|
91
96
|
this.fallback = rawFallback
|
|
92
97
|
? Object.assign(Object.assign({}, rawFallback), { systemPrompt: buildFallbackSystemPrompt(rawFallback, this.specialists) }) : undefined;
|
|
93
|
-
this.chatDriver = new ChatDriver(
|
|
98
|
+
this.chatDriver = new ChatDriver(providerRegistry, {}, [], undefined, undefined, options.maxToolIterations, options.maxFoldOperations, options.maxTurnSnapshots);
|
|
94
99
|
// Proxy events from the shared driver
|
|
95
100
|
this.chatDriver.addEventListener('history-updated', (e) => {
|
|
96
101
|
this.dispatchEvent(new CustomEvent('history-updated', { detail: e.detail }));
|
|
@@ -110,6 +115,9 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
110
115
|
this.chatDriver.addEventListener('interaction-stop', (e) => {
|
|
111
116
|
this.dispatchEvent(new CustomEvent('interaction-stop', { detail: e.detail }));
|
|
112
117
|
});
|
|
118
|
+
this.chatDriver.addEventListener('provider-changed', (e) => {
|
|
119
|
+
this.dispatchEvent(new CustomEvent('provider-changed', { detail: e.detail }));
|
|
120
|
+
});
|
|
113
121
|
}
|
|
114
122
|
resolveInteraction(interactionId, result) {
|
|
115
123
|
this.chatDriver.resolveInteraction(interactionId, result);
|
|
@@ -117,6 +125,10 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
117
125
|
isBusy() {
|
|
118
126
|
return this.chatDriver.isBusy();
|
|
119
127
|
}
|
|
128
|
+
/** Currently active provider name from the underlying ChatDriver. */
|
|
129
|
+
getActiveProviderName() {
|
|
130
|
+
return this.chatDriver.getActiveProviderName();
|
|
131
|
+
}
|
|
120
132
|
/**
|
|
121
133
|
* Pins routing to a specific agent by name. While pinned, the classifier is
|
|
122
134
|
* skipped and the continuation tool is hidden from the agent's tool list, so
|
|
@@ -427,8 +439,15 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
427
439
|
systemPrompt: classifierPrompt,
|
|
428
440
|
tools: [routingTool],
|
|
429
441
|
};
|
|
442
|
+
// Classification is orchestrator-level, not bound to any single agent —
|
|
443
|
+
// always run against the registry default.
|
|
444
|
+
const classifierProvider = this.providerRegistry.default();
|
|
445
|
+
if (!classifierProvider.chat) {
|
|
446
|
+
logger.warn('OrchestratingDriver: default AI provider does not implement chat() — cannot classify.');
|
|
447
|
+
break;
|
|
448
|
+
}
|
|
430
449
|
// oxlint-disable-next-line no-await-in-loop
|
|
431
|
-
const response = yield
|
|
450
|
+
const response = yield classifierProvider.chat([], input, options);
|
|
432
451
|
const tc = (_b = response.toolCalls) === null || _b === void 0 ? void 0 : _b[0];
|
|
433
452
|
const index = (tc === null || tc === void 0 ? void 0 : tc.name) === 'select_agent' ? tc.args.agent_index : -1;
|
|
434
453
|
if (index >= 0 && index < this.specialists.length) {
|
|
@@ -107,6 +107,17 @@ export function defineStatefulAgent(opts) {
|
|
|
107
107
|
return opts.displayName(Object.assign(Object.assign({}, ctx), { state }));
|
|
108
108
|
})
|
|
109
109
|
: undefined;
|
|
110
|
+
// Function-form `provider` needs `state` injected the same way the other
|
|
111
|
+
// per-turn resolvers do; the static-string form is passed through unchanged
|
|
112
|
+
// and validated up-front by OrchestratingDriver.
|
|
113
|
+
const wrappedProvider = typeof opts.provider === 'function'
|
|
114
|
+
? (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
115
|
+
if (!state) {
|
|
116
|
+
throw new Error(`Stateful agent "${opts.name}" provider called before init`);
|
|
117
|
+
}
|
|
118
|
+
return opts.provider(Object.assign(Object.assign({}, ctx), { state }));
|
|
119
|
+
})
|
|
120
|
+
: opts.provider;
|
|
110
121
|
const base = {
|
|
111
122
|
name: opts.name,
|
|
112
123
|
displayName: wrappedDisplayName,
|
|
@@ -116,6 +127,7 @@ export function defineStatefulAgent(opts) {
|
|
|
116
127
|
chatInputDuringExecution: opts.chatInputDuringExecution,
|
|
117
128
|
toolDefinitions: wrappedTools,
|
|
118
129
|
toolHandlers: wrappedHandlers,
|
|
130
|
+
provider: wrappedProvider,
|
|
119
131
|
onActivate: (ctx) => __awaiter(this, void 0, void 0, function* () {
|
|
120
132
|
state = yield opts.init(ctx);
|
|
121
133
|
// Sample once with the init state to fail loud on fold misuse at the
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a provider name against the registry and assert it implements
|
|
3
|
+
* `chat()` — the capability the chat tool-loop depends on. Throws with a
|
|
4
|
+
* message naming the agent so misconfigured agents are easy to track down.
|
|
5
|
+
*
|
|
6
|
+
* Used by both the up-front static walk in `OrchestratingDriver` and by
|
|
7
|
+
* `ChatDriver`'s per-turn resolver for function-form `provider` values.
|
|
8
|
+
*
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export function resolveChatProvider(registry, providerName, agentName) {
|
|
12
|
+
const provider = registry.get(providerName);
|
|
13
|
+
if (!provider) {
|
|
14
|
+
const available = registry.names().join(', ') || '(none)';
|
|
15
|
+
throw new Error(`Agent "${agentName}" references unknown provider "${providerName}". Registered: ${available}`);
|
|
16
|
+
}
|
|
17
|
+
if (!provider.chat) {
|
|
18
|
+
throw new Error(`Agent "${agentName}" resolved to provider "${providerName}" which does not implement chat().`);
|
|
19
|
+
}
|
|
20
|
+
return provider;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Walk an agent tree (including nested `subAgents`) and validate every static
|
|
24
|
+
* `provider: string` against the registry. Function-form `provider` values are
|
|
25
|
+
* deferred — they validate on first resolution inside the driver.
|
|
26
|
+
*
|
|
27
|
+
* Throws on the first failure, with the same message shape produced by
|
|
28
|
+
* {@link resolveChatProvider}.
|
|
29
|
+
*
|
|
30
|
+
* @internal
|
|
31
|
+
*/
|
|
32
|
+
export function validateStaticAgentProviders(agents, registry) {
|
|
33
|
+
const visited = new Set();
|
|
34
|
+
const walk = (agent) => {
|
|
35
|
+
var _a;
|
|
36
|
+
if (visited.has(agent))
|
|
37
|
+
return;
|
|
38
|
+
visited.add(agent);
|
|
39
|
+
if (typeof agent.provider === 'string') {
|
|
40
|
+
resolveChatProvider(registry, agent.provider, agent.name);
|
|
41
|
+
}
|
|
42
|
+
for (const sub of (_a = agent.subAgents) !== null && _a !== void 0 ? _a : [])
|
|
43
|
+
walk(sub);
|
|
44
|
+
};
|
|
45
|
+
for (const root of agents)
|
|
46
|
+
walk(root);
|
|
47
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { __awaiter } from "tslib";
|
|
2
|
+
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
3
|
+
import { resolveChatProvider, validateStaticAgentProviders } from './validate-providers';
|
|
4
|
+
const chatProvider = () => ({
|
|
5
|
+
chat: () => __awaiter(void 0, void 0, void 0, function* () { return ({ role: 'assistant', content: '' }); }),
|
|
6
|
+
});
|
|
7
|
+
const promptOnlyProvider = () => ({
|
|
8
|
+
prompt: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Minimal in-test registry — implements only what the validation helpers
|
|
12
|
+
* touch (`get`, `names`). Avoids depending on foundation-ai's concrete
|
|
13
|
+
* registry impl, and keeps these tests Node-runnable.
|
|
14
|
+
*/
|
|
15
|
+
const makeRegistry = (providers) => {
|
|
16
|
+
const map = new Map(Object.entries(providers));
|
|
17
|
+
return {
|
|
18
|
+
get: (name) => map.get(name),
|
|
19
|
+
default: () => map.values().next().value,
|
|
20
|
+
defaultName: () => map.keys().next().value,
|
|
21
|
+
names: () => [...map.keys()],
|
|
22
|
+
getStatus: () => __awaiter(void 0, void 0, void 0, function* () { return null; }),
|
|
23
|
+
listStatuses: () => __awaiter(void 0, void 0, void 0, function* () { return []; }),
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
const specialist = (overrides) => (Object.assign({ name: overrides.name, description: 'test specialist' }, overrides));
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// resolveChatProvider
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
const resolve = createLogicSuite('resolveChatProvider');
|
|
31
|
+
resolve('returns the provider when the name is registered and has chat()', () => {
|
|
32
|
+
const fast = chatProvider();
|
|
33
|
+
const registry = makeRegistry({ fast });
|
|
34
|
+
assert.is(resolveChatProvider(registry, 'fast', 'A'), fast);
|
|
35
|
+
});
|
|
36
|
+
resolve('throws on an unknown provider name with the agent name in the message', () => {
|
|
37
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
38
|
+
assert.throws(() => resolveChatProvider(registry, 'deep', 'A'), /Agent "A" references unknown provider "deep"/);
|
|
39
|
+
});
|
|
40
|
+
resolve('throws including the registered names so the misconfiguration is debuggable', () => {
|
|
41
|
+
const registry = makeRegistry({
|
|
42
|
+
fast: chatProvider(),
|
|
43
|
+
deep: chatProvider(),
|
|
44
|
+
cheap: chatProvider(),
|
|
45
|
+
});
|
|
46
|
+
assert.throws(() => resolveChatProvider(registry, 'typo', 'A'), /Registered: fast, deep, cheap/);
|
|
47
|
+
});
|
|
48
|
+
resolve('throws when the resolved provider does not implement chat()', () => {
|
|
49
|
+
const registry = makeRegistry({ chrome: promptOnlyProvider() });
|
|
50
|
+
assert.throws(() => resolveChatProvider(registry, 'chrome', 'A'), /Agent "A" resolved to provider "chrome" which does not implement chat\(\)/);
|
|
51
|
+
});
|
|
52
|
+
resolve.run();
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// validateStaticAgentProviders
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
const validate = createLogicSuite('validateStaticAgentProviders');
|
|
57
|
+
validate('accepts agents with no `provider` field (back-compat path)', () => {
|
|
58
|
+
const registry = makeRegistry({ default: chatProvider() });
|
|
59
|
+
assert.not.throws(() => validateStaticAgentProviders([specialist({ name: 'A' })], registry));
|
|
60
|
+
});
|
|
61
|
+
validate('accepts agents that name a registered chat-capable provider', () => {
|
|
62
|
+
const registry = makeRegistry({ fast: chatProvider(), deep: chatProvider() });
|
|
63
|
+
assert.not.throws(() => validateStaticAgentProviders([specialist({ name: 'A', provider: 'deep' })], registry));
|
|
64
|
+
});
|
|
65
|
+
validate('throws when a top-level agent references an unknown provider', () => {
|
|
66
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
67
|
+
assert.throws(() => validateStaticAgentProviders([specialist({ name: 'A', provider: 'deep' })], registry), /Agent "A" references unknown provider "deep"/);
|
|
68
|
+
});
|
|
69
|
+
validate('recurses into subAgents — bad provider on a sub-agent throws', () => {
|
|
70
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
71
|
+
const sub = specialist({ name: 'Sub', provider: 'missing' });
|
|
72
|
+
assert.throws(() => validateStaticAgentProviders([specialist({ name: 'A', subAgents: [sub] })], registry), /Agent "Sub" references unknown provider "missing"/);
|
|
73
|
+
});
|
|
74
|
+
validate('recurses through multiple levels — bad provider on a deeply-nested sub-agent throws', () => {
|
|
75
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
76
|
+
const deepest = specialist({ name: 'Deepest', provider: 'missing' });
|
|
77
|
+
const middle = specialist({ name: 'Middle', subAgents: [deepest] });
|
|
78
|
+
assert.throws(() => validateStaticAgentProviders([specialist({ name: 'Top', subAgents: [middle] })], registry), /Agent "Deepest" references unknown provider "missing"/);
|
|
79
|
+
});
|
|
80
|
+
validate('defers function-form `provider` — it is not invoked at validation time', () => {
|
|
81
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
82
|
+
const agent = specialist({
|
|
83
|
+
name: 'A',
|
|
84
|
+
// If validateStaticAgentProviders eagerly resolved this, it would throw
|
|
85
|
+
// here. The contract is that function-form is deferred to the driver's
|
|
86
|
+
// per-turn resolver.
|
|
87
|
+
provider: () => {
|
|
88
|
+
throw new Error('function-form provider should not be invoked at validation time');
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
assert.not.throws(() => validateStaticAgentProviders([agent], registry));
|
|
92
|
+
});
|
|
93
|
+
validate('shared sub-agent across two parents validates cleanly', () => {
|
|
94
|
+
const registry = makeRegistry({ fast: chatProvider() });
|
|
95
|
+
const shared = specialist({ name: 'Shared', provider: 'fast' });
|
|
96
|
+
const parentA = specialist({ name: 'ParentA', subAgents: [shared] });
|
|
97
|
+
const parentB = specialist({ name: 'ParentB', subAgents: [shared] });
|
|
98
|
+
assert.not.throws(() => validateStaticAgentProviders([parentA, parentB], registry));
|
|
99
|
+
});
|
|
100
|
+
validate.run();
|
package/dist/esm/main/main.js
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
// =============================================================================
|
|
23
23
|
var FoundationAiAssistant_1;
|
|
24
24
|
import { __awaiter, __decorate, __rest } from "tslib";
|
|
25
|
-
import {
|
|
25
|
+
import { AIProviderRegistry } from '@genesislcap/foundation-ai';
|
|
26
26
|
import { avoidTreeShaking } from '@genesislcap/foundation-utils';
|
|
27
27
|
import { customElement, html, GenesisElement, observable, volatile, attr, } from '@genesislcap/web-core';
|
|
28
28
|
import { agenticActivityBus } from '../channel/ai-activity-bus';
|
|
@@ -81,8 +81,11 @@ function stripHandlers(agent) {
|
|
|
81
81
|
* Foundation AI Assistant component.
|
|
82
82
|
*
|
|
83
83
|
* @remarks
|
|
84
|
-
*
|
|
85
|
-
*
|
|
84
|
+
* Register one or more AI providers via `registerAIProviders` from
|
|
85
|
+
* `@genesislcap/foundation-ai`; this element resolves the `AIProviderRegistry`
|
|
86
|
+
* through the DI container. Pass agent configuration via the `agents` property —
|
|
87
|
+
* each agent can override which registered provider it uses via `provider:`.
|
|
88
|
+
* The component creates a `ChatDriver` (single agent) or `OrchestratingDriver`
|
|
86
89
|
* (multiple agents) to manage the conversation loop.
|
|
87
90
|
*
|
|
88
91
|
* Popout/collapse coordination uses `agenticActivityBus` topics `chat-popout` and `chat-popin` — not DOM `CustomEvent`s on this element.
|
|
@@ -422,6 +425,24 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
422
425
|
var _a;
|
|
423
426
|
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setActiveModel(value);
|
|
424
427
|
}
|
|
428
|
+
/** Name of the AI provider used on the most recent turn. */
|
|
429
|
+
get activeProviderName() {
|
|
430
|
+
var _a;
|
|
431
|
+
return (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.activeProviderName;
|
|
432
|
+
}
|
|
433
|
+
set activeProviderName(value) {
|
|
434
|
+
var _a;
|
|
435
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setActiveProviderName(value);
|
|
436
|
+
}
|
|
437
|
+
/** Per-provider status snapshot used by the settings panel. */
|
|
438
|
+
get providerStatuses() {
|
|
439
|
+
var _a, _b;
|
|
440
|
+
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.providerStatuses) !== null && _b !== void 0 ? _b : [];
|
|
441
|
+
}
|
|
442
|
+
set providerStatuses(value) {
|
|
443
|
+
var _a;
|
|
444
|
+
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.setProviderStatuses(value);
|
|
445
|
+
}
|
|
425
446
|
get inputValue() {
|
|
426
447
|
var _a, _b;
|
|
427
448
|
return (_b = (_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.store.aiAssistant.inputValue) !== null && _b !== void 0 ? _b : '';
|
|
@@ -627,7 +648,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
627
648
|
// this via `agent-changed` once applyAgent fires on first sendMessage.
|
|
628
649
|
this.activeAgent = agents[0];
|
|
629
650
|
}
|
|
630
|
-
return new OrchestratingDriver(this.
|
|
651
|
+
return new OrchestratingDriver(this.providerRegistry, agents, {
|
|
631
652
|
sessionKey: (_b = this.getStateKey()) !== null && _b !== void 0 ? _b : '',
|
|
632
653
|
maxHandoffs: agent.maxHandoffs,
|
|
633
654
|
classifierHistoryLength: agent.classifierHistoryLength,
|
|
@@ -637,7 +658,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
637
658
|
maxTurnSnapshots: agent.maxTurnSnapshots,
|
|
638
659
|
});
|
|
639
660
|
}
|
|
640
|
-
return new ChatDriver(this.
|
|
661
|
+
return new ChatDriver(this.providerRegistry, {}, [], undefined, undefined, agent.maxToolIterations, agent.maxFoldOperations, agent.maxTurnSnapshots);
|
|
641
662
|
}
|
|
642
663
|
/**
|
|
643
664
|
* Attaches event listeners to the current driver. Stores a cleanup function
|
|
@@ -697,11 +718,19 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
697
718
|
(_a = this._sessionRef) === null || _a === void 0 ? void 0 : _a.actions.aiAssistant.removeInputOverride({ id: interactionId });
|
|
698
719
|
}
|
|
699
720
|
};
|
|
721
|
+
const onProviderChanged = (e) => {
|
|
722
|
+
const { name } = e.detail;
|
|
723
|
+
this.activeProviderName = name;
|
|
724
|
+
// Status (model id / context limit) belongs to the active provider — refresh
|
|
725
|
+
// the displayed values so the header reflects the provider that just took over.
|
|
726
|
+
void this.resolveContextLimit();
|
|
727
|
+
};
|
|
700
728
|
driver.addEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated);
|
|
701
729
|
driver.addEventListener('sub-agent-start', onSubAgentStart);
|
|
702
730
|
driver.addEventListener('sub-agent-stop', onSubAgentStop);
|
|
703
731
|
driver.addEventListener('interaction-start', onInteractionStart);
|
|
704
732
|
driver.addEventListener('interaction-stop', onInteractionStop);
|
|
733
|
+
driver.addEventListener('provider-changed', onProviderChanged);
|
|
705
734
|
const cleanups = [
|
|
706
735
|
() => driver.removeEventListener('history-updated', onHistoryUpdated),
|
|
707
736
|
() => driver.removeEventListener('sub-agent-history-updated', onSubAgentHistoryUpdated),
|
|
@@ -709,6 +738,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
709
738
|
() => driver.removeEventListener('sub-agent-stop', onSubAgentStop),
|
|
710
739
|
() => driver.removeEventListener('interaction-start', onInteractionStart),
|
|
711
740
|
() => driver.removeEventListener('interaction-stop', onInteractionStop),
|
|
741
|
+
() => driver.removeEventListener('provider-changed', onProviderChanged),
|
|
712
742
|
];
|
|
713
743
|
if (driver instanceof OrchestratingDriver) {
|
|
714
744
|
// Restore the user pin and flow-owner lock from the session store onto
|
|
@@ -837,6 +867,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
837
867
|
}
|
|
838
868
|
this.fetchSuggestions();
|
|
839
869
|
void this.resolveContextLimit();
|
|
870
|
+
void this.loadProviderStatuses();
|
|
840
871
|
if (this.messagesEl) {
|
|
841
872
|
this._scrollListener = () => {
|
|
842
873
|
this._userScrolledAway =
|
|
@@ -885,17 +916,33 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
885
916
|
}
|
|
886
917
|
resolveContextLimit() {
|
|
887
918
|
return __awaiter(this, void 0, void 0, function* () {
|
|
888
|
-
var _a
|
|
919
|
+
var _a;
|
|
889
920
|
try {
|
|
890
|
-
|
|
921
|
+
// Resolve status for the currently active provider when a driver is up
|
|
922
|
+
// (so per-agent provider swaps update the displayed model/limit); fall
|
|
923
|
+
// back to the registry default at startup before any turn has run.
|
|
924
|
+
const activeName = (_a = this.driver) === null || _a === void 0 ? void 0 : _a.getActiveProviderName();
|
|
925
|
+
const status = activeName
|
|
926
|
+
? yield this.providerRegistry.getStatus(activeName)
|
|
927
|
+
: yield this.providerRegistry.getStatus();
|
|
891
928
|
this.contextLimit = status === null || status === void 0 ? void 0 : status.contextLimit;
|
|
892
929
|
this.activeModel = status === null || status === void 0 ? void 0 : status.model;
|
|
893
930
|
}
|
|
894
|
-
catch (
|
|
931
|
+
catch (_b) {
|
|
895
932
|
// Non-fatal — context limit / model display simply won't show
|
|
896
933
|
}
|
|
897
934
|
});
|
|
898
935
|
}
|
|
936
|
+
loadProviderStatuses() {
|
|
937
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
938
|
+
try {
|
|
939
|
+
this.providerStatuses = yield this.providerRegistry.listStatuses();
|
|
940
|
+
}
|
|
941
|
+
catch (_a) {
|
|
942
|
+
// Non-fatal — settings panel just won't list providers
|
|
943
|
+
}
|
|
944
|
+
});
|
|
945
|
+
}
|
|
899
946
|
chatConfigChanged() {
|
|
900
947
|
this.syncShowingSplash();
|
|
901
948
|
}
|
|
@@ -1493,8 +1540,8 @@ FoundationAiAssistant.DEFAULT_LOADING_DELAY_S = 5;
|
|
|
1493
1540
|
FoundationAiAssistant.DEFAULT_SUGGESTION_COUNT = 3;
|
|
1494
1541
|
FoundationAiAssistant.MS_PER_SECOND = 1000;
|
|
1495
1542
|
__decorate([
|
|
1496
|
-
|
|
1497
|
-
], FoundationAiAssistant.prototype, "
|
|
1543
|
+
AIProviderRegistry
|
|
1544
|
+
], FoundationAiAssistant.prototype, "providerRegistry", void 0);
|
|
1498
1545
|
__decorate([
|
|
1499
1546
|
observable
|
|
1500
1547
|
], FoundationAiAssistant.prototype, "designSystemPrefix", void 0);
|