@yeaft/webchat-agent 0.1.683 → 0.1.685
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/package.json +1 -1
- package/unify/engine.js +106 -13
- package/unify/web-bridge.js +63 -3
package/package.json
CHANGED
package/unify/engine.js
CHANGED
|
@@ -1028,6 +1028,43 @@ export class Engine {
|
|
|
1028
1028
|
let t1Fired = false;
|
|
1029
1029
|
const queryNumber = (this.#__queryCounter = (this.#__queryCounter || 0) + 1);
|
|
1030
1030
|
|
|
1031
|
+
// feat-6af5f9f1 PR B: a Turn = one user prompt + all AI responses.
|
|
1032
|
+
// `queryTurnId` is the wire-level turn identifier; every event emitted
|
|
1033
|
+
// during this query() carries it as `turnId`. Each LLM call inside
|
|
1034
|
+
// the loop is a `loopNumber` (was wire field `turnNumber`).
|
|
1035
|
+
const queryTurnId = randomUUID();
|
|
1036
|
+
const queryStartedAt = Date.now();
|
|
1037
|
+
const userQuestionPreview = String(prompt || '').slice(0, 200);
|
|
1038
|
+
const queryVpId = vpPersona && typeof vpPersona === 'object'
|
|
1039
|
+
&& typeof vpPersona.vpId === 'string'
|
|
1040
|
+
? vpPersona.vpId
|
|
1041
|
+
: (typeof senderVpId === 'string' ? senderVpId : null);
|
|
1042
|
+
|
|
1043
|
+
yield {
|
|
1044
|
+
type: 'turn_open',
|
|
1045
|
+
turnId: queryTurnId,
|
|
1046
|
+
userPrompt: userQuestionPreview,
|
|
1047
|
+
vpId: queryVpId,
|
|
1048
|
+
groupId: groupId || null,
|
|
1049
|
+
at: queryStartedAt,
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
// Surface memory recall to the debug panel right after turn_open.
|
|
1053
|
+
// recallResult was loaded above; emit a structured `memory_used`
|
|
1054
|
+
// event so the UI can show "loaded N segments" without parsing
|
|
1055
|
+
// the legacy `recall` event (which only carried entryCount).
|
|
1056
|
+
if (recallResult && Array.isArray(recallResult.entries) && recallResult.entries.length > 0) {
|
|
1057
|
+
yield {
|
|
1058
|
+
type: 'memory_used',
|
|
1059
|
+
turnId: queryTurnId,
|
|
1060
|
+
loaded: recallResult.entries.map(e => ({
|
|
1061
|
+
id: e && e.id || null,
|
|
1062
|
+
score: e && typeof e.score === 'number' ? e.score : null,
|
|
1063
|
+
kind: e && e.kind || null,
|
|
1064
|
+
})),
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1031
1068
|
const toolDefs = this.#getToolDefs();
|
|
1032
1069
|
let turnNumber = 0;
|
|
1033
1070
|
let continueTurns = 0; // auto-continue counter
|
|
@@ -1196,16 +1233,23 @@ export class Engine {
|
|
|
1196
1233
|
responseText,
|
|
1197
1234
|
});
|
|
1198
1235
|
|
|
1199
|
-
// Emit
|
|
1236
|
+
// Emit `loop` event for error path too (was `debug_turn`).
|
|
1237
|
+
const errLoopInputTokens = totalUsage.inputTokens || 0;
|
|
1238
|
+
const errLoopOutputTokens = totalUsage.outputTokens || 0;
|
|
1200
1239
|
yield {
|
|
1201
|
-
type: '
|
|
1202
|
-
|
|
1240
|
+
type: 'loop',
|
|
1241
|
+
turnId: queryTurnId,
|
|
1242
|
+
loopNumber: turnNumber,
|
|
1203
1243
|
model: currentModel,
|
|
1204
1244
|
systemPrompt,
|
|
1205
1245
|
messages: conversationMessages.map(mapDebugMessage),
|
|
1206
1246
|
response: responseText || `Error: ${err.message}`,
|
|
1207
1247
|
toolCalls: toolCalls.map(tc => ({ id: tc.id, name: tc.name, input: tc.input })),
|
|
1208
|
-
usage: {
|
|
1248
|
+
usage: {
|
|
1249
|
+
inputTokens: errLoopInputTokens,
|
|
1250
|
+
outputTokens: errLoopOutputTokens,
|
|
1251
|
+
totalTokens: errLoopInputTokens + errLoopOutputTokens,
|
|
1252
|
+
},
|
|
1209
1253
|
latencyMs,
|
|
1210
1254
|
ttfbMs,
|
|
1211
1255
|
stopReason: 'error',
|
|
@@ -1270,20 +1314,31 @@ export class Engine {
|
|
|
1270
1314
|
responseText,
|
|
1271
1315
|
});
|
|
1272
1316
|
|
|
1273
|
-
// Emit
|
|
1274
|
-
//
|
|
1275
|
-
//
|
|
1276
|
-
//
|
|
1277
|
-
//
|
|
1317
|
+
// Emit `loop` event for the debug panel.
|
|
1318
|
+
// feat-6af5f9f1 PR B: a Loop is one LLM call inside a Turn. The wire
|
|
1319
|
+
// event was historically named `debug_turn` and carried `turnNumber`,
|
|
1320
|
+
// which is misleading — it's per-LLM-call, not per-user-prompt.
|
|
1321
|
+
// We emit the new shape (turnId + loopNumber) and keep totalTokens
|
|
1322
|
+
// pre-computed so the UI doesn't have to.
|
|
1323
|
+
// task-331: preserve toolCalls / toolCallId / isError on each message
|
|
1324
|
+
// so the panel can render function_call requests and their paired
|
|
1325
|
+
// tool_result responses across loops.
|
|
1326
|
+
const loopInputTokens = totalUsage.inputTokens || 0;
|
|
1327
|
+
const loopOutputTokens = totalUsage.outputTokens || 0;
|
|
1278
1328
|
yield {
|
|
1279
|
-
type: '
|
|
1280
|
-
|
|
1329
|
+
type: 'loop',
|
|
1330
|
+
turnId: queryTurnId,
|
|
1331
|
+
loopNumber: turnNumber,
|
|
1281
1332
|
model: currentModel,
|
|
1282
1333
|
systemPrompt,
|
|
1283
1334
|
messages: conversationMessages.map(mapDebugMessage),
|
|
1284
1335
|
response: responseText,
|
|
1285
1336
|
toolCalls: toolCalls.map(tc => ({ id: tc.id, name: tc.name, input: tc.input })),
|
|
1286
|
-
usage: {
|
|
1337
|
+
usage: {
|
|
1338
|
+
inputTokens: loopInputTokens,
|
|
1339
|
+
outputTokens: loopOutputTokens,
|
|
1340
|
+
totalTokens: loopInputTokens + loopOutputTokens,
|
|
1341
|
+
},
|
|
1287
1342
|
latencyMs,
|
|
1288
1343
|
ttfbMs,
|
|
1289
1344
|
stopReason,
|
|
@@ -1390,10 +1445,12 @@ export class Engine {
|
|
|
1390
1445
|
});
|
|
1391
1446
|
if (adjustResult && adjustResult.ran) {
|
|
1392
1447
|
yield {
|
|
1393
|
-
type: '
|
|
1448
|
+
type: 'memory_adjust',
|
|
1449
|
+
turnId: queryTurnId,
|
|
1394
1450
|
groupKey: amsContext.groupKey,
|
|
1395
1451
|
added: adjustResult.added,
|
|
1396
1452
|
evicted: adjustResult.evicted,
|
|
1453
|
+
skipped: adjustResult.skipped || 0,
|
|
1397
1454
|
reason: adjustResult.reason,
|
|
1398
1455
|
};
|
|
1399
1456
|
}
|
|
@@ -1413,6 +1470,8 @@ export class Engine {
|
|
|
1413
1470
|
);
|
|
1414
1471
|
yield {
|
|
1415
1472
|
type: 'reflection',
|
|
1473
|
+
turnId: queryTurnId,
|
|
1474
|
+
loopNumber: turnNumber,
|
|
1416
1475
|
trigger: 't2',
|
|
1417
1476
|
status: 'pending',
|
|
1418
1477
|
loopRange: [arcStart, arcEnd],
|
|
@@ -1437,6 +1496,7 @@ export class Engine {
|
|
|
1437
1496
|
loopRange: [arcStart, arcEnd],
|
|
1438
1497
|
count: pairs.length,
|
|
1439
1498
|
originalUserMsg: prompt,
|
|
1499
|
+
originatingTurnId: queryTurnId,
|
|
1440
1500
|
ready: false,
|
|
1441
1501
|
result: null,
|
|
1442
1502
|
error: null,
|
|
@@ -1534,6 +1594,20 @@ export class Engine {
|
|
|
1534
1594
|
|
|
1535
1595
|
const toolDurationMs = Date.now() - toolStartTime;
|
|
1536
1596
|
|
|
1597
|
+
// feat-6af5f9f1 PR B: emit a structured `tool_exec` event for the
|
|
1598
|
+
// debug panel. Args/output are already in `conversationMessages`
|
|
1599
|
+
// and will be visible in the next loop's snapshot, so we don't
|
|
1600
|
+
// duplicate them here — only the per-tool timing + status.
|
|
1601
|
+
yield {
|
|
1602
|
+
type: 'tool_exec',
|
|
1603
|
+
turnId: queryTurnId,
|
|
1604
|
+
loopNumber: turnNumber,
|
|
1605
|
+
callId: tc.id,
|
|
1606
|
+
name: tc.name,
|
|
1607
|
+
durationMs: toolDurationMs,
|
|
1608
|
+
isError,
|
|
1609
|
+
};
|
|
1610
|
+
|
|
1537
1611
|
// Log tool to debug trace
|
|
1538
1612
|
this.#trace.logTool(turnId, {
|
|
1539
1613
|
toolName: tc.name,
|
|
@@ -1596,6 +1670,8 @@ export class Engine {
|
|
|
1596
1670
|
);
|
|
1597
1671
|
yield {
|
|
1598
1672
|
type: 'reflection',
|
|
1673
|
+
turnId: queryTurnId,
|
|
1674
|
+
loopNumber: turnNumber,
|
|
1599
1675
|
trigger: 't1',
|
|
1600
1676
|
status: 'pending',
|
|
1601
1677
|
loopRange: [arcStart, arcEnd],
|
|
@@ -1616,6 +1692,8 @@ export class Engine {
|
|
|
1616
1692
|
for (const m of next) conversationMessages.push(m);
|
|
1617
1693
|
yield {
|
|
1618
1694
|
type: 'reflection',
|
|
1695
|
+
turnId: queryTurnId,
|
|
1696
|
+
loopNumber: turnNumber,
|
|
1619
1697
|
trigger: 't1',
|
|
1620
1698
|
// PR-L bug fix: keep the same loopRange as the `pending` event
|
|
1621
1699
|
// so the frontend key stays stable across pending → ready and
|
|
@@ -1631,6 +1709,8 @@ export class Engine {
|
|
|
1631
1709
|
// continues normally — never block the turn.
|
|
1632
1710
|
yield {
|
|
1633
1711
|
type: 'reflection',
|
|
1712
|
+
turnId: queryTurnId,
|
|
1713
|
+
loopNumber: turnNumber,
|
|
1634
1714
|
trigger: 't1',
|
|
1635
1715
|
status: 'error',
|
|
1636
1716
|
error: err && err.message || String(err),
|
|
@@ -1656,6 +1736,18 @@ export class Engine {
|
|
|
1656
1736
|
|
|
1657
1737
|
// Loop back to call adapter again with tool results
|
|
1658
1738
|
}
|
|
1739
|
+
|
|
1740
|
+
// feat-6af5f9f1 PR B: turn closed. Emits final totals so the debug
|
|
1741
|
+
// panel can show "Turn done · 4 loops · 12.4s · 5.0k tok" without
|
|
1742
|
+
// having to reduce the loops itself. Always fires (every break path
|
|
1743
|
+
// above falls through here).
|
|
1744
|
+
yield {
|
|
1745
|
+
type: 'turn_close',
|
|
1746
|
+
turnId: queryTurnId,
|
|
1747
|
+
totalMs: Date.now() - queryStartedAt,
|
|
1748
|
+
totalTokens: cumulativeInputTokens + cumulativeOutputTokens,
|
|
1749
|
+
loopCount: turnNumber,
|
|
1750
|
+
};
|
|
1659
1751
|
}
|
|
1660
1752
|
|
|
1661
1753
|
/**
|
|
@@ -1753,6 +1845,7 @@ export class Engine {
|
|
|
1753
1845
|
|
|
1754
1846
|
yield {
|
|
1755
1847
|
type: 'reflection',
|
|
1848
|
+
turnId: info.originatingTurnId || null,
|
|
1756
1849
|
trigger,
|
|
1757
1850
|
status: 'ready',
|
|
1758
1851
|
loopRange: [startIdx, endIdx],
|
package/unify/web-bridge.js
CHANGED
|
@@ -535,6 +535,10 @@ function handleEngineEvent(event, hctx) {
|
|
|
535
535
|
case 'reflection':
|
|
536
536
|
sendUnifyEvent({
|
|
537
537
|
type: 'reflection',
|
|
538
|
+
// feat-6af5f9f1 PR B: stamp turnId/loopNumber so the debug panel
|
|
539
|
+
// can attach reflection cards to the matching loop.
|
|
540
|
+
turnId: event.turnId || null,
|
|
541
|
+
loopNumber: event.loopNumber || null,
|
|
538
542
|
trigger: event.trigger,
|
|
539
543
|
status: event.status,
|
|
540
544
|
loopRange: event.loopRange,
|
|
@@ -545,10 +549,66 @@ function handleEngineEvent(event, hctx) {
|
|
|
545
549
|
}, envelope);
|
|
546
550
|
break;
|
|
547
551
|
|
|
548
|
-
case '
|
|
552
|
+
case 'turn_open':
|
|
549
553
|
sendUnifyEvent({
|
|
550
|
-
type: '
|
|
551
|
-
|
|
554
|
+
type: 'turn_open',
|
|
555
|
+
turnId: event.turnId,
|
|
556
|
+
userPrompt: event.userPrompt,
|
|
557
|
+
vpId: event.vpId,
|
|
558
|
+
groupId: event.groupId,
|
|
559
|
+
at: event.at,
|
|
560
|
+
}, envelope);
|
|
561
|
+
break;
|
|
562
|
+
|
|
563
|
+
case 'turn_close':
|
|
564
|
+
sendUnifyEvent({
|
|
565
|
+
type: 'turn_close',
|
|
566
|
+
turnId: event.turnId,
|
|
567
|
+
totalMs: event.totalMs,
|
|
568
|
+
totalTokens: event.totalTokens,
|
|
569
|
+
loopCount: event.loopCount,
|
|
570
|
+
}, envelope);
|
|
571
|
+
break;
|
|
572
|
+
|
|
573
|
+
case 'memory_used':
|
|
574
|
+
sendUnifyEvent({
|
|
575
|
+
type: 'memory_used',
|
|
576
|
+
turnId: event.turnId,
|
|
577
|
+
loaded: event.loaded || [],
|
|
578
|
+
}, envelope);
|
|
579
|
+
break;
|
|
580
|
+
|
|
581
|
+
case 'memory_adjust':
|
|
582
|
+
sendUnifyEvent({
|
|
583
|
+
type: 'memory_adjust',
|
|
584
|
+
turnId: event.turnId,
|
|
585
|
+
groupKey: event.groupKey,
|
|
586
|
+
added: event.added,
|
|
587
|
+
evicted: event.evicted,
|
|
588
|
+
skipped: event.skipped,
|
|
589
|
+
reason: event.reason,
|
|
590
|
+
}, envelope);
|
|
591
|
+
break;
|
|
592
|
+
|
|
593
|
+
case 'tool_exec':
|
|
594
|
+
sendUnifyEvent({
|
|
595
|
+
type: 'tool_exec',
|
|
596
|
+
turnId: event.turnId,
|
|
597
|
+
loopNumber: event.loopNumber,
|
|
598
|
+
callId: event.callId,
|
|
599
|
+
name: event.name,
|
|
600
|
+
durationMs: event.durationMs,
|
|
601
|
+
isError: event.isError,
|
|
602
|
+
}, envelope);
|
|
603
|
+
break;
|
|
604
|
+
|
|
605
|
+
case 'loop':
|
|
606
|
+
// feat-6af5f9f1 PR B: replaces the old `debug_turn` event. Same
|
|
607
|
+
// payload shape plus turnId + loopNumber + usage.totalTokens.
|
|
608
|
+
sendUnifyEvent({
|
|
609
|
+
type: 'loop',
|
|
610
|
+
turnId: event.turnId,
|
|
611
|
+
loopNumber: event.loopNumber,
|
|
552
612
|
model: event.model,
|
|
553
613
|
systemPrompt: event.systemPrompt,
|
|
554
614
|
messages: event.messages,
|