@animalabs/connectome-host 0.7.3 → 0.7.4

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +156 -10
  2. package/HEADLESS-FLEET-PLAN.md +22 -0
  3. package/README.md +12 -1
  4. package/docs/AGENT-ONBOARDING.md +1 -1
  5. package/docs/debug-context-api.md +2 -2
  6. package/docs/retrieval-traces.md +173 -0
  7. package/docs/webui-deployment.md +2 -1
  8. package/package.json +2 -2
  9. package/scripts/audit-module-optins.ts +288 -0
  10. package/src/framework-strategy.ts +13 -4
  11. package/src/headless.ts +14 -0
  12. package/src/index.ts +12 -9
  13. package/src/modules/fleet-module.ts +60 -1
  14. package/src/modules/fleet-types.ts +30 -1
  15. package/src/modules/mcpl-admin-module.ts +33 -4
  16. package/src/modules/retrieval-module.ts +249 -51
  17. package/src/modules/retrieval-trace-page.ts +254 -0
  18. package/src/modules/retrieval-trace.ts +904 -0
  19. package/src/modules/tts-relay-module.ts +33 -18
  20. package/src/modules/web-ui-module.ts +445 -894
  21. package/src/recipe.ts +55 -4
  22. package/src/retrieval-config.ts +39 -0
  23. package/src/strategies/frontdesk-strategy.ts +34 -125
  24. package/src/tui.ts +325 -54
  25. package/src/web/panel-data.ts +1187 -0
  26. package/src/web/protocol.ts +75 -10
  27. package/test/audit-module-optins.test.ts +167 -0
  28. package/test/fleet-panel-request.test.ts +90 -0
  29. package/test/framework-strategy-defaults.test.ts +22 -0
  30. package/test/frontdesk-strategy.test.ts +25 -37
  31. package/test/headless-panel-request.test.ts +201 -0
  32. package/test/mcpl-admin-module.test.ts +23 -0
  33. package/test/mock-headless-child.ts +14 -0
  34. package/test/retrieval-auth-loopback.test.ts +49 -0
  35. package/test/retrieval-config.test.ts +74 -0
  36. package/test/retrieval-module.test.ts +821 -0
  37. package/test/tui-format.test.ts +106 -0
  38. package/test/web-ui-context-coverage.test.ts +1 -1
  39. package/test/web-ui-module.test.ts +189 -3
  40. package/test/web-ui-observers.test.ts +8 -5
  41. package/test/web-ui-protocol.test.ts +0 -0
  42. package/web/src/App.tsx +159 -44
  43. package/web/src/Context.tsx +35 -8
  44. package/web/src/ContextDocument.tsx +20 -5
  45. package/web/src/Files.tsx +2 -8
  46. package/web/src/Lessons.tsx +2 -38
  47. package/web/src/Mcpl.tsx +80 -14
  48. package/web/src/Pins.tsx +5 -0
  49. package/web/src/Settings.tsx +5 -0
  50. package/web/vite.config.ts +8 -2
@@ -232,6 +232,13 @@ function rawChannelId(mcplId: string): string {
232
232
  return ix === -1 ? mcplId : mcplId.slice(ix + 1);
233
233
  }
234
234
 
235
+ /** Channel-bound inference traces carry `channelId` at runtime, but the
236
+ * framework's TraceEvent union doesn't declare it — read it through a cast. */
237
+ function traceChannelId(event: unknown): string | undefined {
238
+ const v = (event as { channelId?: unknown }).channelId;
239
+ return typeof v === 'string' ? v : undefined;
240
+ }
241
+
235
242
  const collapseWs = (s: string): string => s.replace(/\s+/g, ' ').trim();
236
243
 
237
244
  export class TtsRelayModule implements Module {
@@ -338,18 +345,41 @@ export class TtsRelayModule implements Module {
338
345
  }
339
346
 
340
347
  private onTraceEvent(event: TraceEvent): void {
348
+ // `mcpl:speech-routed` is a custom trace type emitted by the speech
349
+ // router, not part of the framework's TraceEvent union — the typed
350
+ // switch below could never narrow to it. Handle it up front via the
351
+ // standard custom-trace cast.
352
+ if ((event as { type: string }).type === 'mcpl:speech-routed') {
353
+ // Remember what landed where, so an interruption can find its edit
354
+ // target: (channelId, messageId, text) per posted segment.
355
+ const e = event as unknown as {
356
+ channelId: string; messageId?: string; text: string; timestamp: number;
357
+ };
358
+ this.routed.push({
359
+ rawChannelId: rawChannelId(e.channelId),
360
+ mcplChannelId: e.channelId,
361
+ messageId: e.messageId,
362
+ text: e.text,
363
+ at: e.timestamp,
364
+ });
365
+ if (this.routed.length > ROUTED_RING_MAX) {
366
+ this.routed.splice(0, this.routed.length - ROUTED_RING_MAX);
367
+ }
368
+ return;
369
+ }
370
+
341
371
  switch (event.type) {
342
372
  case 'inference:started': {
343
373
  // A context-budget restart re-emits inference:started mid-turn; the
344
374
  // existing activation (announced or not) simply carries on.
345
375
  const st = this.activation(event.agentName);
346
- this.adoptChannel(st, event.agentName, event.channelId);
376
+ this.adoptChannel(st, event.agentName, traceChannelId(event));
347
377
  break;
348
378
  }
349
379
 
350
380
  case 'inference:tokens': {
351
381
  const st = this.activation(event.agentName);
352
- this.adoptChannel(st, event.agentName, event.channelId);
382
+ this.adoptChannel(st, event.agentName, traceChannelId(event));
353
383
  if (!st.rawChannelId) break; // no locus — nothing to voice into
354
384
  st.blocks.set(event.blockIndex, (st.blocks.get(event.blockIndex) ?? '') + event.content);
355
385
  this.client?.emit('chunk', {
@@ -367,7 +397,7 @@ export class TtsRelayModule implements Module {
367
397
 
368
398
  case 'inference:content_block': {
369
399
  const st = this.activation(event.agentName);
370
- this.adoptChannel(st, event.agentName, event.channelId);
400
+ this.adoptChannel(st, event.agentName, traceChannelId(event));
371
401
  if (!st.rawChannelId) break;
372
402
  const base = {
373
403
  channelId: st.rawChannelId,
@@ -398,21 +428,6 @@ export class TtsRelayModule implements Module {
398
428
  this.endActivation(event.agentName, 'error');
399
429
  break;
400
430
 
401
- case 'mcpl:speech-routed': {
402
- // Remember what landed where, so an interruption can find its edit
403
- // target: (channelId, messageId, text) per posted segment.
404
- this.routed.push({
405
- rawChannelId: rawChannelId(event.channelId),
406
- mcplChannelId: event.channelId,
407
- messageId: event.messageId,
408
- text: event.text,
409
- at: event.timestamp,
410
- });
411
- if (this.routed.length > ROUTED_RING_MAX) {
412
- this.routed.splice(0, this.routed.length - ROUTED_RING_MAX);
413
- }
414
- break;
415
- }
416
431
 
417
432
  default:
418
433
  break;