@yeaft/webchat-agent 0.1.616 → 0.1.618
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/connection/message-router.js +5 -5
- package/package.json +1 -1
- package/unify/compact/orchestrator.js +1 -1
- package/unify/{task-message.js → feature-message.js} +38 -38
- package/unify/features/store.js +583 -0
- package/unify/{tasks → features}/summary.js +54 -85
- package/unify/memory/dream-shard.js +15 -15
- package/unify/memory/recall-r6.js +2 -2
- package/unify/memory/schema.js +7 -7
- package/unify/memory/scope-tree.js +6 -6
- package/unify/pipeline/dispatcher.js +7 -7
- package/unify/router/intent-classifier.js +25 -25
- package/unify/session.js +3 -3
- package/unify/threads/store.js +18 -18
- package/unify/tools/{task-tools.js → feature-tools.js} +180 -175
- package/unify/tools/index.js +21 -21
- package/unify/tools/thread-tools.js +29 -108
- package/unify/web-bridge.js +61 -61
- package/unify/memory/migrate-r5-to-r6.js +0 -611
- package/unify/migration/detect.js +0 -176
- package/unify/migration/map-fields.js +0 -293
- package/unify/migration/v0-to-v1.js +0 -588
- package/unify/tasks/store.js +0 -652
|
@@ -425,10 +425,10 @@ export async function handleMessage(msg) {
|
|
|
425
425
|
handleUnifyVpRead(msg);
|
|
426
426
|
break;
|
|
427
427
|
|
|
428
|
-
// task-334h (R6 §Δ28 / §Δ31.6):
|
|
428
|
+
// task-334h (R6 §Δ28 / §Δ31.6): feature-scoped direct message echo.
|
|
429
429
|
// Replaces the withdrawn R3 `unify_task_private_chat`. Agent validates,
|
|
430
|
-
// stamps msgId + ts, and broadcasts the `
|
|
431
|
-
case '
|
|
430
|
+
// stamps msgId + ts, and broadcasts the `feature_message` mirror back.
|
|
431
|
+
case 'unify_feature_message':
|
|
432
432
|
handleUnifyTaskMessage(msg);
|
|
433
433
|
break;
|
|
434
434
|
|
|
@@ -455,11 +455,11 @@ export async function handleMessage(msg) {
|
|
|
455
455
|
handleUnifyMemoryTrace(msg);
|
|
456
456
|
break;
|
|
457
457
|
|
|
458
|
-
// R6 G1a —
|
|
458
|
+
// R6 G1a — feature summary history + feature affiliation CRUD.
|
|
459
459
|
case 'unify_fetch_summary_history':
|
|
460
460
|
await handleUnifyFetchSummaryHistory(msg);
|
|
461
461
|
break;
|
|
462
|
-
case '
|
|
462
|
+
case 'unify_feature_crud':
|
|
463
463
|
await handleUnifyTaskCrud(msg);
|
|
464
464
|
break;
|
|
465
465
|
|
package/package.json
CHANGED
|
@@ -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: '
|
|
114
|
+
await writeSummary({ kind: 'feature', id: taskId }, next, { root });
|
|
115
115
|
taskSummaryRefreshed = true;
|
|
116
116
|
}
|
|
117
117
|
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* feature-message.js — R6 §Δ28 / §Δ31.6 feature-scoped direct messaging.
|
|
3
3
|
*
|
|
4
|
-
* Replaces the withdrawn R3 `
|
|
5
|
-
* echo-able `
|
|
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): `
|
|
8
|
-
* { type, groupId,
|
|
9
|
-
* outbound (agent → web): `
|
|
10
|
-
* { type, groupId,
|
|
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 +
|
|
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
|
|
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
|
-
* `
|
|
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
|
|
31
|
+
export const FEATURE_MESSAGE_REJECT_CODES = Object.freeze({
|
|
32
32
|
MISSING_GROUP_ID: 'missing_group_id',
|
|
33
|
-
|
|
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
|
|
49
|
+
export function validateFeatureMessage(msg) {
|
|
50
50
|
if (!msg || typeof msg !== 'object') {
|
|
51
|
-
return { ok: false, code:
|
|
51
|
+
return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
|
|
52
52
|
}
|
|
53
|
-
const { groupId,
|
|
53
|
+
const { groupId, featureId, vpId, text } = msg;
|
|
54
54
|
if (!groupId || typeof groupId !== 'string') {
|
|
55
|
-
return { ok: false, code:
|
|
55
|
+
return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_GROUP_ID };
|
|
56
56
|
}
|
|
57
|
-
if (!
|
|
58
|
-
return { ok: false, code:
|
|
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:
|
|
61
|
+
return { ok: false, code: FEATURE_MESSAGE_REJECT_CODES.MISSING_VP_ID };
|
|
62
62
|
}
|
|
63
|
-
// Allow the reserved `user` sentinel as a speaker here —
|
|
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:
|
|
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:
|
|
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:
|
|
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,
|
|
85
|
+
payload: { groupId, featureId, vpId, text, mentions, replyTo },
|
|
86
86
|
};
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* Build the outbound `
|
|
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,
|
|
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
|
|
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: '
|
|
101
|
+
type: 'feature_message',
|
|
102
102
|
groupId: payload.groupId,
|
|
103
|
-
|
|
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 `
|
|
117
|
-
* @param {string} code — one of
|
|
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
|
|
121
|
-
const evt = { type: '
|
|
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.
|
|
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
|
|
136
|
-
const result =
|
|
135
|
+
export function handleUnifyFeatureMessage(msg, sendUnifyEvent, opts = {}) {
|
|
136
|
+
const result = validateFeatureMessage(msg);
|
|
137
137
|
if (!result.ok) {
|
|
138
|
-
try { sendUnifyEvent(
|
|
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 =
|
|
142
|
+
const evt = buildFeatureMessageEvent(result.payload, { ...opts, requestId });
|
|
143
143
|
try { sendUnifyEvent(evt); } catch { /* never crash WS pipeline */ }
|
|
144
144
|
}
|