dominds 1.16.5 → 1.16.6

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.
@@ -676,7 +676,7 @@ async function executeDriveRound(args) {
676
676
  }
677
677
  else {
678
678
  await (0, tellask_special_1.deliverTellaskBackReplyFromDirective)({
679
- dlg: dialog,
679
+ replyingDialog: dialog,
680
680
  directive: activeTellaskReplyDirective,
681
681
  replyContent: driveResult.lastAssistantSayingContent,
682
682
  callbacks: {
@@ -67,7 +67,7 @@ export type InvalidTellaskFunctionCall = Readonly<{
67
67
  export declare function isTellaskCallFunctionName(name: string): name is TellaskCallFunctionName;
68
68
  export declare function loadLatestActiveTellaskReplyDirective(dialog: Dialog): Promise<TellaskReplyDirective | undefined>;
69
69
  export declare function deliverTellaskBackReplyFromDirective(args: {
70
- dlg: Dialog;
70
+ replyingDialog: Dialog;
71
71
  directive: Extract<TellaskReplyDirective, {
72
72
  expectedReplyCallName: 'replyTellaskBack';
73
73
  }>;
@@ -136,39 +136,48 @@ function buildTellaskBackReplyDirective(args) {
136
136
  };
137
137
  }
138
138
  async function deliverTellaskBackReplyFromDirective(args) {
139
- const rootDialog = args.dlg instanceof dialog_1.RootDialog
140
- ? args.dlg
141
- : args.dlg instanceof dialog_1.SubDialog
142
- ? args.dlg.rootDialog
139
+ // Type-A ask-back is the one place where the local "caller/callee" intuition flips:
140
+ // the dialog running `replyTellaskBack` is the ask-back responder, while
141
+ // directive.targetDialogId points to the ask-back requester that must receive the canonical
142
+ // tellaskBack result. Keep those roles explicit, otherwise it is very easy to accidentally
143
+ // write the same business result once from the reply-tool path and then again from a fallback
144
+ // path that treats the responder's plain assistant words as if they were the canonical reply.
145
+ const rootDialog = args.replyingDialog instanceof dialog_1.RootDialog
146
+ ? args.replyingDialog
147
+ : args.replyingDialog instanceof dialog_1.SubDialog
148
+ ? args.replyingDialog.rootDialog
143
149
  : undefined;
144
150
  if (!rootDialog) {
145
151
  throw new Error('replyTellaskBack invariant violation: missing root dialog');
146
152
  }
147
- const targetDialogId = new dialog_1.DialogID(args.directive.targetDialogId, rootDialog.id.rootId);
148
- const targetDialog = rootDialog.lookupDialog(targetDialogId.selfId) ??
149
- (await (0, dialog_instance_registry_1.ensureDialogLoaded)(rootDialog, targetDialogId, rootDialog.status));
150
- if (!targetDialog) {
151
- throw new Error(`replyTellaskBack invariant violation: target dialog ${targetDialogId.selfId} not found`);
153
+ const askBackRequesterDialogId = new dialog_1.DialogID(args.directive.targetDialogId, rootDialog.id.rootId);
154
+ const askBackRequesterDialog = rootDialog.lookupDialog(askBackRequesterDialogId.selfId) ??
155
+ (await (0, dialog_instance_registry_1.ensureDialogLoaded)(rootDialog, askBackRequesterDialogId, rootDialog.status));
156
+ if (!askBackRequesterDialog) {
157
+ throw new Error(`replyTellaskBack invariant violation: target dialog ${askBackRequesterDialogId.selfId} not found`);
152
158
  }
153
- targetDialog.setSuspensionState('resumed');
154
159
  const response = (0, inter_dialog_format_1.formatTellaskResponseContent)({
155
160
  callName: 'tellaskBack',
156
- responderId: args.dlg.agentId,
157
- requesterId: targetDialog.agentId,
161
+ responderId: args.replyingDialog.agentId,
162
+ requesterId: askBackRequesterDialog.agentId,
158
163
  tellaskContent: args.directive.tellaskContent,
159
164
  responseBody: args.replyContent,
160
165
  status: 'completed',
161
166
  deliveryMode: args.deliveryMode,
162
167
  language: (0, work_language_1.getWorkLanguage)(),
163
168
  });
164
- const replyMirror = await targetDialog.receiveTellaskResponse(args.dlg.agentId, 'tellaskBack', undefined, args.directive.tellaskContent, 'completed', args.dlg.id, {
169
+ const replyMirror = await askBackRequesterDialog.receiveTellaskResponse(args.replyingDialog.agentId, 'tellaskBack', undefined, args.directive.tellaskContent, 'completed', args.replyingDialog.id, {
165
170
  response,
166
- agentId: args.dlg.agentId,
171
+ agentId: args.replyingDialog.agentId,
167
172
  callId: args.directive.targetCallId,
168
- originMemberId: targetDialog.agentId,
173
+ originMemberId: askBackRequesterDialog.agentId,
169
174
  });
170
- await targetDialog.addChatMessages(replyMirror);
171
- await reviveDialogIfUnblocked(targetDialog, args.callbacks, 'reply_tellask_back_delivered');
175
+ await askBackRequesterDialog.addChatMessages(replyMirror);
176
+ // Do not mark the requester resumed until the canonical tellaskBack result has actually been
177
+ // persisted and mirrored locally. Otherwise a write failure here would leave suspension state
178
+ // claiming "resumed" while the business fact never landed.
179
+ askBackRequesterDialog.setSuspensionState('resumed');
180
+ await reviveDialogIfUnblocked(askBackRequesterDialog, args.callbacks, 'reply_tellask_back_delivered');
172
181
  }
173
182
  function isReplyTellaskCallRecord(record) {
174
183
  return isReplyTellaskCallName(record.name);
@@ -883,9 +892,29 @@ function extractLastAssistantResponse(messages, defaultMessage) {
883
892
  }
884
893
  return responseText;
885
894
  }
886
- async function extractSupdialogResponseForTypeA(supdialog) {
895
+ function findDeliveredTellaskBackReplyOnAskBackRequester(args) {
896
+ // `replyTellaskBack` persists the canonical tellaskBack business result onto the ask-back
897
+ // requester dialog immediately. Type-A orchestration must check that canonical delivery first
898
+ // before it even considers any fallback extraction from responder plaintext, or we risk a
899
+ // second final result with the same target callId.
900
+ for (let i = args.requesterDialog.msgs.length - 1; i >= 0; i -= 1) {
901
+ const msg = args.requesterDialog.msgs[i];
902
+ if (msg.type !== 'tellask_result_msg' || msg.callName !== 'tellaskBack') {
903
+ continue;
904
+ }
905
+ if (msg.callId !== args.targetCallId) {
906
+ continue;
907
+ }
908
+ return msg;
909
+ }
910
+ return undefined;
911
+ }
912
+ async function extractAskBackResponderPlaintextFallback(args) {
913
+ // This fallback is intentionally second-class: it exists only for legacy/plain-reply flows
914
+ // where no explicit `replyTellaskBack` canonical result has been delivered. It must never
915
+ // compete with or overwrite an already delivered canonical tellaskBack result.
887
916
  try {
888
- return extractLastAssistantResponse(supdialog.msgs, 'Supdialog completed without producing output.');
917
+ return extractLastAssistantResponse(args.responderDialog.msgs, 'Supdialog completed without producing output.');
889
918
  }
890
919
  catch (err) {
891
920
  log_1.log.warn('Failed to extract supdialog response for Type A', err);
@@ -1158,14 +1187,20 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1158
1187
  }
1159
1188
  if (parseResult.type === 'A') {
1160
1189
  if (dlg instanceof dialog_1.SubDialog) {
1161
- const supdialog = dlg.supdialog;
1162
- dlg.setSuspensionState('suspended');
1190
+ // Identity map for Type-A ask-back:
1191
+ // - `askBackRequesterDialog` is the sideline dialog that asked upstream for clarification.
1192
+ // - `askBackResponderDialog` is the upstream dialog that must answer that ask-back.
1193
+ // The original tellask relationship is the opposite of the current ask-back relationship,
1194
+ // so variable names like "supdialog" or "target" are too lossy here and invite bugs.
1195
+ const askBackRequesterDialog = dlg;
1196
+ const askBackResponderDialog = dlg.supdialog;
1197
+ askBackRequesterDialog.setSuspensionState('suspended');
1163
1198
  try {
1164
- const assignment = dlg.assignmentFromSup;
1199
+ const assignment = askBackRequesterDialog.assignmentFromSup;
1165
1200
  const supPrompt = {
1166
1201
  content: (0, inter_dialog_format_1.formatSupdialogCallPrompt)({
1167
- fromAgentId: dlg.agentId,
1168
- toAgentId: supdialog.agentId,
1202
+ fromAgentId: askBackRequesterDialog.agentId,
1203
+ toAgentId: askBackResponderDialog.agentId,
1169
1204
  subdialogRequest: {
1170
1205
  callName,
1171
1206
  mentionList,
@@ -1182,12 +1217,12 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1182
1217
  grammar: 'markdown',
1183
1218
  origin: 'runtime',
1184
1219
  tellaskReplyDirective: buildTellaskBackReplyDirective({
1185
- targetDialogId: dlg.id.selfId,
1220
+ targetDialogId: askBackRequesterDialog.id.selfId,
1186
1221
  targetCallId: callId,
1187
1222
  tellaskContent: body,
1188
1223
  }),
1189
1224
  };
1190
- await callbacks.driveDialog(supdialog, {
1225
+ await callbacks.driveDialog(askBackResponderDialog, {
1191
1226
  humanPrompt: supPrompt,
1192
1227
  waitInQue: true,
1193
1228
  driveOptions: {
@@ -1195,20 +1230,34 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1195
1230
  reason: 'type_a_supdialog_roundtrip',
1196
1231
  },
1197
1232
  });
1198
- const responseText = await extractSupdialogResponseForTypeA(supdialog);
1233
+ const explicitReplyDelivery = findDeliveredTellaskBackReplyOnAskBackRequester({
1234
+ requesterDialog: askBackRequesterDialog,
1235
+ targetCallId: callId,
1236
+ });
1237
+ if (explicitReplyDelivery) {
1238
+ // Important invariant: once the responder used `replyTellaskBack`, that write is the
1239
+ // single source of truth. Do not also synthesize another tellask result from the
1240
+ // responder's generic assistant words, even if those words look "compatible".
1241
+ askBackRequesterDialog.setSuspensionState('resumed');
1242
+ toolOutputs.push(explicitReplyDelivery);
1243
+ return toolOutputs;
1244
+ }
1245
+ const responseText = await extractAskBackResponderPlaintextFallback({
1246
+ responderDialog: askBackResponderDialog,
1247
+ });
1199
1248
  const responseContent = (0, inter_dialog_format_1.formatTellaskResponseContent)({
1200
1249
  callName,
1201
1250
  responderId: parseResult.agentId,
1202
- requesterId: dlg.agentId,
1251
+ requesterId: askBackRequesterDialog.agentId,
1203
1252
  mentionList,
1204
1253
  tellaskContent: body,
1205
1254
  responseBody: responseText,
1206
1255
  status: 'completed',
1207
1256
  language: (0, work_language_1.getWorkLanguage)(),
1208
1257
  });
1209
- dlg.setSuspensionState('resumed');
1258
+ askBackRequesterDialog.setSuspensionState('resumed');
1210
1259
  toolOutputs.push(buildTellaskResultToolOutput({
1211
- genseq: dlg.activeGenSeqOrUndefined ?? 1,
1260
+ genseq: askBackRequesterDialog.activeGenSeqOrUndefined ?? 1,
1212
1261
  callId,
1213
1262
  callName,
1214
1263
  content: responseContent,
@@ -1217,24 +1266,24 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1217
1266
  tellaskContent: body,
1218
1267
  mentionList,
1219
1268
  agentId: parseResult.agentId,
1220
- originMemberId: dlg.agentId,
1221
- calleeDialogId: supdialog.id.selfId,
1269
+ originMemberId: askBackRequesterDialog.agentId,
1270
+ calleeDialogId: askBackResponderDialog.id.selfId,
1222
1271
  }));
1223
- await dlg.receiveTellaskResponse(parseResult.agentId, callName, mentionList, body, 'completed', supdialog.id, {
1272
+ await askBackRequesterDialog.receiveTellaskResponse(parseResult.agentId, callName, mentionList, body, 'completed', askBackResponderDialog.id, {
1224
1273
  response: responseContent,
1225
1274
  agentId: parseResult.agentId,
1226
1275
  callId,
1227
- originMemberId: dlg.agentId,
1276
+ originMemberId: askBackRequesterDialog.agentId,
1228
1277
  });
1229
1278
  }
1230
1279
  catch (err) {
1231
1280
  log_1.log.warn('Type A supdialog processing error:', err);
1232
- dlg.setSuspensionState('resumed');
1281
+ askBackRequesterDialog.setSuspensionState('resumed');
1233
1282
  const errorText = `❌ **Error processing request to @${parseResult.agentId}:**\n\n${showErrorToAi(err)}`;
1234
1283
  const errorContent = (0, inter_dialog_format_1.formatTellaskResponseContent)({
1235
1284
  callName,
1236
1285
  responderId: parseResult.agentId,
1237
- requesterId: dlg.agentId,
1286
+ requesterId: askBackRequesterDialog.agentId,
1238
1287
  mentionList,
1239
1288
  tellaskContent: body,
1240
1289
  responseBody: errorText,
@@ -1242,7 +1291,7 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1242
1291
  language: (0, work_language_1.getWorkLanguage)(),
1243
1292
  });
1244
1293
  toolOutputs.push(buildTellaskResultToolOutput({
1245
- genseq: dlg.activeGenSeqOrUndefined ?? 1,
1294
+ genseq: askBackRequesterDialog.activeGenSeqOrUndefined ?? 1,
1246
1295
  callId,
1247
1296
  callName,
1248
1297
  content: errorContent,
@@ -1251,14 +1300,14 @@ async function executeTellaskCall(dlg, mentionList, body, callId, callbacks, opt
1251
1300
  tellaskContent: body,
1252
1301
  mentionList,
1253
1302
  agentId: parseResult.agentId,
1254
- originMemberId: dlg.agentId,
1255
- calleeDialogId: supdialog.id.selfId,
1303
+ originMemberId: askBackRequesterDialog.agentId,
1304
+ calleeDialogId: askBackResponderDialog.id.selfId,
1256
1305
  }));
1257
- await dlg.receiveTellaskResponse(parseResult.agentId, callName, mentionList, body, 'failed', supdialog.id, {
1306
+ await askBackRequesterDialog.receiveTellaskResponse(parseResult.agentId, callName, mentionList, body, 'failed', askBackResponderDialog.id, {
1258
1307
  response: errorContent,
1259
1308
  agentId: parseResult.agentId,
1260
1309
  callId,
1261
- originMemberId: dlg.agentId,
1310
+ originMemberId: askBackRequesterDialog.agentId,
1262
1311
  });
1263
1312
  }
1264
1313
  }
@@ -1779,7 +1828,7 @@ async function executeReplyTellaskCall(args) {
1779
1828
  throw new Error('replyTellaskBack invariant violation: unexpected active reply directive');
1780
1829
  }
1781
1830
  await deliverTellaskBackReplyFromDirective({
1782
- dlg: args.dlg,
1831
+ replyingDialog: args.dlg,
1783
1832
  directive: activeDirective,
1784
1833
  replyContent: args.call.replyContent,
1785
1834
  callbacks: args.callbacks,
@@ -72,6 +72,9 @@ export declare class DiskFileDialogStore extends DialogStore {
72
72
  * Ensure subdialog directory exists (delegate to DialogPersistence)
73
73
  */
74
74
  private ensureSubdialogDirectory;
75
+ private findExistingFuncResultRecord;
76
+ private findExistingTellaskResultRecord;
77
+ private raiseDuplicateCallResultInvariantViolation;
75
78
  /**
76
79
  * Append event to course JSONL file (delegate to DialogPersistence)
77
80
  */
@@ -1433,6 +1433,19 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
1433
1433
  if (!Number.isFinite(genseq) || genseq <= 0) {
1434
1434
  throw new Error(`receiveFuncResult invariant violation: missing valid genseq for func result ${funcResult.id}`);
1435
1435
  }
1436
+ const existingFuncResult = await this.findExistingFuncResultRecord(dialog, funcResult.id);
1437
+ if (existingFuncResult) {
1438
+ await this.raiseDuplicateCallResultInvariantViolation({
1439
+ dialog,
1440
+ kind: 'func_result',
1441
+ callId: funcResult.id,
1442
+ callName: funcResult.name,
1443
+ incomingCourse: course,
1444
+ incomingGenseq: genseq,
1445
+ existingCourse: existingFuncResult.course,
1446
+ existingGenseq: existingFuncResult.record.genseq,
1447
+ });
1448
+ }
1436
1449
  const funcResultRecord = buildFuncResultRecord(funcResult, genseq);
1437
1450
  await this.appendEvent(dialog, course, funcResultRecord);
1438
1451
  // Send event to frontend
@@ -1464,6 +1477,19 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
1464
1477
  ...result,
1465
1478
  genseq,
1466
1479
  };
1480
+ const existingTellaskResult = await this.findExistingTellaskResultRecord(dialog, normalizedResult.callId);
1481
+ if (existingTellaskResult) {
1482
+ await this.raiseDuplicateCallResultInvariantViolation({
1483
+ dialog,
1484
+ kind: 'tellask_result',
1485
+ callId: normalizedResult.callId,
1486
+ callName: normalizedResult.callName,
1487
+ incomingCourse: course,
1488
+ incomingGenseq: genseq,
1489
+ existingCourse: existingTellaskResult.course,
1490
+ existingGenseq: existingTellaskResult.record.genseq,
1491
+ });
1492
+ }
1467
1493
  const record = buildTellaskResultRecord(normalizedResult, genseq);
1468
1494
  await this.appendEvent(dialog, course, record);
1469
1495
  (0, evt_registry_1.postDialogEvent)(dialog, buildTellaskResultEvent(normalizedResult, course));
@@ -1489,6 +1515,74 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
1489
1515
  async ensureSubdialogDirectory(dialogId) {
1490
1516
  return await DialogPersistence.ensureSubdialogDirectory(dialogId);
1491
1517
  }
1518
+ async findExistingFuncResultRecord(dialog, callId) {
1519
+ const latest = await DialogPersistence.loadDialogLatest(dialog.id, dialog.status);
1520
+ const maxCourse = latest?.currentCourse ?? dialog.currentCourse;
1521
+ for (let course = 1; course <= maxCourse; course += 1) {
1522
+ const events = await DialogPersistence.loadCourseEvents(dialog.id, course, dialog.status);
1523
+ for (const event of events) {
1524
+ if (event.type !== 'func_result_record') {
1525
+ continue;
1526
+ }
1527
+ if (event.id !== callId) {
1528
+ continue;
1529
+ }
1530
+ return { course, record: event };
1531
+ }
1532
+ }
1533
+ return undefined;
1534
+ }
1535
+ async findExistingTellaskResultRecord(dialog, callId) {
1536
+ const latest = await DialogPersistence.loadDialogLatest(dialog.id, dialog.status);
1537
+ const maxCourse = latest?.currentCourse ?? dialog.currentCourse;
1538
+ for (let course = 1; course <= maxCourse; course += 1) {
1539
+ const events = await DialogPersistence.loadCourseEvents(dialog.id, course, dialog.status);
1540
+ for (const event of events) {
1541
+ if (event.type !== 'tellask_result_record') {
1542
+ continue;
1543
+ }
1544
+ if (event.callId !== callId) {
1545
+ continue;
1546
+ }
1547
+ return { course, record: event };
1548
+ }
1549
+ }
1550
+ return undefined;
1551
+ }
1552
+ async raiseDuplicateCallResultInvariantViolation(args) {
1553
+ // Duplicate final results are not harmless transcript noise. They mean two different program
1554
+ // paths both believed they owned the same business-level completion fact for one callId.
1555
+ // In ask-back flows this usually points to identity confusion between requester/responder or
1556
+ // canonical reply-tool delivery versus fallback plaintext synthesis. We fail fast here so the
1557
+ // second writer keeps its own stack trace instead of silently corrupting the dialog transcript.
1558
+ const err = new Error(`${args.kind} duplicate callId invariant violation: rootId=${args.dialog.id.rootId} selfId=${args.dialog.id.selfId} ` +
1559
+ `callId=${args.callId} callName=${args.callName} existingCourse=${args.existingCourse} ` +
1560
+ `existingGenseq=${args.existingGenseq} incomingCourse=${args.incomingCourse} incomingGenseq=${args.incomingGenseq}`);
1561
+ log_1.log.error('Duplicate call result detected; rejecting second write', err, {
1562
+ rootId: args.dialog.id.rootId,
1563
+ selfId: args.dialog.id.selfId,
1564
+ callId: args.callId,
1565
+ callName: args.callName,
1566
+ kind: args.kind,
1567
+ existingCourse: args.existingCourse,
1568
+ existingGenseq: args.existingGenseq,
1569
+ incomingCourse: args.incomingCourse,
1570
+ incomingGenseq: args.incomingGenseq,
1571
+ });
1572
+ try {
1573
+ await this.streamError(args.dialog, err.message);
1574
+ }
1575
+ catch (streamErr) {
1576
+ log_1.log.warn('Failed to emit stream_error_evt for duplicate call result', streamErr, {
1577
+ rootId: args.dialog.id.rootId,
1578
+ selfId: args.dialog.id.selfId,
1579
+ callId: args.callId,
1580
+ callName: args.callName,
1581
+ kind: args.kind,
1582
+ });
1583
+ }
1584
+ throw err;
1585
+ }
1492
1586
  /**
1493
1587
  * Append event to course JSONL file (delegate to DialogPersistence)
1494
1588
  */
@@ -1953,7 +2047,7 @@ class DiskFileDialogStore extends dialog_1.DialogStore {
1953
2047
  async streamError(dialog, error) {
1954
2048
  log_1.log.error(`Dialog stream error '${error}'`, new Error(), { dialog });
1955
2049
  const course = dialog.activeGenCourseOrUndefined ?? dialog.currentCourse;
1956
- const genseq = typeof dialog.activeGenSeq === 'number' ? dialog.activeGenSeq : undefined;
2050
+ const genseq = dialog.activeGenSeqOrUndefined;
1957
2051
  // Enhanced stream error event with better error classification
1958
2052
  const streamErrorEvent = {
1959
2053
  type: 'stream_error_evt',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dominds",
3
- "version": "1.16.5",
3
+ "version": "1.16.6",
4
4
  "description": "Dominds CLI and aggregation shell for the LongRun AI kernel/runtime packages.",
5
5
  "type": "commonjs",
6
6
  "publishConfig": {
@@ -52,8 +52,8 @@
52
52
  "ws": "^8.19.0",
53
53
  "yaml": "^2.8.2",
54
54
  "zod": "^4.3.6",
55
- "@longrun-ai/shell": "1.8.13",
56
55
  "@longrun-ai/kernel": "1.8.13",
56
+ "@longrun-ai/shell": "1.8.13",
57
57
  "@longrun-ai/codex-auth": "0.12.0"
58
58
  },
59
59
  "devDependencies": {