@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.js CHANGED
@@ -295,6 +295,72 @@ var DatabaseTask = class extends DeputyTask {
295
295
  var isNode = typeof process !== "undefined" && process.versions?.node != null;
296
296
  var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined";
297
297
 
298
+ // src/utils/inquiry.ts
299
+ var META_INTENT_PREFIX = "meta-";
300
+ var META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT = "meta-runtime-transport-diagnostics";
301
+ function isPlainObject(value) {
302
+ return typeof value === "object" && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
303
+ }
304
+ function deepMergeDeterministic(left, right) {
305
+ if (Array.isArray(left) && Array.isArray(right)) {
306
+ return [...left, ...right];
307
+ }
308
+ if (isPlainObject(left) && isPlainObject(right)) {
309
+ const merged = { ...left };
310
+ const keys = Array.from(/* @__PURE__ */ new Set([...Object.keys(left), ...Object.keys(right)])).sort();
311
+ for (const key of keys) {
312
+ if (!(key in left)) {
313
+ merged[key] = right[key];
314
+ continue;
315
+ }
316
+ if (!(key in right)) {
317
+ merged[key] = left[key];
318
+ continue;
319
+ }
320
+ merged[key] = deepMergeDeterministic(left[key], right[key]);
321
+ }
322
+ return merged;
323
+ }
324
+ return right;
325
+ }
326
+ function mergeInquiryContexts(contexts) {
327
+ return contexts.reduce((acc, next) => deepMergeDeterministic(acc, next), {});
328
+ }
329
+ function isMetaIntentName(intentName) {
330
+ return intentName.startsWith(META_INTENT_PREFIX);
331
+ }
332
+ function shouldExecuteInquiryResponder(inquiry, responderIsMeta) {
333
+ if (!isMetaIntentName(inquiry)) {
334
+ return true;
335
+ }
336
+ return responderIsMeta;
337
+ }
338
+ function compareResponderDescriptors(left, right) {
339
+ if (left.serviceName !== right.serviceName) {
340
+ return left.serviceName.localeCompare(right.serviceName);
341
+ }
342
+ if (left.taskName !== right.taskName) {
343
+ return left.taskName.localeCompare(right.taskName);
344
+ }
345
+ if (left.taskVersion !== right.taskVersion) {
346
+ return left.taskVersion - right.taskVersion;
347
+ }
348
+ return left.localTaskName.localeCompare(right.localTaskName);
349
+ }
350
+ function summarizeResponderStatuses(statuses) {
351
+ let responded = 0;
352
+ let failed = 0;
353
+ let timedOut = 0;
354
+ let pending = 0;
355
+ for (const status of statuses) {
356
+ if (status.status === "fulfilled") responded++;
357
+ if (status.status === "failed") failed++;
358
+ if (status.status === "timed_out") timedOut++;
359
+ }
360
+ pending = Math.max(0, statuses.length - responded - failed - timedOut);
361
+ return { responded, failed, timedOut, pending };
362
+ }
363
+
298
364
  // src/registry/ServiceRegistry.ts
299
365
  var ServiceRegistry = class _ServiceRegistry {
300
366
  /**
@@ -310,11 +376,47 @@ var ServiceRegistry = class _ServiceRegistry {
310
376
  this.instances = /* @__PURE__ */ new Map();
311
377
  this.deputies = /* @__PURE__ */ new Map();
312
378
  this.remoteSignals = /* @__PURE__ */ new Map();
379
+ this.remoteIntents = /* @__PURE__ */ new Map();
380
+ this.remoteIntentDeputiesByKey = /* @__PURE__ */ new Map();
381
+ this.remoteIntentDeputiesByTask = /* @__PURE__ */ new Map();
313
382
  this.serviceName = null;
314
383
  this.serviceInstanceId = null;
315
384
  this.numberOfRunningGraphs = 0;
316
385
  this.useSocket = false;
317
386
  this.retryCount = 3;
387
+ CadenzaService.defineIntent({
388
+ name: META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT,
389
+ description: "Gather transport diagnostics across all services and communication clients.",
390
+ input: {
391
+ type: "object",
392
+ properties: {
393
+ detailLevel: {
394
+ type: "string",
395
+ constraints: {
396
+ oneOf: ["summary", "full"]
397
+ }
398
+ },
399
+ includeErrorHistory: {
400
+ type: "boolean"
401
+ },
402
+ errorHistoryLimit: {
403
+ type: "number",
404
+ constraints: {
405
+ min: 1,
406
+ max: 200
407
+ }
408
+ }
409
+ }
410
+ },
411
+ output: {
412
+ type: "object",
413
+ properties: {
414
+ transportDiagnostics: {
415
+ type: "object"
416
+ }
417
+ }
418
+ }
419
+ });
318
420
  this.handleInstanceUpdateTask = CadenzaService.createMetaTask(
319
421
  "Handle Instance Update",
320
422
  (ctx, emit) => {
@@ -354,7 +456,7 @@ var ServiceRegistry = class _ServiceRegistry {
354
456
  if (this.serviceName === serviceName) {
355
457
  return false;
356
458
  }
357
- if (!isFrontend && this.deputies.has(serviceName) || this.remoteSignals.has(serviceName)) {
459
+ if (!isFrontend && (this.deputies.has(serviceName) || this.remoteIntents.has(serviceName)) || this.remoteSignals.has(serviceName)) {
358
460
  const clientCreated = instances?.some(
359
461
  (i) => i.address === address && i.port === port && i.clientCreated && i.isActive
360
462
  );
@@ -404,7 +506,10 @@ var ServiceRegistry = class _ServiceRegistry {
404
506
  for (const serviceInstance of ctx.serviceInstances) {
405
507
  yield { serviceInstance };
406
508
  }
407
- }).doOn("meta.service_registry.registered_global_signals").then(this.handleInstanceUpdateTask);
509
+ }).doOn(
510
+ "meta.service_registry.registered_global_signals",
511
+ "meta.service_registry.registered_global_intents"
512
+ ).then(this.handleInstanceUpdateTask);
408
513
  this.handleGlobalSignalRegistrationTask = CadenzaService.createMetaTask(
409
514
  "Handle global Signal Registration",
410
515
  (ctx) => {
@@ -445,6 +550,32 @@ var ServiceRegistry = class _ServiceRegistry {
445
550
  },
446
551
  "Handles registration of remote signals"
447
552
  ).emits("meta.service_registry.registered_global_signals").doOn("global.meta.cadenza_db.gathered_sync_data");
553
+ this.handleGlobalIntentRegistrationTask = CadenzaService.createMetaTask(
554
+ "Handle global intent registration",
555
+ (ctx) => {
556
+ const intentToTaskMaps = this.normalizeIntentMaps(ctx);
557
+ const sorted = intentToTaskMaps.sort((a, b) => {
558
+ if (a.deleted && !b.deleted) return -1;
559
+ if (!a.deleted && b.deleted) return 1;
560
+ return 0;
561
+ });
562
+ for (const map of sorted) {
563
+ if (map.deleted) {
564
+ this.unregisterRemoteIntentDeputy(map);
565
+ continue;
566
+ }
567
+ CadenzaService.inquiryBroker.addIntent({
568
+ name: map.intentName
569
+ });
570
+ this.registerRemoteIntentDeputy(map);
571
+ }
572
+ return true;
573
+ },
574
+ "Handles registration of remote inquiry intent responders"
575
+ ).emits("meta.service_registry.registered_global_intents").doOn(
576
+ "global.meta.cadenza_db.gathered_sync_data",
577
+ "global.meta.graph_metadata.task_intent_associated"
578
+ );
448
579
  this.handleServiceNotRespondingTask = CadenzaService.createMetaTask(
449
580
  "Handle service not responding",
450
581
  (ctx, emit) => {
@@ -558,7 +689,10 @@ var ServiceRegistry = class _ServiceRegistry {
558
689
  });
559
690
  return joinedContext;
560
691
  }
561
- ).emits("meta.service_registry.initial_sync_complete").then(this.handleGlobalSignalRegistrationTask);
692
+ ).emits("meta.service_registry.initial_sync_complete").then(
693
+ this.handleGlobalSignalRegistrationTask,
694
+ this.handleGlobalIntentRegistrationTask
695
+ );
562
696
  this.fullSyncTask = CadenzaService.createMetaRoutine("Full sync", [
563
697
  CadenzaService.createCadenzaDBQueryTask("signal_to_task_map", {
564
698
  filter: {
@@ -566,6 +700,15 @@ var ServiceRegistry = class _ServiceRegistry {
566
700
  },
567
701
  fields: ["signal_name", "service_name", "deleted"]
568
702
  }).then(mergeSyncDataTask),
703
+ CadenzaService.createCadenzaDBQueryTask("intent_to_task_map", {
704
+ fields: [
705
+ "intent_name",
706
+ "task_name",
707
+ "task_version",
708
+ "service_name",
709
+ "deleted"
710
+ ]
711
+ }).then(mergeSyncDataTask),
569
712
  CadenzaService.createCadenzaDBQueryTask("service_instance", {
570
713
  filter: {
571
714
  deleted: false,
@@ -756,6 +899,25 @@ var ServiceRegistry = class _ServiceRegistry {
756
899
  __active: self?.isActive ?? false
757
900
  };
758
901
  }).doOn("meta.socket.status_check_requested");
902
+ this.collectTransportDiagnosticsTask = CadenzaService.createMetaTask(
903
+ "Collect transport diagnostics",
904
+ async (ctx) => {
905
+ const inquiryResult = await CadenzaService.inquire(
906
+ META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT,
907
+ {
908
+ detailLevel: ctx.detailLevel,
909
+ includeErrorHistory: ctx.includeErrorHistory,
910
+ errorHistoryLimit: ctx.errorHistoryLimit
911
+ },
912
+ ctx.inquiryOptions ?? ctx.__inquiryOptions ?? {}
913
+ );
914
+ return {
915
+ ...ctx,
916
+ ...inquiryResult
917
+ };
918
+ },
919
+ "Collects distributed transport diagnostics using inquiry responders."
920
+ ).doOn("meta.service_registry.transport_diagnostics_requested").emits("meta.service_registry.transport_diagnostics_collected").emitsOnFail("meta.service_registry.transport_diagnostics_failed");
759
921
  this.insertServiceTask = CadenzaService.createCadenzaDBInsertTask(
760
922
  "service",
761
923
  {
@@ -964,8 +1126,125 @@ var ServiceRegistry = class _ServiceRegistry {
964
1126
  if (!this._instance) this._instance = new _ServiceRegistry();
965
1127
  return this._instance;
966
1128
  }
1129
+ buildRemoteIntentDeputyKey(map) {
1130
+ return `${map.intentName}|${map.serviceName}|${map.taskName}|${map.taskVersion ?? 1}`;
1131
+ }
1132
+ normalizeIntentMaps(ctx) {
1133
+ if (Array.isArray(ctx.intentToTaskMaps)) {
1134
+ return ctx.intentToTaskMaps.map((m) => ({
1135
+ intentName: m.intentName ?? m.intent_name,
1136
+ serviceName: m.serviceName ?? m.service_name,
1137
+ taskName: m.taskName ?? m.task_name,
1138
+ taskVersion: m.taskVersion ?? m.task_version ?? 1,
1139
+ deleted: !!m.deleted
1140
+ })).filter((m) => m.intentName && m.serviceName && m.taskName);
1141
+ }
1142
+ const single = ctx.intentToTaskMap ?? ctx.data ?? (ctx.intentName ? ctx : void 0);
1143
+ if (!single) return [];
1144
+ const normalized = {
1145
+ intentName: single.intentName ?? single.intent_name,
1146
+ serviceName: single.serviceName ?? single.service_name,
1147
+ taskName: single.taskName ?? single.task_name,
1148
+ taskVersion: single.taskVersion ?? single.task_version ?? 1,
1149
+ deleted: !!single.deleted
1150
+ };
1151
+ if (!normalized.intentName || !normalized.serviceName || !normalized.taskName)
1152
+ return [];
1153
+ return [normalized];
1154
+ }
1155
+ registerRemoteIntentDeputy(map) {
1156
+ if (!this.serviceName || map.serviceName === this.serviceName) {
1157
+ return;
1158
+ }
1159
+ const key = this.buildRemoteIntentDeputyKey(map);
1160
+ if (this.remoteIntentDeputiesByKey.has(key)) {
1161
+ return;
1162
+ }
1163
+ const deputyTaskName = `Inquire ${map.intentName} via ${map.serviceName} (${map.taskName} v${map.taskVersion})`;
1164
+ const deputyTask = isMetaIntentName(map.intentName) ? CadenzaService.createMetaDeputyTask(map.taskName, map.serviceName, {
1165
+ register: false,
1166
+ isHidden: true,
1167
+ retryCount: 1,
1168
+ retryDelay: 50,
1169
+ retryDelayFactor: 1.2
1170
+ }) : CadenzaService.createDeputyTask(map.taskName, map.serviceName, {
1171
+ register: false,
1172
+ isHidden: true,
1173
+ retryCount: 1,
1174
+ retryDelay: 50,
1175
+ retryDelayFactor: 1.2
1176
+ });
1177
+ deputyTask.respondsTo(map.intentName);
1178
+ if (!this.remoteIntents.has(map.serviceName)) {
1179
+ this.remoteIntents.set(map.serviceName, /* @__PURE__ */ new Set());
1180
+ }
1181
+ this.remoteIntents.get(map.serviceName).add(map.intentName);
1182
+ const descriptor = {
1183
+ key,
1184
+ intentName: map.intentName,
1185
+ serviceName: map.serviceName,
1186
+ remoteTaskName: map.taskName,
1187
+ remoteTaskVersion: map.taskVersion,
1188
+ localTaskName: deputyTask.name || deputyTaskName,
1189
+ localTask: deputyTask
1190
+ };
1191
+ this.remoteIntentDeputiesByKey.set(key, descriptor);
1192
+ this.remoteIntentDeputiesByTask.set(deputyTask, descriptor);
1193
+ }
1194
+ unregisterRemoteIntentDeputy(map) {
1195
+ const key = this.buildRemoteIntentDeputyKey(map);
1196
+ const descriptor = this.remoteIntentDeputiesByKey.get(key);
1197
+ if (!descriptor) {
1198
+ return;
1199
+ }
1200
+ const task = descriptor.localTask;
1201
+ if (task) {
1202
+ CadenzaService.inquiryBroker.unsubscribe(descriptor.intentName, task);
1203
+ task.destroy();
1204
+ }
1205
+ this.remoteIntentDeputiesByTask.delete(descriptor.localTask);
1206
+ this.remoteIntentDeputiesByKey.delete(key);
1207
+ this.remoteIntents.get(descriptor.serviceName)?.delete(descriptor.intentName);
1208
+ if (!this.remoteIntents.get(descriptor.serviceName)?.size) {
1209
+ this.remoteIntents.delete(descriptor.serviceName);
1210
+ }
1211
+ const deputies = this.deputies.get(descriptor.serviceName);
1212
+ if (deputies) {
1213
+ this.deputies.set(
1214
+ descriptor.serviceName,
1215
+ deputies.filter((d) => d.localTaskName !== descriptor.localTaskName)
1216
+ );
1217
+ if (this.deputies.get(descriptor.serviceName)?.length === 0) {
1218
+ this.deputies.delete(descriptor.serviceName);
1219
+ }
1220
+ }
1221
+ }
1222
+ getInquiryResponderDescriptor(task) {
1223
+ const remote = this.remoteIntentDeputiesByTask.get(task);
1224
+ if (remote) {
1225
+ return {
1226
+ isRemote: true,
1227
+ serviceName: remote.serviceName,
1228
+ taskName: remote.remoteTaskName,
1229
+ taskVersion: remote.remoteTaskVersion,
1230
+ localTaskName: remote.localTaskName
1231
+ };
1232
+ }
1233
+ return {
1234
+ isRemote: false,
1235
+ serviceName: this.serviceName ?? "UnknownService",
1236
+ taskName: task.name,
1237
+ taskVersion: task.version,
1238
+ localTaskName: task.name
1239
+ };
1240
+ }
967
1241
  reset() {
968
1242
  this.instances.clear();
1243
+ this.deputies.clear();
1244
+ this.remoteSignals.clear();
1245
+ this.remoteIntents.clear();
1246
+ this.remoteIntentDeputiesByKey.clear();
1247
+ this.remoteIntentDeputiesByTask.clear();
969
1248
  }
970
1249
  };
971
1250
 
@@ -1082,6 +1361,8 @@ var RestController = class _RestController {
1082
1361
  * It initializes and configures the REST server tasks.
1083
1362
  */
1084
1363
  constructor() {
1364
+ this.fetchClientDiagnostics = /* @__PURE__ */ new Map();
1365
+ this.diagnosticsErrorHistoryLimit = 100;
1085
1366
  /**
1086
1367
  * Fetches data from the given URL with a specified timeout. This function performs
1087
1368
  * a fetch request with the ability to cancel the request if it exceeds the provided timeout duration.
@@ -1122,6 +1403,11 @@ var RestController = class _RestController {
1122
1403
  "meta.rest.delegation_requested",
1123
1404
  "meta.socket.delegation_requested"
1124
1405
  );
1406
+ CadenzaService.createMetaTask(
1407
+ "Collect fetch transport diagnostics",
1408
+ (ctx) => this.collectFetchTransportDiagnostics(ctx),
1409
+ "Responds to distributed transport diagnostics inquiries with REST/fetch client data."
1410
+ ).respondsTo(META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT);
1125
1411
  CadenzaService.createMetaRoutine(
1126
1412
  "RestServer",
1127
1413
  [
@@ -1452,6 +1738,13 @@ var RestController = class _RestController {
1452
1738
  const port = protocol === "https" ? 443 : servicePort;
1453
1739
  const URL = `${protocol}://${serviceAddress}:${port}`;
1454
1740
  const fetchId = `${serviceAddress}_${port}`;
1741
+ const fetchDiagnostics = this.ensureFetchClientDiagnostics(
1742
+ fetchId,
1743
+ serviceName,
1744
+ URL
1745
+ );
1746
+ fetchDiagnostics.destroyed = false;
1747
+ fetchDiagnostics.updatedAt = Date.now();
1455
1748
  if (CadenzaService.get(`Send Handshake to ${URL}`)) {
1456
1749
  console.error("Fetch client already exists", URL);
1457
1750
  return;
@@ -1473,6 +1766,10 @@ var RestController = class _RestController {
1473
1766
  );
1474
1767
  if (response.__status !== "success") {
1475
1768
  const error = response.__error ?? `Failed to connect to service ${serviceName} ${ctx2.serviceInstanceId}`;
1769
+ fetchDiagnostics.connected = false;
1770
+ fetchDiagnostics.lastHandshakeError = error;
1771
+ fetchDiagnostics.updatedAt = Date.now();
1772
+ this.recordFetchClientError(fetchId, serviceName, URL, error);
1476
1773
  CadenzaService.log(
1477
1774
  "Fetch handshake failed.",
1478
1775
  { error, serviceName, URL },
@@ -1482,6 +1779,11 @@ var RestController = class _RestController {
1482
1779
  return { ...ctx2, __error: error, errored: true };
1483
1780
  }
1484
1781
  ctx2.serviceInstanceId = response.__serviceInstanceId;
1782
+ fetchDiagnostics.connected = true;
1783
+ fetchDiagnostics.destroyed = false;
1784
+ fetchDiagnostics.lastHandshakeAt = (/* @__PURE__ */ new Date()).toISOString();
1785
+ fetchDiagnostics.lastHandshakeError = null;
1786
+ fetchDiagnostics.updatedAt = Date.now();
1485
1787
  CadenzaService.log("Fetch client connected.", {
1486
1788
  response,
1487
1789
  serviceName,
@@ -1497,6 +1799,10 @@ var RestController = class _RestController {
1497
1799
  });
1498
1800
  }
1499
1801
  } catch (e) {
1802
+ fetchDiagnostics.connected = false;
1803
+ fetchDiagnostics.lastHandshakeError = this.getErrorMessage(e);
1804
+ fetchDiagnostics.updatedAt = Date.now();
1805
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1500
1806
  CadenzaService.log(
1501
1807
  "Error in fetch handshake",
1502
1808
  { error: e, serviceName, URL, ctx: ctx2 },
@@ -1518,6 +1824,8 @@ var RestController = class _RestController {
1518
1824
  if (ctx2.__remoteRoutineName === void 0) {
1519
1825
  return;
1520
1826
  }
1827
+ fetchDiagnostics.delegationRequests++;
1828
+ fetchDiagnostics.updatedAt = Date.now();
1521
1829
  let resultContext;
1522
1830
  try {
1523
1831
  resultContext = await this.fetchDataWithTimeout(
@@ -1531,8 +1839,21 @@ var RestController = class _RestController {
1531
1839
  },
1532
1840
  3e4
1533
1841
  );
1842
+ if (resultContext?.errored || resultContext?.failed) {
1843
+ fetchDiagnostics.delegationFailures++;
1844
+ fetchDiagnostics.updatedAt = Date.now();
1845
+ this.recordFetchClientError(
1846
+ fetchId,
1847
+ serviceName,
1848
+ URL,
1849
+ resultContext?.__error ?? resultContext?.error ?? "Delegation failed"
1850
+ );
1851
+ }
1534
1852
  } catch (e) {
1535
1853
  console.error("Error in delegation", e);
1854
+ fetchDiagnostics.delegationFailures++;
1855
+ fetchDiagnostics.updatedAt = Date.now();
1856
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1536
1857
  resultContext = {
1537
1858
  __error: `Error: ${e}`,
1538
1859
  errored: true,
@@ -1558,6 +1879,8 @@ var RestController = class _RestController {
1558
1879
  if (ctx2.__signalName === void 0) {
1559
1880
  return;
1560
1881
  }
1882
+ fetchDiagnostics.signalTransmissions++;
1883
+ fetchDiagnostics.updatedAt = Date.now();
1561
1884
  let response;
1562
1885
  try {
1563
1886
  response = await this.fetchDataWithTimeout(
@@ -1574,8 +1897,21 @@ var RestController = class _RestController {
1574
1897
  if (ctx2.__routineExecId) {
1575
1898
  emit(`meta.fetch.transmitted:${ctx2.__routineExecId}`, response);
1576
1899
  }
1900
+ if (response?.errored || response?.failed) {
1901
+ fetchDiagnostics.signalFailures++;
1902
+ fetchDiagnostics.updatedAt = Date.now();
1903
+ this.recordFetchClientError(
1904
+ fetchId,
1905
+ serviceName,
1906
+ URL,
1907
+ response?.__error ?? response?.error ?? "Signal transmission failed"
1908
+ );
1909
+ }
1577
1910
  } catch (e) {
1578
1911
  console.error("Error in transmission", e);
1912
+ fetchDiagnostics.signalFailures++;
1913
+ fetchDiagnostics.updatedAt = Date.now();
1914
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1579
1915
  response = {
1580
1916
  __error: `Error: ${e}`,
1581
1917
  errored: true,
@@ -1593,6 +1929,8 @@ var RestController = class _RestController {
1593
1929
  const statusTask = CadenzaService.createMetaTask(
1594
1930
  `Request status from ${URL}`,
1595
1931
  async (ctx2) => {
1932
+ fetchDiagnostics.statusChecks++;
1933
+ fetchDiagnostics.updatedAt = Date.now();
1596
1934
  let status;
1597
1935
  try {
1598
1936
  status = await this.fetchDataWithTimeout(
@@ -1602,7 +1940,20 @@ var RestController = class _RestController {
1602
1940
  },
1603
1941
  1e3
1604
1942
  );
1943
+ if (status?.errored || status?.failed) {
1944
+ fetchDiagnostics.statusFailures++;
1945
+ fetchDiagnostics.updatedAt = Date.now();
1946
+ this.recordFetchClientError(
1947
+ fetchId,
1948
+ serviceName,
1949
+ URL,
1950
+ status?.__error ?? status?.error ?? "Status check failed"
1951
+ );
1952
+ }
1605
1953
  } catch (e) {
1954
+ fetchDiagnostics.statusFailures++;
1955
+ fetchDiagnostics.updatedAt = Date.now();
1956
+ this.recordFetchClientError(fetchId, serviceName, URL, e);
1606
1957
  status = {
1607
1958
  __error: `Error: ${e}`,
1608
1959
  errored: true,
@@ -1614,6 +1965,9 @@ var RestController = class _RestController {
1614
1965
  "Requests status"
1615
1966
  ).doOn("meta.fetch.status_check_requested").emits("meta.fetch.status_checked").emitsOnFail("meta.fetch.status_check_failed");
1616
1967
  CadenzaService.createEphemeralMetaTask("Destroy fetch client", () => {
1968
+ fetchDiagnostics.connected = false;
1969
+ fetchDiagnostics.destroyed = true;
1970
+ fetchDiagnostics.updatedAt = Date.now();
1617
1971
  CadenzaService.log("Destroying fetch client", { URL, serviceName });
1618
1972
  handshakeTask.destroy();
1619
1973
  delegateTask.destroy();
@@ -1662,6 +2016,144 @@ var RestController = class _RestController {
1662
2016
  if (!this._instance) this._instance = new _RestController();
1663
2017
  return this._instance;
1664
2018
  }
2019
+ resolveTransportDiagnosticsOptions(ctx) {
2020
+ const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
2021
+ const includeErrorHistory = Boolean(ctx.includeErrorHistory);
2022
+ const requestedLimit = Number(ctx.errorHistoryLimit);
2023
+ const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
2024
+ return {
2025
+ detailLevel,
2026
+ includeErrorHistory,
2027
+ errorHistoryLimit
2028
+ };
2029
+ }
2030
+ ensureFetchClientDiagnostics(fetchId, serviceName, url) {
2031
+ let state = this.fetchClientDiagnostics.get(fetchId);
2032
+ if (!state) {
2033
+ state = {
2034
+ fetchId,
2035
+ serviceName,
2036
+ url,
2037
+ connected: false,
2038
+ destroyed: false,
2039
+ lastHandshakeAt: null,
2040
+ lastHandshakeError: null,
2041
+ lastError: null,
2042
+ lastErrorAt: 0,
2043
+ errorHistory: [],
2044
+ delegationRequests: 0,
2045
+ delegationFailures: 0,
2046
+ signalTransmissions: 0,
2047
+ signalFailures: 0,
2048
+ statusChecks: 0,
2049
+ statusFailures: 0,
2050
+ updatedAt: Date.now()
2051
+ };
2052
+ this.fetchClientDiagnostics.set(fetchId, state);
2053
+ } else {
2054
+ state.serviceName = serviceName;
2055
+ state.url = url;
2056
+ }
2057
+ return state;
2058
+ }
2059
+ getErrorMessage(error) {
2060
+ if (error instanceof Error) {
2061
+ return error.message;
2062
+ }
2063
+ if (typeof error === "string") {
2064
+ return error;
2065
+ }
2066
+ try {
2067
+ return JSON.stringify(error);
2068
+ } catch {
2069
+ return String(error);
2070
+ }
2071
+ }
2072
+ recordFetchClientError(fetchId, serviceName, url, error) {
2073
+ const state = this.ensureFetchClientDiagnostics(fetchId, serviceName, url);
2074
+ const message = this.getErrorMessage(error);
2075
+ const now = Date.now();
2076
+ state.lastError = message;
2077
+ state.lastErrorAt = now;
2078
+ state.updatedAt = now;
2079
+ state.errorHistory.push({ at: new Date(now).toISOString(), message });
2080
+ if (state.errorHistory.length > this.diagnosticsErrorHistoryLimit) {
2081
+ state.errorHistory.splice(
2082
+ 0,
2083
+ state.errorHistory.length - this.diagnosticsErrorHistoryLimit
2084
+ );
2085
+ }
2086
+ }
2087
+ collectFetchTransportDiagnostics(ctx) {
2088
+ const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
2089
+ const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
2090
+ const states = Array.from(this.fetchClientDiagnostics.values()).sort(
2091
+ (a, b) => a.fetchId.localeCompare(b.fetchId)
2092
+ );
2093
+ const summary = {
2094
+ detailLevel,
2095
+ totalClients: states.length,
2096
+ connectedClients: states.filter((state) => state.connected).length,
2097
+ destroyedClients: states.filter((state) => state.destroyed).length,
2098
+ delegationRequests: states.reduce(
2099
+ (acc, state) => acc + state.delegationRequests,
2100
+ 0
2101
+ ),
2102
+ delegationFailures: states.reduce(
2103
+ (acc, state) => acc + state.delegationFailures,
2104
+ 0
2105
+ ),
2106
+ signalTransmissions: states.reduce(
2107
+ (acc, state) => acc + state.signalTransmissions,
2108
+ 0
2109
+ ),
2110
+ signalFailures: states.reduce((acc, state) => acc + state.signalFailures, 0),
2111
+ statusChecks: states.reduce((acc, state) => acc + state.statusChecks, 0),
2112
+ statusFailures: states.reduce((acc, state) => acc + state.statusFailures, 0),
2113
+ latestError: states.slice().sort((a, b) => b.lastErrorAt - a.lastErrorAt).find((state) => state.lastError)?.lastError ?? null
2114
+ };
2115
+ if (detailLevel === "summary") {
2116
+ return {
2117
+ transportDiagnostics: {
2118
+ [serviceName]: {
2119
+ fetchClient: summary
2120
+ }
2121
+ }
2122
+ };
2123
+ }
2124
+ const clients = states.map((state) => {
2125
+ const details = {
2126
+ fetchId: state.fetchId,
2127
+ serviceName: state.serviceName,
2128
+ url: state.url,
2129
+ connected: state.connected,
2130
+ destroyed: state.destroyed,
2131
+ lastHandshakeAt: state.lastHandshakeAt,
2132
+ lastHandshakeError: state.lastHandshakeError,
2133
+ latestError: state.lastError,
2134
+ delegationRequests: state.delegationRequests,
2135
+ delegationFailures: state.delegationFailures,
2136
+ signalTransmissions: state.signalTransmissions,
2137
+ signalFailures: state.signalFailures,
2138
+ statusChecks: state.statusChecks,
2139
+ statusFailures: state.statusFailures
2140
+ };
2141
+ if (includeErrorHistory) {
2142
+ details.errorHistory = state.errorHistory.slice(-errorHistoryLimit);
2143
+ }
2144
+ return details;
2145
+ });
2146
+ return {
2147
+ transportDiagnostics: {
2148
+ [serviceName]: {
2149
+ fetchClient: {
2150
+ ...summary,
2151
+ clients
2152
+ }
2153
+ }
2154
+ }
2155
+ };
2156
+ }
1665
2157
  };
1666
2158
 
1667
2159
  // src/network/SocketController.ts
@@ -1709,10 +2201,6 @@ var waitForSocketConnection = async (socket, timeoutMs, createError) => {
1709
2201
 
1710
2202
  // src/network/SocketController.ts
1711
2203
  var SocketController = class _SocketController {
1712
- static get instance() {
1713
- if (!this._instance) this._instance = new _SocketController();
1714
- return this._instance;
1715
- }
1716
2204
  /**
1717
2205
  * Constructs the `SocketServer`, setting up a WebSocket server with specific configurations,
1718
2206
  * including connection state recovery, rate limiting, CORS handling, and custom event handling.
@@ -1731,6 +2219,13 @@ var SocketController = class _SocketController {
1731
2219
  * Initializes the `SocketServer` to be ready for WebSocket communication.
1732
2220
  */
1733
2221
  constructor() {
2222
+ this.socketClientDiagnostics = /* @__PURE__ */ new Map();
2223
+ this.diagnosticsErrorHistoryLimit = 100;
2224
+ CadenzaService.createMetaTask(
2225
+ "Collect socket transport diagnostics",
2226
+ (ctx) => this.collectSocketTransportDiagnostics(ctx),
2227
+ "Responds to distributed transport diagnostics inquiries with socket client data."
2228
+ ).respondsTo(META_RUNTIME_TRANSPORT_DIAGNOSTICS_INTENT);
1734
2229
  CadenzaService.createMetaRoutine(
1735
2230
  "SocketServer",
1736
2231
  [
@@ -1958,6 +2453,13 @@ var SocketController = class _SocketController {
1958
2453
  const port = protocol === "https" ? 443 : servicePort;
1959
2454
  const URL = `${socketProtocol}://${serviceAddress}:${port}`;
1960
2455
  const fetchId = `${serviceAddress}_${port}`;
2456
+ const socketDiagnostics = this.ensureSocketClientDiagnostics(
2457
+ fetchId,
2458
+ serviceName,
2459
+ URL
2460
+ );
2461
+ socketDiagnostics.destroyed = false;
2462
+ socketDiagnostics.updatedAt = Date.now();
1961
2463
  let handshake = false;
1962
2464
  let errorCount = 0;
1963
2465
  const ERROR_LIMIT = 5;
@@ -1967,6 +2469,11 @@ var SocketController = class _SocketController {
1967
2469
  }
1968
2470
  const pendingDelegationIds = /* @__PURE__ */ new Set();
1969
2471
  const pendingTimers = /* @__PURE__ */ new Set();
2472
+ const syncPendingCounts = () => {
2473
+ socketDiagnostics.pendingDelegations = pendingDelegationIds.size;
2474
+ socketDiagnostics.pendingTimers = pendingTimers.size;
2475
+ socketDiagnostics.updatedAt = Date.now();
2476
+ };
1970
2477
  let handshakeTask = null;
1971
2478
  let emitWhenReady = null;
1972
2479
  let transmitTask = null;
@@ -2016,6 +2523,12 @@ var SocketController = class _SocketController {
2016
2523
  { socketId: socket?.id, serviceName, URL, event },
2017
2524
  "error"
2018
2525
  );
2526
+ this.recordSocketClientError(
2527
+ fetchId,
2528
+ serviceName,
2529
+ URL,
2530
+ waitResult.error
2531
+ );
2019
2532
  resolveWithError(waitResult.error);
2020
2533
  return;
2021
2534
  }
@@ -2024,6 +2537,7 @@ var SocketController = class _SocketController {
2024
2537
  timer = setTimeout(() => {
2025
2538
  if (timer) {
2026
2539
  pendingTimers.delete(timer);
2540
+ syncPendingCounts();
2027
2541
  timer = null;
2028
2542
  }
2029
2543
  CadenzaService.log(
@@ -2031,9 +2545,16 @@ var SocketController = class _SocketController {
2031
2545
  { socketId: socket?.id, serviceName, URL },
2032
2546
  "error"
2033
2547
  );
2548
+ this.recordSocketClientError(
2549
+ fetchId,
2550
+ serviceName,
2551
+ URL,
2552
+ `Socket event '${event}' timed out`
2553
+ );
2034
2554
  resolveWithError(`Socket event '${event}' timed out`);
2035
2555
  }, timeoutMs + 10);
2036
2556
  pendingTimers.add(timer);
2557
+ syncPendingCounts();
2037
2558
  }
2038
2559
  const connectedSocket = socket;
2039
2560
  if (!connectedSocket) {
@@ -2046,6 +2567,7 @@ var SocketController = class _SocketController {
2046
2567
  if (timer) {
2047
2568
  clearTimeout(timer);
2048
2569
  pendingTimers.delete(timer);
2570
+ syncPendingCounts();
2049
2571
  timer = null;
2050
2572
  }
2051
2573
  if (err) {
@@ -2059,6 +2581,12 @@ var SocketController = class _SocketController {
2059
2581
  },
2060
2582
  "warning"
2061
2583
  );
2584
+ this.recordSocketClientError(
2585
+ fetchId,
2586
+ serviceName,
2587
+ URL,
2588
+ err
2589
+ );
2062
2590
  response = {
2063
2591
  __error: `Timeout error: ${err}`,
2064
2592
  errored: true,
@@ -2075,6 +2603,10 @@ var SocketController = class _SocketController {
2075
2603
  };
2076
2604
  socket.on("connect", () => {
2077
2605
  if (handshake) return;
2606
+ socketDiagnostics.connected = true;
2607
+ socketDiagnostics.destroyed = false;
2608
+ socketDiagnostics.socketId = socket?.id ?? null;
2609
+ socketDiagnostics.updatedAt = Date.now();
2078
2610
  CadenzaService.emit(`meta.socket_client.connected:${fetchId}`, ctx);
2079
2611
  });
2080
2612
  socket.on("delegation_progress", (ctx2) => {
@@ -2093,6 +2625,12 @@ var SocketController = class _SocketController {
2093
2625
  });
2094
2626
  socket.on("connect_error", (err) => {
2095
2627
  handshake = false;
2628
+ socketDiagnostics.connected = false;
2629
+ socketDiagnostics.handshake = false;
2630
+ socketDiagnostics.connectErrors++;
2631
+ socketDiagnostics.lastHandshakeError = err.message;
2632
+ socketDiagnostics.updatedAt = Date.now();
2633
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2096
2634
  CadenzaService.log(
2097
2635
  "Socket connect error",
2098
2636
  { error: err.message, serviceName, socketId: socket?.id, URL },
@@ -2101,9 +2639,16 @@ var SocketController = class _SocketController {
2101
2639
  CadenzaService.emit(`meta.socket_client.connect_error:${fetchId}`, err);
2102
2640
  });
2103
2641
  socket.on("reconnect_attempt", (attempt) => {
2642
+ socketDiagnostics.reconnectAttempts = Math.max(
2643
+ socketDiagnostics.reconnectAttempts,
2644
+ attempt
2645
+ );
2646
+ socketDiagnostics.updatedAt = Date.now();
2104
2647
  CadenzaService.log(`Reconnect attempt: ${attempt}`);
2105
2648
  });
2106
2649
  socket.on("reconnect", (attempt) => {
2650
+ socketDiagnostics.connected = true;
2651
+ socketDiagnostics.updatedAt = Date.now();
2107
2652
  CadenzaService.log(`Socket reconnected after ${attempt} tries`, {
2108
2653
  socketId: socket?.id,
2109
2654
  URL,
@@ -2112,6 +2657,12 @@ var SocketController = class _SocketController {
2112
2657
  });
2113
2658
  socket.on("reconnect_error", (err) => {
2114
2659
  handshake = false;
2660
+ socketDiagnostics.connected = false;
2661
+ socketDiagnostics.handshake = false;
2662
+ socketDiagnostics.reconnectErrors++;
2663
+ socketDiagnostics.lastHandshakeError = err.message;
2664
+ socketDiagnostics.updatedAt = Date.now();
2665
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2115
2666
  CadenzaService.log(
2116
2667
  "Socket reconnect failed.",
2117
2668
  { error: err.message, serviceName, URL, socketId: socket?.id },
@@ -2120,6 +2671,9 @@ var SocketController = class _SocketController {
2120
2671
  });
2121
2672
  socket.on("error", (err) => {
2122
2673
  errorCount++;
2674
+ socketDiagnostics.socketErrors++;
2675
+ socketDiagnostics.updatedAt = Date.now();
2676
+ this.recordSocketClientError(fetchId, serviceName, URL, err);
2123
2677
  CadenzaService.log(
2124
2678
  "Socket error",
2125
2679
  { error: err, socketId: socket?.id, URL, serviceName },
@@ -2128,6 +2682,11 @@ var SocketController = class _SocketController {
2128
2682
  CadenzaService.emit("meta.socket_client.error", err);
2129
2683
  });
2130
2684
  socket.on("disconnect", () => {
2685
+ const disconnectedAt = (/* @__PURE__ */ new Date()).toISOString();
2686
+ socketDiagnostics.connected = false;
2687
+ socketDiagnostics.handshake = false;
2688
+ socketDiagnostics.lastDisconnectAt = disconnectedAt;
2689
+ socketDiagnostics.updatedAt = Date.now();
2131
2690
  CadenzaService.log(
2132
2691
  "Socket disconnected.",
2133
2692
  { URL, serviceName, socketId: socket?.id },
@@ -2146,6 +2705,8 @@ var SocketController = class _SocketController {
2146
2705
  async (ctx2, emit) => {
2147
2706
  if (handshake) return;
2148
2707
  handshake = true;
2708
+ socketDiagnostics.handshake = true;
2709
+ socketDiagnostics.updatedAt = Date.now();
2149
2710
  await emitWhenReady?.(
2150
2711
  "handshake",
2151
2712
  {
@@ -2157,6 +2718,11 @@ var SocketController = class _SocketController {
2157
2718
  1e4,
2158
2719
  (result) => {
2159
2720
  if (result.status === "success") {
2721
+ socketDiagnostics.connected = true;
2722
+ socketDiagnostics.handshake = true;
2723
+ socketDiagnostics.lastHandshakeAt = (/* @__PURE__ */ new Date()).toISOString();
2724
+ socketDiagnostics.lastHandshakeError = null;
2725
+ socketDiagnostics.updatedAt = Date.now();
2160
2726
  CadenzaService.log("Socket client connected", {
2161
2727
  result,
2162
2728
  serviceName,
@@ -2164,6 +2730,16 @@ var SocketController = class _SocketController {
2164
2730
  URL
2165
2731
  });
2166
2732
  } else {
2733
+ socketDiagnostics.connected = false;
2734
+ socketDiagnostics.handshake = false;
2735
+ socketDiagnostics.lastHandshakeError = result?.__error ?? result?.error ?? "Socket handshake failed";
2736
+ socketDiagnostics.updatedAt = Date.now();
2737
+ this.recordSocketClientError(
2738
+ fetchId,
2739
+ serviceName,
2740
+ URL,
2741
+ socketDiagnostics.lastHandshakeError
2742
+ );
2167
2743
  CadenzaService.log(
2168
2744
  "Socket handshake failed",
2169
2745
  { result, serviceName, socketId: socket?.id, URL },
@@ -2186,6 +2762,7 @@ var SocketController = class _SocketController {
2186
2762
  delete ctx2.__broadcast;
2187
2763
  const requestSentAt = Date.now();
2188
2764
  pendingDelegationIds.add(ctx2.__metadata.__deputyExecId);
2765
+ syncPendingCounts();
2189
2766
  emitWhenReady?.(
2190
2767
  "delegation",
2191
2768
  ctx2,
@@ -2203,6 +2780,15 @@ var SocketController = class _SocketController {
2203
2780
  }
2204
2781
  );
2205
2782
  pendingDelegationIds.delete(ctx2.__metadata.__deputyExecId);
2783
+ syncPendingCounts();
2784
+ if (resultContext?.errored || resultContext?.failed) {
2785
+ this.recordSocketClientError(
2786
+ fetchId,
2787
+ serviceName,
2788
+ URL,
2789
+ resultContext?.__error ?? resultContext?.error ?? "Socket delegation failed"
2790
+ );
2791
+ }
2206
2792
  resolve(resultContext);
2207
2793
  }
2208
2794
  );
@@ -2238,6 +2824,10 @@ var SocketController = class _SocketController {
2238
2824
  `Shutdown SocketClient ${URL}`,
2239
2825
  (ctx2, emit) => {
2240
2826
  handshake = false;
2827
+ socketDiagnostics.connected = false;
2828
+ socketDiagnostics.handshake = false;
2829
+ socketDiagnostics.destroyed = true;
2830
+ socketDiagnostics.updatedAt = Date.now();
2241
2831
  CadenzaService.log("Shutting down socket client", { URL, serviceName });
2242
2832
  socket?.close();
2243
2833
  handshakeTask?.destroy();
@@ -2267,10 +2857,12 @@ var SocketController = class _SocketController {
2267
2857
  });
2268
2858
  }
2269
2859
  pendingDelegationIds.clear();
2860
+ syncPendingCounts();
2270
2861
  for (const timer of pendingTimers) {
2271
2862
  clearTimeout(timer);
2272
2863
  }
2273
2864
  pendingTimers.clear();
2865
+ syncPendingCounts();
2274
2866
  },
2275
2867
  "Shuts down the socket client"
2276
2868
  ).doOn(
@@ -2284,6 +2876,157 @@ var SocketController = class _SocketController {
2284
2876
  "Connects to a specified socket server"
2285
2877
  ).doOn("meta.fetch.handshake_complete").emitsOnFail("meta.socket_client.connect_failed");
2286
2878
  }
2879
+ static get instance() {
2880
+ if (!this._instance) this._instance = new _SocketController();
2881
+ return this._instance;
2882
+ }
2883
+ resolveTransportDiagnosticsOptions(ctx) {
2884
+ const detailLevel = ctx.detailLevel === "full" ? "full" : "summary";
2885
+ const includeErrorHistory = Boolean(ctx.includeErrorHistory);
2886
+ const requestedLimit = Number(ctx.errorHistoryLimit);
2887
+ const errorHistoryLimit = Number.isFinite(requestedLimit) ? Math.max(1, Math.min(200, Math.trunc(requestedLimit))) : 10;
2888
+ return {
2889
+ detailLevel,
2890
+ includeErrorHistory,
2891
+ errorHistoryLimit
2892
+ };
2893
+ }
2894
+ ensureSocketClientDiagnostics(fetchId, serviceName, url) {
2895
+ let state = this.socketClientDiagnostics.get(fetchId);
2896
+ if (!state) {
2897
+ state = {
2898
+ fetchId,
2899
+ serviceName,
2900
+ url,
2901
+ socketId: null,
2902
+ connected: false,
2903
+ handshake: false,
2904
+ reconnectAttempts: 0,
2905
+ connectErrors: 0,
2906
+ reconnectErrors: 0,
2907
+ socketErrors: 0,
2908
+ pendingDelegations: 0,
2909
+ pendingTimers: 0,
2910
+ destroyed: false,
2911
+ lastHandshakeAt: null,
2912
+ lastHandshakeError: null,
2913
+ lastDisconnectAt: null,
2914
+ lastError: null,
2915
+ lastErrorAt: 0,
2916
+ errorHistory: [],
2917
+ updatedAt: Date.now()
2918
+ };
2919
+ this.socketClientDiagnostics.set(fetchId, state);
2920
+ } else {
2921
+ state.serviceName = serviceName;
2922
+ state.url = url;
2923
+ }
2924
+ return state;
2925
+ }
2926
+ getErrorMessage(error) {
2927
+ if (error instanceof Error) {
2928
+ return error.message;
2929
+ }
2930
+ if (typeof error === "string") {
2931
+ return error;
2932
+ }
2933
+ try {
2934
+ return JSON.stringify(error);
2935
+ } catch {
2936
+ return String(error);
2937
+ }
2938
+ }
2939
+ recordSocketClientError(fetchId, serviceName, url, error) {
2940
+ const state = this.ensureSocketClientDiagnostics(fetchId, serviceName, url);
2941
+ const message = this.getErrorMessage(error);
2942
+ const now = Date.now();
2943
+ state.lastError = message;
2944
+ state.lastErrorAt = now;
2945
+ state.updatedAt = now;
2946
+ state.errorHistory.push({
2947
+ at: new Date(now).toISOString(),
2948
+ message
2949
+ });
2950
+ if (state.errorHistory.length > this.diagnosticsErrorHistoryLimit) {
2951
+ state.errorHistory.splice(
2952
+ 0,
2953
+ state.errorHistory.length - this.diagnosticsErrorHistoryLimit
2954
+ );
2955
+ }
2956
+ }
2957
+ collectSocketTransportDiagnostics(ctx) {
2958
+ const { detailLevel, includeErrorHistory, errorHistoryLimit } = this.resolveTransportDiagnosticsOptions(ctx);
2959
+ const serviceName = CadenzaService.serviceRegistry.serviceName ?? "UnknownService";
2960
+ const states = Array.from(this.socketClientDiagnostics.values()).sort(
2961
+ (a, b) => a.fetchId.localeCompare(b.fetchId)
2962
+ );
2963
+ const summary = {
2964
+ detailLevel,
2965
+ totalClients: states.length,
2966
+ connectedClients: states.filter((state) => state.connected).length,
2967
+ activeHandshakes: states.filter((state) => state.handshake).length,
2968
+ pendingDelegations: states.reduce(
2969
+ (acc, state) => acc + state.pendingDelegations,
2970
+ 0
2971
+ ),
2972
+ pendingTimers: states.reduce((acc, state) => acc + state.pendingTimers, 0),
2973
+ reconnectAttempts: states.reduce(
2974
+ (acc, state) => acc + state.reconnectAttempts,
2975
+ 0
2976
+ ),
2977
+ connectErrors: states.reduce((acc, state) => acc + state.connectErrors, 0),
2978
+ reconnectErrors: states.reduce(
2979
+ (acc, state) => acc + state.reconnectErrors,
2980
+ 0
2981
+ ),
2982
+ socketErrors: states.reduce((acc, state) => acc + state.socketErrors, 0),
2983
+ latestError: states.slice().sort((a, b) => b.lastErrorAt - a.lastErrorAt).find((state) => state.lastError)?.lastError ?? null
2984
+ };
2985
+ if (detailLevel === "summary") {
2986
+ return {
2987
+ transportDiagnostics: {
2988
+ [serviceName]: {
2989
+ socketClient: summary
2990
+ }
2991
+ }
2992
+ };
2993
+ }
2994
+ const clients = states.map((state) => {
2995
+ const details = {
2996
+ fetchId: state.fetchId,
2997
+ serviceName: state.serviceName,
2998
+ url: state.url,
2999
+ socketId: state.socketId,
3000
+ connected: state.connected,
3001
+ handshake: state.handshake,
3002
+ reconnectAttempts: state.reconnectAttempts,
3003
+ connectErrors: state.connectErrors,
3004
+ reconnectErrors: state.reconnectErrors,
3005
+ socketErrors: state.socketErrors,
3006
+ pendingDelegations: state.pendingDelegations,
3007
+ pendingTimers: state.pendingTimers,
3008
+ destroyed: state.destroyed,
3009
+ lastHandshakeAt: state.lastHandshakeAt,
3010
+ lastHandshakeError: state.lastHandshakeError,
3011
+ lastDisconnectAt: state.lastDisconnectAt,
3012
+ latestError: state.lastError
3013
+ };
3014
+ if (includeErrorHistory) {
3015
+ details.errorHistory = state.errorHistory.slice(-errorHistoryLimit);
3016
+ }
3017
+ return details;
3018
+ });
3019
+ return {
3020
+ transportDiagnostics: {
3021
+ [serviceName]: {
3022
+ socketClient: {
3023
+ ...summary,
3024
+ clients
3025
+ }
3026
+ }
3027
+ }
3028
+ };
3029
+ }
2287
3030
  };
2288
3031
 
2289
3032
  // src/utils/tools.ts
@@ -2387,25 +3130,8 @@ var GraphMetadataController = class _GraphMetadataController {
2387
3130
  return {
2388
3131
  data: {
2389
3132
  ...ctx.data,
2390
- serviceName: CadenzaService.serviceRegistry.serviceName,
2391
- inputContextSchemaId: ctx.data.inputContextSchemaId ? {
2392
- subOperation: "insert",
2393
- table: "context_schema",
2394
- data: {
2395
- ...ctx.data.inputContextSchemaId
2396
- },
2397
- return: "uuid"
2398
- } : null,
2399
- outputContextSchemaId: ctx.data.outputContextSchemaId ? {
2400
- subOperation: "insert",
2401
- table: "context_schema",
2402
- data: {
2403
- ...ctx.data.outputContextSchemaId
2404
- },
2405
- return: "uuid"
2406
- } : null
2407
- },
2408
- transaction: true
3133
+ serviceName: CadenzaService.serviceRegistry.serviceName
3134
+ }
2409
3135
  };
2410
3136
  }).doOn("meta.task.created").emits("global.meta.graph_metadata.task_created");
2411
3137
  CadenzaService.createMetaTask("Handle task update", (ctx) => {
@@ -2612,9 +3338,11 @@ var GraphMetadataController = class _GraphMetadataController {
2612
3338
  { concurrency: 100, isSubMeta: true }
2613
3339
  ).doOn("meta.node.mapped", "meta.node.detected_previous_task_execution").emits("global.meta.graph_metadata.relationship_executed");
2614
3340
  CadenzaService.createMetaTask("Handle Intent Creation", (ctx) => {
3341
+ const intentName = ctx.data?.name;
2615
3342
  return {
2616
3343
  data: {
2617
- ...ctx.data
3344
+ ...ctx.data,
3345
+ isMeta: intentName ? isMetaIntentName(intentName) : false
2618
3346
  }
2619
3347
  };
2620
3348
  }).doOn("meta.inquiry_broker.added").emits("global.meta.graph_metadata.intent_created");
@@ -2646,6 +3374,52 @@ var SCHEMA_TYPES = [
2646
3374
  // src/database/DatabaseController.ts
2647
3375
  var import_pg = require("pg");
2648
3376
  var import_lodash_es = require("lodash-es");
3377
+ function resolveTableQueryIntents(serviceName, tableName, table, defaultInputSchema) {
3378
+ const resolvedServiceName = serviceName ?? "unknown-service";
3379
+ const defaultIntentName = `query-${resolvedServiceName}-${tableName}`;
3380
+ const defaultDescription = `Perform a query operation on the ${tableName} table`;
3381
+ const intents = [
3382
+ {
3383
+ name: defaultIntentName,
3384
+ description: defaultDescription,
3385
+ input: defaultInputSchema
3386
+ }
3387
+ ];
3388
+ const warnings = [];
3389
+ const names = /* @__PURE__ */ new Set([defaultIntentName]);
3390
+ for (const customIntent of table.customIntents?.query ?? []) {
3391
+ const name = typeof customIntent === "string" ? customIntent.trim() : customIntent.intent?.trim();
3392
+ if (!name) {
3393
+ warnings.push(`Skipped empty custom query intent for table '${tableName}'.`);
3394
+ continue;
3395
+ }
3396
+ if (name.length > 100) {
3397
+ warnings.push(
3398
+ `Skipped custom query intent '${name}' for table '${tableName}': name must be <= 100 characters.`
3399
+ );
3400
+ continue;
3401
+ }
3402
+ if (name.includes(" ") || name.includes(".") || name.includes("\\")) {
3403
+ warnings.push(
3404
+ `Skipped custom query intent '${name}' for table '${tableName}': name cannot contain spaces, dots or backslashes.`
3405
+ );
3406
+ continue;
3407
+ }
3408
+ if (names.has(name)) {
3409
+ warnings.push(
3410
+ `Skipped duplicate custom query intent '${name}' for table '${tableName}'.`
3411
+ );
3412
+ continue;
3413
+ }
3414
+ names.add(name);
3415
+ intents.push({
3416
+ name,
3417
+ description: typeof customIntent === "string" ? `Perform a query operation on the ${tableName} table` : customIntent.description ?? defaultDescription,
3418
+ input: typeof customIntent === "string" ? defaultInputSchema : customIntent.input ?? defaultInputSchema
3419
+ });
3420
+ }
3421
+ return { intents, warnings };
3422
+ }
2649
3423
  var DatabaseController = class _DatabaseController {
2650
3424
  /**
2651
3425
  * Constructor for initializing the `DatabaseService` class.
@@ -2787,6 +3561,20 @@ var DatabaseController = class _DatabaseController {
2787
3561
  }
2788
3562
  }
2789
3563
  }
3564
+ if (table.customIntents?.query) {
3565
+ if (!Array.isArray(table.customIntents.query)) {
3566
+ throw new Error(
3567
+ `Invalid customIntents.query for ${tableName}: expected array`
3568
+ );
3569
+ }
3570
+ for (const customIntent of table.customIntents.query) {
3571
+ if (typeof customIntent !== "string" && (typeof customIntent !== "object" || !customIntent || typeof customIntent.intent !== "string")) {
3572
+ throw new Error(
3573
+ `Invalid custom query intent on ${tableName}: expected string or object with intent`
3574
+ );
3575
+ }
3576
+ }
3577
+ }
2790
3578
  }
2791
3579
  }
2792
3580
  console.log("SCHEMA VALIDATED");
@@ -3823,13 +4611,30 @@ var DatabaseController = class _DatabaseController {
3823
4611
  }) ?? []
3824
4612
  );
3825
4613
  if (op === "query") {
3826
- const intentName = `query-${CadenzaService.serviceRegistry.serviceName}-${tableName}`;
3827
- CadenzaService.defineIntent({
3828
- name: intentName,
3829
- description: `Perform a query operation on the ${tableName} table`,
3830
- input: schema
3831
- });
3832
- task.respondsTo(intentName);
4614
+ const { intents, warnings } = resolveTableQueryIntents(
4615
+ CadenzaService.serviceRegistry?.serviceName,
4616
+ tableName,
4617
+ table,
4618
+ schema
4619
+ );
4620
+ for (const warning of warnings) {
4621
+ CadenzaService.log(
4622
+ "Skipped custom query intent registration.",
4623
+ {
4624
+ tableName,
4625
+ warning
4626
+ },
4627
+ "warning"
4628
+ );
4629
+ }
4630
+ for (const intent of intents) {
4631
+ CadenzaService.defineIntent({
4632
+ name: intent.name,
4633
+ description: intent.description,
4634
+ input: intent.input
4635
+ });
4636
+ }
4637
+ task.respondsTo(...intents.map((intent) => intent.name));
3833
4638
  }
3834
4639
  }
3835
4640
  getInputSchema(op, tableName, table) {
@@ -3921,18 +4726,18 @@ function getInsertDataSchemaFromTable(table, tableName) {
3921
4726
  Object.entries(table.fields).map((field) => {
3922
4727
  return [
3923
4728
  field[0],
3924
- [
3925
- {
4729
+ {
4730
+ value: {
3926
4731
  type: tableFieldTypeToSchemaType(field[1].type),
3927
4732
  description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3928
4733
  },
3929
- {
4734
+ effect: {
3930
4735
  type: "string",
3931
4736
  constraints: {
3932
4737
  oneOf: ["increment", "decrement", "set"]
3933
4738
  }
3934
4739
  },
3935
- {
4740
+ subOperation: {
3936
4741
  type: "object",
3937
4742
  properties: {
3938
4743
  subOperation: {
@@ -3942,17 +4747,17 @@ function getInsertDataSchemaFromTable(table, tableName) {
3942
4747
  table: {
3943
4748
  type: "string"
3944
4749
  },
3945
- data: [
3946
- {
4750
+ data: {
4751
+ single: {
3947
4752
  type: "object"
3948
4753
  },
3949
- {
4754
+ batch: {
3950
4755
  type: "array",
3951
4756
  items: {
3952
4757
  type: "object"
3953
4758
  }
3954
4759
  }
3955
- ],
4760
+ },
3956
4761
  filter: {
3957
4762
  type: "object"
3958
4763
  },
@@ -3968,7 +4773,7 @@ function getInsertDataSchemaFromTable(table, tableName) {
3968
4773
  },
3969
4774
  required: ["subOperation", "table"]
3970
4775
  }
3971
- ]
4776
+ }
3972
4777
  ];
3973
4778
  })
3974
4779
  )
@@ -3976,13 +4781,13 @@ function getInsertDataSchemaFromTable(table, tableName) {
3976
4781
  required: Object.entries(table.fields).filter((field) => field[1].required || field[1].primary).map((field) => field[0]),
3977
4782
  strict: true
3978
4783
  };
3979
- return [
3980
- dataSchema,
3981
- {
4784
+ return {
4785
+ single: dataSchema,
4786
+ batch: {
3982
4787
  type: "array",
3983
4788
  items: dataSchema
3984
4789
  }
3985
- ];
4790
+ };
3986
4791
  }
3987
4792
  function getQueryFilterSchemaFromTable(table, tableName) {
3988
4793
  return {
@@ -3992,24 +4797,24 @@ function getQueryFilterSchemaFromTable(table, tableName) {
3992
4797
  Object.entries(table.fields).map((field) => {
3993
4798
  return [
3994
4799
  field[0],
3995
- [
3996
- {
4800
+ {
4801
+ value: {
3997
4802
  type: tableFieldTypeToSchemaType(field[1].type),
3998
4803
  description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
3999
4804
  },
4000
- {
4805
+ in: {
4001
4806
  type: "array",
4002
4807
  items: {
4003
4808
  type: tableFieldTypeToSchemaType(field[1].type)
4004
4809
  }
4005
4810
  }
4006
- ]
4811
+ }
4007
4812
  ];
4008
4813
  })
4009
4814
  )
4010
4815
  },
4011
4816
  strict: true,
4012
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4817
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4013
4818
  };
4014
4819
  }
4015
4820
  function getQueryFieldsSchemaFromTable(table, tableName) {
@@ -4021,7 +4826,7 @@ function getQueryFieldsSchemaFromTable(table, tableName) {
4021
4826
  oneOf: Object.keys(table.fields)
4022
4827
  }
4023
4828
  },
4024
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4829
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4025
4830
  };
4026
4831
  }
4027
4832
  function getQueryJoinsSchemaFromTable(table, tableName) {
@@ -4068,7 +4873,7 @@ function getQueryJoinsSchemaFromTable(table, tableName) {
4068
4873
  )
4069
4874
  },
4070
4875
  strict: true,
4071
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4876
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4072
4877
  };
4073
4878
  }
4074
4879
  function getQuerySortSchemaFromTable(table, tableName) {
@@ -4090,7 +4895,7 @@ function getQuerySortSchemaFromTable(table, tableName) {
4090
4895
  )
4091
4896
  },
4092
4897
  strict: true,
4093
- description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry.serviceName}.`
4898
+ description: `Inferred from table '${tableName}' on database service ${CadenzaService.serviceRegistry?.serviceName ?? "unknown-service"}.`
4094
4899
  };
4095
4900
  }
4096
4901
  function getQueryLimitSchemaFromTable() {
@@ -4152,12 +4957,10 @@ function getQueryOnConflictSchemaFromTable(table, tableName) {
4152
4957
  Object.entries(table.fields).map((field) => {
4153
4958
  return [
4154
4959
  field[0],
4155
- [
4156
- {
4157
- type: tableFieldTypeToSchemaType(field[1].type),
4158
- description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
4159
- }
4160
- ]
4960
+ {
4961
+ type: tableFieldTypeToSchemaType(field[1].type),
4962
+ description: `Inferred from field '${field[0]}' of type [${field[1].type}] on table ${tableName}.`
4963
+ }
4161
4964
  ];
4162
4965
  })
4163
4966
  )
@@ -4515,6 +5318,75 @@ var GraphSyncController = class _GraphSyncController {
4515
5318
  { concurrency: 30 }
4516
5319
  ) : CadenzaService.get("dbInsertSignalToTaskMap"))?.then(registerSignalTask)
4517
5320
  );
5321
+ const registerIntentTask = CadenzaService.createMetaTask(
5322
+ "Record intent registration",
5323
+ (ctx) => {
5324
+ if (!ctx.__syncing) {
5325
+ return;
5326
+ }
5327
+ CadenzaService.debounce("meta.sync_controller.synced_resource", {
5328
+ delayMs: 3e3
5329
+ });
5330
+ const task = CadenzaService.get(ctx.__taskName);
5331
+ task.__registeredIntents = task.__registeredIntents ?? /* @__PURE__ */ new Set();
5332
+ task.__registeredIntents.add(ctx.__intent);
5333
+ }
5334
+ );
5335
+ this.registerIntentToTaskMapTask = CadenzaService.createMetaTask(
5336
+ "Split intents of task",
5337
+ function* (ctx) {
5338
+ const task = ctx.task;
5339
+ if (task.hidden || !task.register) return;
5340
+ task.__registeredIntents = task.__registeredIntents ?? /* @__PURE__ */ new Set();
5341
+ task.__invalidMetaIntentWarnings = task.__invalidMetaIntentWarnings ?? /* @__PURE__ */ new Set();
5342
+ for (const intent of task.handlesIntents) {
5343
+ if (task.__registeredIntents.has(intent)) continue;
5344
+ if (isMetaIntentName(intent) && !task.isMeta) {
5345
+ if (!task.__invalidMetaIntentWarnings.has(intent)) {
5346
+ task.__invalidMetaIntentWarnings.add(intent);
5347
+ CadenzaService.log(
5348
+ "Skipping intent-to-task registration: non-meta task cannot handle meta intent.",
5349
+ {
5350
+ intent,
5351
+ taskName: task.name,
5352
+ taskVersion: task.version
5353
+ },
5354
+ "warning"
5355
+ );
5356
+ }
5357
+ continue;
5358
+ }
5359
+ yield {
5360
+ data: {
5361
+ intentName: intent,
5362
+ taskName: task.name,
5363
+ taskVersion: task.version,
5364
+ serviceName: CadenzaService.serviceRegistry.serviceName
5365
+ },
5366
+ __taskName: task.name,
5367
+ __intent: intent
5368
+ };
5369
+ }
5370
+ }
5371
+ ).then(
5372
+ (this.isCadenzaDBReady ? CadenzaService.createCadenzaDBInsertTask(
5373
+ "intent_to_task_map",
5374
+ {
5375
+ onConflict: {
5376
+ target: [
5377
+ "intent_name",
5378
+ "task_name",
5379
+ "task_version",
5380
+ "service_name"
5381
+ ],
5382
+ action: {
5383
+ do: "nothing"
5384
+ }
5385
+ }
5386
+ },
5387
+ { concurrency: 30 }
5388
+ ) : CadenzaService.get("dbInsertIntentToTaskMap"))?.then(registerIntentTask)
5389
+ );
4518
5390
  this.registerTaskMapTask = CadenzaService.createMetaTask(
4519
5391
  "Register task map to DB",
4520
5392
  function* (ctx) {
@@ -4637,6 +5509,7 @@ var GraphSyncController = class _GraphSyncController {
4637
5509
  CadenzaService.registry.doForEachTask.clone().doOn("meta.sync_controller.synced_tasks").then(
4638
5510
  this.registerTaskMapTask,
4639
5511
  this.registerSignalToTaskMapTask,
5512
+ this.registerIntentToTaskMapTask,
4640
5513
  this.registerDeputyRelationshipTask
4641
5514
  );
4642
5515
  CadenzaService.registry.getAllRoutines.clone().doOn("meta.sync_controller.synced_routines").then(this.splitTasksInRoutines);
@@ -4778,11 +5651,192 @@ var CadenzaService = class {
4778
5651
  import_core3.default.interval(signal, context, intervalMs, leading, startDateTime);
4779
5652
  }
4780
5653
  static defineIntent(intent) {
4781
- this.inquiryBroker?.intents.set(intent.name, intent);
5654
+ this.inquiryBroker?.addIntent(intent);
4782
5655
  return intent;
4783
5656
  }
4784
- static async inquire(inquiry, context, options) {
4785
- return this.inquiryBroker?.inquire(inquiry, context, options);
5657
+ static getInquiryResponderDescriptor(task) {
5658
+ return this.serviceRegistry.getInquiryResponderDescriptor(task);
5659
+ }
5660
+ static compareInquiryResponders(left, right) {
5661
+ return compareResponderDescriptors(left.descriptor, right.descriptor);
5662
+ }
5663
+ static buildInquirySummary(inquiry, startedAt, statuses, totalResponders) {
5664
+ const counts = summarizeResponderStatuses(statuses);
5665
+ const isMetaInquiry = isMetaIntentName(inquiry);
5666
+ const eligibleResponders = statuses.length;
5667
+ return {
5668
+ inquiry,
5669
+ isMetaInquiry,
5670
+ totalResponders,
5671
+ eligibleResponders,
5672
+ filteredOutResponders: Math.max(0, totalResponders - eligibleResponders),
5673
+ responded: counts.responded,
5674
+ failed: counts.failed,
5675
+ timedOut: counts.timedOut,
5676
+ pending: counts.pending,
5677
+ durationMs: Date.now() - startedAt,
5678
+ responders: statuses
5679
+ };
5680
+ }
5681
+ static async inquire(inquiry, context, options = {}) {
5682
+ this.bootstrap();
5683
+ const observer = this.inquiryBroker?.inquiryObservers.get(inquiry);
5684
+ const allResponders = observer ? Array.from(observer.tasks).map((task) => ({
5685
+ task,
5686
+ descriptor: this.getInquiryResponderDescriptor(task)
5687
+ })) : [];
5688
+ const isMetaInquiry = isMetaIntentName(inquiry);
5689
+ const responders = allResponders.filter(({ task, descriptor }) => {
5690
+ const shouldExecute = shouldExecuteInquiryResponder(inquiry, task.isMeta);
5691
+ if (shouldExecute) {
5692
+ return true;
5693
+ }
5694
+ const warningKey = `${inquiry}|${descriptor.serviceName}|${descriptor.taskName}|${descriptor.taskVersion}|${descriptor.localTaskName}`;
5695
+ if (!this.warnedInvalidMetaIntentResponderKeys.has(warningKey)) {
5696
+ this.warnedInvalidMetaIntentResponderKeys.add(warningKey);
5697
+ this.log(
5698
+ "Skipping non-meta task for meta intent inquiry.",
5699
+ {
5700
+ inquiry,
5701
+ responder: descriptor
5702
+ },
5703
+ "warning",
5704
+ descriptor.serviceName
5705
+ );
5706
+ }
5707
+ return false;
5708
+ });
5709
+ if (responders.length === 0) {
5710
+ return {
5711
+ __inquiryMeta: {
5712
+ inquiry,
5713
+ isMetaInquiry,
5714
+ totalResponders: allResponders.length,
5715
+ eligibleResponders: 0,
5716
+ filteredOutResponders: allResponders.length,
5717
+ responded: 0,
5718
+ failed: 0,
5719
+ timedOut: 0,
5720
+ pending: 0,
5721
+ durationMs: 0,
5722
+ responders: []
5723
+ }
5724
+ };
5725
+ }
5726
+ responders.sort(this.compareInquiryResponders.bind(this));
5727
+ const overallTimeoutMs = options.overallTimeoutMs ?? options.timeout ?? 0;
5728
+ const requireComplete = options.requireComplete ?? false;
5729
+ const perResponderTimeoutMs = options.perResponderTimeoutMs;
5730
+ const startedAt = Date.now();
5731
+ const statuses = [];
5732
+ const statusByTask = /* @__PURE__ */ new Map();
5733
+ for (const responder of responders) {
5734
+ const status = {
5735
+ ...responder.descriptor,
5736
+ status: "timed_out",
5737
+ durationMs: 0
5738
+ };
5739
+ statuses.push(status);
5740
+ statusByTask.set(responder.task, status);
5741
+ }
5742
+ const resultsByTask = /* @__PURE__ */ new Map();
5743
+ const resolverTasks = [];
5744
+ const pending = new Set(responders.map((r) => r.task));
5745
+ const startTimeByTask = /* @__PURE__ */ new Map();
5746
+ this.emit("meta.inquiry_broker.inquire", { inquiry, context });
5747
+ return new Promise((resolve, reject) => {
5748
+ let finalized = false;
5749
+ let timeoutId;
5750
+ const finalize = (timedOut) => {
5751
+ if (finalized) return;
5752
+ finalized = true;
5753
+ if (timeoutId) {
5754
+ clearTimeout(timeoutId);
5755
+ timeoutId = void 0;
5756
+ }
5757
+ for (const resolverTask of resolverTasks) {
5758
+ resolverTask.destroy();
5759
+ }
5760
+ if (timedOut && pending.size > 0) {
5761
+ for (const task of pending) {
5762
+ const status = statusByTask.get(task);
5763
+ if (!status) continue;
5764
+ status.status = "timed_out";
5765
+ status.durationMs = Date.now() - (startTimeByTask.get(task) ?? startedAt);
5766
+ }
5767
+ }
5768
+ const fulfilledContexts = responders.filter((responder) => resultsByTask.has(responder.task)).map((responder) => resultsByTask.get(responder.task));
5769
+ const mergedContext = mergeInquiryContexts(fulfilledContexts);
5770
+ const inquiryMeta = this.buildInquirySummary(
5771
+ inquiry,
5772
+ startedAt,
5773
+ statuses,
5774
+ allResponders.length
5775
+ );
5776
+ const responseContext = {
5777
+ ...mergedContext,
5778
+ __inquiryMeta: inquiryMeta
5779
+ };
5780
+ if (requireComplete && (timedOut || inquiryMeta.failed > 0 || inquiryMeta.timedOut > 0 || inquiryMeta.pending > 0)) {
5781
+ reject({
5782
+ ...responseContext,
5783
+ __error: `Inquiry '${inquiry}' did not complete successfully`,
5784
+ errored: true
5785
+ });
5786
+ return;
5787
+ }
5788
+ resolve(responseContext);
5789
+ };
5790
+ if (overallTimeoutMs > 0) {
5791
+ timeoutId = setTimeout(() => finalize(true), overallTimeoutMs);
5792
+ }
5793
+ for (const responder of responders) {
5794
+ const { task, descriptor } = responder;
5795
+ const inquiryId = (0, import_uuid3.v4)();
5796
+ startTimeByTask.set(task, Date.now());
5797
+ const resolverTask = this.createEphemeralMetaTask(
5798
+ `Resolve inquiry ${inquiry} for ${descriptor.localTaskName}`,
5799
+ (resultCtx) => {
5800
+ if (finalized) {
5801
+ return;
5802
+ }
5803
+ pending.delete(task);
5804
+ const status = statusByTask.get(task);
5805
+ if (status) {
5806
+ status.durationMs = Date.now() - (startTimeByTask.get(task) ?? startedAt);
5807
+ if (resultCtx?.errored || resultCtx?.failed) {
5808
+ status.status = "failed";
5809
+ status.error = String(
5810
+ resultCtx?.__error ?? resultCtx?.error ?? "Inquiry responder failed"
5811
+ );
5812
+ } else {
5813
+ status.status = "fulfilled";
5814
+ resultsByTask.set(task, resultCtx);
5815
+ }
5816
+ }
5817
+ if (pending.size === 0) {
5818
+ finalize(false);
5819
+ }
5820
+ },
5821
+ "Resolves distributed inquiry responder result",
5822
+ { register: false }
5823
+ ).doOn(`meta.node.graph_completed:${inquiryId}`);
5824
+ resolverTasks.push(resolverTask);
5825
+ const executionContext = {
5826
+ ...context,
5827
+ __routineExecId: inquiryId,
5828
+ __isInquiry: true
5829
+ };
5830
+ if (perResponderTimeoutMs !== void 0) {
5831
+ executionContext.__timeout = perResponderTimeoutMs;
5832
+ }
5833
+ if (task.isMeta) {
5834
+ this.metaRunner?.run(task, executionContext);
5835
+ } else {
5836
+ this.runner?.run(task, executionContext);
5837
+ }
5838
+ }
5839
+ });
4786
5840
  }
4787
5841
  /**
4788
5842
  * Executes the given task or graph routine within the provided context using the configured runner.
@@ -5819,6 +6873,7 @@ var CadenzaService = class {
5819
6873
  };
5820
6874
  CadenzaService.isBootstrapped = false;
5821
6875
  CadenzaService.serviceCreated = false;
6876
+ CadenzaService.warnedInvalidMetaIntentResponderKeys = /* @__PURE__ */ new Set();
5822
6877
 
5823
6878
  // src/index.ts
5824
6879
  var import_core4 = require("@cadenza.io/core");