@axiom-lattice/core 6.1.1 → 6.2.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
@@ -1849,6 +1849,7 @@ __export(index_exports, {
1849
1849
  generateDirectHumanProjectId: () => generateDirectHumanProjectId,
1850
1850
  generateToken: () => generateToken,
1851
1851
  getAgentClient: () => getAgentClient,
1852
+ getAgentClientAsync: () => getAgentClientAsync,
1852
1853
  getAgentConfig: () => getAgentConfig,
1853
1854
  getAllAgentConfigs: () => getAllAgentConfigs,
1854
1855
  getAllBuiltInSkillMetas: () => getAllBuiltInSkillMetas,
@@ -17364,6 +17365,324 @@ var agentWorkerGraph = createAgentWorkerGraph();
17364
17365
  // src/deep_agent_new/middleware/subagents.ts
17365
17366
  init_MemoryLatticeManager();
17366
17367
 
17368
+ // src/util/toJsonSafeValue.ts
17369
+ var CIRCULAR_VALUE = "[Circular]";
17370
+ var REPEATED_VALUE = "[Repeated]";
17371
+ var arrayFrom = Array.from.bind(Array);
17372
+ var arrayIsArray = Array.isArray.bind(Array);
17373
+ var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
17374
+ var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
17375
+ var objectCreate = Object.create.bind(Object);
17376
+ var objectDefineProperty = Object.defineProperty.bind(Object);
17377
+ var objectIs = Object.is.bind(Object);
17378
+ var reflectGet = Reflect.get.bind(Reflect);
17379
+ var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
17380
+ var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
17381
+ var stringifyJson = JSON.stringify.bind(JSON);
17382
+ var numberIsFinite = Number.isFinite.bind(Number);
17383
+ var numberIsNaN = Number.isNaN.bind(Number);
17384
+ var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
17385
+ var mathMax = Math.max.bind(Math);
17386
+ var dateConstructor = Date;
17387
+ var datePrototype = dateConstructor.prototype;
17388
+ var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
17389
+ var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
17390
+ var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
17391
+ var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
17392
+ var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
17393
+ var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
17394
+ var WeakMapConstructor = WeakMap;
17395
+ var utf8Encoder = new TextEncoder();
17396
+ var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
17397
+ var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
17398
+ var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
17399
+ if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
17400
+ var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
17401
+ var JSON_SAFE_MAX_DEPTH = 32;
17402
+ var JSON_SAFE_MAX_NODES = 1e4;
17403
+ var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
17404
+ var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
17405
+ var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
17406
+ var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
17407
+ var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
17408
+ var JsonSafeValueError = class extends Error {
17409
+ /**
17410
+ * Create a bounded normalization error.
17411
+ *
17412
+ * @param code Stable normalization failure code.
17413
+ * @param message Human-readable bounded failure description.
17414
+ */
17415
+ constructor(code, message) {
17416
+ super(message);
17417
+ objectDefineProperty(this, "name", {
17418
+ value: "JsonSafeValueError",
17419
+ writable: true,
17420
+ configurable: true
17421
+ });
17422
+ objectDefineProperty(this, "code", {
17423
+ value: code,
17424
+ writable: true,
17425
+ configurable: true
17426
+ });
17427
+ }
17428
+ };
17429
+ function fail(code, message) {
17430
+ throw new JsonSafeValueError(code, message);
17431
+ }
17432
+ function propertyAccess(operation, path8) {
17433
+ try {
17434
+ return operation();
17435
+ } catch {
17436
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
17437
+ }
17438
+ }
17439
+ function serializedStringBytes(value) {
17440
+ if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
17441
+ fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
17442
+ }
17443
+ return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
17444
+ }
17445
+ function validatePropertyKey(key5) {
17446
+ if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
17447
+ fail(
17448
+ "MAX_STRING_LENGTH",
17449
+ `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
17450
+ );
17451
+ }
17452
+ }
17453
+ function chargePropertyKey(state, key5) {
17454
+ state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
17455
+ if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
17456
+ fail(
17457
+ "MAX_PROPERTY_KEY_BYTES",
17458
+ `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
17459
+ );
17460
+ }
17461
+ }
17462
+ function chargeBytes(state, bytes) {
17463
+ state.serializedBytes += bytes;
17464
+ if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
17465
+ fail(
17466
+ "MAX_SERIALIZED_BYTES",
17467
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
17468
+ );
17469
+ }
17470
+ }
17471
+ function chargeString(state, value) {
17472
+ chargeBytes(state, serializedStringBytes(value));
17473
+ }
17474
+ function objectPropertyPath(path8, key5) {
17475
+ const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
17476
+ return `${path8}[${stringifyJson(boundedKey)}]`;
17477
+ }
17478
+ function convertJsonValue(value, state, depth, inArray, path8) {
17479
+ state.nodes += 1;
17480
+ if (state.nodes > JSON_SAFE_MAX_NODES) {
17481
+ fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
17482
+ }
17483
+ if (typeof value === "string") {
17484
+ chargeString(state, value);
17485
+ return value;
17486
+ }
17487
+ if (value === null) {
17488
+ chargeBytes(state, 4);
17489
+ return value;
17490
+ }
17491
+ if (typeof value === "boolean") {
17492
+ chargeBytes(state, value ? 4 : 5);
17493
+ return value;
17494
+ }
17495
+ if (typeof value === "number") {
17496
+ const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
17497
+ chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
17498
+ return normalized;
17499
+ }
17500
+ if (typeof value === "bigint") {
17501
+ const normalized = bigintToString(value);
17502
+ chargeString(state, normalized);
17503
+ return normalized;
17504
+ }
17505
+ if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
17506
+ if (inArray) chargeBytes(state, 4);
17507
+ return inArray ? null : void 0;
17508
+ }
17509
+ const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
17510
+ if (isDate) {
17511
+ const time = propertyAccess(() => dateGetTime(value), path8);
17512
+ if (numberIsNaN(time)) {
17513
+ chargeBytes(state, 4);
17514
+ return null;
17515
+ }
17516
+ const normalized = propertyAccess(() => dateToISOString(value), path8);
17517
+ chargeString(state, normalized);
17518
+ return normalized;
17519
+ }
17520
+ if (depth > JSON_SAFE_MAX_DEPTH) {
17521
+ fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
17522
+ }
17523
+ const referenceState = weakMapGet(state.references, value);
17524
+ if (referenceState === "visiting") {
17525
+ chargeString(state, CIRCULAR_VALUE);
17526
+ return CIRCULAR_VALUE;
17527
+ }
17528
+ if (referenceState === "visited") {
17529
+ chargeString(state, REPEATED_VALUE);
17530
+ return REPEATED_VALUE;
17531
+ }
17532
+ weakMapSet(state.references, value, "visiting");
17533
+ if (propertyAccess(() => arrayIsArray(value), path8)) {
17534
+ const arrayValue = value;
17535
+ const length = propertyAccess(
17536
+ () => arrayValue.length,
17537
+ path8
17538
+ );
17539
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
17540
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
17541
+ }
17542
+ if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
17543
+ fail(
17544
+ "COLLECTION_TOO_LARGE",
17545
+ `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
17546
+ );
17547
+ }
17548
+ chargeBytes(state, 2 + mathMax(0, length - 1));
17549
+ const result2 = arrayFrom({ length }, (_, index) => {
17550
+ const entryPath = `${path8}[${index}]`;
17551
+ const hasEntry = propertyAccess(
17552
+ () => hasOwnProperty(arrayValue, index),
17553
+ entryPath
17554
+ );
17555
+ if (!hasEntry) {
17556
+ chargeBytes(state, 4);
17557
+ return null;
17558
+ }
17559
+ const entry = propertyAccess(() => arrayValue[index], entryPath);
17560
+ return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
17561
+ });
17562
+ objectDefineProperty(result2, "toJSON", {
17563
+ value: void 0,
17564
+ configurable: true,
17565
+ writable: true
17566
+ });
17567
+ weakMapSet(state.references, value, "visited");
17568
+ return result2;
17569
+ }
17570
+ const keys = propertyAccess(() => reflectOwnKeys(value), path8);
17571
+ if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
17572
+ fail(
17573
+ "COLLECTION_TOO_LARGE",
17574
+ `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
17575
+ );
17576
+ }
17577
+ for (let index = 0; index < keys.length; index += 1) {
17578
+ const key5 = keys[index];
17579
+ if (typeof key5 !== "string") continue;
17580
+ validatePropertyKey(key5);
17581
+ chargePropertyKey(state, key5);
17582
+ }
17583
+ chargeBytes(state, 2);
17584
+ const result = objectCreate(null);
17585
+ let emittedProperties = 0;
17586
+ for (let index = 0; index < keys.length; index += 1) {
17587
+ const key5 = keys[index];
17588
+ const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
17589
+ const descriptor = propertyAccess(
17590
+ () => reflectGetOwnPropertyDescriptor(value, key5),
17591
+ entryPath
17592
+ );
17593
+ if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
17594
+ const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
17595
+ const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
17596
+ if (converted !== void 0) {
17597
+ chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
17598
+ propertyAccess(() => objectDefineProperty(result, key5, {
17599
+ value: converted,
17600
+ enumerable: true,
17601
+ configurable: true,
17602
+ writable: true
17603
+ }), entryPath);
17604
+ emittedProperties += 1;
17605
+ }
17606
+ }
17607
+ weakMapSet(state.references, value, "visited");
17608
+ return result;
17609
+ }
17610
+ function toJsonSafeValue(value) {
17611
+ const state = {
17612
+ nodes: 0,
17613
+ propertyKeyBytes: 0,
17614
+ serializedBytes: 0,
17615
+ references: new WeakMapConstructor()
17616
+ };
17617
+ const converted = convertJsonValue(value, state, 0, false, "$");
17618
+ if (converted === void 0) chargeBytes(state, 4);
17619
+ const result = converted ?? null;
17620
+ const serialized = propertyAccess(() => stringifyJson(result), "$");
17621
+ if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
17622
+ fail(
17623
+ "MAX_SERIALIZED_BYTES",
17624
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
17625
+ );
17626
+ }
17627
+ return result;
17628
+ }
17629
+
17630
+ // src/util/truncateForJson.ts
17631
+ var TRUNCATION_MARKER = "...[truncated]";
17632
+ function truncateString(value, cap) {
17633
+ if (value.length <= cap) return value;
17634
+ const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
17635
+ return value.slice(0, budget) + TRUNCATION_MARKER;
17636
+ }
17637
+ function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
17638
+ if (typeof value === "string") return truncateString(value, maxStringLength);
17639
+ if (value === null || typeof value !== "object") return value;
17640
+ if (depth >= maxDepth) return "[truncated:max-depth]";
17641
+ if (seen.has(value)) return "[Circular]";
17642
+ seen.add(value);
17643
+ try {
17644
+ if (value instanceof Date) return value.toISOString();
17645
+ if (Array.isArray(value)) {
17646
+ const limit2 = Math.min(value.length, maxEntries);
17647
+ const output2 = [];
17648
+ for (let index = 0; index < limit2; index += 1) {
17649
+ output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
17650
+ }
17651
+ if (value.length > limit2) output2.push("[truncated:entries]");
17652
+ return output2;
17653
+ }
17654
+ const record = value;
17655
+ const output = {};
17656
+ const keys = Object.keys(record);
17657
+ const limit = Math.min(keys.length, maxEntries);
17658
+ for (let index = 0; index < limit; index += 1) {
17659
+ const key5 = keys[index];
17660
+ output[truncateString(key5, maxStringLength)] = truncateValue(
17661
+ record[key5],
17662
+ depth + 1,
17663
+ maxDepth,
17664
+ maxEntries,
17665
+ maxStringLength,
17666
+ seen
17667
+ );
17668
+ }
17669
+ if (keys.length > limit) output["[truncated]"] = true;
17670
+ return output;
17671
+ } finally {
17672
+ seen.delete(value);
17673
+ }
17674
+ }
17675
+ function truncateForJson(value, options = {}) {
17676
+ return truncateValue(
17677
+ value,
17678
+ 0,
17679
+ options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
17680
+ options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
17681
+ options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
17682
+ /* @__PURE__ */ new WeakSet()
17683
+ );
17684
+ }
17685
+
17367
17686
  // src/services/Agent.ts
