@deepseek-ai/dsh-message-feedback 0.1.2-alpha.5 → 0.1.3-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.
package/lib/index.js CHANGED
@@ -1,82 +1,15 @@
1
1
  import { Buffer } from "node:buffer";
2
2
  import { randomUUID } from "node:crypto";
3
+ import { isDeepStrictEqual } from "node:util";
3
4
  import { Service } from "@deepseek-ai/cordis";
4
5
  import s from "@deepseek-ai/schemastery";
5
- import { SessionLogOffset } from "@deepseek-ai/dsh-session";
6
+ import { z } from "zod";
7
+ import { SessionSeq } from "@deepseek-ai/dsh-session/types";
6
8
  import { deriveEventMessage, isAppendSurfaceEvent } from "@deepseek-ai/dsh-session/surface";
7
9
  import { Remote, TypertRemoteService } from "@deepseek-ai/dsh-typert-protocol";
8
- import { z } from "zod";
9
- import { defineDomain, domainTable } from "@deepseek-ai/dsh-storage-domain";
10
- //#region lib/types/spec.js
11
- /**
12
- * Durable storage-domain declaration for lifecycle-bound message feedback.
13
- * @module @deepseek-ai/dsh-message-feedback/src/spec
14
- */
15
- const nonNegativeSafeInteger = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
16
- /** Runtime schema for the closed rating vocabulary. */
17
- const messageFeedbackRatingSchema = z.union([z.literal("positive"), z.literal("negative")]);
18
- /** Runtime schema for one opaque item version stored on disk. */
19
- const messageFeedbackVersionSchema = z.uuid().transform((value) => value);
20
- /** Runtime schema for one current feedback item. */
21
- const messageFeedbackItemSchema = z.object({
22
- messageId: z.string().min(1).transform((value) => value),
23
- rating: messageFeedbackRatingSchema,
24
- note: z.string().refine((note) => note.trim().length > 0, { message: "message feedback note must contain a non-whitespace character" }).optional(),
25
- version: messageFeedbackVersionSchema,
26
- createdAt: nonNegativeSafeInteger,
27
- updatedAt: nonNegativeSafeInteger
28
- }).refine((item) => item.updatedAt >= item.createdAt, {
29
- path: ["updatedAt"],
30
- message: "message feedback updatedAt must not precede createdAt"
31
- });
32
- /** Persisted Session fields that fence a sidecar row to one log lifecycle. */
33
- const messageFeedbackSessionIdentitySchema = z.object({
34
- createdAt: nonNegativeSafeInteger,
35
- cwd: z.string().optional()
36
- });
37
- /**
38
- * One whole-Session sidecar. Duplicate message ids would make item lookup
39
- * ambiguous; duplicate versions would break their independent identity.
40
- */
41
- const messageFeedbackRowSchema = z.object({
42
- session: messageFeedbackSessionIdentitySchema,
43
- items: z.array(messageFeedbackItemSchema)
44
- }).superRefine((row, ctx) => {
45
- const messageIds = /* @__PURE__ */ new Set();
46
- const versions = /* @__PURE__ */ new Set();
47
- row.items.forEach((item, index) => {
48
- if (messageIds.has(item.messageId)) ctx.addIssue({
49
- code: "custom",
50
- path: [
51
- "items",
52
- index,
53
- "messageId"
54
- ],
55
- message: `duplicate message feedback id '${item.messageId}'`
56
- });
57
- messageIds.add(item.messageId);
58
- if (versions.has(item.version)) ctx.addIssue({
59
- code: "custom",
60
- path: [
61
- "items",
62
- index,
63
- "version"
64
- ],
65
- message: `duplicate message feedback version '${item.version}'`
66
- });
67
- versions.add(item.version);
68
- });
69
- });
70
- /** One lifecycle-bound sidecar record per Session id. */
71
- const messageFeedbackDomainSpec = defineDomain({
72
- name: "message_feedback",
73
- version: 0,
74
- tables: { sessions: domainTable(messageFeedbackRowSchema) }
75
- });
76
- //#endregion
77
10
  //#region lib/types/index.js
