@yeaft/webchat-agent 0.1.616 → 0.1.617

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": "0.1.616",
3
+ "version": "0.1.617",
4
4
  "description": "Remote agent for Yeaft WebChat — connects worker machines to the central server",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -111,7 +111,7 @@ export async function runCompact({ messages, keepHot = 10, taskId = null, root,
111
111
  ? await hooks.readPriorTaskSummary() : '';
112
112
  const next = await hooks.refreshTaskSummary(coolingMessages, prior);
113
113
  if (typeof next === 'string' && next.trim()) {
114
- await writeSummary({ kind: 'task', id: taskId }, next, { root });
114
+ await writeSummary({ kind: 'feature', id: taskId }, next, { root });
115
115
  taskSummaryRefreshed = true;
116
116
  }
117
117
  }
@@ -1,25 +1,25 @@
1
1
  /**
2
- * task-message.js — R6 §Δ28 / §Δ31.6 task-scoped direct messaging.
2
+ * feature-message.js — R6 §Δ28 / §Δ31.6 feature-scoped direct messaging.
3
3
  *
4
- * Replaces the withdrawn R3 `unify_task_private_chat` event with a simple
5
- * echo-able `task_message` pair:
4
+ * Replaces the withdrawn R3 `unify_feature_private_chat` event with a simple
5
+ * echo-able `feature_message` pair:
6
6
  *
7
- * inbound (web → agent): `unify_task_message`
8
- * { type, groupId, taskId, vpId, text, mentions?, replyTo?, requestId? }
9
- * outbound (agent → web): `task_message`
10
- * { type, groupId, taskId, vpId, msgId, text, mentions, replyTo,
7
+ * inbound (web → agent): `unify_feature_message`
8
+ * { type, groupId, featureId, vpId, text, mentions?, replyTo?, requestId? }
9
+ * outbound (agent → web): `feature_message`
10
+ * { type, groupId, featureId, vpId, msgId, text, mentions, replyTo,
11
11
  * ts, requestId? }
12
12
  *
13
13
  * This module owns only the *wire adapter* — the payload is validated,
14
14
  * stamped with msgId + ts, and broadcast back so the sender's UI and any
15
- * other connected views converge on the same record. Persistence + task
15
+ * other connected views converge on the same record. Persistence + feature
16
16
  * ACL enforcement are deliberately deferred to task-334l (per PM dispatch:
17
- * "user_memory_* 实际 ingestion 归 334l"); the parallel task-private
17
+ * "user_memory_* 实际 ingestion 归 334l"); the parallel feature-private
18
18
  * storage hook follows the same phasing.
19
19
  *
20
20
  * Invariants:
21
21
  * • Never throws on the WS hot path — bad payloads reply with a
22
- * `task_message_rejected` event carrying a stable `code` string for
22
+ * `feature_message_rejected` event carrying a stable `code` string for
23
23
  * UI i18n (mirrors the vp_crud_result contract from 334-ui-g).
24
24
  * • The outbound event field order and keys are considered wire-frozen
25
25
  * per R6 §Δ31.6 table; additive fields only in future slices.
@@ -28,9 +28,9 @@
28
28
  import { nextMsgId, isValidVpId } from './groups/ids.js';
29
29
 
30
30
  /** Known `reject` codes — kept stable so 334-ui-* can key i18n on them. */
31
- export const TASK_MESSAGE_REJECT_CODES = Object.freeze({
31
+ export const FEATURE_MESSAGE_REJECT_CODES = Object.freeze({
32
32
  MISSING_GROUP_ID: 'missing_group_id',
33
- MISSING_TASK_ID: 'missing_task_id',
33
+ MISSING_FEATURE_ID: 'missing_feature_id',
34
34
  MISSING_VP_ID: 'missing_vp_id',
35
35
  INVALID_VP_ID: 'invalid_vp_id',
36
36
  EMPTY_TEXT: 'empty_text',
@@ -46,31 +46,31 @@ export const MAX_TEXT_LENGTH = 16_384;
46
46
  *
47
47
  * @param {any} msg — raw WS message from the web client
48
48
  */
49
- export function validateTaskMessage(msg) {
49
+ export function validateFeatureMessage(msg) {
50
50
  if (!msg || typeof msg !== 'object') {
51
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
51
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
52
52
  }
53
- const { groupId, taskId, vpId, text } = msg;
53
+ const { groupId, featureId, vpId, text } = msg;
54
54
  if (!groupId || typeof groupId !== 'string') {
55
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
55
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
56
56
  }
57
- if (!taskId || typeof taskId !== 'string') {
58
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.MISSING_TASK_ID };
57
+ if (!featureId || typeof featureId !== 'string') {
58
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_FEATURE_ID };
59
59
  }
60
60
  if (!vpId || typeof vpId !== 'string') {
61
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.MISSING_VP_ID };
61
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_VP_ID };
62
62
  }
63
- // Allow the reserved `user` sentinel as a speaker here — tasks can have
63
+ // Allow the reserved `user` sentinel as a speaker here — features can have
64
64
  // human-user messages alongside VP messages. Any other vpId must pass
65
65
  // the full shape check (rejects `all`, `system`, pure digits, etc.).
66
66
  if (vpId !== 'user' && !isValidVpId(vpId)) {
67
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.INVALID_VP_ID };
67
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.INVALID_VP_ID };
68
68
  }
69
69
  if (typeof text !== 'string' || text.length === 0) {
70
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.EMPTY_TEXT };
70
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.EMPTY_TEXT };
71
71
  }
