@animalabs/connectome-host 0.7.3 → 0.8.0

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 (97) hide show
  1. package/.env.example +12 -5
  2. package/.github/PULL_REQUEST_TEMPLATE.md +3 -2
  3. package/.github/workflows/changelog.yml +9 -4
  4. package/.github/workflows/ci.yml +5 -3
  5. package/.github/workflows/publish.yml +12 -6
  6. package/CHANGELOG.md +401 -10
  7. package/CONTRIBUTING.md +47 -19
  8. package/HEADLESS-FLEET-PLAN.md +22 -0
  9. package/README.md +39 -1
  10. package/bun.lock +27 -31
  11. package/changelog.d/README.md +28 -0
  12. package/docs/AGENT-ONBOARDING.md +1 -1
  13. package/docs/debug-context-api.md +2 -2
  14. package/docs/retrieval-traces.md +173 -0
  15. package/docs/webui-deployment.md +2 -1
  16. package/package.json +6 -6
  17. package/recipes/SETUP.md +11 -5
  18. package/recipes/TRIUMVIRATE-SETUP.md +68 -14
  19. package/recipes/knowledge-miner.json +0 -30
  20. package/recipes/mock-test.json +19 -0
  21. package/recipes/triumvirate.json +6 -1
  22. package/scripts/audit-module-optins.ts +288 -0
  23. package/scripts/release-changelog.ts +210 -21
  24. package/src/cache-keepalive-log.ts +41 -0
  25. package/src/commands.ts +96 -0
  26. package/src/framework-strategy.ts +50 -4
  27. package/src/gate-telemetry.ts +106 -0
  28. package/src/headless.ts +24 -0
  29. package/src/index.ts +179 -64
  30. package/src/mcpl-config.ts +99 -1
  31. package/src/modules/fleet-module.ts +60 -1
  32. package/src/modules/fleet-types.ts +30 -1
  33. package/src/modules/identity-module.ts +310 -2
  34. package/src/modules/instructions-module.ts +265 -0
  35. package/src/modules/mcpl-admin-module.ts +89 -13
  36. package/src/modules/retrieval-module.ts +249 -51
  37. package/src/modules/retrieval-trace-page.ts +254 -0
  38. package/src/modules/retrieval-trace.ts +904 -0
  39. package/src/modules/subagent-module.ts +18 -0
  40. package/src/modules/tts-relay-module.ts +33 -18
  41. package/src/modules/web-ui-module.ts +445 -894
  42. package/src/recipe.ts +787 -29
  43. package/src/retrieval-config.ts +39 -0
  44. package/src/strategies/frontdesk-strategy.ts +34 -125
  45. package/src/tui.ts +325 -54
  46. package/src/web/panel-data.ts +1206 -0
  47. package/src/web/protocol.ts +75 -10
  48. package/src/workspace-mounts.ts +73 -0
  49. package/test/audit-module-optins.test.ts +174 -0
  50. package/test/cache-keepalive-log.test.ts +83 -0
  51. package/test/conversations-recipe.test.ts +142 -0
  52. package/test/fleet-panel-request.test.ts +90 -0
  53. package/test/framework-fkm-composition.test.ts +35 -3
  54. package/test/framework-strategy-defaults.test.ts +41 -0
  55. package/test/frontdesk-strategy.test.ts +25 -37
  56. package/test/gate-telemetry-adapter.test.ts +84 -0
  57. package/test/gate-telemetry.test.ts +91 -0
  58. package/test/headless-panel-request.test.ts +201 -0
  59. package/test/identity-and-surfaces.test.ts +212 -1
  60. package/test/instructions-module.test.ts +258 -0
  61. package/test/mcpl-admin-module.test.ts +64 -0
  62. package/test/mcpl-agent-overlay.test.ts +51 -3
  63. package/test/mcpl-child-env.test.ts +64 -0
  64. package/test/mock-headless-child.ts +14 -0
  65. package/test/nudge-command.test.ts +47 -0
  66. package/test/recipe-cache-keepalive.test.ts +59 -0
  67. package/test/recipe-compression-fallback.test.ts +19 -0
  68. package/test/recipe-hybrid-prose-routing.test.ts +12 -0
  69. package/test/recipe-instructions.test.ts +176 -0
  70. package/test/recipe-kv-unified.test.ts +87 -0
  71. package/test/recipe-mcp-source.test.ts +54 -0
  72. package/test/recipe-openai-compatible.test.ts +54 -0
  73. package/test/recipe-path-resolution.test.ts +19 -8
  74. package/test/recipe-provider.test.ts +14 -0
  75. package/test/recipe-save-unresolved.test.ts +244 -0
  76. package/test/recipe-source-only.test.ts +38 -0
  77. package/test/release-changelog.test.ts +202 -0
  78. package/test/retrieval-auth-loopback.test.ts +49 -0
  79. package/test/retrieval-config.test.ts +74 -0
  80. package/test/retrieval-module.test.ts +821 -0
  81. package/test/subagent-prose-routing.test.ts +109 -0
  82. package/test/tui-format.test.ts +106 -0
  83. package/test/web-ui-context-coverage.test.ts +1 -1
  84. package/test/web-ui-module.test.ts +189 -3
  85. package/test/web-ui-observers.test.ts +8 -5
  86. package/test/web-ui-protocol.test.ts +0 -0
  87. package/test/workspace-mounts.test.ts +68 -0
  88. package/web/src/App.tsx +160 -44
  89. package/web/src/Context.tsx +35 -8
  90. package/web/src/ContextDocument.tsx +20 -5
  91. package/web/src/Files.tsx +2 -8
  92. package/web/src/Health.tsx +61 -1
  93. package/web/src/Lessons.tsx +2 -38
  94. package/web/src/Mcpl.tsx +80 -14
  95. package/web/src/Pins.tsx +5 -0
  96. package/web/src/Settings.tsx +5 -0
  97. package/web/vite.config.ts +8 -2
