@north-light/crouter 0.3.185 → 0.3.186
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/dist/api/dto/broker.d.ts +0 -32
- package/dist/api/dto/messages.d.ts +0 -5
- package/dist/clients/attach/input/controller.js +3 -4
- package/dist/clients/attach/overlays/mcp.js +1 -3
- package/dist/clients/attach/slash/dispatch.js +0 -2
- package/dist/clients/attach/viewer.js +354 -354
- package/dist/commands/memory/list.js +7 -3
- package/dist/core/__tests__/session-model.test.js +2 -4
- package/dist/core/runtime/broker/event-projection.d.ts +1 -8
- package/dist/core/runtime/broker/event-projection.js +1 -25
- package/dist/core/runtime/broker/frame-dispatch.d.ts +0 -2
- package/dist/core/runtime/broker/frame-dispatch.js +8 -41
- package/dist/core/runtime/broker-protocol.d.ts +1 -46
- package/dist/core/runtime/broker.js +1 -8
- package/dist/core/runtime/interactive-deliver.d.ts +2 -5
- package/dist/core/runtime/interactive-deliver.js +3 -6
- package/dist/core/session-model/session-state.d.ts +3 -6
- package/dist/core/session-model/session-state.js +1 -5
- package/dist/daemon/api/handlers/messages.js +1 -7
- package/package.json +1 -1
- package/runtime.lock.json +2 -2
- package/dist/core/runtime/broker/message-ledger.d.ts +0 -53
- package/dist/core/runtime/broker/message-ledger.js +0 -143
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
// message-ledger.ts — broker-owned message identity across pi's id-less queues.
|
|
2
|
-
//
|
|
3
|
-
// pi's steering/follow-up queues and user messages carry TEXT only: `steer()`
|
|
4
|
-
// pushes bare strings, `queue_update` relays bare string arrays, and retirement
|
|
5
|
-
// (on user `message_start`) is a first-index-of-text splice. Every downstream
|
|
6
|
-
// consumer was therefore forced into order/text heuristics to match its own
|
|
7
|
-
// optimistic send to the wake that echoed it — wrong under duplicates,
|
|
8
|
-
// cross-surface sends, and reconnect replay.
|
|
9
|
-
//
|
|
10
|
-
// The broker is the ONLY writer to the engine (every prompt/steer/follow_up/
|
|
11
|
-
// deliver funnels through driveEngine) and observes pi's event stream
|
|
12
|
-
// synchronously in-process, so it can own identity at the wire boundary: mint
|
|
13
|
-
// (or adopt the sender's) id per accepted frame, mirror pi's queue state by
|
|
14
|
-
// reconciling pi's own `queue_update` events, and attach the retired entry's id
|
|
15
|
-
// to the relayed user `message_start`. Same deterministic algorithm over the
|
|
16
|
-
// same data in the same process as pi's own bookkeeping — it cannot drift.
|
|
17
|
-
//
|
|
18
|
-
// pi ordering facts this relies on (verified at pi 0.83.0, agent-session.js):
|
|
19
|
-
// - `_queueSteer`/`_queueFollowUp` push the text and emit `queue_update`
|
|
20
|
-
// synchronously inside the steer/followUp call.
|
|
21
|
-
// - On a queued message's user `message_start`, `_handleAgentEvent` splices
|
|
22
|
-
// the queue and emits `queue_update` BEFORE emitting the `message_start`,
|
|
23
|
-
// so a retirement's queue_update always precedes its message and two
|
|
24
|
-
// removals never interleave.
|
|
25
|
-
// - An idle `prompt()` never touches a queue — its user message matches a
|
|
26
|
-
// pending dispatch intent by text instead.
|
|
27
|
-
import { randomUUID } from 'node:crypto';
|
|
28
|
-
/** Dispatch intents not yet observed anywhere: bounded FIFO so an intent whose
|
|
29
|
-
* text pi transformed (and so never matches) cannot accumulate forever. */
|
|
30
|
-
const MAX_PENDING_INTENTS = 32;
|
|
31
|
-
/** Recent id-bearing user-message dispatches carried in `welcome` so a
|
|
32
|
-
* reattaching follower can key its snapshot's trailing user wakes. */
|
|
33
|
-
const MAX_RECENT = 8;
|
|
34
|
-
export class MessageIdLedger {
|
|
35
|
-
steering = [];
|
|
36
|
-
followUp = [];
|
|
37
|
-
pendingIntents = [];
|
|
38
|
-
stagedRetirementId = null;
|
|
39
|
-
recent = [];
|
|
40
|
-
/** Record an accepted client frame's identity before its engine call runs.
|
|
41
|
-
* `id` is the sender's `message_id` when it minted one, else broker-minted. */
|
|
42
|
-
noteDispatch(id, text) {
|
|
43
|
-
this.pendingIntents.push({ id, text });
|
|
44
|
-
if (this.pendingIntents.length > MAX_PENDING_INTENTS)
|
|
45
|
-
this.pendingIntents.shift();
|
|
46
|
-
}
|
|
47
|
-
/** Remove a noted intent whose engine call rejected — the message will never
|
|
48
|
-
* appear in a queue or as a user message. No-op if already adopted. */
|
|
49
|
-
dropIntent(id) {
|
|
50
|
-
const idx = this.pendingIntents.findIndex((e) => e.id === id);
|
|
51
|
-
if (idx !== -1)
|
|
52
|
-
this.pendingIntents.splice(idx, 1);
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Fold one pi `queue_update` into the ledger and return the id arrays
|
|
56
|
-
* parallel to its text arrays (total: every position gets an id).
|
|
57
|
-
*
|
|
58
|
-
* Per-queue positional diff against the mirrored entries: a text matching an
|
|
59
|
-
* old entry at-or-after the cursor keeps its id (everything skipped is
|
|
60
|
-
* removed); an unmatched text ADOPTS the first pending intent with equal
|
|
61
|
-
* text, else mints a fresh id. Exactly ONE removal across both queues is
|
|
62
|
-
* pi's per-message retirement (its queue_update precedes the user
|
|
63
|
-
* `message_start` it belongs to) and is staged for `takeUserMessageId`;
|
|
64
|
-
* 0 or >1 removals (an enqueue, clearQueue/dequeue, abort) stage nothing.
|
|
65
|
-
*/
|
|
66
|
-
reconcileQueueUpdate(steering, followUp) {
|
|
67
|
-
const removed = [];
|
|
68
|
-
const next = (old, texts) => {
|
|
69
|
-
const out = [];
|
|
70
|
-
let cursor = 0;
|
|
71
|
-
for (const text of texts) {
|
|
72
|
-
let match = -1;
|
|
73
|
-
for (let j = cursor; j < old.length; j++) {
|
|
74
|
-
if (old[j].text === text) {
|
|
75
|
-
match = j;
|
|
76
|
-
break;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
if (match !== -1) {
|
|
80
|
-
for (let j = cursor; j < match; j++)
|
|
81
|
-
removed.push(old[j].id);
|
|
82
|
-
out.push(old[match]);
|
|
83
|
-
cursor = match + 1;
|
|
84
|
-
continue;
|
|
85
|
-
}
|
|
86
|
-
const intentIdx = this.pendingIntents.findIndex((e) => e.text === text);
|
|
87
|
-
const id = intentIdx !== -1 ? this.pendingIntents.splice(intentIdx, 1)[0].id : randomUUID();
|
|
88
|
-
out.push({ id, text });
|
|
89
|
-
}
|
|
90
|
-
for (let j = cursor; j < old.length; j++)
|
|
91
|
-
removed.push(old[j].id);
|
|
92
|
-
return out;
|
|
93
|
-
};
|
|
94
|
-
this.steering = next(this.steering, steering);
|
|
95
|
-
this.followUp = next(this.followUp, followUp);
|
|
96
|
-
this.stagedRetirementId = removed.length === 1 ? removed[0] : null;
|
|
97
|
-
return {
|
|
98
|
-
steeringIds: this.steering.map((e) => e.id),
|
|
99
|
-
followUpIds: this.followUp.map((e) => e.id),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* The id for a relayed user `message_start`, or undefined when this message
|
|
104
|
-
* carries none (an engine-command expansion, a text pi transformed, or a
|
|
105
|
-
* pre-ledger replay). A staged retirement wins — pi emitted its queue_update
|
|
106
|
-
* synchronously right before this message; otherwise the first pending
|
|
107
|
-
* intent with equal text (the idle-prompt case, which never touches a
|
|
108
|
-
* queue). Id-bearing results are remembered for `recentUserMessages`.
|
|
109
|
-
*/
|
|
110
|
-
takeUserMessageId(messageText) {
|
|
111
|
-
const staged = this.stagedRetirementId;
|
|
112
|
-
if (staged !== null) {
|
|
113
|
-
this.stagedRetirementId = null;
|
|
114
|
-
this.remember(staged, messageText);
|
|
115
|
-
return staged;
|
|
116
|
-
}
|
|
117
|
-
const idx = this.pendingIntents.findIndex((e) => e.text === messageText);
|
|
118
|
-
if (idx === -1)
|
|
119
|
-
return undefined;
|
|
120
|
-
const intent = this.pendingIntents.splice(idx, 1)[0];
|
|
121
|
-
this.remember(intent.id, messageText);
|
|
122
|
-
return intent.id;
|
|
123
|
-
}
|
|
124
|
-
/** The last {@link MAX_RECENT} id-bearing user-message dispatches, oldest
|
|
125
|
-
* first — the `welcome.recentUserMessages` payload. */
|
|
126
|
-
recentUserMessages() {
|
|
127
|
-
return this.recent.map((e) => ({ ...e }));
|
|
128
|
-
}
|
|
129
|
-
/** Session rebind/replacement: the mirrored queues, staged retirement, and
|
|
130
|
-
* recent list all described the OLD session — drop everything. */
|
|
131
|
-
reset() {
|
|
132
|
-
this.steering = [];
|
|
133
|
-
this.followUp = [];
|
|
134
|
-
this.pendingIntents = [];
|
|
135
|
-
this.stagedRetirementId = null;
|
|
136
|
-
this.recent = [];
|
|
137
|
-
}
|
|
138
|
-
remember(id, text) {
|
|
139
|
-
this.recent.push({ id, text });
|
|
140
|
-
if (this.recent.length > MAX_RECENT)
|
|
141
|
-
this.recent.shift();
|
|
142
|
-
}
|
|
143
|
-
}
|