72
72
  if (text.length > MAX_TEXT_LENGTH) {
73
- return { ok: false, code: TASK_MESSAGE_REJECT_CODES.TEXT_TOO_LONG };
73
+ return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.TEXT_TOO_LONG };
74
74
  }
75
75
 
76
76
  const mentions = Array.isArray(msg.mentions)
@@ -82,25 +82,25 @@ export function validateTaskMessage(msg) {
82
82
 
83
83
  return {
84
84
  ok: true,
85
- payload: { groupId, taskId, vpId, text, mentions, replyTo },
85
+ payload: { groupId, featureId, vpId, text, mentions, replyTo },
86
86
  };
87
87
  }
88
88
 
89
89
  /**
90
- * Build the outbound `task_message` event from a validated payload.
90
+ * Build the outbound `feature_message` event from a validated payload.
91
91
  * Exposed separately so tests can snapshot the wire shape without
92
92
  * needing a live send fn.
93
93
  *
94
- * @param {{groupId:string,taskId:string,vpId:string,text:string,mentions:string[],replyTo:?string}} payload
94
+ * @param {{groupId:string,featureId:string,vpId:string,text:string,mentions:string[],replyTo:?string}} payload
95
95
  * @param {{now?:()=>number, msgId?:()=>string, requestId?:string}} [opts]
96
96
  */
97
- export function buildTaskMessageEvent(payload, opts = {}) {
97
+ export function buildFeatureMessageEvent(payload, opts = {}) {
98
98
  const now = typeof opts.now === 'function' ? opts.now : Date.now;
99
99
  const mkId = typeof opts.msgId === 'function' ? opts.msgId : nextMsgId;
100
100
  const evt = {
101
- type: 'task_message',
101
+ type: 'feature_message',
102
102
  groupId: payload.groupId,
103
- taskId: payload.taskId,
103
+ featureId: payload.featureId,
104
104
  vpId: payload.vpId,
105
105
  msgId: mkId(),
106
106
  text: payload.text,
@@ -113,15 +113,15 @@ export function buildTaskMessageEvent(payload, opts = {}) {
113
113
  }
114
114
 
115
115
  /**
116
- * Build the outbound `task_message_rejected` event.
117
- * @param {string} code — one of TASK_MESSAGE_REJECT_CODES
116
+ * Build the outbound `feature_message_rejected` event.
117
+ * @param {string} code — one of FEATURE_MESSAGE_REJECT_CODES
118
118
  * @param {any} msg — original inbound msg (for requestId echo)
119
119
  */
120
- export function buildTaskMessageRejected(code, msg) {
121
- const evt = { type: 'task_message_rejected', code };
120
+ export function buildFeatureMessageRejected(code, msg) {
121
+ const evt = { type: 'feature_message_rejected', code };
122
122
  if (msg && typeof msg.requestId === 'string') evt.requestId = msg.requestId;
123
123
  if (msg && typeof msg.groupId === 'string') evt.groupId = msg.groupId;
124
- if (msg && typeof msg.taskId === 'string') evt.taskId = msg.taskId;
124
+ if (msg && typeof msg.featureId === 'string') evt.featureId = msg.featureId;
125
125
  return evt;
126
126
  }
127
127
 
@@ -132,13 +132,13 @@ export function buildTaskMessageRejected(code, msg) {
132
132
  * @param {(event:object)=>void} sendUnifyEvent
133
133
  * @param {{now?:()=>number, msgId?:()=>string}} [opts] — test seams
134
134
  */
135
- export function handleUnifyTaskMessage(msg, sendUnifyEvent, opts = {}) {
136
- const result = validateTaskMessage(msg);
135
+ export function handleUnifyFeatureMessage(msg, sendUnifyEvent, opts = {}) {
136
+ const result = validateFeatureMessage(msg);
137
137
  if (!result.ok) {
138
- try { sendUnifyEvent(buildTaskMessageRejected(result.code, msg)); } catch { /* best-effort */ }
138
+ try { sendUnifyEvent(buildFeatureMessageRejected(result.code, msg)); } catch { /* best-effort */ }
139
139
  return;
140
140
  }
141
141
  const requestId = msg && typeof msg.requestId === 'string' ? msg.requestId : undefined;
142
- const evt = buildTaskMessageEvent(result.payload, { ...opts, requestId });
142
+ const evt = buildFeatureMessageEvent(result.payload, { ...opts, requestId });
143
143
  try { sendUnifyEvent(evt); } catch { /* never crash WS pipeline */ }
144
144
  }