17368
17687
  var import_protocols10 = require("@axiom-lattice/protocols");
17369
17688
  var import_langgraph6 = require("@langchain/langgraph");
@@ -18902,6 +19221,27 @@ function statusFromSnapshot(state) {
18902
19221
  if (Array.isArray(state.next) && state.next.length > 0) return "busy" /* BUSY */;
18903
19222
  return "idle" /* IDLE */;
18904
19223
  }
19224
+ var MAX_EXECUTION_ERROR_LENGTH = 2e3;
19225
+ function executionErrorFromSnapshot(state) {
19226
+ if (!isPlainRecord(state) || !Array.isArray(state.tasks)) return void 0;
19227
+ for (const task of state.tasks) {
19228
+ if (!isPlainRecord(task) || task.error === void 0 || task.error === null) continue;
19229
+ const raw = task.error;
19230
+ const message = typeof raw === "string" ? raw : raw instanceof Error ? raw.message : isPlainRecord(raw) && typeof raw.message === "string" ? raw.message : (() => {
19231
+ try {
19232
+ return JSON.stringify(raw);
19233
+ } catch {
19234
+ return String(raw);
19235
+ }
19236
+ })();
19237
+ if (typeof message !== "string") continue;
19238
+ const trimmed = message.trim();
19239
+ if (trimmed.length === 0) continue;
19240
+ const bounded = truncateForJson(trimmed, { maxStringLength: MAX_EXECUTION_ERROR_LENGTH });
19241
+ if (typeof bounded === "string" && bounded.length > 0) return bounded;
19242
+ }
19243
+ return void 0;
19244
+ }
18905
19245
  function freshReply(state, preRunMarker, inputMessageId, consumedInputMessageIds) {
18906
19246
  const output = finalAiMessageMarker(state);
18907
19247
  if (output?.text === void 0 || output.index <= (preRunMarker?.index ?? -1) || output.totalMessageCount <= (preRunMarker?.totalMessageCount ?? 0)) return void 0;
@@ -19181,7 +19521,7 @@ var Agent = class {
19181
19521
  state
19182
19522
  });
