@yeaft/webchat-agent 0.1.518 → 0.1.519

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.
@@ -36,7 +36,7 @@ import { sendToServer, flushMessageBuffer } from './buffer.js';
36
36
  import { handleRestartAgent, handleUpgradeAgent } from './upgrade.js';
37
37
  import { loadMcpServers, updateMcpConfig } from '../mcp.js';
38
38
  import { getLlmConfig, updateLlmConfig, getUnifySettings, updateUnifySettings } from '../unify/config-api.js';
39
- import { handleUnifyChat, handleUnifyModeSwitch, handleUnifyModelSwitch, resetUnifySession, handleUnifyLoadHistory, handleUnifyMergeThread, handleUnifyForkThread, handleUnifyAbortThread, handleUnifyAbortAll } from '../unify/web-bridge.js';
39
+ import { handleUnifyChat, handleUnifyModeSwitch, handleUnifyModelSwitch, resetUnifySession, handleUnifyLoadHistory, handleUnifyMergeThread, handleUnifyForkThread, handleUnifyAbortThread, handleUnifyAbortAll, handleUnifyVpSubscribe } from '../unify/web-bridge.js';
40
40
 
41
41
  export async function handleMessage(msg) {
42
42
  switch (msg.type) {
@@ -397,6 +397,12 @@ export async function handleMessage(msg) {
397
397
  handleUnifyAbortAll();
398
398
  break;
399
399
 
400
+ // task-334-ui-a: VP library subscribe — replies with one-shot
401
+ // vp_snapshot event. Live diff (vp_updated/vp_removed) deferred to 334h.
402
+ case 'unify_vp_subscribe':
403
+ handleUnifyVpSubscribe(msg);
404
+ break;
405
+
400
406
  // Expert roles definition (for ExpertPanel detail view)
401
407
  case 'get_expert_roles': {
402
408
  const { getExpertRolesDefinition } = await import('../expert-roles.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yeaft/webchat-agent",
3
- "version": "0.1.518",
3
+ "version": "0.1.519",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -0,0 +1,102 @@
1
+ /**
2
+ * vp-bridge.js — task-334-ui-a snapshot-only WS adapter.
3
+ *
4
+ * Per ruling .crew/context/task-334-ui-a-ruling.md §3 (D3 = mixed):
5
+ * • snapshot path lives here (this slice, in-scope)
6
+ * • live diff (vp_updated / vp_removed) deferred to 334h — see TODO below
7
+ *
8
+ * This module is the SOLE serialiser for the wire-format VP shape.
9
+ * Per ruling §1 (D1 = (b) web-bridge boundary rename), the entity layer
10
+ * (`vp-store.js` / `registry.js`) keeps `id` / `name`; here we map to
11
+ * `vpId` / `displayName` per the spec (§2.1) / architecture §R6.11.
12
+ *
13
+ * Per ruling §2 (D2):
14
+ * • subtitle → agent emits `vp.role` directly
15
+ * • personaHash → agent emits `vp.personaHash` (added by dev-1's
16
+ * 334a-followup patch). Until that lands, this serialiser falls back
17
+ * to undefined and the web layer simply omits the field.
18
+ * • color / avatar → web-derived, NOT emitted here
19
+ */
20
+
21
+ import { defaultRegistry } from './registry.js';
22
+ import { VpLoader } from './vp-loader.js';
23
+
24
+ /** Process-singleton VpLoader; lazily started on first subscribe. */
25
+ let _loaderStarted = false;
26
+ let _loader = null;
27
+
28
+ function ensureLoader() {
29
+ if (_loaderStarted) return _loader;
30
+ _loaderStarted = true;
31
+ try {
32
+ _loader = new VpLoader({ registry: defaultRegistry });
33
+ _loader.start();
34
+ } catch {
35
+ // Hot-reload optional; subscribe still returns whatever scan loaded.
36
+ _loader = null;
37
+ }
38
+ return _loader;
39
+ }
40
+
41
+ /**
42
+ * Serialise a VP (entity layer shape) to the wire-format the web layer
43
+ * expects (spec §2.1). Pure; no IO.
44
+ *
45
+ * @param {{id:string,name:string,role:string,traits?:string[],modelHint?:string,personaHash?:string}} vp
46
+ * @returns {{vpId:string,displayName:string,subtitle:string,role:string,traits:string[],modelHint:?string,personaHash:?string}}
47
+ */
48
+ export function serializeVpForWire(vp) {
49
+ return {
50
+ vpId: vp.id,
51
+ displayName: vp.name,
52
+ role: vp.role || '',
53
+ subtitle: vp.role || '',
54
+ traits: Array.isArray(vp.traits) ? vp.traits.slice() : [],
55
+ modelHint: vp.modelHint ?? null,
56
+ personaHash: vp.personaHash ?? null,
57
+ };
58
+ }
59
+
60
+ /**
61
+ * Build a vp_snapshot event payload from the registry.
62
+ * @param {import('./registry.js').Registry} [registry]
63
+ * @returns {{type:'vp_snapshot', vps:Array, emptyLibrary:boolean}}
64
+ */
65
+ export function buildVpSnapshot(registry = defaultRegistry) {
66
+ const vps = registry.listVps().map(serializeVpForWire);
67
+ return {
68
+ type: 'vp_snapshot',
69
+ vps,
70
+ emptyLibrary: vps.length === 0,
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Handle an `unify_vp_subscribe` request from the web client.
76
+ * Lazily starts the VpLoader on first call (debounced rescan watchers).
77
+ *
78
+ * @param {(event: object) => void} sendUnifyEvent — emit fn (web-bridge wires this)
79
+ * @param {import('./registry.js').Registry} [registry]
80
+ */
81
+ export function handleVpSubscribe(sendUnifyEvent, registry = defaultRegistry) {
82
+ ensureLoader();
83
+ try {
84
+ sendUnifyEvent(buildVpSnapshot(registry));
85
+ } catch {
86
+ // Never crash the WS pipeline from snapshot serialisation.
87
+ }
88
+ // TODO(334h): vp_updated / vp_removed live broadcast.
89
+ // Wire VpLoader.onChange → emit per-vp `vp_updated` and `vp_removed`
90
+ // events using serializeVpForWire(). Out of scope for 334-ui-a.
91
+ }
92
+
93
+ /**
94
+ * Test seam: reset the lazy loader (for vitest).
95
+ */
96
+ export function _resetVpBridgeForTest() {
97
+ if (_loader) {
98
+ try { _loader.stop(); } catch { /* ignore */ }
99
+ }
100
+ _loader = null;
101
+ _loaderStarted = false;
102
+ }
@@ -26,6 +26,7 @@ import { loadSession } from './session.js';
26
26
  import { sendToServer } from '../connection/buffer.js';
27
27
  import ctx from '../context.js';
28
28
  import { getThreadStore, MAIN_THREAD_ID } from './threads/store.js';
29
+ import { handleVpSubscribe } from './vp/vp-bridge.js';
29
30
 
30
31
  /** @type {import('./session.js').Session | null} */
31
32
  let session = null;
@@ -103,6 +104,15 @@ function sendUnifyEvent(event) {
103
104
  });
104
105
  }
105
106
 
107
+ /**
108
+ * task-334-ui-a: respond to `unify_vp_subscribe` from the web client by
109
+ * pushing a one-shot `vp_snapshot` event. Live diff (vp_updated /
110
+ * vp_removed) is intentionally deferred to 334h per ruling §3.
111
+ */
112
+ export function handleUnifyVpSubscribe(_msg) {
113
+ handleVpSubscribe(sendUnifyEvent);
114
+ }
115
+
106
116
  /**
107
117
  * task-318 rev-1 fix: install live-setter bridge between the session's
108
118
  * runtime handles (engineRegistry + threadStore) and `ctx.unifyRuntimeSettings`,