@genesislcap/ai-assistant 14.498.0 → 14.499.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 +132 -0
- package/dist/ai-assistant.d.ts +35 -0
- package/dist/chat-driver.cjs +157 -0
- package/dist/chat-driver.cjs.map +3 -3
- package/dist/chat-driver.mjs +151 -0
- package/dist/chat-driver.mjs.map +3 -3
- package/dist/custom-elements.json +156 -1
- package/dist/dts/chat-driver-node.d.ts +7 -1
- package/dist/dts/chat-driver-node.d.ts.map +1 -1
- package/dist/dts/components/ai-driver/ai-driver.d.ts +8 -0
- package/dist/dts/components/ai-driver/ai-driver.d.ts.map +1 -1
- package/dist/dts/components/chat-driver/chat-driver.d.ts +27 -0
- package/dist/dts/components/chat-driver/chat-driver.d.ts.map +1 -1
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts +3 -0
- package/dist/dts/components/orchestrating-driver/orchestrating-driver.d.ts.map +1 -1
- package/dist/dts/main/main.d.ts.map +1 -1
- package/dist/dts/state/debug-event-log.d.ts +1 -1
- package/dist/dts/state/debug-event-log.d.ts.map +1 -1
- package/dist/dts/state/persistence/build-timeline-entries.d.ts +37 -0
- package/dist/dts/state/persistence/build-timeline-entries.d.ts.map +1 -0
- package/dist/esm/chat-driver-node.js +16 -1
- package/dist/esm/components/chat-driver/chat-driver.js +103 -0
- package/dist/esm/components/chat-driver/chat-driver.test.js +165 -0
- package/dist/esm/components/orchestrating-driver/orchestrating-driver.js +4 -0
- package/dist/esm/main/main.js +18 -28
- package/dist/esm/state/debug-event-log.js +1 -0
- package/dist/esm/state/persistence/build-timeline-entries.js +46 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +17 -17
- package/src/chat-driver-node.ts +20 -0
- package/src/components/ai-driver/ai-driver.ts +9 -0
- package/src/components/chat-driver/chat-driver.test.ts +215 -0
- package/src/components/chat-driver/chat-driver.ts +109 -0
- package/src/components/orchestrating-driver/orchestrating-driver.ts +6 -0
- package/src/main/main.ts +17 -30
- package/src/state/debug-event-log.ts +3 -0
- package/src/state/persistence/build-timeline-entries.ts +66 -0
|
@@ -179,6 +179,23 @@ export class ChatDriver extends EventTarget {
|
|
|
179
179
|
* arrive. See {@link TurnSnapshot} for the captured shape.
|
|
180
180
|
*/
|
|
181
181
|
this.turnSnapshots = [];
|
|
182
|
+
/**
|
|
183
|
+
* `turn` + `message` diagnostic-log entries harvested from an out-of-band source (a resolved
|
|
184
|
+
* interaction whose widget returned `InteractionResult.diagnostics` — e.g. a server-side
|
|
185
|
+
* ChatDriver's debug log). `event` entries are NOT kept here — they're folded into the session's
|
|
186
|
+
* meta-event registry via `mergeMetaEvents` (see `resolveInteraction`) so they inherit fresh host
|
|
187
|
+
* indices, and reach the log through `getMetaEvents`. Append-only; the host folds these into its
|
|
188
|
+
* debug log alongside this driver's own timeline. Not cleared here — it lives with the driver
|
|
189
|
+
* instance, like `turnSnapshots`, so a new chat (fresh driver) starts empty while a compaction
|
|
190
|
+
* (same instance) keeps it. (GENC-1461.)
|
|
191
|
+
*/
|
|
192
|
+
this.externalDiagnostics = [];
|
|
193
|
+
/**
|
|
194
|
+
* Monotonic count of external-diagnostics batches harvested this driver-lifetime. Namespaces each
|
|
195
|
+
* batch's re-keyed `turn` entries so distinct server generations in one chat session can't collide
|
|
196
|
+
* on `turnIndex` in the forward-capture persister (which dedups turns by that key). (GENC-1461.)
|
|
197
|
+
*/
|
|
198
|
+
this.externalDiagnosticsBatches = 0;
|
|
182
199
|
/** Monotonic counter that survives agent swaps — useful for cross-referencing with history. */
|
|
183
200
|
this.globalTurnIndex = 0;
|
|
184
201
|
/**
|
|
@@ -606,6 +623,17 @@ export class ChatDriver extends EventTarget {
|
|
|
606
623
|
getTurnSnapshots() {
|
|
607
624
|
return this.turnSnapshots;
|
|
608
625
|
}
|
|
626
|
+
/**
|
|
627
|
+
* The `turn` + `message` diagnostic-log entries harvested from resolved interactions'
|
|
628
|
+
* `InteractionResult.diagnostics` (e.g. a server-side ChatDriver's collated debug log). The host
|
|
629
|
+
* concatenates these into its own debug log so `downloadDebugLog`/the persisted diagnostics stream
|
|
630
|
+
* include external-engine logs; `event` entries are excluded here because they're merged into the
|
|
631
|
+
* session's meta-event registry instead (see `resolveInteraction`) and reach the log via
|
|
632
|
+
* `getMetaEvents`. Opaque, chronologically sorted by the host at assemble time. (GENC-1461.)
|
|
633
|
+
*/
|
|
634
|
+
getExternalDiagnostics() {
|
|
635
|
+
return this.externalDiagnostics;
|
|
636
|
+
}
|
|
609
637
|
/**
|
|
610
638
|
* Merge a sub-agent's turn snapshots into this driver's buffer so they surface
|
|
611
639
|
* as `kind:'turn'` entries in the exported debug log. The child runs as a
|
|
@@ -988,6 +1016,81 @@ export class ChatDriver extends EventTarget {
|
|
|
988
1016
|
// timeout (and a timeout firing here clears its own already-fired handle).
|
|
989
1017
|
if (interaction.timeoutHandle)
|
|
990
1018
|
clearTimeout(interaction.timeoutHandle);
|
|
1019
|
+
// Harvest any out-of-band diagnostic entries the widget collated (e.g. from a server-side
|
|
1020
|
+
// ChatDriver) so the host's debug log + persisted diagnostics include them. Independent of the
|
|
1021
|
+
// message `idx` below — they describe the widget's own work, not this message.
|
|
1022
|
+
//
|
|
1023
|
+
// The harvested entries carry the SOURCE engine's own index space (0-based turns/events), which
|
|
1024
|
+
// would collide with this host's cursors in the forward-capture persister — turns dedup by
|
|
1025
|
+
// `turnIndex`, events by an `index` high-water mark — so foreign entries get silently dropped
|
|
1026
|
+
// from the persisted stream. Route each kind through the host's own collision-safe machinery,
|
|
1027
|
+
// mirroring how a sub-agent's log is folded in (see `invokeSubAgent`):
|
|
1028
|
+
// • `event` → `mergeMetaEvents`, which re-indexes them onto this session's monotonic event
|
|
1029
|
+
// counter (clearing the high-water) while preserving their timestamps; they then
|
|
1030
|
+
// reach the log via `getMetaEvents` in `buildTimelineEntries`, not this buffer.
|
|
1031
|
+
// • `turn` → re-key `turnIndex` to the turn's local position within a per-batch namespace,
|
|
1032
|
+
// so turns stay unique even when one interaction folds in several independent
|
|
1033
|
+
// server runs that each number their own turns from 0 (a consolidator carries a
|
|
1034
|
+
// consolidator-code run AND a table-code run), and never collide with the host's
|
|
1035
|
+
// own bare-integer turn keys.
|
|
1036
|
+
// • `message` → kept as-is; the persister already keys messages by content, so they survive.
|
|
1037
|
+
// TODO(GENC-1461, option 2 / streaming): expose an imperative `appendDiagnostics(entries)` on
|
|
1038
|
+
// the handler context (see buildHandlerContext) that runs this same decomposition as SSE ticks
|
|
1039
|
+
// arrive, so a streaming widget can surface its external engine's log live rather than only at
|
|
1040
|
+
// resolve time. Batch-at-resolve (here) is the current, non-streaming path.
|
|
1041
|
+
const harvestedDiagnostics = result === null || result === void 0 ? void 0 : result.diagnostics;
|
|
1042
|
+
if (Array.isArray(harvestedDiagnostics) && harvestedDiagnostics.length) {
|
|
1043
|
+
const batch = (this.externalDiagnosticsBatches += 1);
|
|
1044
|
+
const externalEvents = [];
|
|
1045
|
+
let turnCount = 0;
|
|
1046
|
+
let messageCount = 0;
|
|
1047
|
+
for (const raw of harvestedDiagnostics) {
|
|
1048
|
+
// The harvest is external and typed `unknown[]`, so an element could be a primitive, null,
|
|
1049
|
+
// or an object without a string `kind`. Guard before reading `.kind` so a malformed entry
|
|
1050
|
+
// can't throw here (and gets skipped rather than derailing the whole fold).
|
|
1051
|
+
if (!raw ||
|
|
1052
|
+
typeof raw !== 'object' ||
|
|
1053
|
+
typeof raw.kind !== 'string') {
|
|
1054
|
+
continue;
|
|
1055
|
+
}
|
|
1056
|
+
const entry = raw;
|
|
1057
|
+
if (entry.kind === 'event') {
|
|
1058
|
+
const { kind: _kind } = entry, event = __rest(entry, ["kind"]);
|
|
1059
|
+
externalEvents.push(event);
|
|
1060
|
+
}
|
|
1061
|
+
else if (entry.kind === 'turn') {
|
|
1062
|
+
// Local position within THIS harvest, not the source engine's own `turnIndex`: one
|
|
1063
|
+
// interaction can carry several independent server runs (a consolidator folds in its
|
|
1064
|
+
// consolidator-code run and its table-code run), each numbering its turns from 0, so
|
|
1065
|
+
// keying by the source index would collide them. The local position keeps every turn key
|
|
1066
|
+
// distinct within the batch, so the persister's per-`turnIndex` dedup keeps them all.
|
|
1067
|
+
this.externalDiagnostics.push(Object.assign(Object.assign({}, entry), { turnIndex: `server-generation.${batch}:${turnCount}` }));
|
|
1068
|
+
turnCount += 1;
|
|
1069
|
+
}
|
|
1070
|
+
else if (entry.kind === 'message') {
|
|
1071
|
+
messageCount += 1;
|
|
1072
|
+
this.externalDiagnostics.push(entry);
|
|
1073
|
+
}
|
|
1074
|
+
// Any other kind is intentionally dropped, not folded. A sibling's `buildTimelineEntries`
|
|
1075
|
+
// only ever emits message/turn/event; `meta-snapshot` is host/DOM-owned (latest-wins on
|
|
1076
|
+
// reassembly, plus its own persister dedup), so folding a foreign one would pollute this
|
|
1077
|
+
// host's timeline and meta cursor. Restricting to the three real kinds also keeps the
|
|
1078
|
+
// manifest counts accurate (nothing miscounted as a `message`).
|
|
1079
|
+
}
|
|
1080
|
+
if (externalEvents.length)
|
|
1081
|
+
mergeMetaEvents(this.sessionKey, externalEvents);
|
|
1082
|
+
// Manifest: one provenance marker for the fold itself — records that an out-of-band engine's
|
|
1083
|
+
// log crossed into this session and how much of each kind, so a regression that silently
|
|
1084
|
+
// drops a generation's diagnostics (e.g. a new path that forgets to thread them across the
|
|
1085
|
+
// boundary) surfaces as a zero/absent manifest rather than only by diffing a download. Also
|
|
1086
|
+
// the natural seed for the streaming PR's open/close bracket. Stamped at resolve, so it
|
|
1087
|
+
// closes the block on the sorted timeline. (GENC-1461.)
|
|
1088
|
+
recordMetaEvent(this.sessionKey, 'external-diagnostics.folded', {
|
|
1089
|
+
interactionId,
|
|
1090
|
+
batch,
|
|
1091
|
+
counts: { turn: turnCount, event: externalEvents.length, message: messageCount },
|
|
1092
|
+
});
|
|
1093
|
+
}
|
|
991
1094
|
const idx = this.history.findIndex((m) => { var _a; return ((_a = m.interaction) === null || _a === void 0 ? void 0 : _a.interactionId) === interactionId; });
|
|
992
1095
|
if (idx !== -1) {
|
|
993
1096
|
// Fold any widget-reported external (non-LLM) cost onto the message, so
|
|
@@ -1069,6 +1069,171 @@ interactionPresentation('presentation is absent when the option is omitted', ()
|
|
|
1069
1069
|
}));
|
|
1070
1070
|
interactionPresentation.run();
|
|
1071
1071
|
// ---------------------------------------------------------------------------
|
|
1072
|
+
// external diagnostics harvest (GENC-1461) — a widget may return an out-of-band
|
|
1073
|
+
// engine's collated debug log on `InteractionResult.diagnostics` (e.g. a
|
|
1074
|
+
// server-side ChatDriver's). Those entries carry the SOURCE engine's own 0-based
|
|
1075
|
+
// index space, which would collide with this host's forward-capture cursors and
|
|
1076
|
+
// be dropped: the persister dedups `turn` entries by `turnIndex` and `event`
|
|
1077
|
+
// entries by an `index` high-water mark. So the driver decomposes the harvest by
|
|
1078
|
+
// kind — events fold into the session's meta-event registry (re-indexed onto the
|
|
1079
|
+
// host's monotonic counter), turns are re-keyed into a per-batch namespace, and
|
|
1080
|
+
// messages pass through unchanged (the persister already keys those by content).
|
|
1081
|
+
// ---------------------------------------------------------------------------
|
|
1082
|
+
const externalDiagnostics = createLogicSuite('ChatDriver external diagnostics harvest');
|
|
1083
|
+
/** A `diagnostics` payload as a headless engine would collate it — one of each kind,
|
|
1084
|
+
* all carrying that engine's own 0-based indices (`turnIndex: '0'`, event `index: 0`). */
|
|
1085
|
+
const harvestPayload = (marker) => [
|
|
1086
|
+
{ kind: 'message', timestamp: '2026-07-23T10:00:00.000Z', role: 'assistant', content: marker },
|
|
1087
|
+
{ kind: 'turn', timestamp: '2026-07-23T10:00:01.000Z', turnIndex: '0', systemPrompt: 'sys' },
|
|
1088
|
+
{
|
|
1089
|
+
kind: 'event',
|
|
1090
|
+
index: 0,
|
|
1091
|
+
timestamp: '2026-07-23T10:00:02.000Z',
|
|
1092
|
+
type: 'turn.error',
|
|
1093
|
+
importance: 'high',
|
|
1094
|
+
detail: { marker },
|
|
1095
|
+
},
|
|
1096
|
+
];
|
|
1097
|
+
externalDiagnostics('routes harvested events to the meta-event registry (re-indexed) and keeps turns + messages', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1098
|
+
var _a, _b;
|
|
1099
|
+
clearMetaEventRegistry();
|
|
1100
|
+
const sessionKey = 'external-diag-harvest';
|
|
1101
|
+
const driver = makeDriver(agent({ name: 'a' }), scriptedProvider([]), sessionKey);
|
|
1102
|
+
// Requesting the interaction records a host `interaction.requested` meta-event, so the
|
|
1103
|
+
// registry's index counter is already advanced when the harvested event is merged — exactly
|
|
1104
|
+
// the condition that made the foreign 0-based `index` lose the persister's high-water race.
|
|
1105
|
+
const pending = driver.requestInteraction('w', {});
|
|
1106
|
+
const { interactionId } = driver.getHistory().at(-1).interaction;
|
|
1107
|
+
const requestedIndex = getMetaEvents(sessionKey).find((e) => e.type === 'interaction.requested').index;
|
|
1108
|
+
driver.resolveInteraction(interactionId, {
|
|
1109
|
+
status: 'approved',
|
|
1110
|
+
diagnostics: harvestPayload('m1'),
|
|
1111
|
+
});
|
|
1112
|
+
yield pending;
|
|
1113
|
+
// The event left the external buffer and landed in the registry, re-indexed ABOVE the host's
|
|
1114
|
+
// prior event (so it beats the persister's `index <= lastEventIndex` high-water), timestamp kept.
|
|
1115
|
+
const external = driver.getExternalDiagnostics();
|
|
1116
|
+
assert.is(external.filter((e) => e.kind === 'event').length, 0, 'events do not stay in the buffer');
|
|
1117
|
+
const merged = getMetaEvents(sessionKey).find((e) => { var _a; return ((_a = e.detail) === null || _a === void 0 ? void 0 : _a.marker) === 'm1'; });
|
|
1118
|
+
assert.ok(merged, 'the harvested event is folded into the session registry');
|
|
1119
|
+
assert.ok(merged.index > requestedIndex, 're-indexed onto the host counter, above prior events');
|
|
1120
|
+
assert.is(merged.timestamp, '2026-07-23T10:00:02.000Z', 'original timestamp preserved for ordering');
|
|
1121
|
+
// The turn is kept in the buffer but re-keyed out of the host's bare-integer turn-key space,
|
|
1122
|
+
// and the message passes through untouched.
|
|
1123
|
+
const turn = external.find((e) => e.kind === 'turn');
|
|
1124
|
+
assert.ok(turn, 'the harvested turn is kept in the external buffer');
|
|
1125
|
+
assert.is(turn.turnIndex, 'server-generation.1:0', 'turnIndex namespaced per batch');
|
|
1126
|
+
const message = external.find((e) => e.kind === 'message');
|
|
1127
|
+
assert.ok(message, 'the harvested message is kept in the external buffer');
|
|
1128
|
+
assert.is(message.content, 'm1', 'message passes through unchanged');
|
|
1129
|
+
// A single manifest event records the fold's provenance — the fragile boundary this feature
|
|
1130
|
+
// guards is now observable: a dropped generation shows up as a zero/absent manifest.
|
|
1131
|
+
const manifest = getMetaEvents(sessionKey).find((e) => e.type === 'external-diagnostics.folded');
|
|
1132
|
+
assert.ok(manifest, 'a manifest meta-event is recorded for the fold');
|
|
1133
|
+
assert.is((_a = manifest.detail) === null || _a === void 0 ? void 0 : _a.interactionId, interactionId);
|
|
1134
|
+
assert.equal((_b = manifest.detail) === null || _b === void 0 ? void 0 : _b.counts, { turn: 1, event: 1, message: 1 });
|
|
1135
|
+
}));
|
|
1136
|
+
externalDiagnostics('namespaces each batch so distinct server generations cannot collide on turnIndex', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1137
|
+
clearMetaEventRegistry();
|
|
1138
|
+
const driver = makeDriver(agent({ name: 'a' }), scriptedProvider([]), 'external-diag-batches');
|
|
1139
|
+
const first = driver.requestInteraction('w', {});
|
|
1140
|
+
const firstId = driver.getHistory().at(-1).interaction.interactionId;
|
|
1141
|
+
driver.resolveInteraction(firstId, { status: 'approved', diagnostics: harvestPayload('a') });
|
|
1142
|
+
yield first;
|
|
1143
|
+
const second = driver.requestInteraction('w', {});
|
|
1144
|
+
const secondId = driver.getHistory().at(-1).interaction.interactionId;
|
|
1145
|
+
driver.resolveInteraction(secondId, { status: 'approved', diagnostics: harvestPayload('b') });
|
|
1146
|
+
yield second;
|
|
1147
|
+
// Both harvests carried `turnIndex: '0'`; the per-batch namespace keeps them distinct, so the
|
|
1148
|
+
// persister's `emittedTurnKeys` can't fold the second generation's turn into the first.
|
|
1149
|
+
const turnKeys = driver
|
|
1150
|
+
.getExternalDiagnostics()
|
|
1151
|
+
.filter((e) => e.kind === 'turn')
|
|
1152
|
+
.map((e) => e.turnIndex);
|
|
1153
|
+
assert.equal(turnKeys, ['server-generation.1:0', 'server-generation.2:0']);
|
|
1154
|
+
}));
|
|
1155
|
+
externalDiagnostics('keys turns by local position so several server runs in one harvest do not collide', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1156
|
+
clearMetaEventRegistry();
|
|
1157
|
+
const driver = makeDriver(agent({ name: 'a' }), scriptedProvider([]), 'external-diag-multirun');
|
|
1158
|
+
// One interaction carrying two independent server runs (e.g. a consolidator's consolidator-code
|
|
1159
|
+
// run and its table-code run) — each numbers its own turns from 0, so the harvest has two
|
|
1160
|
+
// `turnIndex: '0'` entries. Keying by source index would collapse them; local position keeps
|
|
1161
|
+
// both, so the persister's per-turnIndex dedup drops neither.
|
|
1162
|
+
const pending = driver.requestInteraction('w', {});
|
|
1163
|
+
const { interactionId } = driver.getHistory().at(-1).interaction;
|
|
1164
|
+
driver.resolveInteraction(interactionId, {
|
|
1165
|
+
status: 'approved',
|
|
1166
|
+
diagnostics: [
|
|
1167
|
+
{
|
|
1168
|
+
kind: 'turn',
|
|
1169
|
+
timestamp: '2026-07-23T10:00:00.000Z',
|
|
1170
|
+
turnIndex: '0',
|
|
1171
|
+
systemPrompt: 'run1',
|
|
1172
|
+
},
|
|
1173
|
+
{
|
|
1174
|
+
kind: 'turn',
|
|
1175
|
+
timestamp: '2026-07-23T10:00:01.000Z',
|
|
1176
|
+
turnIndex: '1',
|
|
1177
|
+
systemPrompt: 'run1',
|
|
1178
|
+
},
|
|
1179
|
+
{
|
|
1180
|
+
kind: 'turn',
|
|
1181
|
+
timestamp: '2026-07-23T10:00:02.000Z',
|
|
1182
|
+
turnIndex: '0',
|
|
1183
|
+
systemPrompt: 'run2',
|
|
1184
|
+
},
|
|
1185
|
+
],
|
|
1186
|
+
});
|
|
1187
|
+
yield pending;
|
|
1188
|
+
const turnKeys = driver
|
|
1189
|
+
.getExternalDiagnostics()
|
|
1190
|
+
.filter((e) => e.kind === 'turn')
|
|
1191
|
+
.map((e) => e.turnIndex);
|
|
1192
|
+
assert.equal(turnKeys, [
|
|
1193
|
+
'server-generation.1:0',
|
|
1194
|
+
'server-generation.1:1',
|
|
1195
|
+
'server-generation.1:2',
|
|
1196
|
+
]);
|
|
1197
|
+
// All distinct — no key repeats despite the repeated source `turnIndex: '0'`.
|
|
1198
|
+
assert.is(new Set(turnKeys).size, 3, 'every harvested turn gets a distinct key');
|
|
1199
|
+
}));
|
|
1200
|
+
externalDiagnostics('tolerates malformed entries and does not fold or miscount non-standard kinds', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
1201
|
+
var _a;
|
|
1202
|
+
clearMetaEventRegistry();
|
|
1203
|
+
const sessionKey = 'external-diag-malformed';
|
|
1204
|
+
const driver = makeDriver(agent({ name: 'a' }), scriptedProvider([]), sessionKey);
|
|
1205
|
+
const pending = driver.requestInteraction('w', {});
|
|
1206
|
+
const { interactionId } = driver.getHistory().at(-1).interaction;
|
|
1207
|
+
// The harvest is untrusted `unknown[]`: primitives/null and an object without a string `kind`
|
|
1208
|
+
// must be skipped (not throw), and a `meta-snapshot` (host-owned, never emitted by a sibling)
|
|
1209
|
+
// must be dropped rather than folded or miscounted as a message.
|
|
1210
|
+
driver.resolveInteraction(interactionId, {
|
|
1211
|
+
status: 'approved',
|
|
1212
|
+
diagnostics: [
|
|
1213
|
+
null,
|
|
1214
|
+
'oops',
|
|
1215
|
+
42,
|
|
1216
|
+
{ timestamp: '2026-07-23T10:00:00.000Z' }, // no kind
|
|
1217
|
+
{
|
|
1218
|
+
kind: 'message',
|
|
1219
|
+
timestamp: '2026-07-23T10:00:01.000Z',
|
|
1220
|
+
role: 'assistant',
|
|
1221
|
+
content: 'real',
|
|
1222
|
+
},
|
|
1223
|
+
{ kind: 'meta-snapshot', timestamp: '2026-07-23T10:00:02.000Z', meta: { host: 'foreign' } },
|
|
1224
|
+
],
|
|
1225
|
+
});
|
|
1226
|
+
yield pending;
|
|
1227
|
+
// Only the one real message survives the buffer; the meta-snapshot is not folded.
|
|
1228
|
+
const external = driver.getExternalDiagnostics();
|
|
1229
|
+
assert.equal(external.map((e) => e.kind), ['message']);
|
|
1230
|
+
assert.is(external[0].content, 'real');
|
|
1231
|
+
// Manifest counts only the three real kinds — the meta-snapshot is not miscounted as a message.
|
|
1232
|
+
const manifest = getMetaEvents(sessionKey).find((e) => e.type === 'external-diagnostics.folded');
|
|
1233
|
+
assert.equal((_a = manifest.detail) === null || _a === void 0 ? void 0 : _a.counts, { turn: 0, event: 0, message: 1 });
|
|
1234
|
+
}));
|
|
1235
|
+
externalDiagnostics.run();
|
|
1236
|
+
// ---------------------------------------------------------------------------
|
|
1072
1237
|
// interaction context lifecycle (GENC-1390) — the driver creates a live
|
|
1073
1238
|
// InteractionContext on requestInteraction and disposes+drops it on resolve, so
|
|
1074
1239
|
// widget state survives element remounts but never outlives the interaction.
|
|
@@ -188,6 +188,10 @@ export class OrchestratingDriver extends EventTarget {
|
|
|
188
188
|
getTurnSnapshots() {
|
|
189
189
|
return this.chatDriver.getTurnSnapshots();
|
|
190
190
|
}
|
|
191
|
+
/** Delegates to the inner {@link ChatDriver} — interactions resolve there, so it holds the buffer. */
|
|
192
|
+
getExternalDiagnostics() {
|
|
193
|
+
return this.chatDriver.getExternalDiagnostics();
|
|
194
|
+
}
|
|
191
195
|
getSuggestions(history, prompt, count, allAgentInfo) {
|
|
192
196
|
return __awaiter(this, void 0, void 0, function* () {
|
|
193
197
|
// When pinned to a specialist, scope suggestions to that agent so the
|
package/dist/esm/main/main.js
CHANGED
|
@@ -42,6 +42,7 @@ import { AiWavesIndicator } from '../components/waves-indicator';
|
|
|
42
42
|
import { AssistantAppSettingsProvider, } from '../provider/assistant-app-settings';
|
|
43
43
|
import { recordMetaEvent, getMetaEvents, clearSession as clearMetaSession, DEBUG_LOG_README, } from '../state/debug-event-log';
|
|
44
44
|
import { getOrCreateDriver, getDriver, getDriverAgentsKey, deleteDriver, } from '../state/driver-registry';
|
|
45
|
+
import { buildTimelineEntries } from '../state/persistence/build-timeline-entries';
|
|
45
46
|
import { assembleDebugLog } from '../state/persistence/diagnostics';
|
|
46
47
|
import { deleteDiagnosticsCursorsFor, resetDiagnosticsCursorsFor, } from '../state/persistence/diagnostics-cursors';
|
|
47
48
|
import { getOrCreatePersister, getPersister, deletePersister, } from '../state/persistence/persister-registry';
|
|
@@ -55,7 +56,6 @@ import { resolveExclusiveLoadingStyle } from '../utils/animation-exclusivity';
|
|
|
55
56
|
import { collectSessionModels } from '../utils/collect-session-models';
|
|
56
57
|
import { appendCostSessionRecord, clearCostSessionHistory, loadCostSessionHistory, removeCostSessionRecord, } from '../utils/cost-session-history';
|
|
57
58
|
import { deriveCostSessionTitleFromMessages, resolveCostSessionTitle, } from '../utils/derive-cost-session-title';
|
|
58
|
-
import { flattenSubAgentMessages } from '../utils/flatten-sub-agent-messages';
|
|
59
59
|
import { logger } from '../utils/logger';
|
|
60
60
|
import { filterVisibleMessages, trailingInteractionRow } from '../utils/message-partition';
|
|
61
61
|
import { resolveCostHistoryConfig, } from '../utils/resolve-cost-history-config';
|
|
@@ -2399,7 +2399,7 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2399
2399
|
* been appended to the persisted stream.
|
|
2400
2400
|
*/
|
|
2401
2401
|
buildDiagnosticEntries() {
|
|
2402
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
2402
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
2403
2403
|
const timestamp = new Date().toISOString().replace(/:/g, '-');
|
|
2404
2404
|
// Snapshot the live active agent from the DRIVER — the instance whose
|
|
2405
2405
|
// `onActivate` ran, so its `getDebugSnapshot` closure holds state.
|
|
@@ -2417,32 +2417,14 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2417
2417
|
? Math.round((this.contextTokens / this.contextLimit) * 100)
|
|
2418
2418
|
: undefined;
|
|
2419
2419
|
const stateKey = this.getStateKey();
|
|
2420
|
-
//
|
|
2421
|
-
//
|
|
2422
|
-
//
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
let lastFullIndex = '';
|
|
2428
|
-
const turns = ((_f = (_e = (_d = this.driver) === null || _d === void 0 ? void 0 : _d.getTurnSnapshots) === null || _e === void 0 ? void 0 : _e.call(_d)) !== null && _f !== void 0 ? _f : []).map((t) => {
|
|
2429
|
-
let { systemPrompt } = t;
|
|
2430
|
-
if (systemPrompt != null && systemPrompt === lastFullPrompt) {
|
|
2431
|
-
systemPrompt = `<repeated — identical to turn ${lastFullIndex}>`;
|
|
2432
|
-
}
|
|
2433
|
-
else if (systemPrompt != null) {
|
|
2434
|
-
lastFullPrompt = systemPrompt;
|
|
2435
|
-
lastFullIndex = t.turnIndex;
|
|
2436
|
-
}
|
|
2437
|
-
return Object.assign(Object.assign({ kind: 'turn' }, t), { systemPrompt });
|
|
2420
|
+
// The message/turn/event timeline entries — built by the shared, pure `buildTimelineEntries`
|
|
2421
|
+
// (the same helper a headless consumer uses to harvest its own log), from the driver's pull
|
|
2422
|
+
// surfaces. Prefer the driver's raw history (carries sub-agent traces) over the redux projection.
|
|
2423
|
+
const timelineEntries = buildTimelineEntries({
|
|
2424
|
+
turnSnapshots: (_f = (_e = (_d = this.driver) === null || _d === void 0 ? void 0 : _d.getTurnSnapshots) === null || _e === void 0 ? void 0 : _e.call(_d)) !== null && _f !== void 0 ? _f : [],
|
|
2425
|
+
messages: (_j = (_h = (_g = this.driver) === null || _g === void 0 ? void 0 : _g.getRawHistory) === null || _h === void 0 ? void 0 : _h.call(_g)) !== null && _j !== void 0 ? _j : this.messages,
|
|
2426
|
+
metaEvents: stateKey ? getMetaEvents(stateKey) : [],
|
|
2438
2427
|
});
|
|
2439
|
-
// Sub-agent conversations are stored nested on the parent tool call's
|
|
2440
|
-
// `subAgentTrace`; `flattenSubAgentMessages` hoists them to top-level
|
|
2441
|
-
// `kind: 'message'` entries (breadcrumbed + correlated, the nested copy moved
|
|
2442
|
-
// out — not duplicated) so the timeline reads as one chronological sequence.
|
|
2443
|
-
const messages = (_j = (_h = (_g = this.driver) === null || _g === void 0 ? void 0 : _g.getRawHistory) === null || _h === void 0 ? void 0 : _h.call(_g)) !== null && _j !== void 0 ? _j : this.messages;
|
|
2444
|
-
const messageEntries = flattenSubAgentMessages(messages);
|
|
2445
|
-
const eventEntries = (stateKey ? getMetaEvents(stateKey) : []).map((e) => (Object.assign({ kind: 'event' }, e)));
|
|
2446
2428
|
// The export-time `meta` block, carried on a `meta-snapshot` entry so it lives
|
|
2447
2429
|
// in the same forward stream (the latest one wins on reassembly, and the
|
|
2448
2430
|
// accumulated history exposes config/state evolution across the lifetime).
|
|
@@ -2509,7 +2491,15 @@ let FoundationAiAssistant = FoundationAiAssistant_1 = class FoundationAiAssistan
|
|
|
2509
2491
|
activePrimerHistory: m.activePrimerHistory,
|
|
2510
2492
|
activeFoldStack: m.activeFoldStack,
|
|
2511
2493
|
});
|
|
2512
|
-
|
|
2494
|
+
// Fold in any external diagnostics harvested from an out-of-band driver (e.g. a server-side
|
|
2495
|
+
// ChatDriver whose collated log an interaction widget returned on its result). They ride the
|
|
2496
|
+
// same download + persisted-diagnostics path; `assembleDebugLog` sorts the whole timeline by
|
|
2497
|
+
// timestamp so they interleave chronologically. (GENC-1461 unified diagnostics.)
|
|
2498
|
+
return [
|
|
2499
|
+
...timelineEntries,
|
|
2500
|
+
...((_s = (_r = (_q = this.driver) === null || _q === void 0 ? void 0 : _q.getExternalDiagnostics) === null || _r === void 0 ? void 0 : _r.call(_q)) !== null && _s !== void 0 ? _s : []),
|
|
2501
|
+
metaSnapshot,
|
|
2502
|
+
];
|
|
2513
2503
|
}
|
|
2514
2504
|
downloadDebugLog() {
|
|
2515
2505
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -60,6 +60,7 @@ export const META_EVENT_IMPORTANCE = {
|
|
|
60
60
|
'provider.selected': 'normal',
|
|
61
61
|
'interaction.requested': 'normal',
|
|
62
62
|
'interaction.resolved': 'normal',
|
|
63
|
+
'external-diagnostics.folded': 'normal',
|
|
63
64
|
'session.cleared': 'normal',
|
|
64
65
|
'session.switched': 'low',
|
|
65
66
|
'session.switch-deferred': 'low',
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared, pure builder for the debug-log timeline entries (`message` / `turn` / `event`) — the
|
|
3
|
+
* common core of the host element's `buildDiagnosticEntries` and any HEADLESS consumer that drives
|
|
4
|
+
* a `ChatDriver` of its own (e.g. `ai-service` running the engine server-side) and needs to harvest
|
|
5
|
+
* that engine's debug log for the client to fold into its own download / persisted stream
|
|
6
|
+
* (GENC-1461 unified diagnostics). DOM-clean and dependency-light so it works in bare Node.
|
|
7
|
+
*
|
|
8
|
+
* It deliberately excludes the `meta-snapshot` entry: that block is host/DOM-specific (it reads
|
|
9
|
+
* `window.location.host`, the element's agent list, live context/cost), and a merged log keeps only
|
|
10
|
+
* the newest snapshot anyway — a headless source's agent/prompt/tools are already captured in its
|
|
11
|
+
* `turn` entries.
|
|
12
|
+
*
|
|
13
|
+
* @packageDocumentation
|
|
14
|
+
*/
|
|
15
|
+
import { flattenSubAgentMessages } from '../../utils/flatten-sub-agent-messages';
|
|
16
|
+
/**
|
|
17
|
+
* Build the `message` / `turn` / `event` timeline entries from a driver's pull surfaces
|
|
18
|
+
* (`getRawHistory()` / `getTurnSnapshots()` / `getMetaEvents(sessionKey)`). Order within the array
|
|
19
|
+
* is message → turn → event; the caller (`assembleDebugLog`) sorts the whole timeline by timestamp,
|
|
20
|
+
* so this ordering only sets the co-timestamp tie-break. Pure.
|
|
21
|
+
*/
|
|
22
|
+
export function buildTimelineEntries(input) {
|
|
23
|
+
const { turnSnapshots, messages, metaEvents } = input;
|
|
24
|
+
// Collapse a turn's systemPrompt when byte-identical to the previous turn's — a stable agent
|
|
25
|
+
// repeats the same (often multi-KB) prompt every turn, while a stateful agent's changes. The
|
|
26
|
+
// prompt is shown in full whenever it changes, so prompt evolution stays visible.
|
|
27
|
+
let lastFullPrompt;
|
|
28
|
+
let lastFullIndex = '';
|
|
29
|
+
const turns = turnSnapshots.map((t) => {
|
|
30
|
+
let { systemPrompt } = t;
|
|
31
|
+
if (systemPrompt != null && systemPrompt === lastFullPrompt) {
|
|
32
|
+
systemPrompt = `<repeated — identical to turn ${lastFullIndex}>`;
|
|
33
|
+
}
|
|
34
|
+
else if (systemPrompt != null) {
|
|
35
|
+
lastFullPrompt = systemPrompt;
|
|
36
|
+
lastFullIndex = t.turnIndex;
|
|
37
|
+
}
|
|
38
|
+
return Object.assign(Object.assign({ kind: 'turn' }, t), { systemPrompt });
|
|
39
|
+
});
|
|
40
|
+
// Sub-agent conversations are stored nested on the parent tool call's `subAgentTrace`;
|
|
41
|
+
// `flattenSubAgentMessages` hoists them to top-level `kind: 'message'` entries (breadcrumbed +
|
|
42
|
+
// correlated, the nested copy moved out — not duplicated) so the timeline reads chronologically.
|
|
43
|
+
const messageEntries = flattenSubAgentMessages(messages);
|
|
44
|
+
const eventEntries = metaEvents.map((e) => (Object.assign({ kind: 'event' }, e)));
|
|
45
|
+
return [...messageEntries, ...turns, ...eventEntries];
|
|
46
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"root":["../src/chat-driver-node.ts","../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.compact.test.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.pin.test.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.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/main/popout-interaction-gate.test.ts","../src/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.test.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/interaction-context.test.ts","../src/state/interaction-context.ts","../src/state/session-store.ts","../src/state/persistence/diagnostics-cursors.test.ts","../src/state/persistence/diagnostics-cursors.ts","../src/state/persistence/diagnostics.test.ts","../src/state/persistence/diagnostics.ts","../src/state/persistence/index.ts","../src/state/persistence/persister-registry.ts","../src/state/persistence/session-persistence-provider.test.ts","../src/state/persistence/session-persistence-provider.ts","../src/state/persistence/session-persistence.integration.test.ts","../src/state/persistence/session-persister.test.ts","../src/state/persistence/session-persister.ts","../src/state/persistence/session-snapshot.test.ts","../src/state/persistence/session-snapshot.ts","../src/state/persistence/stateful-restore.e2e.test.ts","../src/styles/ai-colours.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/types/interaction-context.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/collect-session-models.test.ts","../src/utils/collect-session-models.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/cost-session-history.test.ts","../src/utils/cost-session-history.ts","../src/utils/derive-cost-session-title.test.ts","../src/utils/derive-cost-session-title.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.test.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/resolve-cost-history-config.test.ts","../src/utils/resolve-cost-history-config.ts","../src/utils/resolve-preference-baseline.test.ts","../src/utils/resolve-preference-baseline.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/sum-tokens.test.ts","../src/utils/sum-tokens.ts","../src/utils/tool-fold.ts","../src/utils/with-timeout.ts"],"version":"5.9.2"}
|
|
1
|
+
{"root":["../src/chat-driver-node.ts","../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.compact.test.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.pin.test.ts","../src/components/orchestrating-driver/orchestrating-driver.ts","../src/components/popout-manager/index.ts","../src/components/popout-manager/popout-manager.ts","../src/components/settings-modal/index.ts","../src/components/settings-modal/settings-modal.styles.ts","../src/components/settings-modal/settings-modal.template.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/main/popout-interaction-gate.test.ts","../src/provider/ai-provider-switcher.ts","../src/provider/assistant-app-settings.ts","../src/state/ai-assistant-slice.test.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/interaction-context.test.ts","../src/state/interaction-context.ts","../src/state/session-store.ts","../src/state/persistence/build-timeline-entries.ts","../src/state/persistence/diagnostics-cursors.test.ts","../src/state/persistence/diagnostics-cursors.ts","../src/state/persistence/diagnostics.test.ts","../src/state/persistence/diagnostics.ts","../src/state/persistence/index.ts","../src/state/persistence/persister-registry.ts","../src/state/persistence/session-persistence-provider.test.ts","../src/state/persistence/session-persistence-provider.ts","../src/state/persistence/session-persistence.integration.test.ts","../src/state/persistence/session-persister.test.ts","../src/state/persistence/session-persister.ts","../src/state/persistence/session-snapshot.test.ts","../src/state/persistence/session-snapshot.ts","../src/state/persistence/stateful-restore.e2e.test.ts","../src/styles/ai-colours.ts","../src/suggestions/chat-suggestions.ts","../src/tags/index.ts","../src/types/ai-chat-widget.ts","../src/types/interaction-context.ts","../src/utils/animated-panel-toggle.ts","../src/utils/animation-exclusivity.test.ts","../src/utils/animation-exclusivity.ts","../src/utils/collect-session-models.test.ts","../src/utils/collect-session-models.ts","../src/utils/condense-history.test.ts","../src/utils/condense-history.ts","../src/utils/cost-session-history.test.ts","../src/utils/cost-session-history.ts","../src/utils/derive-cost-session-title.test.ts","../src/utils/derive-cost-session-title.ts","../src/utils/flatten-sub-agent-messages.test.ts","../src/utils/flatten-sub-agent-messages.ts","../src/utils/history-transform.test.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/resolve-cost-history-config.test.ts","../src/utils/resolve-cost-history-config.ts","../src/utils/resolve-preference-baseline.test.ts","../src/utils/resolve-preference-baseline.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/sum-tokens.test.ts","../src/utils/sum-tokens.ts","../src/utils/tool-fold.ts","../src/utils/with-timeout.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.499.0",
|
|
5
5
|
"license": "SEE LICENSE IN license.txt",
|
|
6
6
|
"main": "dist/esm/index.js",
|
|
7
7
|
"types": "dist/ai-assistant.d.ts",
|
|
@@ -73,26 +73,26 @@
|
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
|
-
"@genesislcap/foundation-testing": "14.
|
|
77
|
-
"@genesislcap/genx": "14.
|
|
78
|
-
"@genesislcap/rollup-builder": "14.
|
|
79
|
-
"@genesislcap/ts-builder": "14.
|
|
80
|
-
"@genesislcap/uvu-playwright-builder": "14.
|
|
81
|
-
"@genesislcap/vite-builder": "14.
|
|
82
|
-
"@genesislcap/webpack-builder": "14.
|
|
76
|
+
"@genesislcap/foundation-testing": "14.499.0",
|
|
77
|
+
"@genesislcap/genx": "14.499.0",
|
|
78
|
+
"@genesislcap/rollup-builder": "14.499.0",
|
|
79
|
+
"@genesislcap/ts-builder": "14.499.0",
|
|
80
|
+
"@genesislcap/uvu-playwright-builder": "14.499.0",
|
|
81
|
+
"@genesislcap/vite-builder": "14.499.0",
|
|
82
|
+
"@genesislcap/webpack-builder": "14.499.0",
|
|
83
83
|
"@types/dompurify": "^3.0.5",
|
|
84
84
|
"@types/marked": "^5.0.2",
|
|
85
85
|
"esbuild": "0.25.12"
|
|
86
86
|
},
|
|
87
87
|
"dependencies": {
|
|
88
|
-
"@genesislcap/foundation-ai": "14.
|
|
89
|
-
"@genesislcap/foundation-logger": "14.
|
|
90
|
-
"@genesislcap/foundation-notifications": "14.
|
|
91
|
-
"@genesislcap/foundation-redux": "14.
|
|
92
|
-
"@genesislcap/foundation-ui": "14.
|
|
93
|
-
"@genesislcap/foundation-utils": "14.
|
|
94
|
-
"@genesislcap/rapid-design-system": "14.
|
|
95
|
-
"@genesislcap/web-core": "14.
|
|
88
|
+
"@genesislcap/foundation-ai": "14.499.0",
|
|
89
|
+
"@genesislcap/foundation-logger": "14.499.0",
|
|
90
|
+
"@genesislcap/foundation-notifications": "14.499.0",
|
|
91
|
+
"@genesislcap/foundation-redux": "14.499.0",
|
|
92
|
+
"@genesislcap/foundation-ui": "14.499.0",
|
|
93
|
+
"@genesislcap/foundation-utils": "14.499.0",
|
|
94
|
+
"@genesislcap/rapid-design-system": "14.499.0",
|
|
95
|
+
"@genesislcap/web-core": "14.499.0",
|
|
96
96
|
"dompurify": "^3.3.1",
|
|
97
97
|
"marked": "^17.0.3"
|
|
98
98
|
},
|
|
@@ -105,5 +105,5 @@
|
|
|
105
105
|
"access": "public"
|
|
106
106
|
},
|
|
107
107
|
"customElements": "dist/custom-elements.json",
|
|
108
|
-
"gitHead": "
|
|
108
|
+
"gitHead": "49903bfdc57c5c5a7dd0d711d9717908df0b7ac7"
|
|
109
109
|
}
|
package/src/chat-driver-node.ts
CHANGED
|
@@ -37,6 +37,12 @@ export {
|
|
|
37
37
|
GeminiProvider,
|
|
38
38
|
GeminiTransport,
|
|
39
39
|
MutableAIProviderRegistry,
|
|
40
|
+
// Supported-model allowlists — so a headless consumer validates a configured model id against
|
|
41
|
+
// foundation-ai's REAL list instead of maintaining a parallel hardcoded copy that silently drifts
|
|
42
|
+
// as the platform adds models (a valid new model would otherwise look like a misconfiguration).
|
|
43
|
+
// GENC-1461, create PR #1644 review.
|
|
44
|
+
SUPPORTED_ANTHROPIC_MODEL_IDS,
|
|
45
|
+
SUPPORTED_GEMINI_MODEL_IDS,
|
|
40
46
|
isObservableAIProviderRegistry,
|
|
41
47
|
} from '@genesislcap/foundation-ai';
|
|
42
48
|
export type {
|
|
@@ -52,3 +58,17 @@ export type {
|
|
|
52
58
|
ChatToolHandlers,
|
|
53
59
|
GeminiModelId,
|
|
54
60
|
} from '@genesislcap/foundation-ai';
|
|
61
|
+
|
|
62
|
+
// Debug-log harvesting (GENC-1461 unified diagnostics). A headless consumer collates its driver's
|
|
63
|
+
// log — `buildTimelineEntries({ turnSnapshots: driver.getTurnSnapshots(), messages:
|
|
64
|
+
// driver.getHistory(), metaEvents: getMetaEvents(sessionKey) })` → `DiagnosticEntry[]` — ships it to
|
|
65
|
+
// the client, which folds it into the assistant's debug log via `InteractionResult.diagnostics`
|
|
66
|
+
// (see `ChatDriver.getExternalDiagnostics`). `clearSession(sessionKey)` drops the per-request
|
|
67
|
+
// meta-event bucket so the long-lived server process's module registry doesn't grow unbounded.
|
|
68
|
+
// All three modules are DOM-clean, so the node entry stays Node-loadable.
|
|
69
|
+
export { clearSession, getMetaEvents } from './state/debug-event-log';
|
|
70
|
+
export type { MetaEvent } from './state/debug-event-log';
|
|
71
|
+
export { buildTimelineEntries } from './state/persistence/build-timeline-entries';
|
|
72
|
+
export type { TurnSnapshotLike } from './state/persistence/build-timeline-entries';
|
|
73
|
+
export { assembleDebugLog } from './state/persistence/diagnostics';
|
|
74
|
+
export type { DebugLog, DiagnosticEntry } from './state/persistence/diagnostics';
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
ChatToolDefinition,
|
|
6
6
|
} from '@genesislcap/foundation-ai';
|
|
7
7
|
import type { AgentConfig } from '../../config/config';
|
|
8
|
+
import type { DiagnosticEntry } from '../../state/persistence/diagnostics';
|
|
8
9
|
import type { InteractionContext } from '../../types/interaction-context';
|
|
9
10
|
import type { TurnSnapshot } from '../chat-driver/chat-driver';
|
|
10
11
|
|
|
@@ -121,6 +122,14 @@ export interface AiDriver extends EventTarget {
|
|
|
121
122
|
*/
|
|
122
123
|
getTurnSnapshots?(): ReadonlyArray<TurnSnapshot>;
|
|
123
124
|
|
|
125
|
+
/**
|
|
126
|
+
* Diagnostic-log entries harvested from resolved interactions (e.g. a server-side ChatDriver's
|
|
127
|
+
* collated debug log, returned on `InteractionResult.diagnostics`). The host folds these into its
|
|
128
|
+
* debug log. Optional for the same leaf/orchestrator reason as `getTurnSnapshots`.
|
|
129
|
+
* (GENC-1461 unified diagnostics.)
|
|
130
|
+
*/
|
|
131
|
+
getExternalDiagnostics?(): ReadonlyArray<DiagnosticEntry>;
|
|
132
|
+
|
|
124
133
|
/**
|
|
125
134
|
* Name of the AI provider used on the most recent turn. Falls back to the
|
|
126
135
|
* registry's default name when no turn has run yet.
|