19183
19523
  } else if (runStatus === "error" /* ERROR */) {
19184
- const failureReason = "Agent execution ended in an error state";
19524
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19185
19525
  this.addChunk({
19186
19526
  type: "message_failed",
19187
19527
  data: { id: humanContent.id, content: failureReason }
@@ -19294,7 +19634,7 @@ var Agent = class {
19294
19634
  }
19295
19635
  if (runStatus === "busy" /* BUSY */) return;
19296
19636
  if (runStatus === "error" /* ERROR */) {
19297
- const failureReason = "Agent execution ended in an error state";
19637
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19298
19638
  for (const p of collectPendings) {
19299
19639
  const messageId = p.content.id;
19300
19640
  this.addChunk({
@@ -19395,7 +19735,7 @@ var Agent = class {
19395
19735
  });
19396
19736
  if (p.execution_mode === "followup") return;
19397
19737
  } else if (runStatus === "error" /* ERROR */) {
19398
- const failureReason = "Agent execution ended in an error state";
19738
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
19399
19739
  this.addChunk({
19400
19740
  type: "message_failed",
19401
19741
  data: { id: humanContent.id, content: failureReason }
@@ -19702,12 +20042,17 @@ var Agent = class {
19702
20042
  capabilityRuntimeRevision: capabilityRuntime.revision,
19703
20043
  tenantId: this.tenant_id,
19704
20044
  workspaceId: this.workspace_id,
19705
- projectId: this.project_id,
20045
+ // The propagated project scope must not fabricate `"default"`:
20046
+ // `queue_project_id` is `null` when the run had no project, so an unscoped
20047
+ // run stays unscoped instead of later querying a project that may not
20048
+ // exist. An explicitly passed `"default"` is a real project for some
20049
+ // tenants and is preserved.
20050
+ projectId: this.queue_project_id ?? void 0,
19706
20051
  assistant_id: this.assistant_id,
19707
20052
  thread_id: this.thread_id,
19708
20053
  "x-tenant-id": this.tenant_id,
19709
20054
  "x-workspace-id": this.workspace_id,
19710
- "x-project-id": this.project_id,
20055
+ "x-project-id": this.queue_project_id ?? void 0,
19711
20056
  "x-thread-id": this.thread_id,
19712
20057
  "x-assistant-id": this.assistant_id
19713
20058
  };
@@ -20052,7 +20397,15 @@ var Agent = class {
20052
20397
  if (!accepted) throw new Error(`Queue is full (max ${maxSize} messages)`);
20053
20398
  if (useMode === "steer" /* STEER */ && !queueMessage.command) {
20054
20399
  this.stopQueueProcessor();
20055
- await store.resetProcessingToPending(this.thread_id, this.queueScope());
20400
+ let runStatus;
20401
+ try {
20402
+ runStatus = await this.getRunStatus();
20403
+ } catch {
20404
+ runStatus = void 0;
20405
+ }
20406
+ if (runStatus !== "interrupted" /* INTERRUPTED */) {
20407
+ await store.resetProcessingToPending(this.thread_id, this.queueScope());
20408
+ }
20056
20409
  console.log(`[Agent] STEER mode: stopped current processing, reset queue, message ${messageId} will execute next`);
20057
20410
  }
20058
20411
  } else {
@@ -20368,7 +20721,7 @@ var Agent = class {
20368
20721
  }
20369
20722
  } else if (resumedStatus === "error" /* ERROR */) {
20370
20723
  this.clearRecoveryBlock();
20371
- const failureReason = "Agent execution ended in an error state";
20724
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
20372
20725
  for (const msg of processingMessages) {
20373
20726
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
20374
20727
  this.publish("message:failed", {
@@ -20404,7 +20757,7 @@ var Agent = class {
20404
20757
  } else if (runStatus === "error" /* ERROR */) {
20405
20758
  this.processingExecutionContext(processingMessages);
20406
20759
  this.clearRecoveryBlock();
20407
- const failureReason = "Agent execution ended in an error state";
20760
+ const failureReason = executionErrorFromSnapshot(preRunState) ?? "Agent execution ended in an error state";
20408
20761
  for (const msg of processingMessages) {
20409
20762
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
20410
20763
  this.publish("message:failed", {
@@ -20550,8 +20903,19 @@ var AgentInstanceManager = class _AgentInstanceManager {
20550
20903
  }
20551
20904
  return _AgentInstanceManager._instance;
20552
20905
  }
20906
+ /**
20907
+ * A thread's identity is `(tenant_id, assistant_id, thread_id)`.
20908
+ *
20909
+ * Workspace/project are execution scope chosen when the instance is created,
20910
+ * not part of identity: including them let the same thread exist as several
20911
+ * Agents when callers defaulted optional workspace/project headers
20912
+ * differently (e.g. `createRun` passing `undefined` while `abort` defaulted
20913
+ * to `"default"`), so control-plane calls could address a different instance
20914
+ * than the one running. `undefined`/`null` normalize to `""`; ids are assumed
20915
+ * not to contain `:` (UUID-shaped in practice).
20916
+ */
20553
20917
  getKey(params) {
20554
- return `${params.tenant_id}:${params.assistant_id}:${params.thread_id}:${params.workspace_id}:${params.project_id}`;
20918
+ return [params.tenant_id, params.assistant_id, params.thread_id].map((value) => value ?? "").join(":");
20555
20919
  }
20556
20920
  /**
20557
20921
  * Get or create Agent instance for a thread
@@ -20565,6 +20929,24 @@ var AgentInstanceManager = class _AgentInstanceManager {
20565
20929
  }
20566
20930
  return this.agents.get(key5);
20567
20931
  }
20932
+ /**
20933
+ * Get the managed Agent for a thread WITHOUT creating or registering one.
20934
+ *
20935
+ * Read-only control-plane callers (state, memory, inbox) must not be the first
20936
+ * to establish a thread's execution scope: since identity is
20937
+ * `(tenant_id, assistant_id, thread_id)`, whichever caller reaches
20938
+ * {@link getAgent} first fixes the instance's workspace/project for its whole
20939
+ * lifetime, and a later trusted dispatch on that thread would then fail
20940
+ * trusted-scope validation. This returns the existing managed instance when
20941
+ * present, otherwise a transient unregistered Agent that is sufficient for
20942
+ * state reads and disappears with the request.
20943
+ *
20944
+ * @param params - Thread identity; scope is only used for the transient Agent.
20945
+ * @returns The managed instance if any, else an unregistered read-only Agent.
20946
+ */
20947
+ getAgentForRead(params) {
20948
+ return this.agents.get(this.getKey(params)) ?? new Agent(params);
20949
+ }
20568
20950
  /**
20569
20951
  * Check if an agent instance exists for the thread
20570
20952
  */
@@ -20600,55 +20982,6 @@ var AgentInstanceManager = class _AgentInstanceManager {
20600
20982
  });
20601
20983
  this.agents.clear();
20602
20984
  }
20603
- /**
20604
- * Restore agent instances for threads with pending messages after server restart
20605
- * Queries the message queue store for threads with pending/processing messages
20606
- * and recreates agent instances to resume processing
20607
- */
20608
- async restore() {
20609
- const stats = { restored: 0, errors: 0 };
20610
- try {
20611
- const queueStoreLattice = storeLatticeManager.getStoreLattice("default", "threadMessageQueue");
20612
- const queueStore = queueStoreLattice.store;
20613
- const threadsWithPending = await queueStore.getThreadsWithPendingMessages();
20614
- if (threadsWithPending.length === 0) {
20615
- console.log("[AgentInstanceManager] No threads with pending messages found");
20616
- return stats;
20617
- }
20618
- console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
20619
- for (const threadInfo of threadsWithPending) {
20620
- try {
20621
- await this.restoreThread(threadInfo);
20622
- stats.restored++;
20623
- } catch (error) {
20624
- console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
20625
- stats.errors++;
20626
- }
20627
- }
20628
- console.log(`[AgentInstanceManager] Restore complete: ${stats.restored} restored, ${stats.errors} errors`);
20629
- return stats;
20630
- } catch (error) {
20631
- console.error("[AgentInstanceManager] Restore failed:", error);
20632
- throw error;
20633
- }
20634
- }
20635
- /**
20636
- * Restore a single thread
20637
- * Delegates actual recovery logic to Agent.resumeTask()
20638
- */
20639
- async restoreThread(threadInfo) {
20640
- const { tenantId: tenantId2, assistantId, threadId, workspaceId, projectId } = threadInfo;
20641
- const threadParams = {
20642
- tenant_id: tenantId2,
20643
- assistant_id: assistantId,
20644
- thread_id: threadId,
20645
- workspace_id: workspaceId,
20646
- project_id: projectId
20647
- };
20648
- const agent = this.getAgent(threadParams);
20649
- await agent.resumeTask();
20650
- console.log(`[AgentInstanceManager] Restored thread ${threadId}`);
20651
- }
20652
20985
  };
20653
20986
  var agentInstanceManager = AgentInstanceManager.getInstance();
20654
20987
 
@@ -37653,6 +37986,8 @@ function buildParentBeliefActivity(input) {
37653
37986
  }
37654
37987
 
37655
37988
  // src/services/TaskLifecycleService.ts
37989
+ var WORK_ITEM_WRITE_ATTEMPTS = 3;
37990
+ var WORK_ITEM_WRITE_RETRY_DELAYS_MS = [20, 50];
37656
37991
  var RETRYABLE_LIFECYCLE_CODES = /* @__PURE__ */ new Set([
37657
37992
  "TASK_STATUS_CONFLICT",
37658
37993
  "TASK_STORE_WRITE_FAILED",
@@ -38019,7 +38354,8 @@ var TaskLifecycleService = class {
38019
38354
  const resumeKey = this.resumeEventKey(task);
38020
38355
  const audit = { eventKey: resumeKey, previousInterruption };
38021
38356
  const context = withLifecycleAudit(task.context, "lifecycle_resume_audit", audit);
38022
- if (input.threadId && !task.context?.thread_id) context.thread_id = input.threadId;
38357
+ if (input.threadId) context.thread_id = input.threadId;
38358
+ if (input.runId) context.run_id = input.runId;
38023
38359
  const updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
38024
38360
  input.tenantId,
38025
38361
  input.taskId,
@@ -38116,7 +38452,13 @@ var TaskLifecycleService = class {
38116
38452
  if (task.status !== "pending") {
38117
38453
  return { ...failure2("TASK_STATUS_CONFLICT", "Task cannot start."), transitioned: false };
38118
38454
  }
38119
- const context = { ...task.context ?? {}, ...input.threadId ? { thread_id: input.threadId } : {} };
38455
+ const context = {
38456
+ ...task.context ?? {},
38457
+ ...input.threadId ? { thread_id: input.threadId } : {},
38458
+ ...input.runId ? { run_id: input.runId } : {},
38459
+ ...input.callerThreadId ? { caller_thread_id: input.callerThreadId } : {},
38460
+ ...input.callerAssistantId ? { caller_assistant_id: input.callerAssistantId } : {}
38461
+ };
38120
38462
  let updated;
38121
38463
  try {
38122
38464
  updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
@@ -38192,7 +38534,9 @@ var TaskLifecycleService = class {
38192
38534
  expectedStatuses: ["failed"],
38193
38535
  updates: { status: "in_progress", failureReason: null },
38194
38536
  summary: "Task retried",
38195
- detail: { previousStatus: "failed" }
38537
+ detail: { previousStatus: "failed" },
38538
+ // A retry dispatches a new run thread; replace a stale persisted link.
38539
+ replaceThread: true
38196
38540
  });
38197
38541
  }
38198
38542
  /**
@@ -39678,7 +40022,9 @@ var TaskLifecycleService = class {
39678
40022
  }
39679
40023
  if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
39680
40024
  const clearedContext = clearInterruptionContext(task.context);
39681
- const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
40025
+ const threadInput = input.threadId && (input.replaceThread || task.context?.thread_id === void 0) ? { thread_id: input.threadId } : {};
40026
+ const runInput = input.runId ? { run_id: input.runId } : {};
40027
+ const withThread = Object.keys(threadInput).length > 0 || Object.keys(runInput).length > 0 ? { ...clearedContext ?? {}, ...threadInput, ...runInput } : clearedContext;
39682
40028
  const updates = { ...input.updates, context: withThread };
39683
40029
  let updated;
39684
40030
  try {
@@ -39716,6 +40062,31 @@ var TaskLifecycleService = class {
39716
40062
  statusEventKey(task, status, detail) {
39717
40063
  return `task-lifecycle:${task.id}:${status}:${task.updatedAt.toISOString()}:${sha256(detail)}`;
39718
40064
  }
40065
+ /**
40066
+ * Writes a lifecycle work-item event, retrying transient store failures.
40067
+ *
40068
+ * @param request Event request passed through to the work-item store.
40069
+ * @returns The persisted or pre-existing work item.
40070
+ * @remarks The write is idempotent by `eventKey`
40071
+ * (`createIfAbsentByEventKey`), so retrying after a transient failure (pool
40072
+ * exhaustion, shutdown, statement timeout, disk IO) is safe. The status CAS has
40073
+ * already committed by this point, and the event key embeds `updatedAt`, so a
40074
+ * lost event cannot be reconstructed later — hence the bounded retry.
40075
+ */
40076
+ async writeWorkItemWithRetry(request) {
40077
+ let lastError;
40078
+ for (let attempt = 0; attempt < WORK_ITEM_WRITE_ATTEMPTS; attempt += 1) {
40079
+ if (attempt > 0) {
40080
+ await new Promise((resolve4) => setTimeout(resolve4, WORK_ITEM_WRITE_RETRY_DELAYS_MS[attempt - 1]));
40081
+ }
40082
+ try {
40083
+ return await this.deps.workItemStore.createIfAbsentByEventKey(request);
40084
+ } catch (error) {
40085
+ lastError = error;
40086
+ }
40087
+ }
40088
+ throw lastError;
40089
+ }
39719
40090
  async writeStatusEvent(task, actor, threadId, action, summary, detail, eventKey) {
39720
40091
  const warningCode = `${action.toUpperCase()}_WORK_ITEM_WRITE_FAILED`;
39721
40092
  const request = {
@@ -39731,7 +40102,7 @@ var TaskLifecycleService = class {
39731
40102
  eventKey
39732
40103
  };
39733
40104
  try {
39734
- const item = await this.deps.workItemStore.createIfAbsentByEventKey(request);
40105
+ const item = await this.writeWorkItemWithRetry(request);
39735
40106
  if (item.eventKey !== request.eventKey) throw new Error("Canonical lifecycle event key mismatch");
39736
40107
  return { eventKey: item.eventKey };
39737
40108
  } catch {
@@ -39917,7 +40288,7 @@ function createTaskRunBridge(deps) {
39917
40288
  return { success: true, task: updated };
39918
40289
  },
39919
40290
  async beginRun(input) {
39920
- const { tenantId: tenantId2, actor, threadId } = input;
40291
+ const { tenantId: tenantId2, actor, threadId, runId, callerThreadId, callerAssistantId } = input;
39921
40292
  let task = input.task;
39922
40293
  const warnings = [];
39923
40294
  if (task.status === "pending") {
@@ -39926,7 +40297,10 @@ function createTaskRunBridge(deps) {
39926
40297
  tenantId: tenantId2,
39927
40298
  taskId: task.id,
39928
40299
  actor,
39929
- threadId
40300
+ ...threadId !== void 0 ? { threadId } : {},
40301
+ ...runId !== void 0 ? { runId } : {},
40302
+ ...callerThreadId ? { callerThreadId } : {},
40303
+ ...callerAssistantId ? { callerAssistantId } : {}
39930
40304
  });
39931
40305
  if (!started.success) {
39932
40306
  return {
@@ -40014,7 +40388,19 @@ function createTaskRunBridge(deps) {
40014
40388
  error: "Lifecycle transitions only support agent tasks."
40015
40389
  };
40016
40390
  }
40017
- const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({ tenantId: tenantId2, taskId: task.id, actor, threadId }) : await deps.lifecycle.retryTask({ tenantId: tenantId2, taskId: task.id, actor, threadId });
40391
+ const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({
40392
+ tenantId: tenantId2,
40393
+ taskId: task.id,
40394
+ actor,
40395
+ ...threadId !== void 0 ? { threadId } : {},
40396
+ ...runId !== void 0 ? { runId } : {}
40397
+ }) : await deps.lifecycle.retryTask({
40398
+ tenantId: tenantId2,
40399
+ taskId: task.id,
40400
+ actor,
40401
+ ...threadId !== void 0 ? { threadId } : {},
40402
+ ...runId !== void 0 ? { runId } : {}
40403
+ });
40018
40404
  if (!result.success) {
40019
40405
  return {
40020
40406
  success: false,
@@ -40079,6 +40465,86 @@ function createTaskRunBridge(deps) {
40079
40465
  };
40080
40466
  }
40081
40467
 
40468
+ // src/services/TaskRunRegistry.ts
40469
+ var TaskRunRegistry = class {
40470
+ constructor() {
40471
+ this.live = /* @__PURE__ */ new Set();
40472
+ }
40473
+ /** Marks a task as currently held by a live run. */
40474
+ register(taskId) {
40475
+ this.live.add(taskId);
40476
+ }
40477
+ /** Removes a task once its run has ended. */
40478
+ unregister(taskId) {
40479
+ this.live.delete(taskId);
40480
+ }
40481
+ /** Reports whether a task is currently held by a live run. */
40482
+ isLive(taskId) {
40483
+ return this.live.has(taskId);
40484
+ }
40485
+ /** Returns a snapshot of the live task ids (diagnostics/tests). */
40486
+ snapshot() {
40487
+ return [...this.live];
40488
+ }
40489
+ /** Clears all live entries (tests / process teardown). */
40490
+ clear() {
40491
+ this.live.clear();
40492
+ }
40493
+ };
40494
+ var taskRunRegistry = new TaskRunRegistry();
40495
+ async function reconcileStaleTaskRuns(input) {
40496
+ const registry4 = input.registry ?? taskRunRegistry;
40497
+ const converged = [];
40498
+ const convergedTasks = [];
40499
+ for (const task of input.tasks) {
40500
+ if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
40501
+ const result = await input.lifecycle.failTask({
40502
+ tenantId: task.tenantId,
40503
+ taskId: task.id,
40504
+ actor: input.actor,
40505
+ failureReason: "Run is no longer executing this task (no_executor)"
40506
+ });
40507
+ if (result.success) {
40508
+ converged.push(task.id);
40509
+ convergedTasks.push(result.task);
40510
+ }
40511
+ }
40512
+ return { converged, convergedTasks };
40513
+ }
40514
+ async function reconcileTenantTaskRuns(input) {
40515
+ const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
40516
+ const candidates = input.include ? tasks.filter(input.include) : tasks;
40517
+ return reconcileStaleTaskRuns({
40518
+ tasks: candidates,
40519
+ actor: input.actor,
40520
+ lifecycle: input.lifecycle,
40521
+ ...input.registry ? { registry: input.registry } : {}
40522
+ });
40523
+ }
40524
+ async function reconcileAllTenantTaskRuns(input) {
40525
+ const tenants = await input.tenantStore.listTenants();
40526
+ const converged = [];
40527
+ const convergedTasks = [];
40528
+ for (const tenant of tenants) {
40529
+ let result;
40530
+ try {
40531
+ result = await reconcileTenantTaskRuns({
40532
+ tenantId: tenant.id,
40533
+ actor: input.actor,
40534
+ taskStore: input.taskStore,
40535
+ lifecycle: input.lifecycle,
40536
+ ...input.registry ? { registry: input.registry } : {},
40537
+ ...input.include ? { include: input.include } : {}
40538
+ });
40539
+ } catch {
40540
+ continue;
40541
+ }
40542
+ converged.push(...result.converged);
40543
+ convergedTasks.push(...result.convergedTasks);
40544
+ }
40545
+ return { converged, convergedTasks };
40546
+ }
40547
+
40082
40548
  // src/services/ExecutionAuthorityRegistry.ts
40083
40549
  var ManagedTaskStartError = class extends Error {
40084
40550
  /**
@@ -40340,274 +40806,13 @@ async function prepareTaskDispatch(deps, input) {
40340
40806
  agentId: input.agentId,
40341
40807
  actor: input.actor,
40342
40808
  ...input.callerThreadId !== void 0 ? { callerThreadId: input.callerThreadId } : {},
40809
+ ...input.callerAssistantId !== void 0 ? { callerAssistantId: input.callerAssistantId } : {},
40343
40810
  parent,
40344
40811
  completedDependencies
40345
40812
  }
40346
40813
  };
40347
40814
  }
40348
40815
 
40349
- // src/util/toJsonSafeValue.ts
40350
- var CIRCULAR_VALUE = "[Circular]";
40351
- var REPEATED_VALUE = "[Repeated]";
40352
- var arrayFrom = Array.from.bind(Array);
40353
- var arrayIsArray = Array.isArray.bind(Array);
40354
- var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
40355
- var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
40356
- var objectCreate = Object.create.bind(Object);
40357
- var objectDefineProperty = Object.defineProperty.bind(Object);
40358
- var objectIs = Object.is.bind(Object);
40359
- var reflectGet = Reflect.get.bind(Reflect);
40360
- var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
40361
- var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
40362
- var stringifyJson = JSON.stringify.bind(JSON);
40363
- var numberIsFinite = Number.isFinite.bind(Number);
40364
- var numberIsNaN = Number.isNaN.bind(Number);
40365
- var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
40366
- var mathMax = Math.max.bind(Math);
40367
- var dateConstructor = Date;
40368
- var datePrototype = dateConstructor.prototype;
40369
- var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
40370
- var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
40371
- var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
40372
- var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
40373
- var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
40374
- var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
40375
- var WeakMapConstructor = WeakMap;
40376
- var utf8Encoder = new TextEncoder();
40377
- var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
40378
- var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
40379
- var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
40380
- if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
40381
- var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
40382
- var JSON_SAFE_MAX_DEPTH = 32;
40383
- var JSON_SAFE_MAX_NODES = 1e4;
40384
- var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
40385
- var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
40386
- var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
40387
- var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
40388
- var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
40389
- var JsonSafeValueError = class extends Error {
40390
- /**
40391
- * Create a bounded normalization error.
40392
- *
40393
- * @param code Stable normalization failure code.
40394
- * @param message Human-readable bounded failure description.
40395
- */
40396
- constructor(code, message) {
40397
- super(message);
40398
- objectDefineProperty(this, "name", {
40399
- value: "JsonSafeValueError",
40400
- writable: true,
40401
- configurable: true
40402
- });
40403
- objectDefineProperty(this, "code", {
40404
- value: code,
40405
- writable: true,
40406
- configurable: true
40407
- });
40408
- }
40409
- };
40410
- function fail(code, message) {
40411
- throw new JsonSafeValueError(code, message);
40412
- }
40413
- function propertyAccess(operation, path8) {
40414
- try {
40415
- return operation();
40416
- } catch {
40417
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
40418
- }
40419
- }
40420
- function serializedStringBytes(value) {
40421
- if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
40422
- fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
40423
- }
40424
- return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
40425
- }
40426
- function validatePropertyKey(key5) {
40427
- if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
40428
- fail(
40429
- "MAX_STRING_LENGTH",
40430
- `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
40431
- );
40432
- }
40433
- }
40434
- function chargePropertyKey(state, key5) {
40435
- state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
40436
- if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
40437
- fail(
40438
- "MAX_PROPERTY_KEY_BYTES",
40439
- `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
40440
- );
40441
- }
40442
- }
40443
- function chargeBytes(state, bytes) {
40444
- state.serializedBytes += bytes;
40445
- if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
40446
- fail(
40447
- "MAX_SERIALIZED_BYTES",
40448
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
40449
- );
40450
- }
40451
- }
40452
- function chargeString(state, value) {
40453
- chargeBytes(state, serializedStringBytes(value));
40454
- }
40455
- function objectPropertyPath(path8, key5) {
40456
- const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
40457
- return `${path8}[${stringifyJson(boundedKey)}]`;
40458
- }
40459
- function convertJsonValue(value, state, depth, inArray, path8) {
40460
- state.nodes += 1;
40461
- if (state.nodes > JSON_SAFE_MAX_NODES) {
40462
- fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
40463
- }
40464
- if (typeof value === "string") {
40465
- chargeString(state, value);
40466
- return value;
40467
- }
40468
- if (value === null) {
40469
- chargeBytes(state, 4);
40470
- return value;
40471
- }
40472
- if (typeof value === "boolean") {
40473
- chargeBytes(state, value ? 4 : 5);
40474
- return value;
40475
- }
40476
- if (typeof value === "number") {
40477
- const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
40478
- chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
40479
- return normalized;
40480
- }
40481
- if (typeof value === "bigint") {
40482
- const normalized = bigintToString(value);
40483
- chargeString(state, normalized);
40484
- return normalized;
40485
- }
40486
- if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
40487
- if (inArray) chargeBytes(state, 4);
40488
- return inArray ? null : void 0;
40489
- }
40490
- const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
40491
- if (isDate) {
40492
- const time = propertyAccess(() => dateGetTime(value), path8);
40493
- if (numberIsNaN(time)) {
40494
- chargeBytes(state, 4);
40495
- return null;
40496
- }
40497
- const normalized = propertyAccess(() => dateToISOString(value), path8);
40498
- chargeString(state, normalized);
40499
- return normalized;
40500
- }
40501
- if (depth > JSON_SAFE_MAX_DEPTH) {
40502
- fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
40503
- }
40504
- const referenceState = weakMapGet(state.references, value);
40505
- if (referenceState === "visiting") {
40506
- chargeString(state, CIRCULAR_VALUE);
40507
- return CIRCULAR_VALUE;
40508
- }
40509
- if (referenceState === "visited") {
40510
- chargeString(state, REPEATED_VALUE);
40511
- return REPEATED_VALUE;
40512
- }
40513
- weakMapSet(state.references, value, "visiting");
40514
- if (propertyAccess(() => arrayIsArray(value), path8)) {
40515
- const arrayValue = value;
40516
- const length = propertyAccess(
40517
- () => arrayValue.length,
40518
- path8
40519
- );
40520
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
40521
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
40522
- }
40523
- if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
40524
- fail(
40525
- "COLLECTION_TOO_LARGE",
40526
- `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
40527
- );
40528
- }
40529
- chargeBytes(state, 2 + mathMax(0, length - 1));
40530
- const result2 = arrayFrom({ length }, (_, index) => {
40531
- const entryPath = `${path8}[${index}]`;
40532
- const hasEntry = propertyAccess(
40533
- () => hasOwnProperty(arrayValue, index),
40534
- entryPath
40535
- );
40536
- if (!hasEntry) {
40537
- chargeBytes(state, 4);
40538
- return null;
40539
- }
40540
- const entry = propertyAccess(() => arrayValue[index], entryPath);
40541
- return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
40542
- });
40543
- objectDefineProperty(result2, "toJSON", {
40544
- value: void 0,
40545
- configurable: true,
40546
- writable: true
40547
- });
40548
- weakMapSet(state.references, value, "visited");
40549
- return result2;
40550
- }
40551
- const keys = propertyAccess(() => reflectOwnKeys(value), path8);
40552
- if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
40553
- fail(
40554
- "COLLECTION_TOO_LARGE",
40555
- `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
40556
- );
40557
- }
40558
- for (let index = 0; index < keys.length; index += 1) {
40559
- const key5 = keys[index];
40560
- if (typeof key5 !== "string") continue;
40561
- validatePropertyKey(key5);
40562
- chargePropertyKey(state, key5);
40563
- }
40564
- chargeBytes(state, 2);
40565
- const result = objectCreate(null);
40566
- let emittedProperties = 0;
40567
- for (let index = 0; index < keys.length; index += 1) {
40568
- const key5 = keys[index];
40569
- const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
40570
- const descriptor = propertyAccess(
40571
- () => reflectGetOwnPropertyDescriptor(value, key5),
40572
- entryPath
40573
- );
40574
- if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
40575
- const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
40576
- const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
40577
- if (converted !== void 0) {
40578
- chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
40579
- propertyAccess(() => objectDefineProperty(result, key5, {
40580
- value: converted,
40581
- enumerable: true,
40582
- configurable: true,
40583
- writable: true
40584
- }), entryPath);
40585
- emittedProperties += 1;
40586
- }
40587
- }
40588
- weakMapSet(state.references, value, "visited");
40589
- return result;
40590
- }
40591
- function toJsonSafeValue(value) {
40592
- const state = {
40593
- nodes: 0,
40594
- propertyKeyBytes: 0,
40595
- serializedBytes: 0,
40596
- references: new WeakMapConstructor()
40597
- };
40598
- const converted = convertJsonValue(value, state, 0, false, "$");
40599
- if (converted === void 0) chargeBytes(state, 4);
40600
- const result = converted ?? null;
40601
- const serialized = propertyAccess(() => stringifyJson(result), "$");
40602
- if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
40603
- fail(
40604
- "MAX_SERIALIZED_BYTES",
40605
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
40606
- );
40607
- }
40608
- return result;
40609
- }
40610
-
40611
40816
  // src/services/TaskExecutionService.ts
40612
40817
  var import_langgraph14 = require("@langchain/langgraph");
40613
40818
  function persistedExecutionObservation(item, attempted) {
@@ -40656,10 +40861,26 @@ function createTaskExecutionService(deps) {
40656
40861
  const run = async (plan) => {
40657
40862
  const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
40658
40863
  let task = plan.task;
40659
- const persistedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
40864
+ const storedThreadId = (task.status === "interrupted" || task.status === "failed") && typeof task.context?.thread_id === "string" && task.context.thread_id.trim() !== "" ? task.context.thread_id : void 0;
40865
+ const storedRunId = typeof task.context?.run_id === "string" && task.context.run_id.trim() !== "" ? task.context.run_id : void 0;
40866
+ let reuseCurrentRun = false;
40867
+ if (task.status === "interrupted" && storedThreadId) {
40868
+ const currentKey = storedRunId ? `execution-result:${storedThreadId}:${storedRunId}` : `execution-result:${storedThreadId}`;
40869
+ try {
40870
+ reuseCurrentRun = await deps.workItemStore.findByEventKey(tenantId2, task.id, currentKey) === null;
40871
+ } catch {
40872
+ reuseCurrentRun = false;
40873
+ }
40874
+ }
40660
40875
  let threadId;
40876
+ let runId;
40661
40877
  try {
40662
- threadId = persistedThreadId ?? (deps.createThreadId ?? import_node_crypto9.randomUUID)();
40878
+ threadId = storedThreadId ?? (deps.createThreadId ?? import_node_crypto9.randomUUID)();
40879
+ if (task.status === "interrupted" && reuseCurrentRun) {
40880
+ runId = storedRunId;
40881
+ } else if (task.status === "interrupted" || task.status === "failed") {
40882
+ runId = (deps.createRunId ?? import_node_crypto9.randomUUID)();
40883
+ }
40663
40884
  } catch (error) {
40664
40885
  return {
40665
40886
  success: false,
@@ -40669,7 +40890,7 @@ function createTaskExecutionService(deps) {
40669
40890
  agentId
40670
40891
  };
40671
40892
  }
40672
- const eventKey = `execution-result:${threadId}`;
40893
+ const eventKey = runId ? `execution-result:${threadId}:${runId}` : `execution-result:${threadId}`;
40673
40894
  if (!(0, import_protocols32.isExecutionResultEventKey)(eventKey)) {
40674
40895
  return {
40675
40896
  success: false,
@@ -40703,7 +40924,10 @@ function createTaskExecutionService(deps) {
40703
40924
  tenantId: tenantId2,
40704
40925
  task,
40705
40926
  actor,
40706
- threadId
40927
+ threadId,
40928
+ ...runId ? { runId } : {},
40929
+ ...plan.callerThreadId ? { callerThreadId: plan.callerThreadId } : {},
40930
+ ...plan.callerAssistantId ? { callerAssistantId: plan.callerAssistantId } : {}
40707
40931
  });
40708
40932
  if (!begun.success) return { ...begun, taskId: task.id };
40709
40933
  if (!begun.mutated || !begun.transitioned) {
@@ -40717,38 +40941,120 @@ function createTaskExecutionService(deps) {
40717
40941
  task = begun.task;
40718
40942
  warnings.push(...begun.warnings);
40719
40943
  }
40720
- const invocation = {
40721
- tenantId: tenantId2,
40722
- workspaceId: task.workspaceId,
40723
- projectId: task.projectId,
40724
- taskId: task.id,
40725
- agentId,
40726
- threadId,
40727
- message: buildWorkerMessage(task, parent, completedDependencies),
40728
- delegatedTaskId: task.id,
40729
- taskExecutionRole: "worker"
40730
- };
40731
- let observation;
40944
+ taskRunRegistry.register(task.id);
40732
40945
  try {
40733
- observation = toJsonSafeValue(await deps.invokeAgent(invocation));
40734
- } catch (error) {
40735
- if (error instanceof import_langgraph14.GraphInterrupt) {
40946
+ const invocation = {
40947
+ tenantId: tenantId2,
40948
+ workspaceId: task.workspaceId,
40949
+ projectId: task.projectId,
40950
+ taskId: task.id,
40951
+ agentId,
40952
+ threadId,
40953
+ message: buildWorkerMessage(task, parent, completedDependencies),
40954
+ delegatedTaskId: task.id,
40955
+ taskExecutionRole: "worker"
40956
+ };
40957
+ let observation;
40958
+ try {
40959
+ observation = toJsonSafeValue(await deps.invokeAgent(invocation));
40960
+ } catch (error) {
40961
+ if (error instanceof import_langgraph14.GraphInterrupt) {
40962
+ try {
40963
+ await bridge.settleRun({
40964
+ tenantId: tenantId2,
40965
+ task,
40966
+ actor,
40967
+ threadId,
40968
+ outcome: { kind: "interrupted", summary: "Awaiting user input" }
40969
+ });
40970
+ } catch {
40971
+ }
40972
+ throw error;
40973
+ }
40974
+ const normalizationError = error instanceof JsonSafeValueError;
40975
+ const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
40976
+ const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
40736
40977
  try {
40737
- await bridge.settleRun({
40978
+ const settled = await bridge.settleRun({
40738
40979
  tenantId: tenantId2,
40739
40980
  task,
40740
40981
  actor,
40741
40982
  threadId,
40742
- outcome: { kind: "interrupted", summary: "Awaiting user input" }
40983
+ outcome: {
40984
+ kind: "failed",
40985
+ lifecycleHandled: false,
40986
+ error: message.trim() || "Agent invocation failed"
40987
+ }
40743
40988
  });
40989
+ if (!settled.success) {
40990
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
40991
+ }
40744
40992
  } catch {
40993
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
40994
+ }
40995
+ const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
40996
+ try {
40997
+ const persisted = await deps.workItemStore.createIfAbsentByEventKey({
40998
+ taskId: task.id,
40999
+ tenantId: tenantId2,
41000
+ workspaceId: task.workspaceId,
41001
+ projectId: task.projectId,
41002
+ action: "execution_result",
41003
+ actor,
41004
+ threadId,
41005
+ summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
41006
+ detail: {
41007
+ agentId,
41008
+ threadId,
41009
+ observation: failedObservation,
41010
+ success: false
41011
+ },
41012
+ eventKey
41013
+ });
41014
+ const validated = persistedExecutionObservation(persisted, {
41015
+ tenantId: tenantId2,
41016
+ taskId: task.id,
41017
+ agentId,
41018
+ threadId,
41019
+ eventKey,
41020
+ success: false,
41021
+ observation: failedObservation
41022
+ });
41023
+ if (!validated.matches) {
41024
+ return {
41025
+ success: false,
41026
+ code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
41027
+ error: "The execution result identity is already bound to a different execution payload",
41028
+ ...!normalizationError ? { invocationError: message } : {},
41029
+ taskId: task.id,
41030
+ agentId,
41031
+ threadId,
41032
+ ...warnings.length > 0 ? { warnings } : {}
41033
+ };
41034
+ }
41035
+ return {
41036
+ success: false,
41037
+ code: failureCode,
41038
+ error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
41039
+ taskId: task.id,
41040
+ agentId,
41041
+ threadId,
41042
+ executionResultId: eventKey,
41043
+ ...warnings.length > 0 ? { warnings } : {}
41044
+ };
41045
+ } catch (persistenceError) {
41046
+ return {
41047
+ success: false,
41048
+ code: "EXECUTION_RESULT_WRITE_FAILED",
41049
+ error: errorMessage(persistenceError),
41050
+ ...!normalizationError ? { invocationError: message } : {},
41051
+ taskId: task.id,
41052
+ agentId,
41053
+ threadId,
41054
+ ...warnings.length > 0 ? { warnings } : {}
41055
+ };
40745
41056
  }
40746
- throw error;
40747
41057
  }
40748
- const normalizationError = error instanceof JsonSafeValueError;
40749
- const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
40750
- const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
40751
- const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
40752
41058
  try {
40753
41059
  const persisted = await deps.workItemStore.createIfAbsentByEventKey({
40754
41060
  taskId: task.id,
@@ -40758,13 +41064,8 @@ function createTaskExecutionService(deps) {
40758
41064
  action: "execution_result",
40759
41065
  actor,
40760
41066
  threadId,
40761
- summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
40762
- detail: {
40763
- agentId,
40764
- threadId,
40765
- observation: failedObservation,
40766
- success: false
40767
- },
41067
+ summary: `Agent ${agentId} returned an execution observation`,
41068
+ detail: { agentId, threadId, observation, success: true },
40768
41069
  eventKey
40769
41070
  });
40770
41071
  const validated = persistedExecutionObservation(persisted, {
@@ -40773,15 +41074,14 @@ function createTaskExecutionService(deps) {
40773
41074
  agentId,
40774
41075
  threadId,
40775
41076
  eventKey,
40776
- success: false,
40777
- observation: failedObservation
41077
+ success: true,
41078
+ observation
40778
41079
  });
40779
41080
  if (!validated.matches) {
40780
41081
  return {
40781
41082
  success: false,
40782
41083
  code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
40783
41084
  error: "The execution result identity is already bound to a different execution payload",
40784
- ...!normalizationError ? { invocationError: message } : {},
40785
41085
  taskId: task.id,
40786
41086
  agentId,
40787
41087
  threadId,
@@ -40789,80 +41089,27 @@ function createTaskExecutionService(deps) {
40789
41089
  };
40790
41090
  }
40791
41091
  return {
40792
- success: false,
40793
- code: failureCode,
40794
- error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
41092
+ success: true,
40795
41093
  taskId: task.id,
40796
41094
  agentId,
40797
41095
  threadId,
41096
+ observation: validated.observation,
40798
41097
  executionResultId: eventKey,
40799
41098
  ...warnings.length > 0 ? { warnings } : {}
40800
41099
  };
40801
- } catch (persistenceError) {
41100
+ } catch (error) {
40802
41101
  return {
40803
41102
  success: false,
40804
41103
  code: "EXECUTION_RESULT_WRITE_FAILED",
40805
- error: errorMessage(persistenceError),
40806
- ...!normalizationError ? { invocationError: message } : {},
40807
- taskId: task.id,
40808
- agentId,
40809
- threadId,
40810
- ...warnings.length > 0 ? { warnings } : {}
40811
- };
40812
- }
40813
- }
40814
- try {
40815
- const persisted = await deps.workItemStore.createIfAbsentByEventKey({
40816
- taskId: task.id,
40817
- tenantId: tenantId2,
40818
- workspaceId: task.workspaceId,
40819
- projectId: task.projectId,
40820
- action: "execution_result",
40821
- actor,
40822
- threadId,
40823
- summary: `Agent ${agentId} returned an execution observation`,
40824
- detail: { agentId, threadId, observation, success: true },
40825
- eventKey
40826
- });
40827
- const validated = persistedExecutionObservation(persisted, {
40828
- tenantId: tenantId2,
40829
- taskId: task.id,
40830
- agentId,
40831
- threadId,
40832
- eventKey,
40833
- success: true,
40834
- observation
40835
- });
40836
- if (!validated.matches) {
40837
- return {
40838
- success: false,
40839
- code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
40840
- error: "The execution result identity is already bound to a different execution payload",
41104
+ error: errorMessage(error),
40841
41105
  taskId: task.id,
40842
41106
  agentId,
40843
41107
  threadId,
40844
41108
  ...warnings.length > 0 ? { warnings } : {}
40845
41109
  };
40846
41110
  }
40847
- return {
40848
- success: true,
40849
- taskId: task.id,
40850
- agentId,
40851
- threadId,
40852
- observation: validated.observation,
40853
- executionResultId: eventKey,
40854
- ...warnings.length > 0 ? { warnings } : {}
40855
- };
40856
- } catch (error) {
40857
- return {
40858
- success: false,
40859
- code: "EXECUTION_RESULT_WRITE_FAILED",
40860
- error: errorMessage(error),
40861
- taskId: task.id,
40862
- agentId,
40863
- threadId,
40864
- ...warnings.length > 0 ? { warnings } : {}
40865
- };
41111
+ } finally {
41112
+ taskRunRegistry.unregister(task.id);
40866
41113
  }
40867
41114
  };
40868
41115
  return {
@@ -40875,76 +41122,6 @@ function createTaskExecutionService(deps) {
40875
41122
  };
40876
41123
  }
40877
41124
 
40878
- // src/services/TaskRunRegistry.ts
40879
- var TaskRunRegistry = class {
40880
- constructor() {
40881
- this.live = /* @__PURE__ */ new Set();
40882
- }
40883
- /** Marks a task as currently held by a live run. */
40884
- register(taskId) {
40885
- this.live.add(taskId);
40886
- }
40887
- /** Removes a task once its run has ended. */
40888
- unregister(taskId) {
40889
- this.live.delete(taskId);
40890
- }
40891
- /** Reports whether a task is currently held by a live run. */
40892
- isLive(taskId) {
40893
- return this.live.has(taskId);
40894
- }
40895
- /** Returns a snapshot of the live task ids (diagnostics/tests). */
40896
- snapshot() {
40897
- return [...this.live];
40898
- }
40899
- /** Clears all live entries (tests / process teardown). */
40900
- clear() {
40901
- this.live.clear();
40902
- }
40903
- };
40904
- var taskRunRegistry = new TaskRunRegistry();
40905
- async function reconcileStaleTaskRuns(input) {
40906
- const registry4 = input.registry ?? taskRunRegistry;
40907
- const converged = [];
40908
- for (const task of input.tasks) {
40909
- if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
40910
- const result = await input.lifecycle.interruptTask({
40911
- tenantId: task.tenantId,
40912
- taskId: task.id,
40913
- actor: input.actor,
40914
- type: "missing_input",
40915
- summary: "Run is no longer executing this task (no_executor)"
40916
- });
40917
- if (result.success) converged.push(task.id);
40918
- }
40919
- return { converged };
40920
- }
40921
- async function reconcileTenantTaskRuns(input) {
40922
- const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
40923
- const candidates = input.include ? tasks.filter(input.include) : tasks;
40924
- return reconcileStaleTaskRuns({
40925
- tasks: candidates,
40926
- actor: input.actor,
40927
- lifecycle: input.lifecycle,
40928
- ...input.registry ? { registry: input.registry } : {}
40929
- });
40930
- }
40931
- async function reconcileAllTenantTaskRuns(input) {
40932
- const tenants = await input.tenantStore.listTenants();
40933
- const converged = [];
40934
- for (const tenant of tenants) {
40935
- const result = await reconcileTenantTaskRuns({
40936
- tenantId: tenant.id,
40937
- actor: input.actor,
40938
- taskStore: input.taskStore,
40939
- lifecycle: input.lifecycle,
40940
- ...input.registry ? { registry: input.registry } : {},
40941
- ...input.include ? { include: input.include } : {}
40942
- });
40943
- converged.push(...result.converged);
40944
- }
40945
- return { converged };
40946
- }
40947
-
40948
41125
  // src/index.ts
40949
41126
  var Protocols = __toESM(require("@axiom-lattice/protocols"));
40950
41127
 
@@ -43144,65 +43321,32 @@ var widgetPlugin = {
43144
43321
  var import_langchain83 = require("langchain");
43145
43322
  var import_zod68 = require("zod");
43146
43323
  var import_langgraph16 = require("@langchain/langgraph");
43324
+ var import_protocols34 = require("@axiom-lattice/protocols");
43147
43325
 
43148
- // src/util/truncateForJson.ts
43149
- var TRUNCATION_MARKER = "...[truncated]";
43150
- function truncateString(value, cap) {
43151
- if (value.length <= cap) return value;
43152
- const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
43153
- return value.slice(0, budget) + TRUNCATION_MARKER;
43326
+ // src/services/taskWorkerRunConfig.ts
43327
+ var import_protocols33 = require("@axiom-lattice/protocols");
43328
+ function resolveWorkerRunScope(input) {
43329
+ const caller = (0, import_protocols33.resolveRunScope)(input.runConfig);
43330
+ return {
43331
+ workspaceId: (0, import_protocols33.firstNonEmptyString)(input.invocation.workspaceId) ?? caller.workspaceId,
43332
+ projectId: (0, import_protocols33.firstNonEmptyString)(input.invocation.projectId) ?? caller.projectId
43333
+ };
43154
43334
  }
43155
- function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
43156
- if (typeof value === "string") return truncateString(value, maxStringLength);
43157
- if (value === null || typeof value !== "object") return value;
43158
- if (depth >= maxDepth) return "[truncated:max-depth]";
43159
- if (seen.has(value)) return "[Circular]";
43160
- seen.add(value);
43161
- try {
43162
- if (value instanceof Date) return value.toISOString();
43163
- if (Array.isArray(value)) {
43164
- const limit2 = Math.min(value.length, maxEntries);
43165
- const output2 = [];
43166
- for (let index = 0; index < limit2; index += 1) {
43167
- output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
43168
- }
43169
- if (value.length > limit2) output2.push("[truncated:entries]");
43170
- return output2;
43171
- }
43172
- const record = value;
43173
- const output = {};
43174
- const keys = Object.keys(record);
43175
- const limit = Math.min(keys.length, maxEntries);
43176
- for (let index = 0; index < limit; index += 1) {
43177
- const key5 = keys[index];
43178
- output[truncateString(key5, maxStringLength)] = truncateValue(
43179
- record[key5],
43180
- depth + 1,
43181
- maxDepth,
43182
- maxEntries,
43183
- maxStringLength,
43184
- seen
43185
- );
43186
- }
43187
- if (keys.length > limit) output["[truncated]"] = true;
43188
- return output;
43189
- } finally {
43190
- seen.delete(value);
43335
+ function applyWorkerRunScope(runConfig, scope) {
43336
+ const next = { ...runConfig };
43337
+ if (scope.workspaceId !== void 0) {
43338
+ next.workspaceId = scope.workspaceId;
43339
+ next["x-workspace-id"] = scope.workspaceId;
43191
43340
  }
43192
- }
43193
- function truncateForJson(value, options = {}) {
43194
- return truncateValue(
43195
- value,
43196
- 0,
43197
- options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
43198
- options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
43199
- options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
43200
- /* @__PURE__ */ new WeakSet()
43201
- );
43341
+ if (scope.projectId !== void 0) {
43342
+ next.projectId = scope.projectId;
43343
+ next["x-project-id"] = scope.projectId;
43344
+ }
43345
+ return next;
43202
43346
  }
43203
43347
 
43204
43348
  // src/middlewares/taskMiddleware.ts
43205
- var import_protocols33 = require("@axiom-lattice/protocols");
43349
+ var import_protocols35 = require("@axiom-lattice/protocols");
43206
43350
 
43207
43351
  // src/middlewares/taskResponseSerialization.ts
43208
43352
  var TASK_RESPONSE_SCALAR_MAX_BYTES = 4096;
@@ -43670,7 +43814,7 @@ function classifyTaskAuthority(runConfig) {
43670
43814
  return delegatedTaskId ? { kind: "delegated", taskId: delegatedTaskId } : { kind: "ordinary" };
43671
43815
  }
43672
43816
  try {
43673
- const trusted = (0, import_protocols33.parseTrustedRunContext)(hasProjectTask ? { projectTask: runConfig.projectTask } : { projectRoom: runConfig.projectRoom });
43817
+ const trusted = (0, import_protocols35.parseTrustedRunContext)(hasProjectTask ? { projectTask: runConfig.projectTask } : { projectRoom: runConfig.projectRoom });
43674
43818
  return { kind: hasProjectTask ? "projectTask" : "projectRoom", trusted };
43675
43819
  } catch {
43676
43820
  return { kind: "invalid" };
@@ -44007,7 +44151,7 @@ function getTaskWorkItemStore() {
44007
44151
  return getStoreLattice("default", "taskWorkItem").store;
44008
44152
  }
44009
44153
  function getProjectTaskWorkItemStore() {
44010
- return (0, import_protocols33.requireProjectTaskWorkItemStore)(getTaskWorkItemStore());
44154
+ return (0, import_protocols35.requireProjectTaskWorkItemStore)(getTaskWorkItemStore());
44011
44155
  }
44012
44156
  function reviewInterruption(task) {
44013
44157
  const value = task.context?.interruption;
@@ -44057,7 +44201,7 @@ var manageTaskSchema = import_zod68.z.object({
44057
44201
  })).optional().describe("Structured belief reports required when an agent-owned task completes; existing keys update the belief owner's table, and a brand-new key must be declared with isNew: true"),
44058
44202
  content: import_zod68.z.string().optional().describe("Markdown content required for add_activity"),
44059
44203
  summary: import_zod68.z.string().optional().describe("Brief summary of the operation"),
44060
- executionResultId: import_zod68.z.string().refine(import_protocols33.isExecutionResultEventKey, {
44204
+ executionResultId: import_zod68.z.string().refine(import_protocols35.isExecutionResultEventKey, {
44061
44205
  message: "executionResultId must be the execution-result:<threadId> event key returned by task()"
44062
44206
  }).optional().describe(
44063
44207
  "Canonical ASCII `execution-result:<suffix>` event key returned by task(); the nonempty suffix allows only A-Z, a-z, 0-9, period, underscore, colon, and hyphen, and is not a database row ID"
@@ -44122,7 +44266,7 @@ async function getPendingExecutionResultIds(store, tenantId2, taskId) {
44122
44266
  order: "desc",
44123
44267
  limit: PENDING_EXECUTION_RESULT_LIMIT + 1
44124
44268
  });
44125
- const canonicalCandidates = candidates.slice(0, PENDING_EXECUTION_RESULT_LIMIT + 1).filter((item) => (0, import_protocols33.isExecutionResultEventKey)(item.eventKey));
44269
+ const canonicalCandidates = candidates.slice(0, PENDING_EXECUTION_RESULT_LIMIT + 1).filter((item) => (0, import_protocols35.isExecutionResultEventKey)(item.eventKey));
44126
44270
  const reconciliationRows = new Array(canonicalCandidates.length);
44127
44271
  let nextCandidateIndex = 0;
44128
44272
  let firstError;
@@ -44207,8 +44351,9 @@ function createTaskMiddleware(options = {}) {
44207
44351
  const trustedProject = authority.kind === "projectRoom" || authority.kind === "projectTask" ? authority.trusted : void 0;
44208
44352
  const trustedScope = trustedProject?.projectTask ?? trustedProject?.projectRoom;
44209
44353
  const tenantId2 = trustedScope?.tenantId ?? (rc.tenantId || "default");
44210
- const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
44211
- const projectId = trustedScope?.projectId ?? rc.projectId;
44354
+ const runScope = (0, import_protocols34.resolveRunScope)(rc);
44355
+ const workspaceId = trustedScope?.workspaceId ?? runScope.workspaceId;
44356
+ const projectId = trustedScope?.projectId ?? runScope.projectId;
44212
44357
  const revalidateCaller = async () => {
44213
44358
  if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
44214
44359
  try {
@@ -44768,8 +44913,8 @@ function createTaskMiddleware(options = {}) {
44768
44913
  let reconciliationMetadata = {};
44769
44914
  let descriptionMutated = false;
44770
44915
  if (isAgentTask && input.description !== void 0 && !valuesEqual(input.description, existing.description)) {
44771
- const oldBelief = (0, import_protocols33.parseTaskBeliefState)(existing.description ?? "");
44772
- const newBelief = (0, import_protocols33.parseTaskBeliefState)(input.description);
44916
+ const oldBelief = (0, import_protocols35.parseTaskBeliefState)(existing.description ?? "");
44917
+ const newBelief = (0, import_protocols35.parseTaskBeliefState)(input.description);
44773
44918
  const hasBeliefState = oldBelief.success || newBelief.success;
44774
44919
  if (hasBeliefState) {
44775
44920
  await validateExecutionResult();
@@ -45437,15 +45582,16 @@ function createTaskMiddleware(options = {}) {
45437
45582
  assistant_id: invocation.agentId,
45438
45583
  thread_id: invocation.threadId,
45439
45584
  input: { message: invocation.message },
45440
- runConfig: {
45441
- ...rc,
45442
- assistant_id: invocation.agentId,
45443
- thread_id: invocation.threadId,
45444
- taskId: invocation.taskId,
45445
- tenantId: invocation.tenantId,
45446
- workspaceId: invocation.workspaceId,
45447
- projectId: invocation.projectId
45448
- }
45585
+ runConfig: applyWorkerRunScope(
45586
+ {
45587
+ ...rc,
45588
+ assistant_id: invocation.agentId,
45589
+ thread_id: invocation.threadId,
45590
+ taskId: invocation.taskId,
45591
+ tenantId: invocation.tenantId
45592
+ },
45593
+ resolveWorkerRunScope({ invocation, runConfig: rc })
45594
+ )
45449
45595
  });
45450
45596
  const finalState = workerResult?.finalState;
45451
45597
  return boundedWorkerObservation(finalState, void 0);
@@ -45460,7 +45606,7 @@ function createTaskMiddleware(options = {}) {
45460
45606
  agentId,
45461
45607
  actor,
45462
45608
  callerThreadId: rc.thread_id,
45463
- ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
45609
+ ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : rc.assistant_id ? { callerAssistantId: rc.assistant_id } : {}
45464
45610
  }));
45465
45611
  };
45466
45612
  return (0, import_langchain83.createMiddleware)({
@@ -45520,7 +45666,14 @@ function createTaskMiddleware(options = {}) {
45520
45666
  task,
45521
45667
  actor: getRuntimeActor2(rc) ?? "system",
45522
45668
  ...threadId ? { threadId } : {},
45523
- outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
45669
+ // A run that ended without its own lifecycle transition is a mechanical
45670
+ // failure, NOT HITL. Human-in-the-loop pauses arrive as GraphInterrupt
45671
+ // and never reach afterAgent.
45672
+ outcome: {
45673
+ kind: "failed",
45674
+ lifecycleHandled: false,
45675
+ error: "Run ended without a task lifecycle transition"
45676
+ }
45524
45677
  });
45525
45678
  }
45526
45679
  taskRunRegistry.unregister(taskId);
@@ -46248,7 +46401,7 @@ function createParseDocumentTool({
46248
46401
  }
46249
46402
 
46250
46403
  // src/middlewares/documentParserMiddleware.ts
46251
- var import_protocols34 = require("@axiom-lattice/protocols");
46404
+ var import_protocols36 = require("@axiom-lattice/protocols");
46252
46405
 
46253
46406
  // src/middlewares/documentBenchmarkWorkflow.ts
46254
46407
  var DOCUMENT_PARSER_BENCHMARK_YAML = `name: document-parser-benchmark
@@ -46790,7 +46943,7 @@ var documentParserPlugin = {
46790
46943
  agents: {
46791
46944
  "document-parser": {
46792
46945
  key: "document-parser",
46793
- type: import_protocols34.AgentType.DEEP_AGENT,
46946
+ type: import_protocols36.AgentType.DEEP_AGENT,
46794
46947
  name: "Document Parser",
46795
46948
  description: "Parse documents (pdf, docx, images, spreadsheets) into clean Markdown. Defaults to local MarkItDown; escalates to remote engines only when quality or format needs it; runs engine benchmarking only on explicit request.",
46796
46949
  prompt: DOCUMENT_PARSER_SYSTEM_PROMPT,
@@ -46840,7 +46993,7 @@ var documentParserPlugin = {
46840
46993
  },
46841
46994
  "document-parser-benchmark": {
46842
46995
  key: "document-parser-benchmark",
46843
- type: import_protocols34.AgentType.WORKFLOW,
46996
+ type: import_protocols36.AgentType.WORKFLOW,
46844
46997
  name: "Document Parser Benchmark",
46845
46998
  description: "Benchmark document parsing engines. Parses a document with 5 engines in parallel, scores results, and produces a ranking report. Use this when you need to evaluate which parsing engine works best for a given document.",
46846
46999
  prompt: "Benchmark document parsing engines: parse with 5 engines, score, and rank results.",
@@ -46877,7 +47030,7 @@ var documentParserPlugin = {
46877
47030
 
46878
47031
  // src/middlewares/projectRoomMiddleware.ts
46879
47032
  var import_crypto10 = require("crypto");
46880
- var import_protocols35 = require("@axiom-lattice/protocols");
47033
+ var import_protocols37 = require("@axiom-lattice/protocols");
46881
47034
  var import_langchain87 = require("langchain");
46882
47035
  var import_zod70 = require("zod");
46883
47036
  var PROJECT_ROOM_CONTEXT_REQUIRED = "PROJECT_ROOM_CONTEXT_REQUIRED";
@@ -46907,7 +47060,7 @@ function ownDataValue2(record, key5) {
46907
47060
  if (typeof record !== "object" || record === null || Array.isArray(record)) return void 0;
46908
47061
  try {
46909
47062
  const descriptor = Object.getOwnPropertyDescriptor(record, key5);
46910
- return (0, import_protocols35.descriptorDataValue)(descriptor)?.value;
47063
+ return (0, import_protocols37.descriptorDataValue)(descriptor)?.value;
46911
47064
  } catch {
46912
47065
  return void 0;
46913
47066
  }
@@ -46917,14 +47070,14 @@ function readTrustedRoomScope(config) {
46917
47070
  const runConfig = ownDataValue2(configurable, "runConfig");
46918
47071
  const projectRoom = ownDataValue2(runConfig, "projectRoom");
46919
47072
  try {
46920
- return (0, import_protocols35.parseTrustedRunContext)({ projectRoom }).projectRoom;
47073
+ return (0, import_protocols37.parseTrustedRunContext)({ projectRoom }).projectRoom;
46921
47074
  } catch {
46922
47075
  return void 0;
46923
47076
  }
46924
47077
  }
46925
47078
  function exactValues2(value, required, optional = []) {
46926
47079
  try {
46927
- return (0, import_protocols35.snapshotExactRecord)(value, required, optional);
47080
+ return (0, import_protocols37.snapshotExactRecord)(value, required, optional);
46928
47081
  } catch {
46929
47082
  return void 0;
46930
47083
  }
@@ -46960,7 +47113,7 @@ function snapshotMembership3(value) {
46960
47113
  return { ...values, joinedAt, updatedAt };
46961
47114
  }
46962
47115
  function snapshotRows(value) {
46963
- return (0, import_protocols35.snapshotExactArray)(value) ?? [];
47116
+ return (0, import_protocols37.snapshotExactArray)(value) ?? [];
46964
47117
  }
46965
47118
  async function hasActiveCurrentMembership(scope) {
46966
47119
  const memberships = getStoreLattice("default", "projectBotMembership").store;
@@ -47047,7 +47200,7 @@ var projectRoomPlugin = {
47047
47200
  // src/middlewares/sandboxPluginsMiddleware.ts
47048
47201
  var import_langchain88 = require("langchain");
47049
47202
  var import_zod71 = require("zod");
47050
- var import_protocols36 = require("@axiom-lattice/protocols");
47203
+ var import_protocols38 = require("@axiom-lattice/protocols");
47051
47204
 
47052
47205
  // src/middlewares/sandboxPluginsSkills.ts
47053
47206
  var PLUGIN_JSON_TEMPLATE = `{
@@ -47797,7 +47950,7 @@ var sandboxPluginsPlugin = {
47797
47950
  key: "plugin-builder",
47798
47951
  name: "Plugin Builder",
47799
47952
  description: "Author and manage tenant plugins in the shared sandbox: clarify goal, inputs/outputs, credentials, and whether a UI is needed; then write the manifest and JS handlers, add an optional HTML MCP App UI, and validate/test with the manage_plugin tool.",
47800
- type: import_protocols36.AgentType.DEEP_AGENT,
47953
+ type: import_protocols38.AgentType.DEEP_AGENT,
47801
47954
  prompt: PLUGIN_BUILDER_PROMPT,
47802
47955
  middleware: [
47803
47956
  {
@@ -48672,6 +48825,7 @@ registerBuiltinPlugins();
48672
48825
  generateDirectHumanProjectId,
48673
48826
  generateToken,
48674
48827
  getAgentClient,
48828
+ getAgentClientAsync,
48675
48829
  getAgentConfig,
48676
48830
  getAllAgentConfigs,
48677
48831
  getAllBuiltInSkillMetas,