@yeaft/webchat-agent 0.1.987 → 0.1.989
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/yeaft/conversation/persist.js +1 -0
- package/yeaft/engine.js +2 -0
- package/yeaft/routing/router.js +5 -0
- package/yeaft/web-bridge.js +22 -6
package/package.json
CHANGED
|
@@ -1104,6 +1104,7 @@ export class ConversationStore {
|
|
|
1104
1104
|
const all = [...cold, ...hot].sort(compareMessagesBySeq);
|
|
1105
1105
|
const after = all.filter((m) => {
|
|
1106
1106
|
if (!m || m.sessionId !== sessionId) return false;
|
|
1107
|
+
if (m._reflection || m.internal || m.systemOnly || m.systemOnlyMessage) return false;
|
|
1107
1108
|
const seq = parseSeqFromId(m.id);
|
|
1108
1109
|
return Number.isFinite(seq) && seq > cutoff;
|
|
1109
1110
|
});
|
package/yeaft/engine.js
CHANGED
|
@@ -1827,6 +1827,7 @@ export class Engine {
|
|
|
1827
1827
|
loopNumber: turnNumber,
|
|
1828
1828
|
threadId,
|
|
1829
1829
|
preview: String(item.preview || '').slice(0, 200),
|
|
1830
|
+
internal: Boolean(item.internal),
|
|
1830
1831
|
};
|
|
1831
1832
|
}
|
|
1832
1833
|
}
|
|
@@ -2233,6 +2234,7 @@ export class Engine {
|
|
|
2233
2234
|
loopNumber: turnNumber,
|
|
2234
2235
|
threadId,
|
|
2235
2236
|
preview: String(item.preview || '').slice(0, 200),
|
|
2237
|
+
internal: Boolean(item.internal),
|
|
2236
2238
|
};
|
|
2237
2239
|
}
|
|
2238
2240
|
yield { type: 'turn_end', turnNumber, stopReason: 'user_append_continue', threadId };
|
package/yeaft/routing/router.js
CHANGED
|
@@ -143,6 +143,11 @@ export function createRouter(deps = {}) {
|
|
|
143
143
|
role: 'assistant', // VP-authored — persists as assistant turn
|
|
144
144
|
text: injectText,
|
|
145
145
|
taskId: args.taskId ?? null,
|
|
146
|
+
// route_forward is already visible as the source VP's tool action.
|
|
147
|
+
// Persist the synthetic handoff for audit/dispatch, but keep it out
|
|
148
|
+
// of UI replay and future visible history so it doesn't render as a
|
|
149
|
+
// second assistant/user block after the target VP answers.
|
|
150
|
+
internal: true,
|
|
146
151
|
meta: {
|
|
147
152
|
synthetic: true,
|
|
148
153
|
injectedBy: 'route_forward',
|
package/yeaft/web-bridge.js
CHANGED
|
@@ -1032,15 +1032,23 @@ async function routeEnvelopeToVpThread(sessionId, vpId, envelope) {
|
|
|
1032
1032
|
|
|
1033
1033
|
if (related) {
|
|
1034
1034
|
const content = promptParts || prompt;
|
|
1035
|
-
|
|
1035
|
+
const isForwardAppend = envelope?.msg?.meta?.injectedBy === 'route_forward';
|
|
1036
|
+
thread.pendingQueries.push({
|
|
1037
|
+
content,
|
|
1038
|
+
preview: prompt,
|
|
1039
|
+
originalText: text,
|
|
1040
|
+
originalParts: Array.isArray(envelope?._promptParts) ? envelope._promptParts : null,
|
|
1041
|
+
internal: isForwardAppend,
|
|
1042
|
+
});
|
|
1036
1043
|
persistInboundMessageOnceByMsgId({
|
|
1037
1044
|
msgId: envelope?.msg?.id,
|
|
1038
1045
|
text,
|
|
1039
1046
|
sessionId,
|
|
1040
1047
|
threadId: visibleInboundThreadId(envelope, thread.threadId),
|
|
1041
|
-
role:
|
|
1048
|
+
role: isForwardAppend ? 'assistant' : 'user',
|
|
1042
1049
|
speakerVpId: envelope?.msg?.meta?.senderVpId || envelope?.msg?.from || null,
|
|
1043
1050
|
attachments: Array.isArray(envelope?.msg?.meta?.attachments) ? envelope.msg.meta.attachments : [],
|
|
1051
|
+
internal: isForwardAppend,
|
|
1044
1052
|
});
|
|
1045
1053
|
thread.updatedAt = Date.now();
|
|
1046
1054
|
try {
|
|
@@ -1135,6 +1143,7 @@ function ensureDriverRunning(sessionId, vpId, threadId = 'main') {
|
|
|
1135
1143
|
role: isForward ? 'assistant' : 'user',
|
|
1136
1144
|
speakerVpId: senderVpId,
|
|
1137
1145
|
attachments: Array.isArray(meta.attachments) ? meta.attachments : [],
|
|
1146
|
+
internal: isForward,
|
|
1138
1147
|
});
|
|
1139
1148
|
}
|
|
1140
1149
|
} catch { /* never crash WS pipeline */ }
|
|
@@ -2254,7 +2263,7 @@ function handleEngineEvent(event, hctx) {
|
|
|
2254
2263
|
break;
|
|
2255
2264
|
|
|
2256
2265
|
case 'user_append':
|
|
2257
|
-
if (hctx && Array.isArray(hctx.appendedUserPrompts) && event.preview) {
|
|
2266
|
+
if (hctx && Array.isArray(hctx.appendedUserPrompts) && event.preview && !event.internal) {
|
|
2258
2267
|
hctx.appendedUserPrompts.push(String(event.preview));
|
|
2259
2268
|
}
|
|
2260
2269
|
sendSessionEvent({
|
|
@@ -3063,7 +3072,13 @@ async function runVpTurn({ prompt, promptParts = null, sessionId, vpId, threadId
|
|
|
3063
3072
|
}
|
|
3064
3073
|
|
|
3065
3074
|
// Turn completed — atomically append this VP's output to shared history.
|
|
3066
|
-
|
|
3075
|
+
// route_forward handoff text is an internal trigger, already visible as
|
|
3076
|
+
// the source VP's tool action. Do not append it as a visible prompt for
|
|
3077
|
+
// the target VP turn; otherwise UI replay can show a trailing handoff
|
|
3078
|
+
// block after the target response.
|
|
3079
|
+
const inboundIsRouteForward = inboundEnvelope?.msg?.meta?.injectedBy === 'route_forward';
|
|
3080
|
+
const visiblePrompts = inboundIsRouteForward ? appendedUserPrompts : [prompt, ...appendedUserPrompts];
|
|
3081
|
+
appendTurnToSessionHistory(sessionId, threadId, vpId, visiblePrompts, assistantTextParts, toolCallsAccum, toolResultsAccum, thinkingBlocksAccum);
|
|
3067
3082
|
|
|
3068
3083
|
sendSessionOutputFrame({
|
|
3069
3084
|
type: 'assistant',
|
|
@@ -3268,11 +3283,11 @@ function appendTurnToSessionHistory(sessionId, threadId, vpId, prompts, assistan
|
|
|
3268
3283
|
* refresh replay can render chips without leaking image source data into
|
|
3269
3284
|
* the message body.
|
|
3270
3285
|
*
|
|
3271
|
-
* @param {{ msgId:string, text:string, sessionId:string, role?:string, speakerVpId?:string|null, attachments?:Array<object
|
|
3286
|
+
* @param {{ msgId:string, text:string, sessionId:string, role?:string, speakerVpId?:string|null, attachments?:Array<object>, internal?:boolean }} args
|
|
3272
3287
|
* @returns {boolean} true if this call wrote the row, false if a prior
|
|
3273
3288
|
* call already wrote it (dedup hit).
|
|
3274
3289
|
*/
|
|
3275
|
-
function persistInboundMessageOnceByMsgId({ msgId, text, sessionId, threadId = 'main', role, speakerVpId, attachments }) {
|
|
3290
|
+
function persistInboundMessageOnceByMsgId({ msgId, text, sessionId, threadId = 'main', role, speakerVpId, attachments, internal = false }) {
|
|
3276
3291
|
if (!session?.conversationStore) return false;
|
|
3277
3292
|
// No msgId means no dedup key — caller is responsible for guarding.
|
|
3278
3293
|
// Both call sites already do (`if (envMsgId && text)` and
|
|
@@ -3323,6 +3338,7 @@ function persistInboundMessageOnceByMsgId({ msgId, text, sessionId, threadId = '
|
|
|
3323
3338
|
if (persistRole === 'assistant' && speakerVpId && typeof speakerVpId === 'string') {
|
|
3324
3339
|
record.speakerVpId = speakerVpId;
|
|
3325
3340
|
}
|
|
3341
|
+
if (internal) record.internal = true;
|
|
3326
3342
|
if (persistRole === 'user' && Array.isArray(attachments) && attachments.length > 0) {
|
|
3327
3343
|
record.attachments = attachments;
|
|
3328
3344
|
}
|