@@ -1376,6 +1376,18 @@ export class SubagentModule implements Module {
1376
1376
  * 3. parent agent's `maxTokens` (by default, subagents inherit their caller's budget)
1377
1377
  * 4. last-resort framework fallback (4096) — only reached if there's no parent at all
1378
1378
  */
1379
+ /** Ephemeral agents inherit the caller's prose-routing mode. AF's Agent
1380
+ * defaults to 'locus' (ambient locus capture publishes plain prose to the
1381
+ * open channel), so a resident running proseRouting 'disabled' would still
1382
+ * spawn divers whose between-tool-calls prose leaks into its live channel
1383
+ * as parent speech — field-confirmed 2026-08-26. Falls back to the
1384
+ * configured parent agent, then to AF's own default. */
1385
+ private resolveProseRouting(callerAgentName?: string): 'locus' | 'explicit' | 'hybrid' | 'disabled' | undefined {
1386
+ const parentName = callerAgentName ?? this.config.parentAgentName;
1387
+ if (!parentName) return undefined;
1388
+ return this.framework?.getAgent(parentName)?.proseRouting;
1389
+ }
1390
+
1379
1391
  private resolveMaxTokens(callMaxTokens: number | undefined, parentAgentName?: string): number {
1380
1392
  if (callMaxTokens !== undefined) return callMaxTokens;
1381
1393
  if (this.config.defaultMaxTokens !== undefined) return this.config.defaultMaxTokens;
@@ -1703,6 +1715,9 @@ export class SubagentModule implements Module {
1703
1715
  model,
1704
1716
  systemPrompt: input.systemPrompt,
1705
1717
  maxTokens: this.resolveMaxTokens(input.maxTokens, _callerAgentName),
1718
+ ...(this.resolveProseRouting(_callerAgentName) !== undefined
1719
+ ? { proseRouting: this.resolveProseRouting(_callerAgentName) }
1720
+ : {}),
1706
1721
  maxStreamTokens: 500_000,
1707
1722
  strategy: new KnowledgeStrategy({
1708
1723
  headWindowTokens: 2_000,
@@ -1855,6 +1870,9 @@ export class SubagentModule implements Module {
1855
1870
  model,
1856
1871
  systemPrompt,
1857
1872
  maxTokens: this.resolveMaxTokens(input.maxTokens, callerAgentName),
1873
+ ...(this.resolveProseRouting(callerAgentName) !== undefined
1874
+ ? { proseRouting: this.resolveProseRouting(callerAgentName) }
1875
+ : {}),
1858
1876
  maxStreamTokens: 500_000,
1859
1877
  strategy: new KnowledgeStrategy({
1860
1878
  headWindowTokens: 2_000,
@@ -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;