@deepseek-ai/dsh-session 0.2.0-rc.2 → 0.2.1-alpha.2

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.
@@ -1,207 +0,0 @@
1
- /**
2
- * Package-owned relational invariants for the session event log. Load this
3
- * companion beside `@deepseek-ai/dsh-invariants` to enable the checks.
4
- *
5
- * @module @deepseek-ai/dsh-session/invariant
6
- */
7
- import { assertNever } from '@deepseek-ai/dsh-util-values';
8
- import { TOOL_NOT_STARTED } from "./repair.js";
9
- const PACKAGE_NAME = '@deepseek-ai/dsh-session';
10
- /** Cordis companion plugin name. */
11
- export const name = 'session-invariant';
12
- /** Service required before the companion can reserve package ownership. */
13
- export const inject = ['invariants'];
14
- /** Assert that a step-scoped event names the currently open turn and step. */
15
- function requireOpenStep(trace, kind, turn, step, fail) {
16
- if (trace.openTurn !== turn || trace.openStep !== step) {
17
- fail(`${kind} names turn ${turn}/step ${step} but open is turn ${trace.openTurn}/step ${trace.openStep}`);
18
- }
19
- }
20
- /** Validate one candidate event without mutating the committed trace. */
21
- function validateEvent(trace, event, fail) {
22
- if (event.seq <= trace.lastSeq) {
23
- fail(`seq must strictly increase: saw ${event.seq} after ${trace.lastSeq}`);
24
- }
25
- let openTurn = trace.openTurn;
26
- let openStep = trace.openStep;
27
- let nextTurn = trace.nextTurn;
28
- let nextStep = trace.nextStep;
29
- let pendingCalls = { kind: 'none' };
30
- // Context and plugin-owned log-only events may be appended between model
31
- // executions. Core execution events retain their explicit turn relations.
32
- switch (event.type) {
33
- case 'turn/start': {
34
- if (trace.openTurn !== null) {
35
- fail(`turn/start ${event.data.turn} while turn ${trace.openTurn} is still open`);
36
- }
37
- if (event.data.turn !== trace.nextTurn) {
38
- fail(`turn/start expected turn ${trace.nextTurn}, got ${event.data.turn}`);
39
- }
40
- openTurn = event.data.turn;
41
- nextStep = 1;
42
- break;
43
- }
44
- case 'turn/end': {
45
- if (trace.openTurn !== event.data.turn) {
46
- fail(`turn/end ${event.data.turn} does not match open turn ${trace.openTurn}`);
47
- }
48
- if (trace.openStep !== null) {
49
- fail(`turn/end ${event.data.turn} while step ${trace.openStep} is still open`);
50
- }
51
- openTurn = null;
52
- nextTurn += 1;
53
- break;
54
- }
55
- case 'step/start': {
56
- if (trace.openTurn !== event.data.turn) {
57
- fail(`step/start in turn ${event.data.turn} but open turn is ${trace.openTurn}`);
58
- }
59
- if (trace.openStep !== null) {
60
- fail(`step/start ${event.data.step} while step ${trace.openStep} is still open`);
61
- }
62
- if (event.data.step !== trace.nextStep) {
63
- fail(`step/start expected step ${trace.nextStep} in turn ${event.data.turn}, got ${event.data.step}`);
64
- }
65
- openStep = event.data.step;
66
- break;
67
- }
68
- case 'developer/message': {
69
- requireOpenStep(trace, 'developer/message', event.data.turn, event.data.step, fail);
70
- break;
71
- }
72
- case 'step/end': {
73
- requireOpenStep(trace, 'step/end', event.data.turn, event.data.step, fail);
74
- pendingCalls = { kind: 'clear' };
75
- openStep = null;
76
- nextStep += 1;
77
- break;
78
- }
79
- case 'assistant/attempt': {
80
- requireOpenStep(trace, 'assistant/attempt', event.data.turn, event.data.step, fail);
81
- break;
82
- }
83
- case 'assistant/message': {
84
- requireOpenStep(trace, 'assistant/message', event.data.turn, event.data.step, fail);
85
- break;
86
- }
87
- case 'tool/call': {
88
- requireOpenStep(trace, 'tool/call', event.data.turn, event.data.step, fail);
89
- pendingCalls = { kind: 'add', callId: event.data.callId };
90
- break;
91
- }
92
- case 'tool/result': {
93
- // Session has already validated a content rewrite that cites its replaced event.
94
- // It is durable turn work, not a second execution of the original call.
95
- if (event.surfaceOp !== 'append') {
96
- if (trace.openTurn === null) {
97
- fail('tool/result surface replacement appended outside any open turn');
98
- }
99
- break;
100
- }
101
- requireOpenStep(trace, 'tool/result', event.data.turn, event.data.step, fail);
102
- const callId = event.data.message.source.callId;
103
- const syntheticNotStarted = event.data.message.isError === true && event.data.error?.code === TOOL_NOT_STARTED;
104
- if (!trace.pendingCalls.has(callId) && !syntheticNotStarted) {
105
- fail(`tool/result for ${callId} with no prior tool/call in this step`);
106
- }
107
- pendingCalls = { kind: 'delete', callId };
108
- break;
109
- }
110
- case 'system/message': {
111
- requireOpenStep(trace, 'system/message', event.data.turn, event.data.step, fail);
112
- break;
113
- }
114
- case 'user/message':
115
- break;
116
- case 'session/end-seed':
117
- // Unconstrained: an unbalanced seed legally puts it inside an open turn.
118
- break;
119
- case 'request/header':
120
- case 'request/context': {
121
- if (trace.openTurn === null) {
122
- fail(`${event.type} appended outside any open turn (core execution events must be turn-enclosed)`);
123
- }
124
- break;
125
- }
126
- default:
127
- // Merge-extensible event relations belong to their owning plugin.
128
- break;
129
- }
130
- return {
131
- scalars: { lastSeq: event.seq, openTurn, openStep, nextTurn, nextStep },
132
- pendingCalls,
133
- };
134
- }
135
- /** Apply one already-validated transition after its event commits. */
136
- function applyTransition(trace, transition) {
137
- Object.assign(trace, transition.scalars);
138
- switch (transition.pendingCalls.kind) {
139
- case 'none':
140
- break;
141
- case 'add':
142
- trace.pendingCalls.add(transition.pendingCalls.callId);
143
- break;
144
- case 'delete':
145
- trace.pendingCalls.delete(transition.pendingCalls.callId);
146
- break;
147
- case 'clear':
148
- trace.pendingCalls.clear();
149
- break;
150
- /* v8 ignore next -- validateEvent produces this closed transition union */
151
- default:
152
- assertNever(transition.pendingCalls, 'session trace pending-call transition');
153
- }
154
- }
155
- /** Install the session contribution into its child registration fiber. */
156
- const install = Object.assign((ctx, fail) => {
157
- const traces = new WeakMap();
158
- const stagedTransitions = new WeakMap();
159
- const freshTrace = () => ({
160
- lastSeq: -1,
161
- openTurn: null,
162
- openStep: null,
163
- nextTurn: 1,
164
- nextStep: 1,
165
- pendingCalls: new Set(),
166
- });
167
- const seedSession = (session) => {
168
- const trace = freshTrace();
169
- traces.set(session, trace);
170
- // oxlint-disable-next-line typescript/no-deprecated -- Existing Session history read; migration deferred.
171
- for (const event of session.snapshotEvents()) {
172
- applyTransition(trace, validateEvent(trace, event, fail));
173
- }
174
- return trace;
175
- };
176
- /* v8 ignore next -- session/event always follows list() or session/created seeding */
177
- const traceFor = (session) => traces.get(session) ?? seedSession(session);
178
- for (const session of ctx.sessions.list())
179
- seedSession(session);
180
- ctx.on('session/created', (session) => { seedSession(session); }, { global: true });
181
- ctx.on('session/event', (session, event) => {
182
- const staged = stagedTransitions.get(event);
183
- /* v8 ignore next 2 -- internal/dispatch stages the exact callback arguments */
184
- if (staged === undefined || staged.session !== session) {
185
- return fail('session/event reached publication without matching pre-commit validation');
186
- }
187
- stagedTransitions.delete(event);
188
- applyTransition(staged.trace, staged.transition);
189
- }, { global: true });
190
- ctx.on('internal/dispatch', (_mode, eventName, args) => {
191
- if (eventName !== 'session/event')
192
- return;
193
- const [session, event] = args;
194
- const trace = traceFor(session);
195
- const transition = validateEvent(trace, event, fail);
196
- // A later dispatch listener may veto. Validation is pure, so abandoning
197
- // this weakly keyed transition does not advance or retain the session.
198
- stagedTransitions.set(event, { session, trace, transition });
199
- }, { global: true });
200
- }, { inject: ['sessions'] });
201
- /**
202
- * Register the session invariant companion.
203
- * @param ctx - Cordis context carrying the invariant service.
204
- * @returns the installed registration's disposer after setup succeeds.
205
- */
206
- export const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
207
- //# sourceMappingURL=invariant.js.map