@khorsheed/dsh-room 0.2.3 → 0.2.4

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.
@@ -138,7 +138,17 @@ export declare class DispatchEngine {
138
138
  * coordinator for plan work, else the dispatch's `replyTo`), at most once
139
139
  * per delivery. Public so a removal can settle the waits it breaks.
140
140
  */
141
+ /** Report-gate decisions per recipient, one at a time (see reportOutcome). */
142
+ private readonly gateQueues;
143
+ /**
144
+ * Gate one arrived report for the member waiting on it. Decisions for the
145
+ * same recipient run one at a time: a decision-model judgement takes a
146
+ * second or two, and a later report deciding meanwhile (the 「最后一个结果」
147
+ * rule) would hand over its batch without the one still being judged —
148
+ * which then got held behind a round that had already answered.
149
+ */
141
150
  reportOutcome(room: Session, dispatchSeq: number, deliveryId: string, fromId: string, outcome: string, text: string): Promise<void>;
151
+ private gateReport;
142
152
  /**
143
153
  * Mark the relays this run delivered as sent. Delivery = the member's own
144
154
  * session received the prompt (the followup accepted / the CLI run
@@ -451,7 +451,28 @@ export class DispatchEngine {
451
451
  * coordinator for plan work, else the dispatch's `replyTo`), at most once
452
452
  * per delivery. Public so a removal can settle the waits it breaks.
453
453
  */
454
+ /** Report-gate decisions per recipient, one at a time (see reportOutcome). */
455
+ gateQueues = new Map();
456
+ /**
457
+ * Gate one arrived report for the member waiting on it. Decisions for the
458
+ * same recipient run one at a time: a decision-model judgement takes a
459
+ * second or two, and a later report deciding meanwhile (the 「最后一个结果」
460
+ * rule) would hand over its batch without the one still being judged —
461
+ * which then got held behind a round that had already answered.
462
+ */
454
463
  async reportOutcome(room, dispatchSeq, deliveryId, fromId, outcome, text) {
464
+ const source = room.snapshotEvents().find(event => event.seq === dispatchSeq);
465
+ const key = `${room.id} ${source?.type === 'room/dispatch' ? source.data.replyTo ?? '' : ''}`;
466
+ const next = (this.gateQueues.get(key) ?? Promise.resolve())
467
+ .catch(() => { })
468
+ .then(() => this.gateReport(room, dispatchSeq, deliveryId, fromId, outcome, text));
469
+ this.gateQueues.set(key, next);
470
+ void next.then(() => { if (this.gateQueues.get(key) === next)
471
+ this.gateQueues.delete(key); }, () => { if (this.gateQueues.get(key) === next)
472
+ this.gateQueues.delete(key); });
473
+ return next;
474
+ }
475
+ async gateReport(room, dispatchSeq, deliveryId, fromId, outcome, text) {
455
476
  const events = room.snapshotEvents();
456
477
  const source = events.find(event => event.seq === dispatchSeq);
457
478
  if (source?.type !== 'room/dispatch' || (source.data.origin !== 'coordinator' && source.data.origin !== 'member') || source.data.replyTo === undefined)
@@ -891,6 +891,12 @@ let RoomService = (() => {
891
891
  const loaded = await this.loadCold(request.sessionId);
892
892
  if (!loaded.ok)
893
893
  return { ok: false, error: loaded.error };
894
+ // A held report's wake timer lives in the process that held it: after a
895
+ // restart nothing would ever hand it over. A cold room holding one is
896
+ // brought live, whose recovery hands every untimed hold over.
897
+ if (this.ctx.sessions.get(request.sessionId) === undefined && (loaded.state.deliveries ?? []).some(row => row.status === 'held')) {
898
+ void this.ensureLive(request.sessionId).catch((error) => { this.ctx.logger.warn(`room: reviving held reports failed: ${String(error)}`); });
899
+ }
894
900
  return { ok: true, value: { ...this.engine.view(request.sessionId, loaded.state), ...loaded.state.plan === undefined ? {} : { plan: this.plans.view(request.sessionId, loaded.state.plan) } } };
895
901
  }
896
902
  /**
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "cordis",
8
8
  "multi-agent"
9
9
  ],
10
- "version": "0.2.3",
10
+ "version": "0.2.4",
11
11
  "type": "module",
12
12
  "main": "lib/index.js",
13
13
  "types": "lib/types/index.d.ts",
@@ -85,7 +85,7 @@
85
85
  "@deepseek-ai/dsh-tool-todo": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
86
86
  "@deepseek-ai/dsh-tools": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
87
87
  "@deepseek-ai/dsh-typert-protocol": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1",
88
- "@khorsheed/dsh-local-agent": "^0.2.0",
88
+ "@khorsheed/dsh-local-agent": "^0.2.1",
89
89
  "react": "^18.2.0",
90
90
  "@deepseek-ai/dsh-client-ui-sidebar-right": "^0.1.0-rc.6 || ^0.2.0-rc.1 || ^0.2.1-rc.1"
91
91
  },