@cadenza.io/service 2.4.0 → 2.5.0

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/index.mjs CHANGED
@@ -247,6 +247,72 @@ var DatabaseTask = class extends DeputyTask {
247
247
  var isNode = typeof process !== "undefined" && process.versions?.node != null;
248
248
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
249
249
 
250
+ // src/utils/inquiry.ts
251
+ var META_INTENT_PREFIX = "meta-";
252
+ var META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT = "meta-runtime-transport-diagnostics";
253
+ function isPlainObject(value) {
254
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
255
+ }
256
+ function deepMergeDeterministic(left, right) {
257
+ if (Array.isArray(left) && Array.isArray(right)) {
258
+ return [...left, ...right];
259
+ }
260
+ if (isPlainObject(left) && isPlainObject(right)) {
261
+ const merged = { ...left };
262
+ const keys = Array.from(/* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)])).sort();
263
+ for (const key of keys) {
264
+ if (!(key in left)) {
265
+ merged[key] = right[key];
266
+ continue;
267
+ }
268
+ if (!(key in right)) {
269
+ merged[key] = left[key];
270
+ continue;
271
+ }
272
+ merged[key] = deepMergeDeterministic(left[key], right[key]);
273
+ }
274
+ return merged;
275
+ }
276
+ return right;
277
+ }
278
+ function mergeInquiryContexts(contexts) {
279
+ return contexts.reduce((acc, next) => deepMergeDeterministic(acc, next), {});
280
+ }
281
+ function isMetaIntentName(intentName) {
282
+ return intentName.startsWith(META_INTENT_PREFIX);
283
+ }
284
+ function shouldExecuteInquiryResponder(inquiry, responderIsMeta) {
285
+ if (!isMetaIntentName(inquiry)) {
286
+ return true;
287
+ }
288
+ return responderIsMeta;
289
+ }
290
+ function compareResponderDescriptors(left, right) {
291
+ if (left.serviceName !== right.serviceName) {
292
+ return left.serviceName.localeCompare(right.serviceName);
293
+ }
294
+ if (left.taskName !== right.taskName) {
295
+ return left.taskName.localeCompare(right.taskName);
296
+ }
297
+ if (left.taskVersion !== right.taskVersion) {
298
+ return left.taskVersion - right.taskVersion;
299
+ }
300
+ return left.localTaskName.localeCompare(right.localTaskName);
301
+ }
302
+ function summarizeResponderStatuses(statuses) {
303
+ let responded = 0;
304
+ let failed = 0;
305
+ let timedOut = 0;
306
+ let pending = 0;
307
+ for (const status of statuses) {
308
+ if (status.status === "fulfilled") responded++;
309
+ if (status.status === "failed") failed++;
310
+ if (status.status === "timed_out") timedOut++;
311
+ }
312
+ pending = Math.max(0, statuses.length - responded - failed - timedOut);
313
+ return { responded, failed, timedOut, pending };
314
+ }
315
+
250
316
  // src/registry/ServiceRegistry.ts
251
317
  var ServiceRegistry = class _ServiceRegistry {
252
318
  /**
@@ -262,11 +328,47 @@ var ServiceRegistry = class _ServiceRegistry {
262
328
  this.instances = /* @__PURE__ */ new Map();
263
329
  this.deputies = /* @__PURE__ */ new Map();
264
330
  this.remoteSignals = /* @__PURE__ */ new Map();
331
+ this.remoteIntents = /* @__PURE__ */ new Map();
332
+ this.remoteIntentDeputiesByKey = /* @__PURE__ */ new Map();
333
+ this.remoteIntentDeputiesByTask = /* @__PURE__ */ new Map();
265
334
  this.serviceName = null;
266
335
  this.serviceInstanceId = null;
267
336
  this.numberOfRunningGraphs = 0;
268
337
  this.useSocket = false;
269
338
  this.retryCount = 3;
339
+ CadenzaService.defineIntent({
340
+ name: META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT,
341
+ description: "Gather transport diagnostics across all services and communication clients.",
342
+ input: {
343
+ type: "object",
344
+ properties: {
345
+ detailLevel: {
346
+ type: "string",
347
+ constraints: {
348
+ oneOf: ["summary", "full"]
349
+ }
350
+ },
351
+ includeErrorHistory: {
352
+ type: "boolean"
353
+ },
354
+ errorHistoryLimit: {
355
+ type: "number",
356
+ constraints: {
357
+ min: 1,
358
+ max: 200
359
+ }
360
+ }
361
+ }
362
+ },
363
+ output: {
364
+ type: "object",
365
+ properties: {
366
+ transportDiagnostics: {
367
+ type: "object"
368
+ }
369
+ }
370
+ }
371
+ });
270
372
  this.handleInstanceUpdateTask = CadenzaService.createMetaTask(
271
373
  "Handle Instance Update",
272
374
  (ctx, emit) => {
@@ -306,7 +408,7 @@ var ServiceRegistry = class _ServiceRegistry {
306
408
  if (this.serviceName === serviceName) {
307
409
  return false;
308
410
  }
309
- if (!isFrontend && this.deputies.has(serviceName) || this.remoteSignals.has(serviceName)) {
411
+ if (!isFrontend && (this.deputies.has(serviceName) || this.remoteIntents.has(serviceName)) || this.remoteSignals.has(serviceName)) {
310
412
  const clientCreated = instances?.some(
311
413
  (i) => i.address === address && i.port === port && i.clientCreated && i.isActive
312
414
  );
@@ -356,7 +458,10 @@ var ServiceRegistry = class _ServiceRegistry {
356
458
  for (const serviceInstance of ctx.serviceInstances) {
357
459
  yield { serviceInstance };
358
460
  }
359
- }).doOn("meta.service_registry.registered_global_signals").then(this.handleInstanceUpdateTask);
461
+ }).doOn(
462
+ "meta.service_registry.registered_global_signals",
463
+ "meta.service_registry.registered_global_intents"
464
+ ).then(this.handleInstanceUpdateTask);
360
465
  this.handleGlobalSignalRegistrationTask = CadenzaService.createMetaTask(
361
466
  "Handle global Signal Registration",
362
467
  (ctx) => {
@@ -397,6 +502,32 @@ var ServiceRegistry = class _ServiceRegistry {
397
502
  },
398
503
  "Handles registration of remote signals"
399
504
  ).emits("meta.service_registry.registered_global_signals").doOn("global.meta.cadenza_db.gathered_sync_data");
505
+ this.handleGlobalIntentRegistrationTask = CadenzaService.createMetaTask(
506
+ "Handle global intent registration",
507
+ (ctx) => {
508
+ const intentToTaskMaps = this.normalizeIntentMaps(ctx);
509
+ const sorted = intentToTaskMaps.sort((a, b) => {
510
+ if (a.deleted && !b.deleted) return -1;
511
+ if (!a.deleted && b.deleted) return 1;
512
+ return 0;
513
+ });
514
+ for (const map of sorted) {
515
+ if (map.deleted) {
516
+ this.unregisterRemoteIntentDeputy(map);
517
+ continue;
518
+ }
519
+ CadenzaService.inquiryBroker.addIntent({
520
+ name: map.intentName
521
+ });
522
+ this.registerRemoteIntentDeputy(map);
523
+ }
524
+ return true;
525
+ },
526
+ "Handles registration of remote inquiry intent responders"
527
+ ).emits("meta.service_registry.registered_global_intents").doOn(
528
+ "global.meta.cadenza_db.gathered_sync_data",
529
+ "global.meta.graph_metadata.task_intent_associated"
530
+ );
400
531
  this.handleServiceNotRespondingTask = CadenzaService.createMetaTask(
401
532
  "Handle service not responding",
402
533
  (ctx, emit) => {
@@ -510,7 +641,10 @@ var ServiceRegistry = class _ServiceRegistry {
510
641
  });
511
642
  return joinedContext;
512
643
  }
513
- ).emits("meta.service_registry.initial_sync_complete").then(this.handleGlobalSignalRegistrationTask);
644
+ ).emits("meta.service_registry.initial_sync_complete").then(
645
+ this.handleGlobalSignalRegistrationTask,
646
+ this.handleGlobalIntentRegistrationTask
647
+ );
514
648
  this.fullSyncTask = CadenzaService.createMetaRoutine("Full sync", [
515
649
  CadenzaService.createCadenzaDBQueryTask("signal_to_task_map", {
516
650
  filter: {
@@ -518,6 +652,15 @@ var ServiceRegistry = class _ServiceRegistry {
518
652
  },
519
653
  fields: ["signal_name", "service_name", "deleted"]
520
654
  }).then(mergeSyncDataTask),
655
+ CadenzaService.createCadenzaDBQueryTask("intent_to_task_map", {
656
+ fields: [
657
+ "intent_name",
658
+ "task_name",
659
+ "task_version",
660
+ "service_name",
661
+ "deleted"
662
+ ]
663
+ }).then(mergeSyncDataTask),
521
664
  CadenzaService.createCadenzaDBQueryTask("service_instance", {
522
665
  filter: {
523
666
  deleted: false,
@@ -708,6 +851,25 @@ var ServiceRegistry = class _ServiceRegistry {
708
851
  __active: self?.isActive ?? false
709
852
  };
710
853
  }).doOn("meta.socket.status_check_requested");
854
+ this.collectTransportDiagnosticsTask = CadenzaService.createMetaTask(
855
+ "Collect transport diagnostics",
856
+ async (ctx) => {
857
+ const inquiryResult = await CadenzaService.inquire(
858
+ META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT,
859
+ {
860
+ detailLevel: ctx.detailLevel,
861
+ includeErrorHistory: ctx.includeErrorHistory,
862
+ errorHistoryLimit: ctx.errorHistoryLimit
863
+ },
864
+ ctx.inquiryOptions ?? ctx.__inquiryOptions ?? {}
865
+ );
866
+ return {
867
+ ...ctx,
868
+ ...inquiryResult
869
+ };
870
+ },
871
+ "Collects distributed transport diagnostics using inquiry responders."
872
+ ).doOn("meta.service_registry.transport_diagnostics_requested").emits("meta.service_registry.transport_diagnostics_collected").emitsOnFail("meta.service_registry.transport_diagnostics_failed");
711
873
  this.insertServiceTask = CadenzaService.createCadenzaDBInsertTask(
712
874
  "service",
713
875
  {
@@ -916,8 +1078,125 @@ var ServiceRegistry = class _ServiceRegistry {
916
1078
  if (!this._instance) this._instance = new _ServiceRegistry();
917
1079
  return this._instance;
918
1080
  }
1081
+ buildRemoteIntentDeputyKey(map) {
1082
+ return `${map.intentName}|${map.serviceName}|${map.taskName}|${map.taskVersion ?? 1}`;
1083
+ }
1084
+ normalizeIntentMaps(ctx) {
1085
+ if (Array.isArray(ctx.intentToTaskMaps)) {
1086
+ return ctx.intentToTaskMaps.map((m) => ({
1087
+ intentName: m.intentName ?? m.intent_name,
1088
+ serviceName: m.serviceName ?? m.service_name,
1089
+ taskName: m.taskName ?? m.task_name,
1090
+ taskVersion: m.taskVersion ?? m.task_version ?? 1,
1091
+ deleted: !!m.deleted
1092
+ })).filter((m) => m.intentName && m.serviceName && m.taskName);
1093
+ }
1094
+ const single = ctx.intentToTaskMap ?? ctx.data ?? (ctx.intentName ? ctx : void 0);
1095
+ if (!single) return [];
1096
+ const normalized = {
1097
+ intentName: single.intentName ?? single.intent_name,
1098
+ serviceName: single.serviceName ?? single.service_name,
1099
+ taskName: single.taskName ?? single.task_name,
1100
+ taskVersion: single.taskVersion ?? single.task_version ?? 1,
1101
+ deleted: !!single.deleted
1102
+ };
1103
+ if (!normalized.intentName || !normalized.serviceName || !normalized.taskName)
1104
+ return [];
1105
+ return [normalized];
1106
+ }
1107
+ registerRemoteIntentDeputy(map) {
1108
+ if (!this.serviceName || map.serviceName === this.serviceName) {
1109
+ return;
1110
+ }
1111
+ const key = this.buildRemoteIntentDeputyKey(map);
1112
+ if (this.remoteIntentDeputiesByKey.has(key)) {
1113
+ return;
1114
+ }
1115
+ const deputyTaskName = `Inquire ${map.intentName} via ${map.serviceName} (${map.taskName} v${map.taskVersion})`;
1116
+ const deputyTask = isMetaIntentName(map.intentName) ? CadenzaService.createMetaDeputyTask(map.taskName, map.serviceName, {
1117
+ register: false,
1118
+ isHidden: true,
1119
+ retryCount: 1,
1120
+ retryDelay: 50,
1121
+ retryDelayFactor: 1.2
1122
+ }) : CadenzaService.createDeputyTask(map.taskName, map.serviceName, {
1123
+ register: false,
1124
+ isHidden: true,
1125
+ retryCount: 1,
1126
+ retryDelay: 50,
1127
+ retryDelayFactor: 1.2
1128
+ });
1129
+ deputyTask.respondsTo(map.intentName);
1130
+ if (!this.remoteIntents.has(map.serviceName)) {
1131
+ this.remoteIntents.set(map.serviceName, /* @__PURE__ */ new Set());
1132
+ }
1133
+ this.remoteIntents.get(map.serviceName).add(map.intentName);
1134
+ const descriptor = {
1135
+ key,
1136
+ intentName: map.intentName,
1137
+ serviceName: map.serviceName,
1138
+ remoteTaskName: map.taskName,
1139
+ remoteTaskVersion: map.taskVersion,
1140
+ localTaskName: deputyTask.name || deputyTaskName,
1141
+ localTask: deputyTask
1142
+ };
1143
+ this.remoteIntentDeputiesByKey.set(key, descriptor);
1144
+ this.remoteIntentDeputiesByTask.set(deputyTask, descriptor);
1145
+ }
1146
+ unregisterRemoteIntentDeputy(map) {
1147
+ const key = this.buildRemoteIntentDeputyKey(map);
1148
+ const descriptor = this.remoteIntentDeputiesByKey.get(key);
1149
+ if (!descriptor) {
1150
+ return;
1151
+ }
1152
+ const task = descriptor.localTask;
1153
+ if (task) {
1154
+ CadenzaService.inquiryBroker.unsubscribe(descriptor.intentName, task);
1155
+ task.destroy();
1156
+ }
1157
+ this.remoteIntentDeputiesByTask.delete(descriptor.localTask);
1158
+ this.remoteIntentDeputiesByKey.delete(key);
1159
+ this.remoteIntents.get(descriptor.serviceName)?.delete(descriptor.intentName);
1160
+ if (!this.remoteIntents.get(descriptor.serviceName)?.size) {
1161
+ this.remoteIntents.delete(descriptor.serviceName);
1162
+ }
1163
+ const deputies = this.deputies.get(descriptor.serviceName);
1164
+ if (deputies) {
1165
+ this.deputies.set(
1166
+ descriptor.serviceName,
1167
+ deputies.filter((d) => d.localTaskName !== descriptor.localTaskName)
1168
+ );
1169
+ if (this.deputies.get(descriptor.serviceName)?.length === 0) {
1170
+ this.deputies.delete(descriptor.serviceName);
1171
+ }
1172
+ }
1173
+ }
1174
+ getInquiryResponderDescriptor(task) {
1175
+ const remote = this.remoteIntentDeputiesByTask.get(task);
1176
+ if (remote) {
1177
+ return {
1178
+ isRemote: true,
1179
+ serviceName: remote.serviceName,
1180
+ taskName: remote.remoteTaskName,
1181
+ taskVersion: remote.remoteTaskVersion,
1182
+ localTaskName: remote.localTaskName
1183
+ };
1184
+ }
1185
+ return {
1186
+ isRemote: false,
1187
+ serviceName: this.serviceName ?? "UnknownService",
1188
+ taskName: task.name,
1189
+ taskVersion: task.version,
1190
+ localTaskName: task.name
1191
+ };
1192
+ }
919
1193
  reset() {
920
1194
  this.instances.clear();
1195
+ this.deputies.clear();
1196
+ this.remoteSignals.clear();
1197
+ this.remoteIntents.clear();
1198
+ this.remoteIntentDeputiesByKey.clear();
1199
+ this.remoteIntentDeputiesByTask.clear();
921
1200
  }
922
1201
  };
923
1202
 
@@ -1034,6 +1313,8 @@ var RestController = class _RestController {
1034
1313
  * It initializes and configures the REST server tasks.
1035
1314
  */
1036
1315
  constructor() {
1316
+ this.fetchClientDiagnostics = /* @__PURE__ */ new Map();
1317
+ this.diagnosticsErrorHistoryLimit = 100;
1037
1318
  /**
1038
1319
  * Fetches data from the given URL with a specified timeout. This function performs
1039
1320
  * a fetch request with the ability to cancel the request if it exceeds the provided timeout duration.
@@ -1074,6 +1355,11 @@ var RestController = class _RestController {
1074
1355
  "meta.rest.delegation_requested",
1075
1356
  "meta.socket.delegation_requested"
1076
1357
  );
1358
+ CadenzaService.createMetaTask(
1359
+ "Collect fetch transport diagnostics",
1360
+ (ctx) => this.collectFetchTransportDiagnostics(ctx),
1361
+ "Responds to distributed transport diagnostics inquiries with REST/fetch client data."
1362
+ ).respondsTo(META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT);
1077
1363
  CadenzaService.createMetaRoutine(
1078
1364
  "RestServer",
1079
1365
  [
@@ -1404,6 +1690,13 @@ var RestController = class _RestController {
1404
1690
  const port = protocol === "https" ? 443 : servicePort;
1405
1691
  const URL = `${protocol}://${serviceAddress}:${port}`;
1406
1692
  const fetchId = `${serviceAddress}_${port}`;
1693
+ const fetchDiagnostics = this.ensureFetchClientDiagnostics(
1694
+ fetchId,
1695
+ serviceName,
1696
+ URL
1697
+ );
1698
+ fetchDiagnostics.destroyed = false;
1699
+ fetchDiagnostics.updatedAt = Date.now();
1407
1700
  if (CadenzaService.get(`Send Handshake to ${URL}`)) {
1408
1701
  console.error("Fetch client already exists", URL);
1409
1702
  return;
@@ -1425,6 +1718,10 @@ var RestController = class _RestController {
1425
1718
  );
1426
1719
  if (response.__status !== "success") {
1427
1720
  const error = response.__error ?? `Failed to connect to service ${serviceName} ${ctx2.serviceInstanceId}`;
1721
+ fetchDiagnostics.connected = false;
1722
+ fetchDiagnostics.lastHandshakeError = error;
1723
+ fetchDiagnostics.updatedAt = Date.now();
1724
+ this.recordFetchClientError(fetchId, serviceName, URL, error);
1428
1725
  CadenzaService.log(
1429
1726
  "Fetch handshake failed.",
1430
1727
  { error, serviceName, URL },
@@ -1434,6 +1731,11 @@ var RestController = class _RestController {
1434
1731
  return { ...ctx2, __error: error, errored: true };
1435
1732
  }
1436
1733
  ctx2.serviceInstanceId = response.__serviceInstanceId;
1734
+ fetchDiagnostics.connected = true;
1735
+ fetchDiagnostics.destroyed = false;
1736
+ fetchDiagnostics.lastHandshakeAt = (/* @__PURE__ */ new Date()).toISOString();
1737
+ fetchDiagnostics.lastHandshakeError = null;
1738
+ fetchDiagnostics.updatedAt = Date.now();
1437
1739
  CadenzaService.log("Fetch client connected.", {
1438
1740
  response,
1439
1741
  serviceName,
@@ -1449,6 +1751,10 @@ var RestController = class _RestController {
1449
1751
  });
1450
1752
  }
1451
1753
  } catch (e) {
1754
+ fetchDiagnostics.connected = false;
1755
+ fetchDiagnostics.lastHandshakeError = this.getErrorMessage(e);
1756
+ fetchDiagnostics.updatedAt = Date.now();
1757
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1452
1758
  CadenzaService.log(
1453
1759
  "Error in fetch handshake",
1454
1760
  { error: e, serviceName, URL, ctx: ctx2 },
@@ -1470,6 +1776,8 @@ var RestController = class _RestController {
1470
1776
  if (ctx2.__remoteRoutineName === void 0) {
1471
1777
  return;
1472
1778
  }
1779
+ fetchDiagnostics.delegationRequests++;
1780
+ fetchDiagnostics.updatedAt = Date.now();
1473
1781
  let resultContext;
1474
1782
  try {
1475
1783
  resultContext = await this.fetchDataWithTimeout(
@@ -1483,8 +1791,21 @@ var RestController = class _RestController {
1483
1791
  },
1484
1792
  3e4
1485
1793
  );
1794
+ if (resultContext?.errored || resultContext?.failed) {
1795
+ fetchDiagnostics.delegationFailures++;
1796
+ fetchDiagnostics.updatedAt = Date.now();
1797
+ this.recordFetchClientError(
1798
+ fetchId,
1799
+ serviceName,
1800
+ URL,
1801
+ resultContext?.__error ?? resultContext?.error ?? "Delegation failed"
1802
+ );
1803
+ }
1486
1804
  } catch (e) {
1487
1805
  console.error("Error in delegation", e);
1806
+ fetchDiagnostics.delegationFailures++;
1807
+ fetchDiagnostics.updatedAt = Date.now();
1808
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1488
1809
  resultContext = {
1489
1810
  __error: `Error: ${e}`,
1490
1811
  errored: true,
@@ -1510,6 +1831,8 @@ var RestController = class _RestController {
1510
1831
  if (ctx2.__signalName === void 0) {
1511
1832
  return;
1512
1833
  }
1834
+ fetchDiagnostics.signalTransmissions++;
1835
+ fetchDiagnostics.updatedAt = Date.now();
1513
1836
  let response;
1514
1837
  try {
1515
1838
  response = await this.fetchDataWithTimeout(
@@ -1526,8 +1849,21 @@ var RestController = class _RestController {
1526
1849
  if (ctx2.__routineExecId) {
1527
1850
  emit(`meta.fetch.transmitted:${ctx2.__routineExecId}`, response);
1528
1851
  }
1852
+ if (response?.errored || response?.failed) {
1853
+ fetchDiagnostics.signalFailures++;
1854
+ fetchDiagnostics.updatedAt = Date.now();
1855
+ this.recordFetchClientError(
1856
+ fetchId,
1857
+ serviceName,
1858
+ URL,
1859
+ response?.__error ?? response?.error ?? "Signal transmission failed"
1860
+ );
1861
+ }
1529
1862
  } catch (e) {
1530
1863
  console.error("Error in transmission", e);
1864
+ fetchDiagnostics.signalFailures++;
1865
+ fetchDiagnostics.updatedAt = Date.now();
1866
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1531
1867
  response = {
1532
1868
  __error: `Error: ${e}`,
1533
1869
  errored: true,
@@ -1545,6 +1881,8 @@ var RestController = class _RestController {
1545
1881
  const statusTask = CadenzaService.createMetaTask(
1546
1882
  `Request status from ${URL}`,
1547
1883
  async (ctx2) => {
1884
+ fetchDiagnostics.statusChecks++;
1885
+ fetchDiagnostics.updatedAt = Date.now();
1548
1886
  let status;
1549
1887
  try {
1550
1888
  status = await this.fetchDataWithTimeout(
@@ -1554,7 +1892,20 @@ var RestController = class _RestController {
1554
1892
  },
1555
1893
  1e3
1556
1894
  );
1895
+ if (status?.errored || status?.failed) {
1896
+ fetchDiagnostics.statusFailures++;
1897
+ fetchDiagnostics.updatedAt = Date.now();
1898
+ this.recordFetchClientError(
1899
+ fetchId,
1900
+ serviceName,
1901
+ URL,
1902
+ status?.__error ?? status?.error ?? "Status check failed"
1903
+ );
1904
+ }
1557
1905
  } catch (e) {
1906
+ fetchDiagnostics.statusFailures++;
1907
+ fetchDiagnostics.updatedAt = Date.now();
1908
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1558
1909
  status = {
1559
1910
  __error: `Error: ${e}`,
1560
1911
  errored: true,
@@ -1566,6 +1917,9 @@ var RestController = class _RestController {
1566
1917
  "Requests status"
1567
1918
  ).doOn("meta.fetch.status_check_requested").emits("meta.fetch.status_checked").emitsOnFail("meta.fetch.status_check_failed");
1568
1919
  CadenzaService.createEphemeralMetaTask("Destroy fetch client", () => {
1920
+ fetchDiagnostics.connected = false;
1921
+ fetchDiagnostics.destroyed = true;
1922
+ fetchDiagnostics.updatedAt = Date.now();
1569
1923
  CadenzaService.log("Destroying fetch client", { URL, serviceName });
1570
1924
  handshakeTask.destroy();
1571
1925
  delegateTask.destroy();
@@ -1614,6 +1968,144 @@ var RestController = class _RestController {
1614
1968
  if (!this._instance) this._instance = new _RestController();
1615
1969
  return this._instance;
1616
1970
  }
1971
+ resolveTransportDiagnosticsOptions(ctx) {
1972
+ const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
1973
+ const includeErrorHistory = Boolean(ctx.includeErrorHistory);
1974
+ const requestedLimit = Number(ctx.errorHistoryLimit);
1975
+ const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
1976
+ return {
1977
+ detailLevel,
1978
+ includeErrorHistory,
1979
+ errorHistoryLimit
1980
+ };
1981
+ }
1982
+ ensureFetchClientDiagnostics(fetchId, serviceName, url) {
1983
+ let state = this.fetchClientDiagnostics.get(fetchId);
1984
+ if (!state) {
1985
+ state = {
1986
+ fetchId,
1987
+ serviceName,
1988
+ url,
1989
+ connected: false,
1990
+ destroyed: false,
1991
+ lastHandshakeAt: null,
1992
+ lastHandshakeError: null,
1993
+ lastError: null,
1994
+ lastErrorAt: 0,
1995
+ errorHistory: [],
1996
+ delegationRequests: 0,
1997
+ delegationFailures: 0,
1998
+ signalTransmissions: 0,
1999
+ signalFailures: 0,
2000
+ statusChecks: 0,
2001
+ statusFailures: 0,
2002
+ updatedAt: Date.now()
2003
+ };
2004
+ this.fetchClientDiagnostics.set(fetchId, state);
2005
+ } else {
2006
+ state.serviceName = serviceName;
2007
+ state.url = url;
2008
+ }
2009
+ return state;
2010
+ }
2011
+ getErrorMessage(error) {
2012
+ if (error instanceof Error) {
2013
+ return error.message;
2014
+ }
2015
+ if (typeof error === "string") {
2016
+ return error;
2017
+ }
2018
+ try {
2019
+ return JSON.stringify(error);
2020
+ } catch {
2021
+ return String(error);
2022
+ }
2023
+ }
2024
+ recordFetchClientError(fetchId, serviceName, url, error) {
2025
+ const state = this.ensureFetchClientDiagnostics(fetchId, serviceName, url);
2026
+ const message = this.getErrorMessage(error);
2027
+ const now = Date.now();
2028
+ state.lastError = message;
2029
+ state.lastErrorAt = now;
2030
+ state.updatedAt = now;
2031
+ state.errorHistory.push({ at: new Date(now).toISOString(), message });
2032
+ if (state.errorHistory.length > this.diagnosticsErrorHistoryLimit) {
2033
+ state.errorHistory.splice(
2034
+ 0,
2035
+ state.errorHistory.length - this.diagnosticsErrorHistoryLimit
2036
+ );
2037
+ }
2038
+ }
2039
+ collectFetchTransportDiagnostics(ctx) {
2040
+ const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
2041
+ const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
2042
+ const states = Array.from(this.fetchClientDiagnostics.values()).sort(
2043
+ (a, b) => a.fetchId.localeCompare(b.fetchId)
2044
+ );
2045
+ const summary = {
2046
+ detailLevel,
2047
+ totalClients: states.length,
2048
+ connectedClients: states.filter((state) => state.connected).length,
2049
+ destroyedClients: states.filter((state) => state.destroyed).length,
2050
+ delegationRequests: states.reduce(
2051
+ (acc, state) => acc + state.delegationRequests,
2052
+ 0
2053
+ ),
2054
+ delegationFailures: states.reduce(
2055
+ (acc, state) => acc + state.delegationFailures,
2056
+ 0
2057
+ ),
2058
+ signalTransmissions: states.reduce(
2059
+ (acc, state) => acc + state.signalTransmissions,
2060
+ 0
2061
+ ),
2062
+ signalFailures: states.reduce((acc, state) => acc + state.signalFailures, 0),
2063
+ statusChecks: states.reduce((acc, state) => acc + state.statusChecks, 0),
2064
+ statusFailures: states.reduce((acc, state) => acc + state.statusFailures, 0),
2065
+ latestError: states.slice().sort((a, b) => b.lastErrorAt - a.lastErrorAt).find((state) => state.lastError)?.lastError ?? null
2066
+ };
2067
+ if (detailLevel === "summary") {
2068
+ return {
2069
+ transportDiagnostics: {
2070
+ [serviceName]: {
2071
+ fetchClient: summary
2072
+ }
2073
+ }
2074
+ };
2075
+ }
2076
+ const clients = states.map((state) => {
2077
+ const details = {
2078
+ fetchId: state.fetchId,
2079
+ serviceName: state.serviceName,
2080
+ url: state.url,
2081
+ connected: state.connected,
2082
+ destroyed: state.destroyed,
2083
+ lastHandshakeAt: state.lastHandshakeAt,
2084
+ lastHandshakeError: state.lastHandshakeError,
2085
+ latestError: state.lastError,
2086
+ delegationRequests: state.delegationRequests,
2087
+ delegationFailures: state.delegationFailures,
2088
+ signalTransmissions: state.signalTransmissions,
2089
+ signalFailures: state.signalFailures,
2090
+ statusChecks: state.statusChecks,
2091
+ statusFailures: state.statusFailures
2092
+ };
2093
+ if (includeErrorHistory) {
2094
+ details.errorHistory = state.errorHistory.slice(-errorHistoryLimit);
2095
+ }
2096
+ return details;
2097
+ });
2098
+ return {
2099
+ transportDiagnostics: {
2100
+ [serviceName]: {
2101
+ fetchClient: {
2102
+ ...summary,
2103
+ clients
2104
+ }
2105
+ }
2106
+ }
2107
+ };
2108
+ }
1617
2109
  };
1618
2110
 
1619
2111
  // src/network/SocketController.ts
@@ -1661,10 +2153,6 @@ var waitForSocketConnection = async (socket, timeoutMs, createError) => {
1661
2153
 
1662
2154
  // src/network/SocketController.ts
1663
2155
  var SocketController = class _SocketController {
1664
- static get instance() {
1665
- if (!this._instance) this._instance = new _SocketController();
1666
- return this._instance;
1667
- }
1668
2156
  /**
1669
2157
  * Constructs the `SocketServer`, setting up a WebSocket server with specific configurations,
1670
2158
  * including connection state recovery, rate limiting, CORS handling, and custom event handling.
@@ -1683,6 +2171,13 @@ var SocketController = class _SocketController {
1683
2171
  * Initializes the `SocketServer` to be ready for WebSocket communication.
1684
2172
  */
1685
2173
  constructor() {
2174
+ this.socketClientDiagnostics = /* @__PURE__ */ new Map();
2175
+ this.diagnosticsErrorHistoryLimit = 100;
2176
+ CadenzaService.createMetaTask(
2177
+ "Collect socket transport diagnostics",
2178
+ (ctx) => this.collectSocketTransportDiagnostics(ctx),
2179
+ "Responds to distributed transport diagnostics inquiries with socket client data."
2180
+ ).respondsTo(META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT);
1686
2181
  CadenzaService.createMetaRoutine(
1687
2182
  "SocketServer",
1688
2183
  [
@@ -1910,6 +2405,13 @@ var SocketController = class _SocketController {
1910
2405
  const port = protocol === "https" ? 443 : servicePort;
1911
2406
  const URL = `${socketProtocol}://${serviceAddress}:${port}`;
1912
2407
  const fetchId = `${serviceAddress}_${port}`;
2408
+ const socketDiagnostics = this.ensureSocketClientDiagnostics(
2409
+ fetchId,
2410
+ serviceName,
2411
+ URL
2412
+ );
2413
+ socketDiagnostics.destroyed = false;
2414
+ socketDiagnostics.updatedAt = Date.now();
1913
2415
  let handshake = false;
1914
2416
  let errorCount = 0;
1915
2417
  const ERROR_LIMIT = 5;
@@ -1919,6 +2421,11 @@ var SocketController = class _SocketController {
1919
2421
  }
1920
2422
  const pendingDelegationIds = /* @__PURE__ */ new Set();
1921
2423
  const pendingTimers = /* @__PURE__ */ new Set();
2424
+ const syncPendingCounts = () => {
2425
+ socketDiagnostics.pendingDelegations = pendingDelegationIds.size;
2426
+ socketDiagnostics.pendingTimers = pendingTimers.size;
2427
+ socketDiagnostics.updatedAt = Date.now();
2428
+ };
1922
2429
  let handshakeTask = null;
1923
2430
  let emitWhenReady = null;
1924
2431
  let transmitTask = null;
@@ -1968,6 +2475,12 @@ var SocketController = class _SocketController {
1968
2475
  { socketId: socket?.id, serviceName, URL, event },
1969
2476
  "error"
1970
2477
  );
2478
+ this.recordSocketClientError(
2479
+ fetchId,
2480
+ serviceName,
2481
+ URL,
2482
+ waitResult.error
2483
+ );
1971
2484
  resolveWithError(waitResult.error);
1972
2485
  return;
1973
2486
  }
@@ -1976,6 +2489,7 @@ var SocketController = class _SocketController {
1976
2489
  timer = setTimeout(() => {
1977
2490
  if (timer) {
1978
2491
  pendingTimers.delete(timer);
2492
+ syncPendingCounts();
1979
2493
  timer = null;
1980
2494
  }
1981
2495
  CadenzaService.log(
@@ -1983,9 +2497,16 @@ var SocketController = class _SocketController {
1983
2497
  { socketId: socket?.id, serviceName, URL },
1984
2498
  "error"
1985
2499
  );
2500
+ this.recordSocketClientError(
2501
+ fetchId,
2502
+ serviceName,
2503
+ URL,
2504
+ `Socket event '${event}' timed out`
2505
+ );
1986
2506
  resolveWithError(`Socket event '${event}' timed out`);
1987
2507
  }, timeoutMs + 10);
1988
2508
  pendingTimers.add(timer);
2509
+ syncPendingCounts();
1989
2510
  }
1990
2511
  const connectedSocket = socket;
1991
2512
  if (!connectedSocket) {
@@ -1998,6 +2519,7 @@ var SocketController = class _SocketController {
1998
2519
  if (timer) {
1999
2520
  clearTimeout(timer);
2000
2521
  pendingTimers.delete(timer);
2522
+ syncPendingCounts();
2001
2523
  timer = null;
2002
2524
  }
2003
2525
  if (err) {
@@ -2011,6 +2533,12 @@ var SocketController = class _SocketController {
2011
2533
  },
2012
2534
  "warning"
2013
2535
  );
2536
+ this.recordSocketClientError(
2537
+ fetchId,
2538
+ serviceName,
2539
+ URL,
2540
+ err
2541
+ );
2014
2542
  response = {
2015
2543
  __error: `Timeout error: ${err}`,
2016
2544
  errored: true,
@@ -2027,6 +2555,10 @@ var SocketController = class _SocketController {
2027
2555
  };
2028
2556
  socket.on("connect", () => {
2029
2557
  if (handshake) return;
2558
+ socketDiagnostics.connected = true;
2559
+ socketDiagnostics.destroyed = false;
2560
+ socketDiagnostics.socketId = socket?.id ?? null;
2561
+ socketDiagnostics.updatedAt = Date.now();
2030
2562
  CadenzaService.emit(`meta.socket_client.connected:${fetchId}`, ctx);
2031
2563
  });
2032
2564
  socket.on("delegation_progress", (ctx2) => {
@@ -2045,6 +2577,12 @@ var SocketController = class _SocketController {
2045
2577
  });
2046
2578
  socket.on("connect_error", (err) => {
2047
2579
  handshake = false;
2580
+ socketDiagnostics.connected = false;
2581
+ socketDiagnostics.handshake = false;
2582
+ socketDiagnostics.connectErrors++;
2583
+ socketDiagnostics.lastHandshakeError = err.message;
2584
+ socketDiagnostics.updatedAt = Date.now();
2585
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2048
2586
  CadenzaService.log(
2049
2587
  "Socket connect error",
2050
2588
  { error: err.message, serviceName, socketId: socket?.id, URL },
@@ -2053,9 +2591,16 @@ var SocketController = class _SocketController {
2053
2591
  CadenzaService.emit(`meta.socket_client.connect_error:${fetchId}`, err);
2054
2592
  });
2055
2593
  socket.on("reconnect_attempt", (attempt) => {
2594
+ socketDiagnostics.reconnectAttempts = Math.max(
2595
+ socketDiagnostics.reconnectAttempts,
2596
+ attempt
2597
+ );
2598
+ socketDiagnostics.updatedAt = Date.now();
2056
2599
  CadenzaService.log(`Reconnect attempt: ${attempt}`);
2057
2600
  });
2058
2601
  socket.on("reconnect", (attempt) => {
2602
+ socketDiagnostics.connected = true;
2603
+ socketDiagnostics.updatedAt = Date.now();
2059
2604
  CadenzaService.log(`Socket reconnected after ${attempt} tries`, {
2060
2605
  socketId: socket?.id,
2061
2606
  URL,
@@ -2064,6 +2609,12 @@ var SocketController = class _SocketController {
2064
2609
  });
2065
2610
  socket.on("reconnect_error", (err) => {
2066
2611
  handshake = false;
2612
+ socketDiagnostics.connected = false;
2613
+ socketDiagnostics.handshake = false;
2614
+ socketDiagnostics.reconnectErrors++;
2615
+ socketDiagnostics.lastHandshakeError = err.message;
2616
+ socketDiagnostics.updatedAt = Date.now();
2617
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2067
2618
  CadenzaService.log(
2068
2619
  "Socket reconnect failed.",
2069
2620
  { error: err.message, serviceName, URL, socketId: socket?.id },
@@ -2072,6 +2623,9 @@ var SocketController = class _SocketController {
2072
2623
  });
2073
2624
  socket.on("error", (err) => {
2074
2625
  errorCount++;
2626
+ socketDiagnostics.socketErrors++;
2627
+ socketDiagnostics.updatedAt = Date.now();
2628
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2075
2629
  CadenzaService.log(
2076
2630
  "Socket error",
2077
2631
  { error: err, socketId: socket?.id, URL, serviceName },
@@ -2080,6 +2634,11 @@ var SocketController = class _SocketController {
2080
2634
  CadenzaService.emit("meta.socket_client.error", err);
2081
2635
  });
2082
2636
  socket.on("disconnect", () => {
2637
+ const disconnectedAt = (/* @__PURE__ */ new Date()).toISOString();
2638
+ socketDiagnostics.connected = false;
2639
+ socketDiagnostics.handshake = false;
2640
+ socketDiagnostics.lastDisconnectAt = disconnectedAt;
2641
+ socketDiagnostics.updatedAt = Date.now();
2083
2642
  CadenzaService.log(
2084
2643
  "Socket disconnected.",
2085
2644
  { URL, serviceName, socketId: socket?.id },
@@ -2098,6 +2657,8 @@ var SocketController = class _SocketController {
2098
2657
  async (ctx2, emit) => {
2099
2658
  if (handshake) return;
2100
2659
  handshake = true;
2660
+ socketDiagnostics.handshake = true;
2661
+ socketDiagnostics.updatedAt = Date.now();
2101
2662
  await emitWhenReady?.(
2102
2663
  "handshake",
2103
2664
  {
@@ -2109,6 +2670,11 @@ var SocketController = class _SocketController {
2109
2670
  1e4,
2110
2671
  (result) => {
2111
2672
  if (result.status === "success") {
2673
+ socketDiagnostics.connected = true;
2674
+ socketDiagnostics.handshake = true;
2675
+ socketDiagnostics.lastHandshakeAt = (/* @__PURE__ */ new Date()).toISOString();
2676
+ socketDiagnostics.lastHandshakeError = null;
2677
+ socketDiagnostics.updatedAt = Date.now();
2112
2678
  CadenzaService.log("Socket client connected", {
2113
2679
  result,
2114
2680
  serviceName,
@@ -2116,6 +2682,16 @@ var SocketController = class _SocketController {
2116
2682
  URL
2117
2683
  });
2118
2684
  } else {
2685
+ socketDiagnostics.connected = false;
2686
+ socketDiagnostics.handshake = false;
2687
+ socketDiagnostics.lastHandshakeError = result?.__error ?? result?.error ?? "Socket handshake failed";
2688
+ socketDiagnostics.updatedAt = Date.now();
2689
+ this.recordSocketClientError(
2690
+ fetchId,
2691
+ serviceName,
2692
+ URL,
2693
+ socketDiagnostics.lastHandshakeError
2694
+ );
2119
2695
  CadenzaService.log(
2120
2696
  "Socket handshake failed",
2121
2697
  { result, serviceName, socketId: socket?.id, URL },
@@ -2138,6 +2714,7 @@ var SocketController = class _SocketController {
2138
2714
  delete ctx2.__broadcast;
2139
2715
  const requestSentAt = Date.now();
2140
2716
  pendingDelegationIds.add(ctx2.__metadata.__deputyExecId);
2717
+ syncPendingCounts();
2141
2718
  emitWhenReady?.(
2142
2719
  "delegation",
2143
2720
  ctx2,
@@ -2155,6 +2732,15 @@ var SocketController = class _SocketController {
2155
2732
  }
2156
2733
  );
2157
2734
  pendingDelegationIds.delete(ctx2.__metadata.__deputyExecId);
2735
+ syncPendingCounts();
2736
+ if (resultContext?.errored || resultContext?.failed) {
2737
+ this.recordSocketClientError(
2738
+ fetchId,
2739
+ serviceName,
2740
+ URL,
2741
+ resultContext?.__error ?? resultContext?.error ?? "Socket delegation failed"
2742
+ );
2743
+ }
2158
2744
  resolve(resultContext);
2159
2745
  }
2160
2746
  );
@@ -2190,6 +2776,10 @@ var SocketController = class _SocketController {
2190
2776
  `Shutdown SocketClient ${URL}`,
2191
2777
  (ctx2, emit) => {
2192
2778
  handshake = false;
2779
+ socketDiagnostics.connected = false;
2780
+ socketDiagnostics.handshake = false;
2781
+ socketDiagnostics.destroyed = true;
2782
+ socketDiagnostics.updatedAt = Date.now();
2193
2783
  CadenzaService.log("Shutting down socket client", { URL, serviceName });
2194
2784
  socket?.close();
2195
2785
  handshakeTask?.destroy();
@@ -2219,10 +2809,12 @@ var SocketController = class _SocketController {
2219
2809
  });
2220
2810
  }
2221
2811
  pendingDelegationIds.clear();
2812
+ syncPendingCounts();
2222
2813
  for (const timer of pendingTimers) {
2223
2814
  clearTimeout(timer);
2224
2815
  }
2225
2816
  pendingTimers.clear();
2817
+ syncPendingCounts();
2226
2818
  },
2227
2819
  "Shuts down the socket client"
2228
2820
  ).doOn(
@@ -2236,6 +2828,157 @@ var SocketController = class _SocketController {
2236
2828
  "Connects to a specified socket server"
2237
2829
  ).doOn("meta.fetch.handshake_complete").emitsOnFail("meta.socket_client.connect_failed");
2238
2830
  }
2831
+ static get instance() {
2832
+ if (!this._instance) this._instance = new _SocketController();
2833
+ return this._instance;
2834
+ }
2835
+ resolveTransportDiagnosticsOptions(ctx) {
2836
+ const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
2837
+ const includeErrorHistory = Boolean(ctx.includeErrorHistory);
2838
+ const requestedLimit = Number(ctx.errorHistoryLimit);
2839
+ const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
2840
+ return {
2841
+ detailLevel,
2842
+ includeErrorHistory,
2843
+ errorHistoryLimit
2844
+ };
2845
+ }
2846
+ ensureSocketClientDiagnostics(fetchId, serviceName, url) {
2847
+ let state = this.socketClientDiagnostics.get(fetchId);
2848
+ if (!state) {
2849
+ state = {
2850
+ fetchId,
2851
+ serviceName,
2852
+ url,
2853
+ socketId: null,
2854
+ connected: false,
2855
+ handshake: false,
2856
+ reconnectAttempts: 0,
2857
+ connectErrors: 0,
2858
+ reconnectErrors: 0,
2859
+ socketErrors: 0,
2860
+ pendingDelegations: 0,
2861
+ pendingTimers: 0,
2862
+ destroyed: false,
2863
+ lastHandshakeAt: null,
2864
+ lastHandshakeError: null,
2865
+ lastDisconnectAt: null,
2866
+ lastError: null,
2867
+ lastErrorAt: 0,
2868
+ errorHistory: [],
2869
+ updatedAt: Date.now()
2870
+ };
2871
+ this.socketClientDiagnostics.set(fetchId, state);
2872
+ } else {
2873
+ state.serviceName = serviceName;
2874
+ state.url = url;
2875
+ }
2876
+ return state;
2877
+ }
2878
+ getErrorMessage(error) {
2879
+ if (error instanceof Error) {
2880
+ return error.message;
2881
+ }
2882
+ if (typeof error === "string") {
2883
+ return error;
2884
+ }
2885
+ try {
2886
+ return JSON.stringify(error);
2887
+ } catch {
2888
+ return String(error);
2889
+ }
2890
+ }
2891
+ recordSocketClientError(fetchId, serviceName, url, error) {
2892
+ const state = this.ensureSocketClientDiagnostics(fetchId, serviceName, url);
2893
+ const message = this.getErrorMessage(error);
2894
+ const now = Date.now();
2895
+ state.lastError = message;
2896
+ state.lastErrorAt = now;
2897
+ state.updatedAt = now;
2898
+ state.errorHistory.push({
2899
+ at: new Date(now).toISOString(),
2900
+ message
2901
+ });
2902
+ if (state.errorHistory.length > this.diagnosticsErrorHistoryLimit) {
2903
+ state.errorHistory.splice(
2904
+ 0,
2905
+ state.errorHistory.length - this.diagnosticsErrorHistoryLimit
2906
+ );
2907
+ }
2908
+ }
2909
+ collectSocketTransportDiagnostics(ctx) {
2910
+ const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
2911
+ const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
2912
+ const states = Array.from(this.socketClientDiagnostics.values()).sort(
2913
+ (a, b) => a.fetchId.localeCompare(b.fetchId)
2914
+ );
2915
+ const summary = {
2916
+ detailLevel,
2917
+ totalClients: states.length,
2918
+ connectedClients: states.filter((state) => state.connected).length,
2919
+ activeHandshakes: states.filter((state) => state.handshake).length,
2920
+ pendingDelegations: states.reduce(
2921
+ (acc, state) => acc + state.pendingDelegations,
2922
+ 0
2923
+ ),
2924
+ pendingTimers: states.reduce((acc, state) => acc + state.pendingTimers, 0),
2925
+ reconnectAttempts: states.reduce(
2926
+ (acc, state) => acc + state.reconnectAttempts,
2927
+ 0
2928
+ ),
2929
+ connectErrors: states.reduce((acc, state) => acc + state.connectErrors, 0),
2930
+ reconnectErrors: states.reduce(
2931
+ (acc, state) => acc + state.reconnectErrors,
2932
+ 0
2933
+ ),
2934
+ socketErrors: states.reduce((acc, state) => acc + state.socketErrors, 0),
2935
+ latestError: states.slice().sort((a, b) => b.lastErrorAt - a.lastErrorAt).find((state) => state.lastError)?.lastError ?? null
2936
+ };
2937
+ if (detailLevel === "summary") {
2938
+ return {
2939
+ transportDiagnostics: {
2940
+ [serviceName]: {
2941
+ socketClient: summary
2942
+ }
2943
+ }
2944
+ };
2945
+ }
2946
+ const clients = states.map((state) => {
2947
+ const details = {
2948
+ fetchId: state.fetchId,
2949
+ serviceName: state.serviceName,
2950
+ url: state.url,
2951
+ socketId: state.socketId,
2952
+ connected: state.connected,
2953
+ handshake: state.handshake,
2954
+ reconnectAttempts: state.reconnectAttempts,
2955
+ connectErrors: state.connectErrors,
2956
+ reconnectErrors: state.reconnectErrors,
2957
+ socketErrors: state.socketErrors,
2958
+ pendingDelegations: state.pendingDelegations,
2959
+ pendingTimers: state.pendingTimers,
2960
+ destroyed: state.destroyed,
2961
+ lastHandshakeAt: state.lastHandshakeAt,
2962
+ lastHandshakeError: state.lastHandshakeError,
2963
+ lastDisconnectAt: state.lastDisconnectAt,
2964
+ latestError: state.lastError
2965
+ };
2966
+ if (includeErrorHistory) {
2967
+ details.errorHistory = state.errorHistory.slice(-errorHistoryLimit);
2968
+ }
2969
+ return details;
2970
+ });
2971
+ return {
2972
+ transportDiagnostics: {
2973
+ [serviceName]: {
2974
+ socketClient: {
2975
+ ...summary,
2976
+ clients
2977
+ }
2978
+ }
2979
+ }
2980
+ };
2981
+ }
2239
2982
  };
2240
2983
 
2241
2984
  // src/utils/tools.ts
@@ -2339,25 +3082,8 @@ var GraphMetadataController = class _GraphMetadataController {
2339
3082
  return {
2340
3083
  data: {
2341
3084
  ...ctx.data,
2342
- serviceName: CadenzaService.serviceRegistry.serviceName,
2343
- inputContextSchemaId: ctx.data.inputContextSchemaId ? {
2344
- subOperation: "insert",
2345
- table: "context_schema",
2346
- data: {
2347
- ...ctx.data.inputContextSchemaId
2348
- },
2349
- return: "uuid"
2350
- } : null,
2351
- outputContextSchemaId: ctx.data.outputContextSchemaId ? {
2352
- subOperation: "insert",
2353
- table: "context_schema",
2354
- data: {
2355
- ...ctx.data.outputContextSchemaId
2356
- },
2357
- return: "uuid"
2358
- } : null
2359
- },
2360
- transaction: true
3085
+ serviceName: CadenzaService.serviceRegistry.serviceName
3086
+ }
2361
3087
  };
2362
3088
  }).doOn("meta.task.created").emits("global.meta.graph_metadata.task_created");
2363
3089
  CadenzaService.createMetaTask("Handle task update", (ctx) => {
@@ -2564,9 +3290,11 @@ var GraphMetadataController = class _GraphMetadataController {
2564
3290
  { concurrency: 100, isSubMeta: true }
2565
3291
  ).doOn("meta.node.mapped", "meta.node.detected_previous_task_execution").emits("global.meta.graph_metadata.relationship_executed");
2566
3292
  CadenzaService.createMetaTask("Handle Intent Creation", (ctx) => {
3293
+ const intentName = ctx.data?.name;
2567
3294
  return {
2568
3295
  data: {
2569
- ...ctx.data
3296
+ ...ctx.data,
3297
+ isMeta: intentName ? isMetaIntentName(intentName) : false
2570
3298
  }
2571
3299
  };
2572
3300
  }).doOn("meta.inquiry_broker.added").emits("global.meta.graph_metadata.intent_created");
@@ -2598,6 +3326,52 @@ var SCHEMA_TYPES = [
2598
3326
  // src/database/DatabaseController.ts
2599
3327
  import { Pool } from "pg";
2600
3328
  import { camelCase, snakeCase } from "lodash-es";
3329
+ function resolveTableQueryIntents(serviceName, tableName, table, defaultInputSchema) {
3330
+ const resolvedServiceName = serviceName ?? "unknown-service";
3331
+ const defaultIntentName = `query-${resolvedServiceName}-${tableName}`;
3332
+ const defaultDescription = `Perform a query operation on the ${tableName} table`;
3333
+ const intents = [
3334
+ {
3335
+ name: defaultIntentName,
3336
+ description: defaultDescription,
3337
+ input: defaultInputSchema
3338
+ }
3339
+ ];
3340
+ const warnings = [];
3341
+ const names = /* @__PURE__ */ new Set([defaultIntentName]);
3342
+ for (const customIntent of table.customIntents?.query ?? []) {
3343
+ const name = typeof customIntent === "string" ? customIntent.trim() : customIntent.intent?.trim();
3344
+ if (!name) {
3345
+ warnings.push(`Skipped empty custom query intent for table '${tableName}'.`);
3346
+ continue;
3347
+ }
3348
+ if (name.length > 100) {
3349
+ warnings.push(
3350
+ `Skipped custom query intent '${name}' for table '${tableName}': name must be <= 100 characters.`
3351
+ );
3352
+ continue;
3353
+ }
3354
+ if (name.includes(" ") || name.includes(".") || name.includes("\\")) {
3355
+ warnings.push(
3356
+ `Skipped custom query intent '${name}' for table '${tableName}': name cannot contain spaces, dots or backslashes.`
3357
+ );
3358
+ continue;
3359
+ }
3360
+ if (names.has(name)) {
3361
+ warnings.push(
3362
+ `Skipped duplicate custom query intent '${name}' for table '${tableName}'.`
3363
+ );
3364
+ continue;
3365
+ }
3366
+ names.add(name);
3367
+ intents.push({
3368
+ name,
3369
+ description: typeof customIntent === "string" ? `Perform a query operation on the ${tableName} table` : customIntent.description ?? defaultDescription,
3370
+ input: typeof customIntent === "string" ? defaultInputSchema : customIntent.input ?? defaultInputSchema
3371
+ });
3372
+ }
3373
+ return { intents, warnings };
3374
+ }
2601
3375
  var DatabaseController = class _DatabaseController {
2602
3376
  /**
2603
3377
  * Constructor for initializing the `DatabaseService` class.
@@ -2739,6 +3513,20 @@ var DatabaseController = class _DatabaseController {
2739
3513
  }
2740
3514
  }
2741
3515
  }
3516
+ if (table.customIntents?.query) {
3517
+ if (!Array.isArray(table.customIntents.query)) {
3518
+ throw new Error(
3519
+ `Invalid customIntents.query for ${tableName}: expected array`
3520
+ );
3521
+ }
3522
+ for (const customIntent of table.customIntents.query) {
3523
+ if (typeof customIntent !== "string" && (typeof customIntent !== "object" || !customIntent || typeof customIntent.intent !== "string")) {
3524
+ throw new Error(
3525
+ `Invalid custom query intent on ${tableName}: expected string or object with intent`
3526
+ );
3527
+ }
3528
+ }
3529
+ }
2742
3530
  }
2743
3531
  }
2744
3532
  console.log("SCHEMA VALIDATED");
@@ -3775,13 +4563,30 @@ var DatabaseController = class _DatabaseController {
3775
4563
  }) ?? []
3776
4564
  );
3777
4565
  if (op === "query") {
3778
- const intentName = `query-${CadenzaService.serviceRegistry.serviceName}-${tableName}`;
3779
- CadenzaService.defineIntent({
3780
- name: intentName,
3781
- description: `Perform a query operation on the ${tableName} table`,
3782
- input: schema
3783
- });
3784
- task.respondsTo(intentName);
4566
+ const { intents, warnings } = resolveTableQueryIntents(
4567
+ CadenzaService.serviceRegistry?.serviceName,
4568
+ tableName,
4569
+ table,
4570
+ schema
4571
+ );
4572
+ for (const warning of warnings) {
4573
+ CadenzaService.log(
4574
+ "Skipped custom query intent registration.",
4575
+ {
4576
+ tableName,
4577
+ warning
4578
+ },
4579
+ "warning"
4580
+ );
4581
+ }
4582
+ for (const intent of intents) {
4583
+ CadenzaService.defineIntent({
4584
+ name: intent.name,
4585
+ description: intent.description,
4586
+ input: intent.input
4587
+ });
4588
+ }
4589
+ task.respondsTo(...intents.map((intent) => intent.name));
3785
4590
  }
3786
4591
  }
3787
4592
  getInputSchema(op, tableName, table) {
@@ -3873,18 +4678,18 @@ function getInsertDataSchemaFromTable(table, tableName) {
3873
4678
  Object.entries(table.fields).map((field) => {
3874
4679
  return [
3875
4680
  field[0],
3876
- [
3877
- {
4681
+ {
4682
+ value: {
3878
4683
  type: tableFieldTypeToSchemaType(field[1].type),
3879
4684
  description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3880
4685
  },
3881
- {
4686
+ effect: {
3882
4687
  type: "string",
3883
4688
  constraints: {
3884
4689
  oneOf: ["increment", "decrement", "set"]
3885
4690
  }
3886
4691
  },
3887
- {
4692
+ subOperation: {
3888
4693
  type: "object",
3889
4694
  properties: {
3890
4695
  subOperation: {
@@ -3894,17 +4699,17 @@ function getInsertDataSchemaFromTable(table, tableName) {
3894
4699
  table: {
3895
4700
  type: "string"
3896
4701
  },
3897
- data: [
3898
- {
4702
+ data: {
4703
+ single: {
3899
4704
  type: "object"
3900
4705
  },
3901
- {
4706
+ batch: {
3902
4707
  type: "array",
3903
4708
  items: {
3904
4709
  type: "object"
3905
4710
  }
3906
4711
  }
3907
- ],
4712
+ },
3908
4713
  filter: {
3909
4714
  type: "object"
3910
4715
  },
@@ -3920,7 +4725,7 @@ function getInsertDataSchemaFromTable(table, tableName) {
3920
4725
  },
3921
4726
  required: ["subOperation", "table"]
3922
4727
  }
3923
- ]
4728
+ }
3924
4729
  ];
3925
4730
  })
3926
4731
  )
@@ -3928,13 +4733,13 @@ function getInsertDataSchemaFromTable(table, tableName) {
3928
4733
  required: Object.entries(table.fields).filter((field) => field[1].required || field[1].primary).map((field) => field[0]),
3929
4734
  strict: true
3930
4735
  };
3931
- return [
3932
- dataSchema,
3933
- {
4736
+ return {
4737
+ single: dataSchema,
4738
+ batch: {
3934
4739
  type: "array",
3935
4740
  items: dataSchema
3936
4741
  }
3937
- ];
4742
+ };
3938
4743
  }
3939
4744
  function getQueryFilterSchemaFromTable(table, tableName) {
3940
4745
  return {
@@ -3944,24 +4749,24 @@ function getQueryFilterSchemaFromTable(table, tableName) {
3944
4749
  Object.entries(table.fields).map((field) => {
3945
4750
  return [
3946
4751
  field[0],
3947
- [
3948
- {
4752
+ {
4753
+ value: {
3949
4754
  type: tableFieldTypeToSchemaType(field[1].type),
3950
4755
  description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3951
4756
  },
3952
- {
4757
+ in: {
3953
4758
  type: "array",
3954
4759
  items: {
3955
4760
  type: tableFieldTypeToSchemaType(field[1].type)
3956
4761
  }
3957
4762
  }
3958
- ]
4763
+ }
3959
4764
  ];
3960
4765
  })
3961
4766
  )
3962
4767
  },
3963
4768
  strict: true,
3964
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4769
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
3965
4770
  };
3966
4771
  }
3967
4772
  function getQueryFieldsSchemaFromTable(table, tableName) {
@@ -3973,7 +4778,7 @@ function getQueryFieldsSchemaFromTable(table, tableName) {
3973
4778
  oneOf: Object.keys(table.fields)
3974
4779
  }
3975
4780
  },
3976
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4781
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
3977
4782
  };
3978
4783
  }
3979
4784
  function getQueryJoinsSchemaFromTable(table, tableName) {
@@ -4020,7 +4825,7 @@ function getQueryJoinsSchemaFromTable(table, tableName) {
4020
4825
  )
4021
4826
  },
4022
4827
  strict: true,
4023
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4828
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4024
4829
  };
4025
4830
  }
4026
4831
  function getQuerySortSchemaFromTable(table, tableName) {
@@ -4042,7 +4847,7 @@ function getQuerySortSchemaFromTable(table, tableName) {
4042
4847
  )
4043
4848
  },
4044
4849
  strict: true,
4045
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4850
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4046
4851
  };
4047
4852
  }
4048
4853
  function getQueryLimitSchemaFromTable() {
@@ -4104,12 +4909,10 @@ function getQueryOnConflictSchemaFromTable(table, tableName) {
4104
4909
  Object.entries(table.fields).map((field) => {
4105
4910
  return [
4106
4911
  field[0],
4107
- [
4108
- {
4109
- type: tableFieldTypeToSchemaType(field[1].type),
4110
- description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
4111
- }
4112
- ]
4912
+ {
4913
+ type: tableFieldTypeToSchemaType(field[1].type),
4914
+ description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
4915
+ }
4113
4916
  ];
4114
4917
  })
4115
4918
  )
@@ -4467,6 +5270,75 @@ var GraphSyncController = class _GraphSyncController {
4467
5270
  { concurrency: 30 }
4468
5271
  ) : CadenzaService.get("dbInsertSignalToTaskMap"))?.then(registerSignalTask)
4469
5272
  );
5273
+ const registerIntentTask = CadenzaService.createMetaTask(
5274
+ "Record intent registration",
5275
+ (ctx) => {
5276
+ if (!ctx.__syncing) {
5277
+ return;
5278
+ }
5279
+ CadenzaService.debounce("meta.sync_controller.synced_resource", {
5280
+ delayMs: 3e3
5281
+ });
5282
+ const task = CadenzaService.get(ctx.__taskName);
5283
+ task.__registeredIntents = task.__registeredIntents ?? /* @__PURE__ */ new Set();
5284
+ task.__registeredIntents.add(ctx.__intent);
5285
+ }
5286
+ );
5287
+ this.registerIntentToTaskMapTask = CadenzaService.createMetaTask(
5288
+ "Split intents of task",
5289
+ function* (ctx) {
5290
+ const task = ctx.task;
5291
+ if (task.hidden || !task.register) return;
5292
+ task.__registeredIntents = task.__registeredIntents ?? /* @__PURE__ */ new Set();
5293
+ task.__invalidMetaIntentWarnings = task.__invalidMetaIntentWarnings ?? /* @__PURE__ */ new Set();
5294
+ for (const intent of task.handlesIntents) {
5295
+ if (task.__registeredIntents.has(intent)) continue;
5296
+ if (isMetaIntentName(intent) && !task.isMeta) {
5297
+ if (!task.__invalidMetaIntentWarnings.has(intent)) {
5298
+ task.__invalidMetaIntentWarnings.add(intent);
5299
+ CadenzaService.log(
5300
+ "Skipping intent-to-task registration: non-meta task cannot handle meta intent.",
5301
+ {
5302
+ intent,
5303
+ taskName: task.name,
5304
+ taskVersion: task.version
5305
+ },
5306
+ "warning"
5307
+ );
5308
+ }
5309
+ continue;
5310
+ }
5311
+ yield {
5312
+ data: {
5313
+ intentName: intent,
5314
+ taskName: task.name,
5315
+ taskVersion: task.version,
5316
+ serviceName: CadenzaService.serviceRegistry.serviceName
5317
+ },
5318
+ __taskName: task.name,
5319
+ __intent: intent
5320
+ };
5321
+ }
5322
+ }
5323
+ ).then(
5324
+ (this.isCadenzaDBReady ? CadenzaService.createCadenzaDBInsertTask(
5325
+ "intent_to_task_map",
5326
+ {
5327
+ onConflict: {
5328
+ target: [
5329
+ "intent_name",
5330
+ "task_name",
5331
+ "task_version",
5332
+ "service_name"
5333
+ ],
5334
+ action: {
5335
+ do: "nothing"
5336
+ }
5337
+ }
5338
+ },
5339
+ { concurrency: 30 }
5340
+ ) : CadenzaService.get("dbInsertIntentToTaskMap"))?.then(registerIntentTask)
5341
+ );
4470
5342
  this.registerTaskMapTask = CadenzaService.createMetaTask(
4471
5343
  "Register task map to DB",
4472
5344
  function* (ctx) {
@@ -4589,6 +5461,7 @@ var GraphSyncController = class _GraphSyncController {
4589
5461
  CadenzaService.registry.doForEachTask.clone().doOn("meta.sync_controller.synced_tasks").then(
4590
5462
  this.registerTaskMapTask,
4591
5463
  this.registerSignalToTaskMapTask,
5464
+ this.registerIntentToTaskMapTask,
4592
5465
  this.registerDeputyRelationshipTask
4593
5466
  );
4594
5467
  CadenzaService.registry.getAllRoutines.clone().doOn("meta.sync_controller.synced_routines").then(this.splitTasksInRoutines);
@@ -4730,11 +5603,192 @@ var CadenzaService = class {
4730
5603
  Cadenza.interval(signal, context, intervalMs, leading, startDateTime);
4731
5604
  }
4732
5605
  static defineIntent(intent) {
4733
- this.inquiryBroker?.intents.set(intent.name, intent);
5606
+ this.inquiryBroker?.addIntent(intent);
4734
5607
  return intent;
4735
5608
  }
4736
- static async inquire(inquiry, context, options) {
4737
- return this.inquiryBroker?.inquire(inquiry, context, options);
5609
+ static getInquiryResponderDescriptor(task) {
5610
+ return this.serviceRegistry.getInquiryResponderDescriptor(task);
5611
+ }
5612
+ static compareInquiryResponders(left, right) {
5613
+ return compareResponderDescriptors(left.descriptor, right.descriptor);
5614
+ }
5615
+ static buildInquirySummary(inquiry, startedAt, statuses, totalResponders) {
5616
+ const counts = summarizeResponderStatuses(statuses);
5617
+ const isMetaInquiry = isMetaIntentName(inquiry);
5618
+ const eligibleResponders = statuses.length;
5619
+ return {
5620
+ inquiry,
5621
+ isMetaInquiry,
5622
+ totalResponders,
5623
+ eligibleResponders,
5624
+ filteredOutResponders: Math.max(0, totalResponders - eligibleResponders),
5625
+ responded: counts.responded,
5626
+ failed: counts.failed,
5627
+ timedOut: counts.timedOut,
5628
+ pending: counts.pending,
5629
+ durationMs: Date.now() - startedAt,
5630
+ responders: statuses
5631
+ };
5632
+ }
5633
+ static async inquire(inquiry, context, options = {}) {
5634
+ this.bootstrap();
5635
+ const observer = this.inquiryBroker?.inquiryObservers.get(inquiry);
5636
+ const allResponders = observer ? Array.from(observer.tasks).map((task) => ({
5637
+ task,
5638
+ descriptor: this.getInquiryResponderDescriptor(task)
5639
+ })) : [];
5640
+ const isMetaInquiry = isMetaIntentName(inquiry);
5641
+ const responders = allResponders.filter(({ task, descriptor }) => {
5642
+ const shouldExecute = shouldExecuteInquiryResponder(inquiry, task.isMeta);
5643
+ if (shouldExecute) {
5644
+ return true;
5645
+ }
5646
+ const warningKey = `${inquiry}|${descriptor.serviceName}|${descriptor.taskName}|${descriptor.taskVersion}|${descriptor.localTaskName}`;
5647
+ if (!this.warnedInvalidMetaIntentResponderKeys.has(warningKey)) {
5648
+ this.warnedInvalidMetaIntentResponderKeys.add(warningKey);
5649
+ this.log(
5650
+ "Skipping non-meta task for meta intent inquiry.",
5651
+ {
5652
+ inquiry,
5653
+ responder: descriptor
5654
+ },
5655
+ "warning",
5656
+ descriptor.serviceName
5657
+ );
5658
+ }
5659
+ return false;
5660
+ });
5661
+ if (responders.length === 0) {
5662
+ return {
5663
+ __inquiryMeta: {
5664
+ inquiry,
5665
+ isMetaInquiry,
5666
+ totalResponders: allResponders.length,
5667
+ eligibleResponders: 0,
5668
+ filteredOutResponders: allResponders.length,
5669
+ responded: 0,
5670
+ failed: 0,
5671
+ timedOut: 0,
5672
+ pending: 0,
5673
+ durationMs: 0,
5674
+ responders: []
5675
+ }
5676
+ };
5677
+ }
5678
+ responders.sort(this.compareInquiryResponders.bind(this));
5679
+ const overallTimeoutMs = options.overallTimeoutMs ?? options.timeout ?? 0;
5680
+ const requireComplete = options.requireComplete ?? false;
5681
+ const perResponderTimeoutMs = options.perResponderTimeoutMs;
5682
+ const startedAt = Date.now();
5683
+ const statuses = [];
5684
+ const statusByTask = /* @__PURE__ */ new Map();
5685
+ for (const responder of responders) {
5686
+ const status = {
5687
+ ...responder.descriptor,
5688
+ status: "timed_out",
5689
+ durationMs: 0
5690
+ };
5691
+ statuses.push(status);
5692
+ statusByTask.set(responder.task, status);
5693
+ }
5694
+ const resultsByTask = /* @__PURE__ */ new Map();
5695
+ const resolverTasks = [];
5696
+ const pending = new Set(responders.map((r) => r.task));
5697
+ const startTimeByTask = /* @__PURE__ */ new Map();
5698
+ this.emit("meta.inquiry_broker.inquire", { inquiry, context });
5699
+ return new Promise((resolve, reject) => {
5700
+ let finalized = false;
5701
+ let timeoutId;
5702
+ const finalize = (timedOut) => {
5703
+ if (finalized) return;
5704
+ finalized = true;
5705
+ if (timeoutId) {
5706
+ clearTimeout(timeoutId);
5707
+ timeoutId = void 0;
5708
+ }
5709
+ for (const resolverTask of resolverTasks) {
5710
+ resolverTask.destroy();
5711
+ }
5712
+ if (timedOut && pending.size > 0) {
5713
+ for (const task of pending) {
5714
+ const status = statusByTask.get(task);
5715
+ if (!status) continue;
5716
+ status.status = "timed_out";
5717
+ status.durationMs = Date.now() - (startTimeByTask.get(task) ?? startedAt);
5718
+ }
5719
+ }
5720
+ const fulfilledContexts = responders.filter((responder) => resultsByTask.has(responder.task)).map((responder) => resultsByTask.get(responder.task));
5721
+ const mergedContext = mergeInquiryContexts(fulfilledContexts);
5722
+ const inquiryMeta = this.buildInquirySummary(
5723
+ inquiry,
5724
+ startedAt,
5725
+ statuses,
5726
+ allResponders.length
5727
+ );
5728
+ const responseContext = {
5729
+ ...mergedContext,
5730
+ __inquiryMeta: inquiryMeta
5731
+ };
5732
+ if (requireComplete && (timedOut || inquiryMeta.failed > 0 || inquiryMeta.timedOut > 0 || inquiryMeta.pending > 0)) {
5733
+ reject({
5734
+ ...responseContext,
5735
+ __error: `Inquiry '${inquiry}' did not complete successfully`,
5736
+ errored: true
5737
+ });
5738
+ return;
5739
+ }
5740
+ resolve(responseContext);
5741
+ };
5742
+ if (overallTimeoutMs > 0) {
5743
+ timeoutId = setTimeout(() => finalize(true), overallTimeoutMs);
5744
+ }
5745
+ for (const responder of responders) {
5746
+ const { task, descriptor } = responder;
5747
+ const inquiryId = uuid3();
5748
+ startTimeByTask.set(task, Date.now());
5749
+ const resolverTask = this.createEphemeralMetaTask(
5750
+ `Resolve inquiry ${inquiry} for ${descriptor.localTaskName}`,
5751
+ (resultCtx) => {
5752
+ if (finalized) {
5753
+ return;
5754
+ }
5755
+ pending.delete(task);
5756
+ const status = statusByTask.get(task);
5757
+ if (status) {
5758
+ status.durationMs = Date.now() - (startTimeByTask.get(task) ?? startedAt);
5759
+ if (resultCtx?.errored || resultCtx?.failed) {
5760
+ status.status = "failed";
5761
+ status.error = String(
5762
+ resultCtx?.__error ?? resultCtx?.error ?? "Inquiry responder failed"
5763
+ );
5764
+ } else {
5765
+ status.status = "fulfilled";
5766
+ resultsByTask.set(task, resultCtx);
5767
+ }
5768
+ }
5769
+ if (pending.size === 0) {
5770
+ finalize(false);
5771
+ }
5772
+ },
5773
+ "Resolves distributed inquiry responder result",
5774
+ { register: false }
5775
+ ).doOn(`meta.node.graph_completed:${inquiryId}`);
5776
+ resolverTasks.push(resolverTask);
5777
+ const executionContext = {
5778
+ ...context,
5779
+ __routineExecId: inquiryId,
5780
+ __isInquiry: true
5781
+ };
5782
+ if (perResponderTimeoutMs !== void 0) {
5783
+ executionContext.__timeout = perResponderTimeoutMs;
5784
+ }
5785
+ if (task.isMeta) {
5786
+ this.metaRunner?.run(task, executionContext);
5787
+ } else {
5788
+ this.runner?.run(task, executionContext);
5789
+ }
5790
+ }
5791
+ });
4738
5792
  }
4739
5793
  /**
4740
5794
  * Executes the given task or graph routine within the provided context using the configured runner.
@@ -5771,6 +6825,7 @@ var CadenzaService = class {
5771
6825
  };
5772
6826
  CadenzaService.isBootstrapped = false;
5773
6827
  CadenzaService.serviceCreated = false;
6828
+ CadenzaService.warnedInvalidMetaIntentResponderKeys = /* @__PURE__ */ new Set();
5774
6829
 
5775
6830
  // src/index.ts
5776
6831
  import {