@yeaft/webchat-agent 1.0.229 → 1.0.232

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "1.0.229",
3
+ "version": "1.0.232",
4
4
  "description": "Remote worker agent for Yeaft Web Code Agent — connects the native Yeaft engine, CLI providers, and workbench tools",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -181,6 +181,49 @@ function threadRuns(action, runs) {
181
181
  });
182
182
  }
183
183
 
184
+ function projectVpSpeaker(snapshot) {
185
+ if (!snapshot || typeof snapshot !== 'object') return null;
186
+ const id = typeof snapshot.id === 'string' && snapshot.id ? snapshot.id : null;
187
+ const name = typeof snapshot.name === 'string' && snapshot.name ? snapshot.name : id;
188
+ return id || name ? { id, name } : null;
189
+ }
190
+
191
+ function compareEventIds(leftId, rightId) {
192
+ const left = String(leftId ?? '');
193
+ const right = String(rightId ?? '');
194
+ if (/^\d+$/.test(left) && /^\d+$/.test(right)) {
195
+ const leftNumber = BigInt(left);
196
+ const rightNumber = BigInt(right);
197
+ if (leftNumber < rightNumber) return -1;
198
+ if (leftNumber > rightNumber) return 1;
199
+ return 0;
200
+ }
201
+ return left.localeCompare(right);
202
+ }
203
+
204
+ function compareStoredEvents(left, right) {
205
+ return count(left?.createdAt) - count(right?.createdAt)
206
+ || compareEventIds(left?.id, right?.id);
207
+ }
208
+
209
+ function projectedEventId(message) {
210
+ return typeof message?.id === 'string' && message.id.startsWith('event:')
211
+ ? message.id.slice('event:'.length)
212
+ : null;
213
+ }
214
+
215
+ function compareProjectedMessages(left, right) {
216
+ const timeOrder = count(left?.createdAt) - count(right?.createdAt);
217
+ if (timeOrder) return timeOrder;
218
+ const leftEventId = projectedEventId(left);
219
+ const rightEventId = projectedEventId(right);
220
+ if (leftEventId != null && rightEventId != null) {
221
+ return compareEventIds(leftEventId, rightEventId);
222
+ }
223
+ return (left?.role === 'user' ? -1 : 1)
224
+ || String(left?.id || '').localeCompare(String(right?.id || ''));
225
+ }
226
+
184
227
  function normalizeProjectedMessage(message) {
185
228
  if (!message || typeof message !== 'object') return null;
186
229
  const text = typeof message.text === 'string'
@@ -188,6 +231,7 @@ function normalizeProjectedMessage(message) {
188
231
  : '';
189
232
  const attachments = projectAttachments(message.attachments);
190
233
  if (!text && attachments.length === 0) return null;
234
+ const speaker = message.role === 'user' ? null : projectVpSpeaker(message.speaker);
191
235
  return {
192
236
  id: String(message.id || ''),
193
237
  role: message.role === 'user' ? 'user' : 'assistant',
@@ -201,6 +245,7 @@ function normalizeProjectedMessage(message) {
201
245
  ...(message.generation == null ? {} : { generation: Math.max(1, count(message.generation) || 1) }),
202
246
  ...(message.attempt == null ? {} : { attempt: Math.max(1, count(message.attempt) || 1) }),
203
247
  ...(message.runId == null ? {} : { runId: String(message.runId) }),
248
+ ...(speaker ? { speaker } : {}),
204
249
  };
205
250
  }
206
251
 
@@ -232,34 +277,52 @@ function runResponseMessage(run, includeThreadIdentity = false) {
232
277
  createdAt: count(run.startedAt),
233
278
  updatedAt: count(run.endedAt || run.startedAt),
234
279
  progressRevision: count(run.progressRevision),
235
- ...(includeThreadIdentity ? {
236
- generation: runGeneration(run),
237
- attempt: run.actionAttempt,
238
- runId: run.id,
239
- } : {}),
280
+ generation: includeThreadIdentity ? runGeneration(run) : null,
281
+ attempt: includeThreadIdentity ? run.actionAttempt : null,
282
+ runId: run.id,
283
+ speaker: run.vpSnapshot,
240
284
  });
241
285
  }