78
11
  /**
79
- * Durable, lifecycle-bound feedback for finalized assistant messages.
12
+ * Canonical Session-log feedback for finalized assistant messages.
80
13
  * @module @deepseek-ai/dsh-message-feedback
81
14
  */
82
15
  var __runInitializers = function(thisArg, initializers, value) {
@@ -117,74 +50,56 @@ var __esDecorate = function(ctor, descriptorIn, decorators, contextIn, initializ
117
50
  if (target) Object.defineProperty(target, contextIn.name, descriptor);
118
51
  done = true;
119
52
  };
120
- /** Immutable empty list reused only as an input to caller-owned copying. */
121
- const EMPTY_ITEMS = Object.freeze([]);
122
- /** Validate the one deployment-varying limit at the configuration boundary. */
123
- function resolveMaxNoteBytes(value) {
124
- if (!Number.isSafeInteger(value) || value < 1) throw new TypeError(`message-feedback: maxNoteBytes must be a positive safe integer, got ${String(value)}`);
125
- return value;
126
- }
127
- /** Copy and freeze one item before it crosses the service boundary. */
53
+ const timestamp = z.number().int().nonnegative().max(Number.MAX_SAFE_INTEGER);
54
+ const itemSchema = z.object({
55
+ messageId: z.string().min(1),
56
+ rating: z.enum(["positive", "negative"]),
57
+ note: z.string().refine((note) => note.trim().length > 0).optional(),
58
+ version: z.uuid(),
59
+ createdAt: timestamp,
60
+ updatedAt: timestamp
61
+ }).refine((item) => item.updatedAt >= item.createdAt);
62
+ const putSchema = z.object({
63
+ sessionId: z.string().min(1),
64
+ item: itemSchema
65
+ });
66
+ const deleteSchema = z.object({
67
+ sessionId: z.string().min(1),
68
+ messageId: z.string().min(1)
69
+ });
70
+ /** Return a caller-owned immutable value, detached from the log. */
128
71
  function snapshotItem(item) {
129
- return Object.freeze({
130
- messageId: item.messageId,
131
- rating: item.rating,
132
- ...item.note === void 0 ? {} : { note: item.note },
133
- version: item.version,
134
- createdAt: item.createdAt,
135
- updatedAt: item.updatedAt
136
- });
137
- }
138
- /** Copy and freeze a list response. */
139
- function snapshotList(items) {
140
- return Object.freeze({ items: Object.freeze(items.map(snapshotItem)) });
72
+ return Object.freeze({ ...item });
141
73
  }
142
- /** Build a frozen success branch. */
143
74
  function success(value) {
144
75
  return Object.freeze({
145
76
  ok: true,
146
77
  value
147
78
  });
148
79
  }
149
- /** Build a frozen business-failure branch. */
150
80
  function rejected(error) {
151
81
  return Object.freeze({
152
82
  ok: false,
153
83
  error: Object.freeze(error)
154
84
  });
155
85
  }
156
- /** Project the Session fields that distinguish one persisted log lifecycle. */
157
- function identityOf(header) {
158
- return Object.freeze({
159
- createdAt: header.createdAt,
160
- ...header.cwd === void 0 ? {} : { cwd: header.cwd }
161
- });
162
- }
163
- /** Whether a stored row belongs to the inspected Session lifecycle. */
164
- function sameIdentity(row, header) {
165
- return row.session.createdAt === header.createdAt && row.session.cwd === header.cwd;
166
- }
167
- /** Whether two observations name the same persisted Session lifecycle. */
168
- function sameHeaderIdentity(left, right) {
169
- return left.id === right.id && left.createdAt === right.createdAt && left.cwd === right.cwd;
170
- }
171
- /** Freeze the replacement row so storage-domain never exposes mutable aliases. */
172
- function rowSnapshot(session, items) {
173
- const copiedItems = items.map(snapshotItem);
174
- Object.freeze(copiedItems);
175
- return Object.freeze({
176
- session,
177
- items: copiedItems
178
- });
179
- }
180
- /** Generate an opaque equality token for one material mutation. */
181
- function nextVersion() {
182
- return randomUUID();
86
+ /** Validate persisted payloads before deriving current, Session-owned feedback. */
87
+ function currentItems(sessionId, events) {
88
+ const items = /* @__PURE__ */ new Map();
89
+ for (const event of events) switch (event.type) {
90
+ case "feedback/message-put":
91
+ putSchema.parse(event.data);
92
+ if (event.data.sessionId === sessionId) items.set(event.data.item.messageId, event.data.item);
93
+ break;
94
+ case "feedback/message-delete":
95
+ deleteSchema.parse(event.data);
96
+ if (event.data.sessionId === sessionId) items.delete(event.data.messageId);
97
+ break;
98
+ default: break;
99
+ }
100
+ return [...items.values()];
183
101
  }
184
- /**
185
- * Storage-domain sidecar service. It inspects persisted Session history and
186
- * never creates or resumes an Agent or Session.
187
- */
102
+ /** Session-log service; cold operations never construct a Session or Agent. */
188
103
  let MessageFeedbackService = (() => {
189
104
  let _classSuper = TypertRemoteService;
190
105
  let _instanceExtraInitializers = [];
@@ -237,151 +152,149 @@ let MessageFeedbackService = (() => {
237
152
  value: _metadata
238
153
  });
239
154
  }
240
- static inject = [
241
- "storageDomain",
242
- "sessionPersistence",
243
- "sessions"
244
- ];
155
+ static inject = ["sessionPersistence", "sessions"];
245
156
  /** Loader validation for the required note-size policy. */
246
157
  static Config = s.object({ maxNoteBytes: s.number().step(1).min(1).required() });
247
158
  maxNoteBytes = __runInitializers(this, _instanceExtraInitializers);
248
- table;
249
159
  operationTails = /* @__PURE__ */ new Map();
250
160
  mutationAdmissionOpen = true;
251
161
  /**
252
- * @param ctx - Host context carrying persistence and the storage-domain form.
162
+ * @param ctx - Host context carrying Session persistence and live owners.
253
163
  * @param config - Required note-size policy.
254
164
  */
255
165
  constructor(ctx, config) {
256
166
  super(ctx, "messageFeedback");
257
- this.maxNoteBytes = resolveMaxNoteBytes(config.maxNoteBytes);
167
+ if (!Number.isSafeInteger(config.maxNoteBytes) || config.maxNoteBytes < 1) throw new TypeError("message-feedback: maxNoteBytes must be a positive safe integer");
168
+ this.maxNoteBytes = config.maxNoteBytes;
258
169
  }
259
- /** Open and own the one message-feedback sidecar domain. */
260
- async [Service.init]() {
261
- const domain = await this.ctx.storageDomain.open(messageFeedbackDomainSpec);
170
+ [Service.init]() {
262
171
  this.ctx.effect(() => async () => {
263
172
  this.mutationAdmissionOpen = false;
264
173
  await Promise.all(this.operationTails.values());
265
- await domain.close();
266
- }, "message-feedback.domainClose");
267
- this.table = domain.table("sessions");
174
+ }, "message-feedback.drain");
268
175
  }
269
176
  /**
270
- * Read feedback belonging to the current persisted Session lifecycle.
271
- * A stale row from a reused Session id is invisible.
272
- * @param request - Session identity to inspect and list.
273
- * @returns current immutable items or `session-not-found`.
177
+ * Read current feedback from the canonical log.
178
+ * @param request - Session to inspect.
179
+ * @returns immutable items or a definite persistence miss.
274
180
  */
275
- async list(request) {
276
- const known = await this.inspectSession(request.sessionId);
277
- if (!known.ok) return known;
278
- const row = this.requireTable().get(request.sessionId);
279
- return success(snapshotList(row !== void 0 && sameIdentity(row, known.value.meta) ? row.items : EMPTY_ITEMS));
181
+ list(request) {
182
+ return this.enqueue(request.sessionId, () => this.withSession(request.sessionId, false, (events) => success(Object.freeze({ items: Object.freeze(currentItems(request.sessionId, events).map(snapshotItem)) }))));
280
183
  }
281
184
  /**
282
- * Create or replace feedback for one derived append-origin assistant
283
- * message. Every request must match the addressed item's current version;
284
- * a matching no-op returns the stored item without changing its revision.
285
- * @param request - target, desired value, and observed item version.
286
- * @returns the committed item or an explicit business failure.
185
+ * Create or replace feedback after checking its current version.
186
+ * Matching no-ops retain the version and append no event.
187
+ * @param request - Target, desired value, and observed item version.
188
+ * @returns the durable item or an explicit business failure.
287
189
  */
288
190
  put(request) {
289
191
  const note = this.resolveNote(request.note);
290
192
  if (!note.ok) return Promise.resolve(note);
291
- return this.enqueue(request.sessionId, async () => {
292
- const known = await this.inspectSession(request.sessionId);
293
- if (!known.ok) return known;
294
- if (!this.hasFeedbackTarget(known.value, request.messageId)) return rejected({
295
- code: "target-not-found",
296
- sessionId: request.sessionId,
297
- messageId: request.messageId
298
- });
299
- const durable = await this.ensureTargetDurable(known.value);
300
- if (!sameHeaderIdentity(durable.meta, known.value.meta) || !this.hasFeedbackTarget(durable, request.messageId)) return rejected({
193
+ return this.enqueue(request.sessionId, () => this.withSession(request.sessionId, true, async (events, append) => {
194
+ const items = currentItems(request.sessionId, events);
195
+ if (!events.some((event) => event.type === "assistant/message" && isAppendSurfaceEvent(event) && deriveEventMessage(event)?.id === request.messageId)) return rejected({
301
196
  code: "target-not-found",
302
197
  sessionId: request.sessionId,
303
198
  messageId: request.messageId
304
199
  });
305
- const table = this.requireTable();
306
- const stored = table.get(request.sessionId);
307
- const items = (stored !== void 0 && sameIdentity(stored, durable.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS;
308
- const index = items.findIndex((item) => item.messageId === request.messageId);
309
- const existing = items[index];
200
+ const existing = items.find((item) => item.messageId === request.messageId);
310
201
  if (request.ifVersion !== (existing?.version ?? null)) return rejected(this.versionConflict(existing ?? null));
311
- if (existing !== void 0 && existing.rating === request.rating && existing.note === note.value) return success(snapshotItem(existing));
202
+ if (existing !== void 0 && existing.rating === request.rating && existing.note === note.value) {
203
+ await append();
204
+ return success(snapshotItem(existing));
205
+ }
312
206
  const now = Date.now();
313
- const item = snapshotItem({
207
+ const item = {
314
208
  messageId: request.messageId,
315
209
  rating: request.rating,
316
210
  ...note.value === void 0 ? {} : { note: note.value },
317
- version: nextVersion(),
211
+ version: randomUUID(),
318
212
  createdAt: existing?.createdAt ?? now,
319
213
  updatedAt: existing === void 0 ? now : Math.max(now, existing.updatedAt)
214
+ };
215
+ await append({
216
+ type: "feedback/message-put",
217
+ data: {
218
+ sessionId: request.sessionId,
219
+ item
220
+ }
320
221
  });
321
- const nextItems = [...items];
322
- if (index === -1) nextItems.push(item);
323
- else nextItems[index] = item;
324
- await table.put(request.sessionId, rowSnapshot(identityOf(durable.meta), nextItems));
325
222
  return success(snapshotItem(item));
326
- });
223
+ }));
327
224
  }
328
225
  /**
329
- * Delete one feedback item. Absence is successful regardless of the
330
- * supplied version; an existing item requires an exact version match.
226
+ * Delete one item after checking its version; absence succeeds without an event.
331
227
  * @param request - Session, message, and observed item version.
332
- * @returns the stable absent postcondition, or an explicit failure.
228
+ * @returns the stable absent postcondition or an explicit failure.
333
229
  */
334
230
  delete(request) {
335
- return this.enqueue(request.sessionId, async () => {
336
- const known = await this.inspectSession(request.sessionId);
337
- if (!known.ok) return known;
338
- const table = this.requireTable();
339
- const stored = table.get(request.sessionId);
340
- const items = (stored !== void 0 && sameIdentity(stored, known.value.meta) ? stored : void 0)?.items ?? EMPTY_ITEMS;
341
- const existing = items.find((item) => item.messageId === request.messageId);
342
- if (existing === void 0) return success(Object.freeze({ absent: true }));
343
- if (request.ifVersion !== existing.version) return rejected(this.versionConflict(existing));
344
- await table.put(request.sessionId, rowSnapshot(identityOf(known.value.meta), items.filter((item) => item !== existing)));
231
+ return this.enqueue(request.sessionId, () => this.withSession(request.sessionId, true, async (events, append) => {
232
+ const existing = currentItems(request.sessionId, events).find((item) => item.messageId === request.messageId);
233
+ if (existing !== void 0) {
234
+ if (request.ifVersion !== existing.version) return rejected(this.versionConflict(existing));
235
+ await append({
236
+ type: "feedback/message-delete",
237
+ data: {
238
+ sessionId: request.sessionId,
239
+ messageId: request.messageId
240
+ }
241
+ });
242
+ } else await append();
345
243
  return success(Object.freeze({ absent: true }));
346
- });
347
- }
348
- /**
349
- * Resolve a live owner directly; otherwise use the storage catalog as the
350
- * existence authority before inspecting the log. Inspection failures for a
351
- * catalogued Session remain infrastructure failures rather than being
352
- * guessed into the business `session-not-found` branch.
353
- */
354
- async inspectSession(sessionId) {
355
- if (this.ctx.sessions.get(sessionId) === void 0) {
356
- if (!(await this.ctx.sessionPersistence.listSnapshots()).some((snapshot) => snapshot.header.id === sessionId) && this.ctx.sessions.get(sessionId) === void 0) return rejected({
357
- code: "session-not-found",
358
- sessionId
359
- });
360
- }
361
- return success(await this.ctx.sessionPersistence.inspect(sessionId));
244
+ }));
362
245
  }
363
- /** Require the exact finalized append-origin assistant message projection. */
364
- hasFeedbackTarget(inspection, messageId) {
365
- return inspection.events.some((event) => {
366
- if (event.type !== "assistant/message" || !isAppendSurfaceEvent(event)) return false;
367
- const message = deriveEventMessage(event);
368
- return message?.role === "assistant" && message.id === messageId;
246
+ /** Hold cold write ownership across read/compare/append; use live owners directly. */
247
+ async withSession(sessionId, write, operation) {
248
+ if (this.ctx.sessions.get(sessionId) === void 0 && await this.ctx.sessionPersistence.stat(sessionId) === void 0 && this.ctx.sessions.get(sessionId) === void 0) return rejected({
249
+ code: "session-not-found",
250
+ sessionId
369
251
  });
370
- }
371
- /**
372
- * Put the target log prefix behind a durability barrier before its sidecar.
373
- * A live owner flushes through the SessionStore's canonical checkpoint; a
374
- * cold owner is re-read from the physical durable prefix.
375
- */
376
- async ensureTargetDurable(inspection) {
377
- const live = this.ctx.sessions.get(inspection.meta.id);
378
- if (live !== void 0 && sameHeaderIdentity(live.header, inspection.meta)) {
379
- if (!await this.ctx.sessions.flush(live)) throw new Error(`message-feedback: no durability listener participated for live session '${inspection.meta.id}'`);
380
- return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, SessionLogOffset(0));
252
+ const live = this.ctx.sessions.get(sessionId);
253
+ if (live !== void 0) return operation(live.snapshotEvents(), async (event) => {
254
+ if (event !== void 0) live.append(event.type, event.data);
255
+ const last = live.snapshotEvents().at(-1);
256
+ if (!await this.ctx.sessions.flush(live)) throw new Error(`message-feedback: no durability listener participated for live session '${sessionId}'`);
257
+ const handle = await this.ctx.sessionPersistence.open(sessionId, "read");
258
+ try {
259
+ const { events: stored } = await handle.read(last?.seq ?? 0, 1);
260
+ if (!isDeepStrictEqual([
261
+ handle.header.id,
262
+ handle.header.createdAt,
263
+ handle.header.cwd
264
+ ], [
265
+ live.header.id,
266
+ live.header.createdAt,
267
+ live.header.cwd
268
+ ]) || last !== void 0 && !isDeepStrictEqual(stored[0], last)) throw new Error(`message-feedback: feedback prefix is not durable for live session '${sessionId}'`);
269
+ } finally {
270
+ await handle.close();
271
+ }
272
+ });
273
+ const handle = await this.ctx.sessionPersistence.open(sessionId, write ? "write" : "read");
274
+ try {
275
+ const { events } = await handle.read();
276
+ return await operation(events, async (event) => {
277
+ const entry = event === void 0 ? void 0 : {
278
+ ...event,
279
+ seq: SessionSeq(events.length),
280
+ time: Date.now()
281
+ };
282
+ if (entry !== void 0) await handle.append([entry]);
283
+ await handle.flush();
284
+ if (entry !== void 0) try {
285
+ await this.ctx.parallel("feedback/committed", {
286
+ meta: handle.header,
287
+ inheritedEventCount: handle.inheritedEventCount,
288
+ events: [...events, entry]
289
+ });
290
+ } catch (error) {
291
+ this.ctx.logger.warn("message-feedback: committed feedback observer failed", error);
292
+ }
293
+ });
294
+ } finally {
295
+ await handle.close();
381
296
  }
382
- return await this.ctx.sessionPersistence.readFrom(inspection.meta.id, SessionLogOffset(0));
383
297
  }
384
- /** Validate optional-note semantics and the configured complete UTF-8 byte bound. */
385
298
  resolveNote(note) {
386
299
  if (note === void 0) return success(void 0);
387
300
  if (note.trim().length === 0) return rejected({ code: "note-blank" });
@@ -393,14 +306,13 @@ let MessageFeedbackService = (() => {
393
306
  });
394
307
  return success(note);
395
308
  }
396
- /** Return the authoritative item needed to reconcile one failed comparison. */
397
309
  versionConflict(current) {
398
310
  return {
399
311
  code: "version-conflict",
400
312
  current: current === null ? null : snapshotItem(current)
401
313
  };
402
314
  }
403
- /** Queue a complete read/compare/write mutation behind this Session's prior mutation. */
315
+ /** Serialize complete operations and drain their handles before disposal. */
404
316
  enqueue(sessionId, operation) {
405
317
  if (!this.mutationAdmissionOpen) return Promise.reject(/* @__PURE__ */ new Error("message-feedback: service is disposing"));
406
318
  const result = (this.operationTails.get(sessionId) ?? Promise.resolve()).then(operation);
@@ -410,12 +322,7 @@ let MessageFeedbackService = (() => {
410
322
  if (this.operationTails.get(sessionId) === tail) this.operationTails.delete(sessionId);
411
323
  });
412
324
  }
413
- /** Resolve the initialized durable table or fail a broken service lifecycle. */
414
- requireTable() {
415
- if (this.table === void 0) throw new Error("message-feedback: durable domain is not initialized");
416
- return this.table;
417
- }
418
325
  };
419
326
  })();
420
327
  //#endregion
421
- export { MessageFeedbackService, MessageFeedbackService as default, messageFeedbackDomainSpec, messageFeedbackItemSchema, messageFeedbackRatingSchema, messageFeedbackRowSchema, messageFeedbackSessionIdentitySchema, messageFeedbackVersionSchema };
328
+ export { MessageFeedbackService, MessageFeedbackService as default };
@@ -124,7 +124,7 @@ export const TYPERT = {
124
124
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult',
125
125
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema,
126
126
  },
127
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":273,"column":3},
127
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":203,"column":3},
128
128
  },
129
129
  {
130
130
  id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list',
@@ -149,7 +149,7 @@ export const TYPERT = {
149
149
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult',
150
150
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema,
151
151
  },
152
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":191,"column":9},
152
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":153,"column":3},
153
153
  },
154
154
  {
155
155
  id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put',
@@ -174,39 +174,39 @@ export const TYPERT = {
174
174
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult',
175
175
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema,
176
176
  },
177
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":207,"column":3},
177
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":165,"column":3},
178
178
  },
179
179
  ],
180
180
  model: {
181
181
  "services": [
182
182
  {
183
- "description": "Storage-domain sidecar service. It inspects persisted Session history and never creates or resumes an Agent or Session.",
184
- "summary": "Storage-domain sidecar service.",
183
+ "description": "Session-log service; cold operations never construct a Session or Agent.",
184
+ "summary": "Session-log service; cold operations never construct a Session or Agent.",
185
185
  "tags": [],
186
- "jsDoc": "/**\n * Storage-domain sidecar service. It inspects persisted Session history and\n * never creates or resumes an Agent or Session.\n */",
186
+ "jsDoc": "/** Session-log service; cold operations never construct a Session or Agent. */",
187
187
  "key": "messageFeedback",
188
188
  "exportName": "MessageFeedbackService",
189
189
  "members": [
190
190
  {
191
191
  "kind": "method",
192
192
  "name": "list",
193
- "signature": "@Remote('list') async list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>",
194
- "summary": "Read feedback belonging to the current persisted Session lifecycle.",
195
- "jsDoc": "/**\n * Read feedback belonging to the current persisted Session lifecycle.\n * A stale row from a reused Session id is invisible.\n * @param request - Session identity to inspect and list.\n * @returns current immutable items or `session-not-found`.\n */"
193
+ "signature": "@Remote('list') list(request: MessageFeedbackListRequest): Promise<MessageFeedbackListResult>",
194
+ "summary": "Read current feedback from the canonical log.",
195
+ "jsDoc": "/**\n * Read current feedback from the canonical log.\n * @param request - Session to inspect.\n * @returns immutable items or a definite persistence miss.\n */"
196
196
  },
197
197
  {
198
198
  "kind": "method",
199
199
  "name": "put",
200
200
  "signature": "@Remote('put') put(request: MessageFeedbackPutRequest): Promise<MessageFeedbackPutResult>",
201
- "summary": "Create or replace feedback for one derived append-origin assistant message.",
202
- "jsDoc": "/**\n * Create or replace feedback for one derived append-origin assistant\n * message. Every request must match the addressed item's current version;\n * a matching no-op returns the stored item without changing its revision.\n * @param request - target, desired value, and observed item version.\n * @returns the committed item or an explicit business failure.\n */"
201
+ "summary": "Create or replace feedback after checking its current version.",
202
+ "jsDoc": "/**\n * Create or replace feedback after checking its current version.\n * Matching no-ops retain the version and append no event.\n * @param request - Target, desired value, and observed item version.\n * @returns the durable item or an explicit business failure.\n */"
203
203
  },
204
204
  {
205
205
  "kind": "method",
206
206
  "name": "delete",
207
207
  "signature": "@Remote('delete') delete(request: MessageFeedbackDeleteRequest): Promise<MessageFeedbackDeleteResult>",
208
- "summary": "Delete one feedback item.",
209
- "jsDoc": "/**\n * Delete one feedback item. Absence is successful regardless of the\n * supplied version; an existing item requires an exact version match.\n * @param request - Session, message, and observed item version.\n * @returns the stable absent postcondition, or an explicit failure.\n */"
208
+ "summary": "Delete one item after checking its version; absence succeeds without an event.",
209
+ "jsDoc": "/**\n * Delete one item after checking its version; absence succeeds without an event.\n * @param request - Session, message, and observed item version.\n * @returns the stable absent postcondition or an explicit failure.\n */"
210
210
  }
211
211
  ],
212
212
  "types": [
@@ -301,7 +301,29 @@ export const TYPERT = {
301
301
  ]
302
302
  }
303
303
  ],
304
- "events": [],
304
+ "events": [
305
+ {
306
+ "description": "Observe a durable cold feedback mutation without publishing a live Session. Observers run before write ownership is released and must not await another message-feedback operation for this Session. The payload is borrowed read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).",
307
+ "summary": "Observe a durable cold feedback mutation without publishing a live Session.",
308
+ "tags": [
309
+ {
310
+ "name": "param",
311
+ "argument": "inspection",
312
+ "comment": "- committed canonical prefix, including the feedback as its last event.",
313
+ "text": "@param inspection - committed canonical prefix, including the feedback as its last event.\n *"
314
+ },
315
+ {
316
+ "name": "mode",
317
+ "comment": "parallel",
318
+ "text": "@mode parallel"
319
+ }
320
+ ],
321
+ "jsDoc": "/**\n * Observe a durable cold feedback mutation without publishing a live Session.\n * Observers run before write ownership is released and must not await\n * another message-feedback operation for this Session. The payload is borrowed\n * read-only; deep-clone it before transferring ownership (for example, to Session.fromRestore).\n * @param inspection - committed canonical prefix, including the feedback as its last event.\n * @mode parallel\n */",
322
+ "name": "feedback/committed",
323
+ "mode": "parallel",
324
+ "signature": "'feedback/committed'(inspection: SessionInspection): void"
325
+ }
326
+ ],
305
327
  "objects": []
306
328
  },
307
329
  }
@@ -121,7 +121,7 @@ export const TYPERT_REMOTE = {
121
121
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackDeleteResult',
122
122
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_delete_result$schema,
123
123
  },
124
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":273,"column":3},
124
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":203,"column":3},
125
125
  },
126
126
  {
127
127
  id: '@deepseek-ai/dsh-message-feedback#messageFeedback/list',
@@ -146,7 +146,7 @@ export const TYPERT_REMOTE = {
146
146
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackListResult',
147
147
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_list_result$schema,
148
148
  },
149
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":191,"column":9},
149
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":153,"column":3},
150
150
  },
151
151
  {
152
152
  id: '@deepseek-ai/dsh-message-feedback#messageFeedback/put',
@@ -171,7 +171,7 @@ export const TYPERT_REMOTE = {
171
171
  typeSymbol: '@deepseek-ai/dsh-message-feedback/types#MessageFeedbackPutResult',
172
172
  schema: _deepseek_ai_dsh_message_feedback_messageFeedback_put_result$schema,
173
173
  },
174
- sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":207,"column":3},
174
+ sourceLocation: {"file":"packages/feedback/message-feedback/src/index.ts","line":165,"column":3},
175
175
  },
176
176
  ],
177
177
  }