@genesislcap/ai-assistant 14.472.1 → 14.473.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/dts/main/main.d.ts.map +1 -1
- package/dist/dts/state/driver-registry.d.ts +11 -3
- package/dist/dts/state/driver-registry.d.ts.map +1 -1
- package/dist/dts/state/driver-registry.test.d.ts +2 -0
- package/dist/dts/state/driver-registry.test.d.ts.map +1 -0
- package/dist/esm/main/main.js +38 -3
- package/dist/esm/state/driver-registry.js +20 -18
- package/dist/esm/state/driver-registry.test.js +55 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +16 -16
- package/src/main/main.ts +45 -3
- package/src/state/driver-registry.test.ts +70 -0
- package/src/state/driver-registry.ts +37 -9
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/main/main.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACV,6BAA6B,EAC7B,cAAc,EACd,UAAU,EACV,4BAA4B,EAC5B,WAAW,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,kBAAkB,EAAkC,MAAM,4BAA4B,CAAC;AAEhG,OAAO,EAGL,cAAc,EAIf,MAAM,uBAAuB,CAAC;AAe/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAIL,KAAK,aAAa,EACnB,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../src/main/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
import type { AiDriver } from '../components/ai-driver/ai-driver';
|
|
2
2
|
/**
|
|
3
|
-
* Returns the existing driver for the given key, or calls the factory
|
|
4
|
-
*
|
|
3
|
+
* Returns the existing driver for the given key, or calls the factory to create
|
|
4
|
+
* and register a new one. `agentsKey` is the fingerprint of the agents the
|
|
5
|
+
* driver is being built for; it is recorded only when a driver is created (a
|
|
6
|
+
* reused driver keeps the fingerprint it was originally built with).
|
|
5
7
|
*/
|
|
6
|
-
export declare function getOrCreateDriver(key: string, factory: () => AiDriver): AiDriver;
|
|
8
|
+
export declare function getOrCreateDriver(key: string, agentsKey: string, factory: () => AiDriver): AiDriver;
|
|
7
9
|
/**
|
|
8
10
|
* Returns the existing driver for the given key, or `undefined`.
|
|
9
11
|
*/
|
|
10
12
|
export declare function getDriver(key: string): AiDriver | undefined;
|
|
13
|
+
/**
|
|
14
|
+
* The agents fingerprint the registry driver for `key` was built with, or
|
|
15
|
+
* `undefined` if no driver is registered. Used by `agentsChanged` to decide
|
|
16
|
+
* whether a sibling has already rebuilt the shared driver to the desired agents.
|
|
17
|
+
*/
|
|
18
|
+
export declare function getDriverAgentsKey(key: string): string | undefined;
|
|
11
19
|
/**
|
|
12
20
|
* Removes and returns the driver for the given key.
|
|
13
21
|
* Used when agents change (driver must be rebuilt) or on explicit session teardown.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"driver-registry.d.ts","sourceRoot":"","sources":["../../../src/state/driver-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"driver-registry.d.ts","sourceRoot":"","sources":["../../../src/state/driver-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AA2BlE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,QAAQ,GACtB,QAAQ,CAMV;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAE3D;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAElE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAI9D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"driver-registry.test.d.ts","sourceRoot":"","sources":["../../../src/state/driver-registry.test.ts"],"names":[],"mappings":""}
|
package/dist/esm/main/main.js
CHANGED
|
@@ -39,7 +39,7 @@ import { OrchestratingDriver } from '../components/orchestrating-driver/orchestr
|
|
|
39
39
|
import { AiPlasmaOrbIndicator } from '../components/plasma-orb-indicator';
|
|
40
40
|
import { AiWavesIndicator } from '../components/waves-indicator';
|
|
41
41
|
import { recordMetaEvent, getMetaEvents, DEBUG_LOG_README, } from '../state/debug-event-log';
|
|
42
|
-
import { getOrCreateDriver, getDriver, deleteDriver } from '../state/driver-registry';
|
|
42
|
+
import { getOrCreateDriver, getDriver, getDriverAgentsKey, deleteDriver, } from '../state/driver-registry';
|
|
43
43
|
import { getSessionStore, hasSessionStore } from '../state/session-store';
|
|
44
44
|
import { AI_COLOUR_AMBER, AI_COLOUR_CYAN, AI_COLOUR_PINK, AI_COLOUR_VIOLET, } from '../styles/ai-colours';
|
|
45
45
|
import { ChatSuggestions } from '../suggestions/chat-suggestions';
|
|
@@ -617,6 +617,24 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
617
617
|
const newKey = this.getAgentsKey(this.agents);
|
|
618
618
|
if (newKey === this._driverAgentsKey)
|
|
619
619
|
return;
|
|
620
|
+
// GENC-1388: a sibling component sharing this session key (e.g. the popped-out
|
|
621
|
+
// panel and the docked standalone, both keyed off one stateKey) may have
|
|
622
|
+
// already rebuilt the shared registry driver to this exact agent set. Adopt
|
|
623
|
+
// it rather than recreating: a rebuild calls deleteDriver + getOrCreateDriver,
|
|
624
|
+
// which evicts the sibling's driver and orphans whichever element is mid-turn
|
|
625
|
+
// on it — a later remount then rebinds to the wrong, idle driver (stuck
|
|
626
|
+
// "Thinking…" / lost end-message). Never adopt away from a busy local driver.
|
|
627
|
+
const registryDriver = getDriver(key);
|
|
628
|
+
if (registryDriver &&
|
|
629
|
+
registryDriver !== this.driver &&
|
|
630
|
+
getDriverAgentsKey(key) === newKey &&
|
|
631
|
+
!this.driver.isBusy()) {
|
|
632
|
+
this.unwireDriver();
|
|
633
|
+
this.driver = registryDriver;
|
|
634
|
+
this.wireDriver();
|
|
635
|
+
this._driverAgentsKey = newKey;
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
620
638
|
// Don't rebuild while the driver is busy — pending interactions and the
|
|
621
639
|
// in-flight tool loop reference the captured agents array. The swap is
|
|
622
640
|
// re-attempted from the `state` setter on the loading→idle transition.
|
|
@@ -624,6 +642,12 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
624
642
|
// the new agents, so the deferred re-attempt still sees the mismatch.
|
|
625
643
|
if (this.driver.isBusy())
|
|
626
644
|
return;
|
|
645
|
+
// GENC-1388: likewise never evict a *busy* registry driver. A sibling may be
|
|
646
|
+
// mid-turn on the shared driver even when this element's local ref is a stale
|
|
647
|
+
// idle one; recreating would orphan that in-flight turn. Defer — the swap
|
|
648
|
+
// re-attempts when the turn settles.
|
|
649
|
+
if (registryDriver && registryDriver !== this.driver && registryDriver.isBusy())
|
|
650
|
+
return;
|
|
627
651
|
const history = (_c = (_b = (_a = this.driver).getRawHistory) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : [];
|
|
628
652
|
const oldDriver = this.driver;
|
|
629
653
|
this.unwireDriver();
|
|
@@ -641,7 +665,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
641
665
|
if (this.flowOwnerAgentName !== null) {
|
|
642
666
|
this.flowOwnerAgentName = null;
|
|
643
667
|
}
|
|
644
|
-
this.driver = getOrCreateDriver(key, () => this.createDriver());
|
|
668
|
+
this.driver = getOrCreateDriver(key, newKey, () => this.createDriver());
|
|
645
669
|
this.wireDriver();
|
|
646
670
|
if (history.length)
|
|
647
671
|
this.driver.loadHistory([...history]);
|
|
@@ -750,6 +774,17 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
750
774
|
this.messages = [...e.detail];
|
|
751
775
|
};
|
|
752
776
|
driver.addEventListener('history-updated', onHistoryUpdated);
|
|
777
|
+
// Re-seed the rendered list from the driver's current history. `wireDriver`
|
|
778
|
+
// runs on (re)connect, popin, and when adopting a sibling's driver
|
|
779
|
+
// (GENC-1388); in those cases `messages` would otherwise stay stale until the
|
|
780
|
+
// next `history-updated` fires. A turn that completed while this element was
|
|
781
|
+
// detached (its summary already committed to history) would then never
|
|
782
|
+
// render. The listener above keeps it live thereafter. The rebuild path
|
|
783
|
+
// wires the fresh (empty) driver then calls `loadHistory`, which re-emits and
|
|
784
|
+
// overwrites this seed — so this is safe there too.
|
|
785
|
+
if (driver.getRawHistory) {
|
|
786
|
+
this.messages = [...driver.getRawHistory()];
|
|
787
|
+
}
|
|
753
788
|
const onSubAgentHistoryUpdated = (e) => {
|
|
754
789
|
const { agentName, history } = e.detail;
|
|
755
790
|
this.liveSubAgentName = agentName;
|
|
@@ -909,8 +944,8 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
909
944
|
}
|
|
910
945
|
}
|
|
911
946
|
const driverExisted = !!getDriver(key);
|
|
912
|
-
this.driver = getOrCreateDriver(key, () => this.createDriver());
|
|
913
947
|
this._driverAgentsKey = this.getAgentsKey(this.agents);
|
|
948
|
+
this.driver = getOrCreateDriver(key, this._driverAgentsKey, () => this.createDriver());
|
|
914
949
|
this.wireDriver();
|
|
915
950
|
if (this.popoutMode === 'expand') {
|
|
916
951
|
// Dual-listener guard: when the assistant is popped out into the layout
|
|
@@ -1,40 +1,42 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Module-level registry of AI drivers keyed by session identity string.
|
|
3
|
-
*
|
|
4
|
-
* Driver lifetime is tied to the conversation session, not the DOM.
|
|
5
|
-
* Components look up or create drivers on connect and only unwire
|
|
6
|
-
* event listeners on disconnect — the driver is never destroyed by
|
|
7
|
-
* a lifecycle event.
|
|
8
|
-
*
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
1
|
const driverRegistry = new Map();
|
|
12
2
|
/**
|
|
13
|
-
* Returns the existing driver for the given key, or calls the factory
|
|
14
|
-
*
|
|
3
|
+
* Returns the existing driver for the given key, or calls the factory to create
|
|
4
|
+
* and register a new one. `agentsKey` is the fingerprint of the agents the
|
|
5
|
+
* driver is being built for; it is recorded only when a driver is created (a
|
|
6
|
+
* reused driver keeps the fingerprint it was originally built with).
|
|
15
7
|
*/
|
|
16
|
-
export function getOrCreateDriver(key, factory) {
|
|
8
|
+
export function getOrCreateDriver(key, agentsKey, factory) {
|
|
17
9
|
const existing = driverRegistry.get(key);
|
|
18
10
|
if (existing)
|
|
19
|
-
return existing;
|
|
11
|
+
return existing.driver;
|
|
20
12
|
const driver = factory();
|
|
21
|
-
driverRegistry.set(key, driver);
|
|
13
|
+
driverRegistry.set(key, { driver, agentsKey });
|
|
22
14
|
return driver;
|
|
23
15
|
}
|
|
24
16
|
/**
|
|
25
17
|
* Returns the existing driver for the given key, or `undefined`.
|
|
26
18
|
*/
|
|
27
19
|
export function getDriver(key) {
|
|
28
|
-
|
|
20
|
+
var _a;
|
|
21
|
+
return (_a = driverRegistry.get(key)) === null || _a === void 0 ? void 0 : _a.driver;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* The agents fingerprint the registry driver for `key` was built with, or
|
|
25
|
+
* `undefined` if no driver is registered. Used by `agentsChanged` to decide
|
|
26
|
+
* whether a sibling has already rebuilt the shared driver to the desired agents.
|
|
27
|
+
*/
|
|
28
|
+
export function getDriverAgentsKey(key) {
|
|
29
|
+
var _a;
|
|
30
|
+
return (_a = driverRegistry.get(key)) === null || _a === void 0 ? void 0 : _a.agentsKey;
|
|
29
31
|
}
|
|
30
32
|
/**
|
|
31
33
|
* Removes and returns the driver for the given key.
|
|
32
34
|
* Used when agents change (driver must be rebuilt) or on explicit session teardown.
|
|
33
35
|
*/
|
|
34
36
|
export function deleteDriver(key) {
|
|
35
|
-
const
|
|
37
|
+
const entry = driverRegistry.get(key);
|
|
36
38
|
driverRegistry.delete(key);
|
|
37
|
-
return driver;
|
|
39
|
+
return entry === null || entry === void 0 ? void 0 : entry.driver;
|
|
38
40
|
}
|
|
39
41
|
/**
|
|
40
42
|
* Removes all entries. Exposed for test isolation only — not part of the public API.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
2
|
+
import { clearDriverRegistry, deleteDriver, getDriver, getDriverAgentsKey, getOrCreateDriver, } from './driver-registry';
|
|
3
|
+
// Minimal stub — the registry only stores and returns the reference; it never
|
|
4
|
+
// invokes driver methods, so an opaque object is sufficient.
|
|
5
|
+
const stub = (id) => ({ id });
|
|
6
|
+
const suite = createLogicSuite('driver-registry agents-key tracking');
|
|
7
|
+
suite('getOrCreateDriver creates once and records the agents key', () => {
|
|
8
|
+
clearDriverRegistry();
|
|
9
|
+
const d = stub('a');
|
|
10
|
+
const created = getOrCreateDriver('k', 'agentsKeyA', () => d);
|
|
11
|
+
assert.is(created, d);
|
|
12
|
+
assert.is(getDriver('k'), d);
|
|
13
|
+
assert.is(getDriverAgentsKey('k'), 'agentsKeyA');
|
|
14
|
+
});
|
|
15
|
+
suite('reuse returns the existing driver and keeps its original agents key', () => {
|
|
16
|
+
clearDriverRegistry();
|
|
17
|
+
const first = stub('first');
|
|
18
|
+
getOrCreateDriver('k', 'agentsKeyA', () => first);
|
|
19
|
+
// A second component sharing the key, even with a different desired agents
|
|
20
|
+
// fingerprint, must NOT replace the driver or overwrite the recorded key.
|
|
21
|
+
let factoryCalled = false;
|
|
22
|
+
const reused = getOrCreateDriver('k', 'agentsKeyB', () => {
|
|
23
|
+
factoryCalled = true;
|
|
24
|
+
return stub('second');
|
|
25
|
+
});
|
|
26
|
+
assert.is(reused, first);
|
|
27
|
+
assert.is(factoryCalled, false);
|
|
28
|
+
assert.is(getDriverAgentsKey('k'), 'agentsKeyA');
|
|
29
|
+
});
|
|
30
|
+
suite('deleteDriver clears both the driver and its recorded agents key', () => {
|
|
31
|
+
clearDriverRegistry();
|
|
32
|
+
getOrCreateDriver('k', 'agentsKeyA', () => stub('a'));
|
|
33
|
+
deleteDriver('k');
|
|
34
|
+
assert.is(getDriver('k'), undefined);
|
|
35
|
+
assert.is(getDriverAgentsKey('k'), undefined);
|
|
36
|
+
});
|
|
37
|
+
suite('a rebuild under the same key records the new agents key (the adopt signal)', () => {
|
|
38
|
+
clearDriverRegistry();
|
|
39
|
+
// Initial driver, built for the old agent set.
|
|
40
|
+
getOrCreateDriver('k', 'old', () => stub('d-old'));
|
|
41
|
+
// Rebuild: the host deletes then recreates with the new fingerprint.
|
|
42
|
+
deleteDriver('k');
|
|
43
|
+
const rebuilt = stub('d-new');
|
|
44
|
+
getOrCreateDriver('k', 'new', () => rebuilt);
|
|
45
|
+
// GENC-1388: a sibling sharing the key can now detect that the registry driver
|
|
46
|
+
// already matches its desired agents and adopt `rebuilt`, rather than
|
|
47
|
+
// recreating (which would orphan a driver mid-turn).
|
|
48
|
+
assert.is(getDriver('k'), rebuilt);
|
|
49
|
+
assert.is(getDriverAgentsKey('k'), 'new');
|
|
50
|
+
});
|
|
51
|
+
suite('getDriverAgentsKey is undefined for an unknown key', () => {
|
|
52
|
+
clearDriverRegistry();
|
|
53
|
+
assert.is(getDriverAgentsKey('missing'), undefined);
|
|
54
|
+
});
|
|
55
|
+
suite.run();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.ts","../src/components/ai-driver/ai-driver.ts","../src/components/ai-driver/index.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/components/orchestrating-driver/index.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/styles/index.ts","../src/styles/styles.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.ts","../src/utils/index.ts","../src/utils/logger.ts","../src/utils/message-partition.test.ts","../src/utils/message-partition.ts","../src/utils/strip-agent-handlers.test.ts","../src/utils/strip-agent-handlers.ts","../src/utils/sum-costs.test.ts","../src/utils/sum-costs.ts","../src/utils/tool-fold.ts"],"version":"5.9.2"}
|
|
1
|
+
{"root":["../src/index.ts","../src/channel/ai-activity-bus.ts","../src/channel/ai-activity-channel.ts","../src/components/flowing-waves-indicator.ts","../src/components/halo-overlay.ts","../src/components/plasma-orb-indicator.ts","../src/components/waves-indicator.ts","../src/components/activity-halo/activity-halo.ts","../src/components/agent-picker/agent-picker.constants.ts","../src/components/agent-picker/agent-picker.styles.ts","../src/components/agent-picker/agent-picker.template.ts","../src/components/agent-picker/agent-picker.ts","../src/components/agent-picker/index.ts","../src/components/ai-driver/ai-driver.ts","../src/components/ai-driver/index.ts","../src/components/chat-bubble/chat-bubble.styles.ts","../src/components/chat-bubble/chat-bubble.template.ts","../src/components/chat-bubble/chat-bubble.ts","../src/components/chat-bubble/index.ts","../src/components/chat-driver/align-event-globals.ts","../src/components/chat-driver/chat-driver.test.ts","../src/components/chat-driver/chat-driver.ts","../src/components/chat-driver/index.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.styles.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.template.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.test.ts","../src/components/chat-interaction-wrapper/chat-interaction-wrapper.ts","../src/components/chat-interaction-wrapper/index.ts","../src/components/chat-markdown/chat-markdown.ts","../src/components/chat-markdown/index.ts","../src/components/orchestrating-driver/index.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/config/config.ts","../src/config/define-stateful-agent.test.ts","../src/config/define-stateful-agent.ts","../src/config/fallback-agents.ts","../src/config/index.ts","../src/config/validate-providers.test.ts","../src/config/validate-providers.ts","../src/main/index.ts","../src/main/main.styles.ts","../src/main/main.template.ts","../src/main/main.ts","../src/main/main.types.ts","../src/state/ai-assistant-slice.ts","../src/state/debug-event-log.test.ts","../src/state/debug-event-log.ts","../src/state/driver-registry.test.ts","../src/state/driver-registry.ts","../src/state/session-store.ts","../src/styles/ai-colours.ts","../src/styles/index.ts","../src/styles/styles.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.ts","../src/utils/index.ts","../src/utils/logger.ts","../src/utils/message-partition.test.ts","../src/utils/message-partition.ts","../src/utils/strip-agent-handlers.test.ts","../src/utils/strip-agent-handlers.ts","../src/utils/sum-costs.test.ts","../src/utils/sum-costs.ts","../src/utils/tool-fold.ts"],"version":"5.9.2"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@genesislcap/ai-assistant",
|
|
3
3
|
"description": "Genesis AI Assistant micro-frontend",
|
|
4
|
-
"version": "14.
|
|
4
|
+
"version": "14.473.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -64,24 +64,24 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
|
-
"@genesislcap/foundation-testing": "14.
|
|
68
|
-
"@genesislcap/genx": "14.
|
|
69
|
-
"@genesislcap/rollup-builder": "14.
|
|
70
|
-
"@genesislcap/ts-builder": "14.
|
|
71
|
-
"@genesislcap/uvu-playwright-builder": "14.
|
|
72
|
-
"@genesislcap/vite-builder": "14.
|
|
73
|
-
"@genesislcap/webpack-builder": "14.
|
|
67
|
+
"@genesislcap/foundation-testing": "14.473.0",
|
|
68
|
+
"@genesislcap/genx": "14.473.0",
|
|
69
|
+
"@genesislcap/rollup-builder": "14.473.0",
|
|
70
|
+
"@genesislcap/ts-builder": "14.473.0",
|
|
71
|
+
"@genesislcap/uvu-playwright-builder": "14.473.0",
|
|
72
|
+
"@genesislcap/vite-builder": "14.473.0",
|
|
73
|
+
"@genesislcap/webpack-builder": "14.473.0",
|
|
74
74
|
"@types/dompurify": "^3.0.5",
|
|
75
75
|
"@types/marked": "^5.0.2"
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@genesislcap/foundation-ai": "14.
|
|
79
|
-
"@genesislcap/foundation-logger": "14.
|
|
80
|
-
"@genesislcap/foundation-redux": "14.
|
|
81
|
-
"@genesislcap/foundation-ui": "14.
|
|
82
|
-
"@genesislcap/foundation-utils": "14.
|
|
83
|
-
"@genesislcap/rapid-design-system": "14.
|
|
84
|
-
"@genesislcap/web-core": "14.
|
|
78
|
+
"@genesislcap/foundation-ai": "14.473.0",
|
|
79
|
+
"@genesislcap/foundation-logger": "14.473.0",
|
|
80
|
+
"@genesislcap/foundation-redux": "14.473.0",
|
|
81
|
+
"@genesislcap/foundation-ui": "14.473.0",
|
|
82
|
+
"@genesislcap/foundation-utils": "14.473.0",
|
|
83
|
+
"@genesislcap/rapid-design-system": "14.473.0",
|
|
84
|
+
"@genesislcap/web-core": "14.473.0",
|
|
85
85
|
"dompurify": "^3.3.1",
|
|
86
86
|
"marked": "^17.0.3"
|
|
87
87
|
},
|
|
@@ -93,5 +93,5 @@
|
|
|
93
93
|
"publishConfig": {
|
|
94
94
|
"access": "public"
|
|
95
95
|
},
|
|
96
|
-
"gitHead": "
|
|
96
|
+
"gitHead": "2408f54cd71e4fe715ab6cbb43b6fd16ec2b733e"
|
|
97
97
|
}
|
package/src/main/main.ts
CHANGED
|
@@ -59,7 +59,12 @@ import {
|
|
|
59
59
|
DEBUG_LOG_README,
|
|
60
60
|
type MetaEventType,
|
|
61
61
|
} from '../state/debug-event-log';
|
|
62
|
-
import {
|
|
62
|
+
import {
|
|
63
|
+
getOrCreateDriver,
|
|
64
|
+
getDriver,
|
|
65
|
+
getDriverAgentsKey,
|
|
66
|
+
deleteDriver,
|
|
67
|
+
} from '../state/driver-registry';
|
|
63
68
|
import { getSessionStore, hasSessionStore, type SessionStoreReturn } from '../state/session-store';
|
|
64
69
|
import {
|
|
65
70
|
AI_COLOUR_AMBER,
|
|
@@ -718,12 +723,37 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
718
723
|
// destroy pending interactions in the existing driver.
|
|
719
724
|
const newKey = this.getAgentsKey(this.agents);
|
|
720
725
|
if (newKey === this._driverAgentsKey) return;
|
|
726
|
+
// GENC-1388: a sibling component sharing this session key (e.g. the popped-out
|
|
727
|
+
// panel and the docked standalone, both keyed off one stateKey) may have
|
|
728
|
+
// already rebuilt the shared registry driver to this exact agent set. Adopt
|
|
729
|
+
// it rather than recreating: a rebuild calls deleteDriver + getOrCreateDriver,
|
|
730
|
+
// which evicts the sibling's driver and orphans whichever element is mid-turn
|
|
731
|
+
// on it — a later remount then rebinds to the wrong, idle driver (stuck
|
|
732
|
+
// "Thinking…" / lost end-message). Never adopt away from a busy local driver.
|
|
733
|
+
const registryDriver = getDriver(key);
|
|
734
|
+
if (
|
|
735
|
+
registryDriver &&
|
|
736
|
+
registryDriver !== this.driver &&
|
|
737
|
+
getDriverAgentsKey(key) === newKey &&
|
|
738
|
+
!this.driver.isBusy()
|
|
739
|
+
) {
|
|
740
|
+
this.unwireDriver();
|
|
741
|
+
this.driver = registryDriver;
|
|
742
|
+
this.wireDriver();
|
|
743
|
+
this._driverAgentsKey = newKey;
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
721
746
|
// Don't rebuild while the driver is busy — pending interactions and the
|
|
722
747
|
// in-flight tool loop reference the captured agents array. The swap is
|
|
723
748
|
// re-attempted from the `state` setter on the loading→idle transition.
|
|
724
749
|
// `_driverAgentsKey` is updated only after the rebuild actually installs
|
|
725
750
|
// the new agents, so the deferred re-attempt still sees the mismatch.
|
|
726
751
|
if (this.driver.isBusy()) return;
|
|
752
|
+
// GENC-1388: likewise never evict a *busy* registry driver. A sibling may be
|
|
753
|
+
// mid-turn on the shared driver even when this element's local ref is a stale
|
|
754
|
+
// idle one; recreating would orphan that in-flight turn. Defer — the swap
|
|
755
|
+
// re-attempts when the turn settles.
|
|
756
|
+
if (registryDriver && registryDriver !== this.driver && registryDriver.isBusy()) return;
|
|
727
757
|
const history = this.driver.getRawHistory?.() ?? [];
|
|
728
758
|
const oldDriver = this.driver;
|
|
729
759
|
this.unwireDriver();
|
|
@@ -741,7 +771,7 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
741
771
|
if (this.flowOwnerAgentName !== null) {
|
|
742
772
|
this.flowOwnerAgentName = null;
|
|
743
773
|
}
|
|
744
|
-
this.driver = getOrCreateDriver(key, () => this.createDriver());
|
|
774
|
+
this.driver = getOrCreateDriver(key, newKey, () => this.createDriver());
|
|
745
775
|
this.wireDriver();
|
|
746
776
|
if (history.length) this.driver.loadHistory([...history]);
|
|
747
777
|
this._driverAgentsKey = newKey;
|
|
@@ -863,6 +893,18 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
863
893
|
};
|
|
864
894
|
driver.addEventListener('history-updated', onHistoryUpdated);
|
|
865
895
|
|
|
896
|
+
// Re-seed the rendered list from the driver's current history. `wireDriver`
|
|
897
|
+
// runs on (re)connect, popin, and when adopting a sibling's driver
|
|
898
|
+
// (GENC-1388); in those cases `messages` would otherwise stay stale until the
|
|
899
|
+
// next `history-updated` fires. A turn that completed while this element was
|
|
900
|
+
// detached (its summary already committed to history) would then never
|
|
901
|
+
// render. The listener above keeps it live thereafter. The rebuild path
|
|
902
|
+
// wires the fresh (empty) driver then calls `loadHistory`, which re-emits and
|
|
903
|
+
// overwrites this seed — so this is safe there too.
|
|
904
|
+
if (driver.getRawHistory) {
|
|
905
|
+
this.messages = [...driver.getRawHistory()];
|
|
906
|
+
}
|
|
907
|
+
|
|
866
908
|
const onSubAgentHistoryUpdated = (e: Event) => {
|
|
867
909
|
const { agentName, history } = (e as CustomEvent).detail;
|
|
868
910
|
this.liveSubAgentName = agentName;
|
|
@@ -1034,8 +1076,8 @@ export class FoundationAiAssistant extends GenesisElement {
|
|
|
1034
1076
|
}
|
|
1035
1077
|
|
|
1036
1078
|
const driverExisted = !!getDriver(key);
|
|
1037
|
-
this.driver = getOrCreateDriver(key, () => this.createDriver());
|
|
1038
1079
|
this._driverAgentsKey = this.getAgentsKey(this.agents);
|
|
1080
|
+
this.driver = getOrCreateDriver(key, this._driverAgentsKey, () => this.createDriver());
|
|
1039
1081
|
this.wireDriver();
|
|
1040
1082
|
|
|
1041
1083
|
if (this.popoutMode === 'expand') {
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { assert, createLogicSuite } from '@genesislcap/foundation-testing';
|
|
2
|
+
import type { AiDriver } from '../components/ai-driver/ai-driver';
|
|
3
|
+
import {
|
|
4
|
+
clearDriverRegistry,
|
|
5
|
+
deleteDriver,
|
|
6
|
+
getDriver,
|
|
7
|
+
getDriverAgentsKey,
|
|
8
|
+
getOrCreateDriver,
|
|
9
|
+
} from './driver-registry';
|
|
10
|
+
|
|
11
|
+
// Minimal stub — the registry only stores and returns the reference; it never
|
|
12
|
+
// invokes driver methods, so an opaque object is sufficient.
|
|
13
|
+
const stub = (id: string): AiDriver => ({ id }) as unknown as AiDriver;
|
|
14
|
+
|
|
15
|
+
const suite = createLogicSuite('driver-registry agents-key tracking');
|
|
16
|
+
|
|
17
|
+
suite('getOrCreateDriver creates once and records the agents key', () => {
|
|
18
|
+
clearDriverRegistry();
|
|
19
|
+
const d = stub('a');
|
|
20
|
+
const created = getOrCreateDriver('k', 'agentsKeyA', () => d);
|
|
21
|
+
assert.is(created, d);
|
|
22
|
+
assert.is(getDriver('k'), d);
|
|
23
|
+
assert.is(getDriverAgentsKey('k'), 'agentsKeyA');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
suite('reuse returns the existing driver and keeps its original agents key', () => {
|
|
27
|
+
clearDriverRegistry();
|
|
28
|
+
const first = stub('first');
|
|
29
|
+
getOrCreateDriver('k', 'agentsKeyA', () => first);
|
|
30
|
+
// A second component sharing the key, even with a different desired agents
|
|
31
|
+
// fingerprint, must NOT replace the driver or overwrite the recorded key.
|
|
32
|
+
let factoryCalled = false;
|
|
33
|
+
const reused = getOrCreateDriver('k', 'agentsKeyB', () => {
|
|
34
|
+
factoryCalled = true;
|
|
35
|
+
return stub('second');
|
|
36
|
+
});
|
|
37
|
+
assert.is(reused, first);
|
|
38
|
+
assert.is(factoryCalled, false);
|
|
39
|
+
assert.is(getDriverAgentsKey('k'), 'agentsKeyA');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
suite('deleteDriver clears both the driver and its recorded agents key', () => {
|
|
43
|
+
clearDriverRegistry();
|
|
44
|
+
getOrCreateDriver('k', 'agentsKeyA', () => stub('a'));
|
|
45
|
+
deleteDriver('k');
|
|
46
|
+
assert.is(getDriver('k'), undefined);
|
|
47
|
+
assert.is(getDriverAgentsKey('k'), undefined);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
suite('a rebuild under the same key records the new agents key (the adopt signal)', () => {
|
|
51
|
+
clearDriverRegistry();
|
|
52
|
+
// Initial driver, built for the old agent set.
|
|
53
|
+
getOrCreateDriver('k', 'old', () => stub('d-old'));
|
|
54
|
+
// Rebuild: the host deletes then recreates with the new fingerprint.
|
|
55
|
+
deleteDriver('k');
|
|
56
|
+
const rebuilt = stub('d-new');
|
|
57
|
+
getOrCreateDriver('k', 'new', () => rebuilt);
|
|
58
|
+
// GENC-1388: a sibling sharing the key can now detect that the registry driver
|
|
59
|
+
// already matches its desired agents and adopt `rebuilt`, rather than
|
|
60
|
+
// recreating (which would orphan a driver mid-turn).
|
|
61
|
+
assert.is(getDriver('k'), rebuilt);
|
|
62
|
+
assert.is(getDriverAgentsKey('k'), 'new');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
suite('getDriverAgentsKey is undefined for an unknown key', () => {
|
|
66
|
+
clearDriverRegistry();
|
|
67
|
+
assert.is(getDriverAgentsKey('missing'), undefined);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
suite.run();
|
|
@@ -10,17 +10,36 @@ import type { AiDriver } from '../components/ai-driver/ai-driver';
|
|
|
10
10
|
*
|
|
11
11
|
* @internal
|
|
12
12
|
*/
|
|
13
|
-
|
|
13
|
+
interface DriverRegistryEntry {
|
|
14
|
+
driver: AiDriver;
|
|
15
|
+
/**
|
|
16
|
+
* Fingerprint (see `FoundationAiAssistant.getAgentsKey`) of the agents array
|
|
17
|
+
* the driver was built for. Lets a second component sharing the same session
|
|
18
|
+
* key recognise that the registry driver already matches its desired agents
|
|
19
|
+
* and ADOPT it, instead of tearing it down and recreating — which would evict
|
|
20
|
+
* the sibling's driver and orphan whichever element is mid-turn on it
|
|
21
|
+
* (GENC-1388).
|
|
22
|
+
*/
|
|
23
|
+
agentsKey: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const driverRegistry = new Map<string, DriverRegistryEntry>();
|
|
14
27
|
|
|
15
28
|
/**
|
|
16
|
-
* Returns the existing driver for the given key, or calls the factory
|
|
17
|
-
*
|
|
29
|
+
* Returns the existing driver for the given key, or calls the factory to create
|
|
30
|
+
* and register a new one. `agentsKey` is the fingerprint of the agents the
|
|
31
|
+
* driver is being built for; it is recorded only when a driver is created (a
|
|
32
|
+
* reused driver keeps the fingerprint it was originally built with).
|
|
18
33
|
*/
|
|
19
|
-
export function getOrCreateDriver(
|
|
34
|
+
export function getOrCreateDriver(
|
|
35
|
+
key: string,
|
|
36
|
+
agentsKey: string,
|
|
37
|
+
factory: () => AiDriver,
|
|
38
|
+
): AiDriver {
|
|
20
39
|
const existing = driverRegistry.get(key);
|
|
21
|
-
if (existing) return existing;
|
|
40
|
+
if (existing) return existing.driver;
|
|
22
41
|
const driver = factory();
|
|
23
|
-
driverRegistry.set(key, driver);
|
|
42
|
+
driverRegistry.set(key, { driver, agentsKey });
|
|
24
43
|
return driver;
|
|
25
44
|
}
|
|
26
45
|
|
|
@@ -28,7 +47,16 @@ export function getOrCreateDriver(key: string, factory: () => AiDriver): AiDrive
|
|
|
28
47
|
* Returns the existing driver for the given key, or `undefined`.
|
|
29
48
|
*/
|
|
30
49
|
export function getDriver(key: string): AiDriver | undefined {
|
|
31
|
-
return driverRegistry.get(key);
|
|
50
|
+
return driverRegistry.get(key)?.driver;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* The agents fingerprint the registry driver for `key` was built with, or
|
|
55
|
+
* `undefined` if no driver is registered. Used by `agentsChanged` to decide
|
|
56
|
+
* whether a sibling has already rebuilt the shared driver to the desired agents.
|
|
57
|
+
*/
|
|
58
|
+
export function getDriverAgentsKey(key: string): string | undefined {
|
|
59
|
+
return driverRegistry.get(key)?.agentsKey;
|
|
32
60
|
}
|
|
33
61
|
|
|
34
62
|
/**
|
|
@@ -36,9 +64,9 @@ export function getDriver(key: string): AiDriver | undefined {
|
|
|
36
64
|
* Used when agents change (driver must be rebuilt) or on explicit session teardown.
|
|
37
65
|
*/
|
|
38
66
|
export function deleteDriver(key: string): AiDriver | undefined {
|
|
39
|
-
const
|
|
67
|
+
const entry = driverRegistry.get(key);
|
|
40
68
|
driverRegistry.delete(key);
|
|
41
|
-
return driver;
|
|
69
|
+
return entry?.driver;
|
|
42
70
|
}
|
|
43
71
|
|
|
44
72
|
/**
|