@yeaft/webchat-agent 0.1.787 → 0.1.788
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/conversation/persist.js +11 -0
- package/unify/web-bridge.js +19 -16
package/package.json
CHANGED
|
@@ -107,6 +107,13 @@ function serializeMessage(msg) {
|
|
|
107
107
|
// the speaker so the UI can render the message on the correct VP track.
|
|
108
108
|
// For real user messages this is unset.
|
|
109
109
|
if (msg.speakerVpId) fm.push(`speakerVpId: ${msg.speakerVpId}`);
|
|
110
|
+
// Internal/synthetic rows must round-trip so refresh/history replay can
|
|
111
|
+
// keep them out of the user-visible conversation. Reflection folding uses
|
|
112
|
+
// `_reflection`; other engine-only rows may use one of the explicit flags.
|
|
113
|
+
if (msg._reflection) fm.push('_reflection: true');
|
|
114
|
+
if (msg.internal) fm.push('internal: true');
|
|
115
|
+
if (msg.systemOnly) fm.push('systemOnly: true');
|
|
116
|
+
if (msg.systemOnlyMessage) fm.push('systemOnlyMessage: true');
|
|
110
117
|
|
|
111
118
|
// Token estimate
|
|
112
119
|
const content = msg.content || '';
|
|
@@ -179,6 +186,10 @@ export function parseMessage(raw) {
|
|
|
179
186
|
case 'sourceThreadId': msg.sourceThreadId = value; break;
|
|
180
187
|
case 'groupId': msg.groupId = value; break;
|
|
181
188
|
case 'speakerVpId': msg.speakerVpId = value; break;
|
|
189
|
+
case '_reflection': msg._reflection = value === 'true'; break;
|
|
190
|
+
case 'internal': msg.internal = value === 'true'; break;
|
|
191
|
+
case 'systemOnly': msg.systemOnly = value === 'true'; break;
|
|
192
|
+
case 'systemOnlyMessage': msg.systemOnlyMessage = value === 'true'; break;
|
|
182
193
|
// toolCalls are multi-line YAML — handled separately below
|
|
183
194
|
}
|
|
184
195
|
}
|
package/unify/web-bridge.js
CHANGED
|
@@ -366,7 +366,11 @@ function makeGroupContextStub() {
|
|
|
366
366
|
function projectPersistedToHistoryEntry(m) {
|
|
367
367
|
if (!m) return null;
|
|
368
368
|
if (m.role !== 'user' && m.role !== 'assistant' && m.role !== 'tool') return null;
|
|
369
|
+
if (m._reflection || m.internal || m.systemOnly || m.systemOnlyMessage) return null;
|
|
369
370
|
const entry = { role: m.role, content: m.content };
|
|
371
|
+
if (m.id) entry.id = m.id;
|
|
372
|
+
if (m.groupId) entry.groupId = m.groupId;
|
|
373
|
+
if (m.speakerVpId) entry.speakerVpId = m.speakerVpId;
|
|
370
374
|
if (m.toolCallId) entry.toolCallId = m.toolCallId;
|
|
371
375
|
if (Array.isArray(m.toolCalls) && m.toolCalls.length > 0) {
|
|
372
376
|
entry.toolCalls = m.toolCalls.map(tc => ({
|
|
@@ -2986,20 +2990,22 @@ export async function handleUnifyLoadHistory(msg) {
|
|
|
2986
2990
|
const compactSummary = session.conversationStore.readCompactSummary();
|
|
2987
2991
|
|
|
2988
2992
|
for (const m of messages) {
|
|
2989
|
-
|
|
2990
|
-
|
|
2991
|
-
|
|
2993
|
+
const entry = projectPersistedToHistoryEntry(m);
|
|
2994
|
+
if (!entry) continue;
|
|
2995
|
+
if (entry.role === 'user') {
|
|
2996
|
+
sendUnifyOutput({ type: 'user', message: { content: entry.content, id: entry.id || null } }, { groupId: entry.groupId || null });
|
|
2997
|
+
} else if (entry.role === 'assistant') {
|
|
2992
2998
|
// speakerVpId rides on the envelope so the frontend can route this
|
|
2993
2999
|
// replayed assistant text to the correct VP track. Without it, the
|
|
2994
3000
|
// history replay would merge replies from different VPs onto one
|
|
2995
3001
|
// anonymous assistant turn.
|
|
2996
3002
|
const envelopeOpts = {
|
|
2997
|
-
groupId:
|
|
3003
|
+
groupId: entry.groupId || null,
|
|
2998
3004
|
};
|
|
2999
|
-
if (
|
|
3005
|
+
if (entry.speakerVpId) envelopeOpts.vpId = entry.speakerVpId;
|
|
3000
3006
|
sendUnifyOutput({
|
|
3001
3007
|
type: 'assistant',
|
|
3002
|
-
message: { content: [{ type: 'text', text:
|
|
3008
|
+
message: { id: entry.id || null, content: [{ type: 'text', text: entry.content }] },
|
|
3003
3009
|
}, envelopeOpts);
|
|
3004
3010
|
sendUnifyOutput({ type: 'result', result_text: '' }, envelopeOpts);
|
|
3005
3011
|
}
|
|
@@ -3081,22 +3087,19 @@ export async function handleUnifyLoadMoreHistory(msg) {
|
|
|
3081
3087
|
result = { messages: [], oldestSeq: null, hasMore: false };
|
|
3082
3088
|
}
|
|
3083
3089
|
|
|
3084
|
-
// Wire shape mirrors handleUnifyLoadHistory's projection: only
|
|
3085
|
-
// assistant text rows.
|
|
3086
|
-
//
|
|
3087
|
-
//
|
|
3088
|
-
// We intentionally do NOT ship `id` or `time` over the wire:
|
|
3089
|
-
// `handleUnifyHistoryChunk` reads only role / content / groupId. The
|
|
3090
|
-
// pagination cursor (`oldestSeq`) is sent once at the envelope level,
|
|
3091
|
-
// so per-row ids are dead weight. `time` would be useful if we render
|
|
3092
|
-
// "5 days ago" stamps on older history rows — when that ships, add it
|
|
3093
|
-
// back here and consume it in conversationHandler.
|
|
3090
|
+
// Wire shape mirrors handleUnifyLoadHistory's projection: only visible
|
|
3091
|
+
// user / assistant text rows. Internal reflection/system-only rows stay
|
|
3092
|
+
// server-side, and stable ids + speaker attribution ride with each row
|
|
3093
|
+
// so older-history prepend renders exactly like refresh replay.
|
|
3094
3094
|
const projected = (result.messages || [])
|
|
3095
|
+
.map(projectPersistedToHistoryEntry)
|
|
3095
3096
|
.filter(m => m && (m.role === 'user' || m.role === 'assistant'))
|
|
3096
3097
|
.map(m => ({
|
|
3098
|
+
...(m.id ? { id: m.id } : {}),
|
|
3097
3099
|
role: m.role,
|
|
3098
3100
|
content: m.content,
|
|
3099
3101
|
groupId: m.groupId || null,
|
|
3102
|
+
...(m.speakerVpId ? { speakerVpId: m.speakerVpId } : {}),
|
|
3100
3103
|
}));
|
|
3101
3104
|
|
|
3102
3105
|
emit({
|