242
286
 
243
- function loopOutputMessages(action, events, matchingRunIds, generation = actionGeneration(action?.generation), includeThreadIdentity = false) {
244
- return (Array.isArray(events) ? events : [])
287
+ function loopOutputMessages(action, events, matchingRuns, generation = actionGeneration(action?.generation), includeThreadIdentity = false) {
288
+ const runById = new Map(matchingRuns.map(run => [run.id, run]));
289
+ const projected = [];
290
+ let previousTranscriptEvent = null;
291
+ const timeline = (Array.isArray(events) ? events : [])
245
292
  .filter(event => event?.actionId === action?.id
246
- && actionGeneration(event.actionGeneration ?? event.data?.actionGeneration) === generation
247
- && matchingRunIds.has(event.runId)
248
- && event.type === 'run.loop_output')
249
- .map(event => normalizeProjectedMessage({
293
+ && actionGeneration(event.actionGeneration ?? event.data?.actionGeneration) === generation)
294
+ .sort(compareStoredEvents);
295
+ for (const event of timeline) {
296
+ if (['action.guidance_added', 'action.input_added'].includes(event.type)) {
297
+ previousTranscriptEvent = { type: 'input' };
298
+ continue;
299
+ }
300
+ if (event.type !== 'run.loop_output') continue;
301
+ if (!runById.has(event.runId)) {
302
+ previousTranscriptEvent = { type: 'other_loop_output' };
303
+ continue;
304
+ }
305
+ const run = runById.get(event.runId);
306
+ const message = normalizeProjectedMessage({
250
307
  id: `event:${event.id}`,
251
308
  role: 'assistant',
252
309
  kind: 'response',
253
310
  status: 'completed',
254
311
  text: event.data?.response || '',
255
312
  createdAt: event.createdAt,
256
- ...(includeThreadIdentity ? {
257
- generation: event.actionGeneration ?? event.data?.actionGeneration,
258
- attempt: event.data?.actionAttempt,
259
- runId: event.runId,
260
- } : {}),
261
- }))
262
- .filter(Boolean);
313
+ generation: includeThreadIdentity ? event.actionGeneration ?? event.data?.actionGeneration : null,
314
+ attempt: includeThreadIdentity ? event.data?.actionAttempt : null,
315
+ runId: event.runId,
316
+ speaker: run.vpSnapshot,
317
+ });
318
+ if (!message) continue;
319
+ if (previousTranscriptEvent?.type === 'loop_output'
320
+ && previousTranscriptEvent.runId === message.runId
321
+ && previousTranscriptEvent.text === message.text) continue;
322
+ previousTranscriptEvent = { type: 'loop_output', runId: message.runId, text: message.text };
323
+ projected.push(message);
324
+ }
325
+ return projected;
263
326
  }
264
327
 
265
328
  function messagesForGeneration(action, runs, events, generation, includeThreadIdentity = false) {
@@ -273,15 +336,13 @@ function messagesForGeneration(action, runs, events, generation, includeThreadId
273
336
  .map(event => event.runId));
274
337
  return [
275
338
  ...actionInputMessages(action, events, generation, includeThreadIdentity),
276
- ...loopOutputMessages(action, events, matchingRunIds, generation, includeThreadIdentity),
339
+ ...loopOutputMessages(action, events, matchingRuns, generation, includeThreadIdentity),
277
340
  ...matchingRuns
278
341
  .sort((left, right) => count(left.startedAt) - count(right.startedAt))
279
342
  .filter(run => !runsWithLoopOutput.has(run.id))
280
343
  .map(run => runResponseMessage(run, includeThreadIdentity))
281
344
  .filter(Boolean)]
282
- .sort((left, right) => left.createdAt - right.createdAt
283
- || (left.role === 'user' ? -1 : 1)
284
- || left.id.localeCompare(right.id));
345
+ .sort(compareProjectedMessages);
285
346
  }
286
347
 
287
348
  function actionMessages(action, runs, events) {