@axiom-lattice/core 6.1.0 → 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.mjs CHANGED
@@ -11551,8 +11551,8 @@ function readLoopBreakerConfig(env = process.env) {
11551
11551
  return Math.floor(parsed);
11552
11552
  };
11553
11553
  return {
11554
- repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 3),
11555
- repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 5),
11554
+ repeatWarn: parse(env.AGENT_REPEATED_TOOL_CALL_WARN, 20),
11555
+ repeatStop: parse(env.AGENT_REPEATED_TOOL_CALL_STOP, 25),
11556
11556
  runLimit: parse(env.AGENT_TOOL_CALL_RUN_LIMIT, 300),
11557
11557
  skillRunLimit: parse(env.AGENT_SKILL_CALL_RUN_LIMIT, 8)
11558
11558
  };
@@ -11575,9 +11575,9 @@ var BREAKER_STATE_SCHEMA = z41.object({
11575
11575
  repeatedToolCallMemberSignatures: z41.array(z41.string()).default([])
11576
11576
  });
11577
11577
  function createRepeatedToolCallBreakerMiddleware(options = {}) {
11578
- const rawWarn = options.warnThreshold ?? 3;
11578
+ const rawWarn = options.warnThreshold ?? 20;
11579
11579
  const warnThreshold = rawWarn > 0 ? Math.max(2, rawWarn) : 0;
11580
- const stopThreshold = Math.max(1, options.stopThreshold ?? 5);
11580
+ const stopThreshold = Math.max(1, options.stopThreshold ?? 25);
11581
11581
  return createMiddleware10({
11582
11582
  name: "RepeatedToolCallBreaker",
11583
11583
  stateSchema: BREAKER_STATE_SCHEMA,
@@ -15404,6 +15404,324 @@ function createAgentWorkerGraph() {
15404
15404
  }
15405
15405
  var agentWorkerGraph = createAgentWorkerGraph();
15406
15406
 
15407
+ // src/util/toJsonSafeValue.ts
15408
+ var CIRCULAR_VALUE = "[Circular]";
15409
+ var REPEATED_VALUE = "[Repeated]";
15410
+ var arrayFrom = Array.from.bind(Array);
15411
+ var arrayIsArray = Array.isArray.bind(Array);
15412
+ var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
15413
+ var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
15414
+ var objectCreate = Object.create.bind(Object);
15415
+ var objectDefineProperty = Object.defineProperty.bind(Object);
15416
+ var objectIs = Object.is.bind(Object);
15417
+ var reflectGet = Reflect.get.bind(Reflect);
15418
+ var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
15419
+ var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
15420
+ var stringifyJson = JSON.stringify.bind(JSON);
15421
+ var numberIsFinite = Number.isFinite.bind(Number);
15422
+ var numberIsNaN = Number.isNaN.bind(Number);
15423
+ var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
15424
+ var mathMax = Math.max.bind(Math);
15425
+ var dateConstructor = Date;
15426
+ var datePrototype = dateConstructor.prototype;
15427
+ var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
15428
+ var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
15429
+ var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
15430
+ var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
15431
+ var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
15432
+ var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
15433
+ var WeakMapConstructor = WeakMap;
15434
+ var utf8Encoder = new TextEncoder();
15435
+ var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
15436
+ var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
15437
+ var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
15438
+ if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
15439
+ var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
15440
+ var JSON_SAFE_MAX_DEPTH = 32;
15441
+ var JSON_SAFE_MAX_NODES = 1e4;
15442
+ var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
15443
+ var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
15444
+ var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
15445
+ var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
15446
+ var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
15447
+ var JsonSafeValueError = class extends Error {
15448
+ /**
15449
+ * Create a bounded normalization error.
15450
+ *
15451
+ * @param code Stable normalization failure code.
15452
+ * @param message Human-readable bounded failure description.
15453
+ */
15454
+ constructor(code, message) {
15455
+ super(message);
15456
+ objectDefineProperty(this, "name", {
15457
+ value: "JsonSafeValueError",
15458
+ writable: true,
15459
+ configurable: true
15460
+ });
15461
+ objectDefineProperty(this, "code", {
15462
+ value: code,
15463
+ writable: true,
15464
+ configurable: true
15465
+ });
15466
+ }
15467
+ };
15468
+ function fail(code, message) {
15469
+ throw new JsonSafeValueError(code, message);
15470
+ }
15471
+ function propertyAccess(operation, path8) {
15472
+ try {
15473
+ return operation();
15474
+ } catch {
15475
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
15476
+ }
15477
+ }
15478
+ function serializedStringBytes(value) {
15479
+ if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
15480
+ fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
15481
+ }
15482
+ return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
15483
+ }
15484
+ function validatePropertyKey(key5) {
15485
+ if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
15486
+ fail(
15487
+ "MAX_STRING_LENGTH",
15488
+ `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
15489
+ );
15490
+ }
15491
+ }
15492
+ function chargePropertyKey(state, key5) {
15493
+ state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
15494
+ if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
15495
+ fail(
15496
+ "MAX_PROPERTY_KEY_BYTES",
15497
+ `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
15498
+ );
15499
+ }
15500
+ }
15501
+ function chargeBytes(state, bytes) {
15502
+ state.serializedBytes += bytes;
15503
+ if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
15504
+ fail(
15505
+ "MAX_SERIALIZED_BYTES",
15506
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
15507
+ );
15508
+ }
15509
+ }
15510
+ function chargeString(state, value) {
15511
+ chargeBytes(state, serializedStringBytes(value));
15512
+ }
15513
+ function objectPropertyPath(path8, key5) {
15514
+ const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
15515
+ return `${path8}[${stringifyJson(boundedKey)}]`;
15516
+ }
15517
+ function convertJsonValue(value, state, depth, inArray, path8) {
15518
+ state.nodes += 1;
15519
+ if (state.nodes > JSON_SAFE_MAX_NODES) {
15520
+ fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
15521
+ }
15522
+ if (typeof value === "string") {
15523
+ chargeString(state, value);
15524
+ return value;
15525
+ }
15526
+ if (value === null) {
15527
+ chargeBytes(state, 4);
15528
+ return value;
15529
+ }
15530
+ if (typeof value === "boolean") {
15531
+ chargeBytes(state, value ? 4 : 5);
15532
+ return value;
15533
+ }
15534
+ if (typeof value === "number") {
15535
+ const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
15536
+ chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
15537
+ return normalized;
15538
+ }
15539
+ if (typeof value === "bigint") {
15540
+ const normalized = bigintToString(value);
15541
+ chargeString(state, normalized);
15542
+ return normalized;
15543
+ }
15544
+ if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
15545
+ if (inArray) chargeBytes(state, 4);
15546
+ return inArray ? null : void 0;
15547
+ }
15548
+ const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
15549
+ if (isDate) {
15550
+ const time = propertyAccess(() => dateGetTime(value), path8);
15551
+ if (numberIsNaN(time)) {
15552
+ chargeBytes(state, 4);
15553
+ return null;
15554
+ }
15555
+ const normalized = propertyAccess(() => dateToISOString(value), path8);
15556
+ chargeString(state, normalized);
15557
+ return normalized;
15558
+ }
15559
+ if (depth > JSON_SAFE_MAX_DEPTH) {
15560
+ fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
15561
+ }
15562
+ const referenceState = weakMapGet(state.references, value);
15563
+ if (referenceState === "visiting") {
15564
+ chargeString(state, CIRCULAR_VALUE);
15565
+ return CIRCULAR_VALUE;
15566
+ }
15567
+ if (referenceState === "visited") {
15568
+ chargeString(state, REPEATED_VALUE);
15569
+ return REPEATED_VALUE;
15570
+ }
15571
+ weakMapSet(state.references, value, "visiting");
15572
+ if (propertyAccess(() => arrayIsArray(value), path8)) {
15573
+ const arrayValue = value;
15574
+ const length = propertyAccess(
15575
+ () => arrayValue.length,
15576
+ path8
15577
+ );
15578
+ if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
15579
+ fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
15580
+ }
15581
+ if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
15582
+ fail(
15583
+ "COLLECTION_TOO_LARGE",
15584
+ `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
15585
+ );
15586
+ }
15587
+ chargeBytes(state, 2 + mathMax(0, length - 1));
15588
+ const result2 = arrayFrom({ length }, (_, index) => {
15589
+ const entryPath = `${path8}[${index}]`;
15590
+ const hasEntry = propertyAccess(
15591
+ () => hasOwnProperty(arrayValue, index),
15592
+ entryPath
15593
+ );
15594
+ if (!hasEntry) {
15595
+ chargeBytes(state, 4);
15596
+ return null;
15597
+ }
15598
+ const entry = propertyAccess(() => arrayValue[index], entryPath);
15599
+ return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
15600
+ });
15601
+ objectDefineProperty(result2, "toJSON", {
15602
+ value: void 0,
15603
+ configurable: true,
15604
+ writable: true
15605
+ });
15606
+ weakMapSet(state.references, value, "visited");
15607
+ return result2;
15608
+ }
15609
+ const keys = propertyAccess(() => reflectOwnKeys(value), path8);
15610
+ if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
15611
+ fail(
15612
+ "COLLECTION_TOO_LARGE",
15613
+ `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
15614
+ );
15615
+ }
15616
+ for (let index = 0; index < keys.length; index += 1) {
15617
+ const key5 = keys[index];
15618
+ if (typeof key5 !== "string") continue;
15619
+ validatePropertyKey(key5);
15620
+ chargePropertyKey(state, key5);
15621
+ }
15622
+ chargeBytes(state, 2);
15623
+ const result = objectCreate(null);
15624
+ let emittedProperties = 0;
15625
+ for (let index = 0; index < keys.length; index += 1) {
15626
+ const key5 = keys[index];
15627
+ const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
15628
+ const descriptor = propertyAccess(
15629
+ () => reflectGetOwnPropertyDescriptor(value, key5),
15630
+ entryPath
15631
+ );
15632
+ if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
15633
+ const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
15634
+ const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
15635
+ if (converted !== void 0) {
15636
+ chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
15637
+ propertyAccess(() => objectDefineProperty(result, key5, {
15638
+ value: converted,
15639
+ enumerable: true,
15640
+ configurable: true,
15641
+ writable: true
15642
+ }), entryPath);
15643
+ emittedProperties += 1;
15644
+ }
15645
+ }
15646
+ weakMapSet(state.references, value, "visited");
15647
+ return result;
15648
+ }
15649
+ function toJsonSafeValue(value) {
15650
+ const state = {
15651
+ nodes: 0,
15652
+ propertyKeyBytes: 0,
15653
+ serializedBytes: 0,
15654
+ references: new WeakMapConstructor()
15655
+ };
15656
+ const converted = convertJsonValue(value, state, 0, false, "$");
15657
+ if (converted === void 0) chargeBytes(state, 4);
15658
+ const result = converted ?? null;
15659
+ const serialized = propertyAccess(() => stringifyJson(result), "$");
15660
+ if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
15661
+ fail(
15662
+ "MAX_SERIALIZED_BYTES",
15663
+ `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
15664
+ );
15665
+ }
15666
+ return result;
15667
+ }
15668
+
15669
+ // src/util/truncateForJson.ts
15670
+ var TRUNCATION_MARKER = "...[truncated]";
15671
+ function truncateString(value, cap) {
15672
+ if (value.length <= cap) return value;
15673
+ const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
15674
+ return value.slice(0, budget) + TRUNCATION_MARKER;
15675
+ }
15676
+ function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
15677
+ if (typeof value === "string") return truncateString(value, maxStringLength);
15678
+ if (value === null || typeof value !== "object") return value;
15679
+ if (depth >= maxDepth) return "[truncated:max-depth]";
15680
+ if (seen.has(value)) return "[Circular]";
15681
+ seen.add(value);
15682
+ try {
15683
+ if (value instanceof Date) return value.toISOString();
15684
+ if (Array.isArray(value)) {
15685
+ const limit2 = Math.min(value.length, maxEntries);
15686
+ const output2 = [];
15687
+ for (let index = 0; index < limit2; index += 1) {
15688
+ output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
15689
+ }
15690
+ if (value.length > limit2) output2.push("[truncated:entries]");
15691
+ return output2;
15692
+ }
15693
+ const record = value;
15694
+ const output = {};
15695
+ const keys = Object.keys(record);
15696
+ const limit = Math.min(keys.length, maxEntries);
15697
+ for (let index = 0; index < limit; index += 1) {
15698
+ const key5 = keys[index];
15699
+ output[truncateString(key5, maxStringLength)] = truncateValue(
15700
+ record[key5],
15701
+ depth + 1,
15702
+ maxDepth,
15703
+ maxEntries,
15704
+ maxStringLength,
15705
+ seen
15706
+ );
15707
+ }
15708
+ if (keys.length > limit) output["[truncated]"] = true;
15709
+ return output;
15710
+ } finally {
15711
+ seen.delete(value);
15712
+ }
15713
+ }
15714
+ function truncateForJson(value, options = {}) {
15715
+ return truncateValue(
15716
+ value,
15717
+ 0,
15718
+ options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
15719
+ options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
15720
+ options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
15721
+ /* @__PURE__ */ new WeakSet()
15722
+ );
15723
+ }
15724
+
15407
15725
  // src/services/Agent.ts
15408
15726
  import { descriptorDataValue } from "@axiom-lattice/protocols";
15409
15727
  import { Command as Command2 } from "@langchain/langgraph";
@@ -16945,6 +17263,27 @@ function statusFromSnapshot(state) {
16945
17263
  if (Array.isArray(state.next) && state.next.length > 0) return "busy" /* BUSY */;
16946
17264
  return "idle" /* IDLE */;
16947
17265
  }
17266
+ var MAX_EXECUTION_ERROR_LENGTH = 2e3;
17267
+ function executionErrorFromSnapshot(state) {
17268
+ if (!isPlainRecord(state) || !Array.isArray(state.tasks)) return void 0;
17269
+ for (const task of state.tasks) {
17270
+ if (!isPlainRecord(task) || task.error === void 0 || task.error === null) continue;
17271
+ const raw = task.error;
17272
+ const message = typeof raw === "string" ? raw : raw instanceof Error ? raw.message : isPlainRecord(raw) && typeof raw.message === "string" ? raw.message : (() => {
17273
+ try {
17274
+ return JSON.stringify(raw);
17275
+ } catch {
17276
+ return String(raw);
17277
+ }
17278
+ })();
17279
+ if (typeof message !== "string") continue;
17280
+ const trimmed = message.trim();
17281
+ if (trimmed.length === 0) continue;
17282
+ const bounded = truncateForJson(trimmed, { maxStringLength: MAX_EXECUTION_ERROR_LENGTH });
17283
+ if (typeof bounded === "string" && bounded.length > 0) return bounded;
17284
+ }
17285
+ return void 0;
17286
+ }
16948
17287
  function freshReply(state, preRunMarker, inputMessageId, consumedInputMessageIds) {
16949
17288
  const output = finalAiMessageMarker(state);
16950
17289
  if (output?.text === void 0 || output.index <= (preRunMarker?.index ?? -1) || output.totalMessageCount <= (preRunMarker?.totalMessageCount ?? 0)) return void 0;
@@ -17224,7 +17563,7 @@ var Agent = class {
17224
17563
  state
17225
17564
  });
17226
17565
  } else if (runStatus === "error" /* ERROR */) {
17227
- const failureReason = "Agent execution ended in an error state";
17566
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
17228
17567
  this.addChunk({
17229
17568
  type: "message_failed",
17230
17569
  data: { id: humanContent.id, content: failureReason }
@@ -17337,7 +17676,7 @@ var Agent = class {
17337
17676
  }
17338
17677
  if (runStatus === "busy" /* BUSY */) return;
17339
17678
  if (runStatus === "error" /* ERROR */) {
17340
- const failureReason = "Agent execution ended in an error state";
17679
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
17341
17680
  for (const p of collectPendings) {
17342
17681
  const messageId = p.content.id;
17343
17682
  this.addChunk({
@@ -17438,7 +17777,7 @@ var Agent = class {
17438
17777
  });
17439
17778
  if (p.execution_mode === "followup") return;
17440
17779
  } else if (runStatus === "error" /* ERROR */) {
17441
- const failureReason = "Agent execution ended in an error state";
17780
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
17442
17781
  this.addChunk({
17443
17782
  type: "message_failed",
17444
17783
  data: { id: humanContent.id, content: failureReason }
@@ -17745,12 +18084,17 @@ var Agent = class {
17745
18084
  capabilityRuntimeRevision: capabilityRuntime.revision,
17746
18085
  tenantId: this.tenant_id,
17747
18086
  workspaceId: this.workspace_id,
17748
- projectId: this.project_id,
18087
+ // The propagated project scope must not fabricate `"default"`:
18088
+ // `queue_project_id` is `null` when the run had no project, so an unscoped
18089
+ // run stays unscoped instead of later querying a project that may not
18090
+ // exist. An explicitly passed `"default"` is a real project for some
18091
+ // tenants and is preserved.
18092
+ projectId: this.queue_project_id ?? void 0,
17749
18093
  assistant_id: this.assistant_id,
17750
18094
  thread_id: this.thread_id,
17751
18095
  "x-tenant-id": this.tenant_id,
17752
18096
  "x-workspace-id": this.workspace_id,
17753
- "x-project-id": this.project_id,
18097
+ "x-project-id": this.queue_project_id ?? void 0,
17754
18098
  "x-thread-id": this.thread_id,
17755
18099
  "x-assistant-id": this.assistant_id
17756
18100
  };
@@ -18095,7 +18439,15 @@ var Agent = class {
18095
18439
  if (!accepted) throw new Error(`Queue is full (max ${maxSize} messages)`);
18096
18440
  if (useMode === "steer" /* STEER */ && !queueMessage.command) {
18097
18441
  this.stopQueueProcessor();
18098
- await store.resetProcessingToPending(this.thread_id, this.queueScope());
18442
+ let runStatus;
18443
+ try {
18444
+ runStatus = await this.getRunStatus();
18445
+ } catch {
18446
+ runStatus = void 0;
18447
+ }
18448
+ if (runStatus !== "interrupted" /* INTERRUPTED */) {
18449
+ await store.resetProcessingToPending(this.thread_id, this.queueScope());
18450
+ }
18099
18451
  console.log(`[Agent] STEER mode: stopped current processing, reset queue, message ${messageId} will execute next`);
18100
18452
  }
18101
18453
  } else {
@@ -18411,7 +18763,7 @@ var Agent = class {
18411
18763
  }
18412
18764
  } else if (resumedStatus === "error" /* ERROR */) {
18413
18765
  this.clearRecoveryBlock();
18414
- const failureReason = "Agent execution ended in an error state";
18766
+ const failureReason = executionErrorFromSnapshot(state) ?? "Agent execution ended in an error state";
18415
18767
  for (const msg of processingMessages) {
18416
18768
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
18417
18769
  this.publish("message:failed", {
@@ -18447,7 +18799,7 @@ var Agent = class {
18447
18799
  } else if (runStatus === "error" /* ERROR */) {
18448
18800
  this.processingExecutionContext(processingMessages);
18449
18801
  this.clearRecoveryBlock();
18450
- const failureReason = "Agent execution ended in an error state";
18802
+ const failureReason = executionErrorFromSnapshot(preRunState) ?? "Agent execution ended in an error state";
18451
18803
  for (const msg of processingMessages) {
18452
18804
  this.addChunk({ type: "message_failed", data: { id: msg.id, content: failureReason } });
18453
18805
  this.publish("message:failed", {
@@ -18593,8 +18945,19 @@ var AgentInstanceManager = class _AgentInstanceManager {
18593
18945
  }
18594
18946
  return _AgentInstanceManager._instance;
18595
18947
  }
18948
+ /**
18949
+ * A thread's identity is `(tenant_id, assistant_id, thread_id)`.
18950
+ *
18951
+ * Workspace/project are execution scope chosen when the instance is created,
18952
+ * not part of identity: including them let the same thread exist as several
18953
+ * Agents when callers defaulted optional workspace/project headers
18954
+ * differently (e.g. `createRun` passing `undefined` while `abort` defaulted
18955
+ * to `"default"`), so control-plane calls could address a different instance
18956
+ * than the one running. `undefined`/`null` normalize to `""`; ids are assumed
18957
+ * not to contain `:` (UUID-shaped in practice).
18958
+ */
18596
18959
  getKey(params) {
18597
- return `${params.tenant_id}:${params.assistant_id}:${params.thread_id}:${params.workspace_id}:${params.project_id}`;
18960
+ return [params.tenant_id, params.assistant_id, params.thread_id].map((value) => value ?? "").join(":");
18598
18961
  }
18599
18962
  /**
18600
18963
  * Get or create Agent instance for a thread
@@ -18608,6 +18971,24 @@ var AgentInstanceManager = class _AgentInstanceManager {
18608
18971
  }
18609
18972
  return this.agents.get(key5);
18610
18973
  }
18974
+ /**
18975
+ * Get the managed Agent for a thread WITHOUT creating or registering one.
18976
+ *
18977
+ * Read-only control-plane callers (state, memory, inbox) must not be the first
18978
+ * to establish a thread's execution scope: since identity is
18979
+ * `(tenant_id, assistant_id, thread_id)`, whichever caller reaches
18980
+ * {@link getAgent} first fixes the instance's workspace/project for its whole
18981
+ * lifetime, and a later trusted dispatch on that thread would then fail
18982
+ * trusted-scope validation. This returns the existing managed instance when
18983
+ * present, otherwise a transient unregistered Agent that is sufficient for
18984
+ * state reads and disappears with the request.
18985
+ *
18986
+ * @param params - Thread identity; scope is only used for the transient Agent.
18987
+ * @returns The managed instance if any, else an unregistered read-only Agent.
18988
+ */
18989
+ getAgentForRead(params) {
18990
+ return this.agents.get(this.getKey(params)) ?? new Agent(params);
18991
+ }
18611
18992
  /**
18612
18993
  * Check if an agent instance exists for the thread
18613
18994
  */
@@ -18643,55 +19024,6 @@ var AgentInstanceManager = class _AgentInstanceManager {
18643
19024
  });
18644
19025
  this.agents.clear();
18645
19026
  }
18646
- /**
18647
- * Restore agent instances for threads with pending messages after server restart
18648
- * Queries the message queue store for threads with pending/processing messages
18649
- * and recreates agent instances to resume processing
18650
- */
18651
- async restore() {
18652
- const stats = { restored: 0, errors: 0 };
18653
- try {
18654
- const queueStoreLattice = storeLatticeManager.getStoreLattice("default", "threadMessageQueue");
18655
- const queueStore = queueStoreLattice.store;
18656
- const threadsWithPending = await queueStore.getThreadsWithPendingMessages();
18657
- if (threadsWithPending.length === 0) {
18658
- console.log("[AgentInstanceManager] No threads with pending messages found");
18659
- return stats;
18660
- }
18661
- console.log(`[AgentInstanceManager] Found ${threadsWithPending.length} threads with pending messages, restoring...`);
18662
- for (const threadInfo of threadsWithPending) {
18663
- try {
18664
- await this.restoreThread(threadInfo);
18665
- stats.restored++;
18666
- } catch (error) {
18667
- console.error(`[AgentInstanceManager] Failed to restore thread ${threadInfo.threadId}:`, error);
18668
- stats.errors++;
18669
- }
18670
- }
18671
- console.log(`[AgentInstanceManager] Restore complete: ${stats.restored} restored, ${stats.errors} errors`);
18672
- return stats;
18673
- } catch (error) {
18674
- console.error("[AgentInstanceManager] Restore failed:", error);
18675
- throw error;
18676
- }
18677
- }
18678
- /**
18679
- * Restore a single thread
18680
- * Delegates actual recovery logic to Agent.resumeTask()
18681
- */
18682
- async restoreThread(threadInfo) {
18683
- const { tenantId: tenantId2, assistantId, threadId, workspaceId, projectId } = threadInfo;
18684
- const threadParams = {
18685
- tenant_id: tenantId2,
18686
- assistant_id: assistantId,
18687
- thread_id: threadId,
18688
- workspace_id: workspaceId,
18689
- project_id: projectId
18690
- };
18691
- const agent = this.getAgent(threadParams);
18692
- await agent.resumeTask();
18693
- console.log(`[AgentInstanceManager] Restored thread ${threadId}`);
18694
- }
18695
19027
  };
18696
19028
  var agentInstanceManager = AgentInstanceManager.getInstance();
18697
19029
 
@@ -35687,6 +36019,8 @@ function buildParentBeliefActivity(input) {
35687
36019
  }
35688
36020
 
35689
36021
  // src/services/TaskLifecycleService.ts
36022
+ var WORK_ITEM_WRITE_ATTEMPTS = 3;
36023
+ var WORK_ITEM_WRITE_RETRY_DELAYS_MS = [20, 50];
35690
36024
  var RETRYABLE_LIFECYCLE_CODES = /* @__PURE__ */ new Set([
35691
36025
  "TASK_STATUS_CONFLICT",
35692
36026
  "TASK_STORE_WRITE_FAILED",
@@ -36053,7 +36387,8 @@ var TaskLifecycleService = class {
36053
36387
  const resumeKey = this.resumeEventKey(task);
36054
36388
  const audit = { eventKey: resumeKey, previousInterruption };
36055
36389
  const context = withLifecycleAudit(task.context, "lifecycle_resume_audit", audit);
36056
- if (input.threadId && !task.context?.thread_id) context.thread_id = input.threadId;
36390
+ if (input.threadId) context.thread_id = input.threadId;
36391
+ if (input.runId) context.run_id = input.runId;
36057
36392
  const updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
36058
36393
  input.tenantId,
36059
36394
  input.taskId,
@@ -36150,7 +36485,13 @@ var TaskLifecycleService = class {
36150
36485
  if (task.status !== "pending") {
36151
36486
  return { ...failure2("TASK_STATUS_CONFLICT", "Task cannot start."), transitioned: false };
36152
36487
  }
36153
- const context = { ...task.context ?? {}, ...input.threadId ? { thread_id: input.threadId } : {} };
36488
+ const context = {
36489
+ ...task.context ?? {},
36490
+ ...input.threadId ? { thread_id: input.threadId } : {},
36491
+ ...input.runId ? { run_id: input.runId } : {},
36492
+ ...input.callerThreadId ? { caller_thread_id: input.callerThreadId } : {},
36493
+ ...input.callerAssistantId ? { caller_assistant_id: input.callerAssistantId } : {}
36494
+ };
36154
36495
  let updated;
36155
36496
  try {
36156
36497
  updated = await this.deps.taskStore.updateIfStatusAndUpdatedAt(
@@ -36226,7 +36567,9 @@ var TaskLifecycleService = class {
36226
36567
  expectedStatuses: ["failed"],
36227
36568
  updates: { status: "in_progress", failureReason: null },
36228
36569
  summary: "Task retried",
36229
- detail: { previousStatus: "failed" }
36570
+ detail: { previousStatus: "failed" },
36571
+ // A retry dispatches a new run thread; replace a stale persisted link.
36572
+ replaceThread: true
36230
36573
  });
36231
36574
  }
36232
36575
  /**
@@ -37712,7 +38055,9 @@ var TaskLifecycleService = class {
37712
38055
  }
37713
38056
  if (!input.expectedStatuses.includes(task.status)) return failure2("TASK_STATUS_CONFLICT", "Task status cannot make this transition.");
37714
38057
  const clearedContext = clearInterruptionContext(task.context);
37715
- const withThread = input.threadId && task.context?.thread_id === void 0 ? { ...clearedContext ?? {}, thread_id: input.threadId } : clearedContext;
38058
+ const threadInput = input.threadId && (input.replaceThread || task.context?.thread_id === void 0) ? { thread_id: input.threadId } : {};
38059
+ const runInput = input.runId ? { run_id: input.runId } : {};
38060
+ const withThread = Object.keys(threadInput).length > 0 || Object.keys(runInput).length > 0 ? { ...clearedContext ?? {}, ...threadInput, ...runInput } : clearedContext;
37716
38061
  const updates = { ...input.updates, context: withThread };
37717
38062
  let updated;
37718
38063
  try {
@@ -37750,6 +38095,31 @@ var TaskLifecycleService = class {
37750
38095
  statusEventKey(task, status, detail) {
37751
38096
  return `task-lifecycle:${task.id}:${status}:${task.updatedAt.toISOString()}:${sha256(detail)}`;
37752
38097
  }
38098
+ /**
38099
+ * Writes a lifecycle work-item event, retrying transient store failures.
38100
+ *
38101
+ * @param request Event request passed through to the work-item store.
38102
+ * @returns The persisted or pre-existing work item.
38103
+ * @remarks The write is idempotent by `eventKey`
38104
+ * (`createIfAbsentByEventKey`), so retrying after a transient failure (pool
38105
+ * exhaustion, shutdown, statement timeout, disk IO) is safe. The status CAS has
38106
+ * already committed by this point, and the event key embeds `updatedAt`, so a
38107
+ * lost event cannot be reconstructed later — hence the bounded retry.
38108
+ */
38109
+ async writeWorkItemWithRetry(request) {
38110
+ let lastError;
38111
+ for (let attempt = 0; attempt < WORK_ITEM_WRITE_ATTEMPTS; attempt += 1) {
38112
+ if (attempt > 0) {
38113
+ await new Promise((resolve4) => setTimeout(resolve4, WORK_ITEM_WRITE_RETRY_DELAYS_MS[attempt - 1]));
38114
+ }
38115
+ try {
38116
+ return await this.deps.workItemStore.createIfAbsentByEventKey(request);
38117
+ } catch (error) {
38118
+ lastError = error;
38119
+ }
38120
+ }
38121
+ throw lastError;
38122
+ }
37753
38123
  async writeStatusEvent(task, actor, threadId, action, summary, detail, eventKey) {
37754
38124
  const warningCode = `${action.toUpperCase()}_WORK_ITEM_WRITE_FAILED`;
37755
38125
  const request = {
@@ -37765,7 +38135,7 @@ var TaskLifecycleService = class {
37765
38135
  eventKey
37766
38136
  };
37767
38137
  try {
37768
- const item = await this.deps.workItemStore.createIfAbsentByEventKey(request);
38138
+ const item = await this.writeWorkItemWithRetry(request);
37769
38139
  if (item.eventKey !== request.eventKey) throw new Error("Canonical lifecycle event key mismatch");
37770
38140
  return { eventKey: item.eventKey };
37771
38141
  } catch {
@@ -37951,7 +38321,7 @@ function createTaskRunBridge(deps) {
37951
38321
  return { success: true, task: updated };
37952
38322
  },
37953
38323
  async beginRun(input) {
37954
- const { tenantId: tenantId2, actor, threadId } = input;
38324
+ const { tenantId: tenantId2, actor, threadId, runId, callerThreadId, callerAssistantId } = input;
37955
38325
  let task = input.task;
37956
38326
  const warnings = [];
37957
38327
  if (task.status === "pending") {
@@ -37960,7 +38330,10 @@ function createTaskRunBridge(deps) {
37960
38330
  tenantId: tenantId2,
37961
38331
  taskId: task.id,
37962
38332
  actor,
37963
- threadId
38333
+ ...threadId !== void 0 ? { threadId } : {},
38334
+ ...runId !== void 0 ? { runId } : {},
38335
+ ...callerThreadId ? { callerThreadId } : {},
38336
+ ...callerAssistantId ? { callerAssistantId } : {}
37964
38337
  });
37965
38338
  if (!started.success) {
37966
38339
  return {
@@ -38048,7 +38421,19 @@ function createTaskRunBridge(deps) {
38048
38421
  error: "Lifecycle transitions only support agent tasks."
38049
38422
  };
38050
38423
  }
38051
- 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 });
38424
+ const result = task.status === "interrupted" ? await deps.lifecycle.resumeInterruption({
38425
+ tenantId: tenantId2,
38426
+ taskId: task.id,
38427
+ actor,
38428
+ ...threadId !== void 0 ? { threadId } : {},
38429
+ ...runId !== void 0 ? { runId } : {}
38430
+ }) : await deps.lifecycle.retryTask({
38431
+ tenantId: tenantId2,
38432
+ taskId: task.id,
38433
+ actor,
38434
+ ...threadId !== void 0 ? { threadId } : {},
38435
+ ...runId !== void 0 ? { runId } : {}
38436
+ });
38052
38437
  if (!result.success) {
38053
38438
  return {
38054
38439
  success: false,
@@ -38113,6 +38498,86 @@ function createTaskRunBridge(deps) {
38113
38498
  };
38114
38499
  }
38115
38500
 
38501
+ // src/services/TaskRunRegistry.ts
38502
+ var TaskRunRegistry = class {
38503
+ constructor() {
38504
+ this.live = /* @__PURE__ */ new Set();
38505
+ }
38506
+ /** Marks a task as currently held by a live run. */
38507
+ register(taskId) {
38508
+ this.live.add(taskId);
38509
+ }
38510
+ /** Removes a task once its run has ended. */
38511
+ unregister(taskId) {
38512
+ this.live.delete(taskId);
38513
+ }
38514
+ /** Reports whether a task is currently held by a live run. */
38515
+ isLive(taskId) {
38516
+ return this.live.has(taskId);
38517
+ }
38518
+ /** Returns a snapshot of the live task ids (diagnostics/tests). */
38519
+ snapshot() {
38520
+ return [...this.live];
38521
+ }
38522
+ /** Clears all live entries (tests / process teardown). */
38523
+ clear() {
38524
+ this.live.clear();
38525
+ }
38526
+ };
38527
+ var taskRunRegistry = new TaskRunRegistry();
38528
+ async function reconcileStaleTaskRuns(input) {
38529
+ const registry4 = input.registry ?? taskRunRegistry;
38530
+ const converged = [];
38531
+ const convergedTasks = [];
38532
+ for (const task of input.tasks) {
38533
+ if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
38534
+ const result = await input.lifecycle.failTask({
38535
+ tenantId: task.tenantId,
38536
+ taskId: task.id,
38537
+ actor: input.actor,
38538
+ failureReason: "Run is no longer executing this task (no_executor)"
38539
+ });
38540
+ if (result.success) {
38541
+ converged.push(task.id);
38542
+ convergedTasks.push(result.task);
38543
+ }
38544
+ }
38545
+ return { converged, convergedTasks };
38546
+ }
38547
+ async function reconcileTenantTaskRuns(input) {
38548
+ const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
38549
+ const candidates = input.include ? tasks.filter(input.include) : tasks;
38550
+ return reconcileStaleTaskRuns({
38551
+ tasks: candidates,
38552
+ actor: input.actor,
38553
+ lifecycle: input.lifecycle,
38554
+ ...input.registry ? { registry: input.registry } : {}
38555
+ });
38556
+ }
38557
+ async function reconcileAllTenantTaskRuns(input) {
38558
+ const tenants = await input.tenantStore.listTenants();
38559
+ const converged = [];
38560
+ const convergedTasks = [];
38561
+ for (const tenant of tenants) {
38562
+ let result;
38563
+ try {
38564
+ result = await reconcileTenantTaskRuns({
38565
+ tenantId: tenant.id,
38566
+ actor: input.actor,
38567
+ taskStore: input.taskStore,
38568
+ lifecycle: input.lifecycle,
38569
+ ...input.registry ? { registry: input.registry } : {},
38570
+ ...input.include ? { include: input.include } : {}
38571
+ });
38572
+ } catch {
38573
+ continue;
38574
+ }
38575
+ converged.push(...result.converged);
38576
+ convergedTasks.push(...result.convergedTasks);
38577
+ }
38578
+ return { converged, convergedTasks };
38579
+ }
38580
+
38116
38581
  // src/services/ExecutionAuthorityRegistry.ts
38117
38582
  var ManagedTaskStartError = class extends Error {
38118
38583
  /**
@@ -38374,274 +38839,13 @@ async function prepareTaskDispatch(deps, input) {
38374
38839
  agentId: input.agentId,
38375
38840
  actor: input.actor,
38376
38841
  ...input.callerThreadId !== void 0 ? { callerThreadId: input.callerThreadId } : {},
38842
+ ...input.callerAssistantId !== void 0 ? { callerAssistantId: input.callerAssistantId } : {},
38377
38843
  parent,
38378
38844
  completedDependencies
38379
38845
  }
38380
38846
  };
38381
38847
  }
38382
38848
 
38383
- // src/util/toJsonSafeValue.ts
38384
- var CIRCULAR_VALUE = "[Circular]";
38385
- var REPEATED_VALUE = "[Repeated]";
38386
- var arrayFrom = Array.from.bind(Array);
38387
- var arrayIsArray = Array.isArray.bind(Array);
38388
- var hasOwnProperty = Object.prototype.hasOwnProperty.call.bind(Object.prototype.hasOwnProperty);
38389
- var isPrototypeOf = Object.prototype.isPrototypeOf.call.bind(Object.prototype.isPrototypeOf);
38390
- var objectCreate = Object.create.bind(Object);
38391
- var objectDefineProperty = Object.defineProperty.bind(Object);
38392
- var objectIs = Object.is.bind(Object);
38393
- var reflectGet = Reflect.get.bind(Reflect);
38394
- var reflectGetOwnPropertyDescriptor = Reflect.getOwnPropertyDescriptor.bind(Reflect);
38395
- var reflectOwnKeys = Reflect.ownKeys.bind(Reflect);
38396
- var stringifyJson = JSON.stringify.bind(JSON);
38397
- var numberIsFinite = Number.isFinite.bind(Number);
38398
- var numberIsNaN = Number.isNaN.bind(Number);
38399
- var numberIsSafeInteger = Number.isSafeInteger.bind(Number);
38400
- var mathMax = Math.max.bind(Math);
38401
- var dateConstructor = Date;
38402
- var datePrototype = dateConstructor.prototype;
38403
- var dateGetTime = datePrototype.getTime.call.bind(datePrototype.getTime);
38404
- var dateToISOString = datePrototype.toISOString.call.bind(datePrototype.toISOString);
38405
- var bigintToString = BigInt.prototype.toString.call.bind(BigInt.prototype.toString);
38406
- var stringSlice = String.prototype.slice.call.bind(String.prototype.slice);
38407
- var weakMapGet = WeakMap.prototype.get.call.bind(WeakMap.prototype.get);
38408
- var weakMapSet = WeakMap.prototype.set.call.bind(WeakMap.prototype.set);
38409
- var WeakMapConstructor = WeakMap;
38410
- var utf8Encoder = new TextEncoder();
38411
- var encodeUtf8 = TextEncoder.prototype.encode.bind(utf8Encoder);
38412
- var typedArrayPrototype = Object.getPrototypeOf(Uint8Array.prototype);
38413
- var typedArrayByteLengthGetter = Object.getOwnPropertyDescriptor(typedArrayPrototype, "byteLength")?.get;
38414
- if (!typedArrayByteLengthGetter) throw new Error("TypedArray byteLength getter is unavailable");
38415
- var typedArrayByteLength = typedArrayByteLengthGetter.call.bind(typedArrayByteLengthGetter);
38416
- var JSON_SAFE_MAX_DEPTH = 32;
38417
- var JSON_SAFE_MAX_NODES = 1e4;
38418
- var JSON_SAFE_MAX_COLLECTION_ENTRIES = 1e4;
38419
- var JSON_SAFE_MAX_STRING_LENGTH = 64 * 1024;
38420
- var JSON_SAFE_MAX_PROPERTY_KEY_LENGTH = JSON_SAFE_MAX_STRING_LENGTH;
38421
- var JSON_SAFE_MAX_PROPERTY_KEY_BYTES = 256 * 1024;
38422
- var JSON_SAFE_MAX_SERIALIZED_BYTES = 256 * 1024;
38423
- var JsonSafeValueError = class extends Error {
38424
- /**
38425
- * Create a bounded normalization error.
38426
- *
38427
- * @param code Stable normalization failure code.
38428
- * @param message Human-readable bounded failure description.
38429
- */
38430
- constructor(code, message) {
38431
- super(message);
38432
- objectDefineProperty(this, "name", {
38433
- value: "JsonSafeValueError",
38434
- writable: true,
38435
- configurable: true
38436
- });
38437
- objectDefineProperty(this, "code", {
38438
- value: code,
38439
- writable: true,
38440
- configurable: true
38441
- });
38442
- }
38443
- };
38444
- function fail(code, message) {
38445
- throw new JsonSafeValueError(code, message);
38446
- }
38447
- function propertyAccess(operation, path8) {
38448
- try {
38449
- return operation();
38450
- } catch {
38451
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe value at ${path8}`);
38452
- }
38453
- }
38454
- function serializedStringBytes(value) {
38455
- if (value.length > JSON_SAFE_MAX_STRING_LENGTH) {
38456
- fail("MAX_STRING_LENGTH", `JSON-safe string exceeds ${JSON_SAFE_MAX_STRING_LENGTH} characters`);
38457
- }
38458
- return typedArrayByteLength(encodeUtf8(stringifyJson(value)));
38459
- }
38460
- function validatePropertyKey(key5) {
38461
- if (key5.length > JSON_SAFE_MAX_PROPERTY_KEY_LENGTH) {
38462
- fail(
38463
- "MAX_STRING_LENGTH",
38464
- `JSON-safe property key exceeds ${JSON_SAFE_MAX_PROPERTY_KEY_LENGTH} characters`
38465
- );
38466
- }
38467
- }
38468
- function chargePropertyKey(state, key5) {
38469
- state.propertyKeyBytes += typedArrayByteLength(encodeUtf8(key5));
38470
- if (state.propertyKeyBytes > JSON_SAFE_MAX_PROPERTY_KEY_BYTES) {
38471
- fail(
38472
- "MAX_PROPERTY_KEY_BYTES",
38473
- `JSON-safe property keys exceed ${JSON_SAFE_MAX_PROPERTY_KEY_BYTES} traversed UTF-8 bytes`
38474
- );
38475
- }
38476
- }
38477
- function chargeBytes(state, bytes) {
38478
- state.serializedBytes += bytes;
38479
- if (state.serializedBytes > JSON_SAFE_MAX_SERIALIZED_BYTES) {
38480
- fail(
38481
- "MAX_SERIALIZED_BYTES",
38482
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
38483
- );
38484
- }
38485
- }
38486
- function chargeString(state, value) {
38487
- chargeBytes(state, serializedStringBytes(value));
38488
- }
38489
- function objectPropertyPath(path8, key5) {
38490
- const boundedKey = key5.length > 128 ? `${stringSlice(key5, 0, 128)}...` : key5;
38491
- return `${path8}[${stringifyJson(boundedKey)}]`;
38492
- }
38493
- function convertJsonValue(value, state, depth, inArray, path8) {
38494
- state.nodes += 1;
38495
- if (state.nodes > JSON_SAFE_MAX_NODES) {
38496
- fail("MAX_NODES", `JSON-safe value exceeds ${JSON_SAFE_MAX_NODES} total nodes`);
38497
- }
38498
- if (typeof value === "string") {
38499
- chargeString(state, value);
38500
- return value;
38501
- }
38502
- if (value === null) {
38503
- chargeBytes(state, 4);
38504
- return value;
38505
- }
38506
- if (typeof value === "boolean") {
38507
- chargeBytes(state, value ? 4 : 5);
38508
- return value;
38509
- }
38510
- if (typeof value === "number") {
38511
- const normalized = numberIsFinite(value) ? objectIs(value, -0) ? 0 : value : null;
38512
- chargeBytes(state, normalized === null ? 4 : stringifyJson(normalized).length);
38513
- return normalized;
38514
- }
38515
- if (typeof value === "bigint") {
38516
- const normalized = bigintToString(value);
38517
- chargeString(state, normalized);
38518
- return normalized;
38519
- }
38520
- if (typeof value === "undefined" || typeof value === "function" || typeof value === "symbol") {
38521
- if (inArray) chargeBytes(state, 4);
38522
- return inArray ? null : void 0;
38523
- }
38524
- const isDate = propertyAccess(() => isPrototypeOf(datePrototype, value), path8);
38525
- if (isDate) {
38526
- const time = propertyAccess(() => dateGetTime(value), path8);
38527
- if (numberIsNaN(time)) {
38528
- chargeBytes(state, 4);
38529
- return null;
38530
- }
38531
- const normalized = propertyAccess(() => dateToISOString(value), path8);
38532
- chargeString(state, normalized);
38533
- return normalized;
38534
- }
38535
- if (depth > JSON_SAFE_MAX_DEPTH) {
38536
- fail("MAX_DEPTH", `JSON-safe value exceeds maximum depth ${JSON_SAFE_MAX_DEPTH}`);
38537
- }
38538
- const referenceState = weakMapGet(state.references, value);
38539
- if (referenceState === "visiting") {
38540
- chargeString(state, CIRCULAR_VALUE);
38541
- return CIRCULAR_VALUE;
38542
- }
38543
- if (referenceState === "visited") {
38544
- chargeString(state, REPEATED_VALUE);
38545
- return REPEATED_VALUE;
38546
- }
38547
- weakMapSet(state.references, value, "visiting");
38548
- if (propertyAccess(() => arrayIsArray(value), path8)) {
38549
- const arrayValue = value;
38550
- const length = propertyAccess(
38551
- () => arrayValue.length,
38552
- path8
38553
- );
38554
- if (typeof length !== "number" || !numberIsSafeInteger(length) || length < 0) {
38555
- fail("PROPERTY_ACCESS_FAILED", `Unable to inspect JSON-safe array length at ${path8}`);
38556
- }
38557
- if (length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
38558
- fail(
38559
- "COLLECTION_TOO_LARGE",
38560
- `JSON-safe array exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} entries`
38561
- );
38562
- }
38563
- chargeBytes(state, 2 + mathMax(0, length - 1));
38564
- const result2 = arrayFrom({ length }, (_, index) => {
38565
- const entryPath = `${path8}[${index}]`;
38566
- const hasEntry = propertyAccess(
38567
- () => hasOwnProperty(arrayValue, index),
38568
- entryPath
38569
- );
38570
- if (!hasEntry) {
38571
- chargeBytes(state, 4);
38572
- return null;
38573
- }
38574
- const entry = propertyAccess(() => arrayValue[index], entryPath);
38575
- return convertJsonValue(entry, state, depth + 1, true, `${path8}[${index}]`);
38576
- });
38577
- objectDefineProperty(result2, "toJSON", {
38578
- value: void 0,
38579
- configurable: true,
38580
- writable: true
38581
- });
38582
- weakMapSet(state.references, value, "visited");
38583
- return result2;
38584
- }
38585
- const keys = propertyAccess(() => reflectOwnKeys(value), path8);
38586
- if (keys.length > JSON_SAFE_MAX_COLLECTION_ENTRIES) {
38587
- fail(
38588
- "COLLECTION_TOO_LARGE",
38589
- `JSON-safe object exceeds ${JSON_SAFE_MAX_COLLECTION_ENTRIES} own keys`
38590
- );
38591
- }
38592
- for (let index = 0; index < keys.length; index += 1) {
38593
- const key5 = keys[index];
38594
- if (typeof key5 !== "string") continue;
38595
- validatePropertyKey(key5);
38596
- chargePropertyKey(state, key5);
38597
- }
38598
- chargeBytes(state, 2);
38599
- const result = objectCreate(null);
38600
- let emittedProperties = 0;
38601
- for (let index = 0; index < keys.length; index += 1) {
38602
- const key5 = keys[index];
38603
- const entryPath = typeof key5 === "string" ? objectPropertyPath(path8, key5) : path8;
38604
- const descriptor = propertyAccess(
38605
- () => reflectGetOwnPropertyDescriptor(value, key5),
38606
- entryPath
38607
- );
38608
- if (typeof key5 !== "string" || !descriptor?.enumerable) continue;
38609
- const entry = propertyAccess(() => reflectGet(value, key5), entryPath);
38610
- const converted = convertJsonValue(entry, state, depth + 1, false, entryPath);
38611
- if (converted !== void 0) {
38612
- chargeBytes(state, serializedStringBytes(key5) + 1 + (emittedProperties === 0 ? 0 : 1));
38613
- propertyAccess(() => objectDefineProperty(result, key5, {
38614
- value: converted,
38615
- enumerable: true,
38616
- configurable: true,
38617
- writable: true
38618
- }), entryPath);
38619
- emittedProperties += 1;
38620
- }
38621
- }
38622
- weakMapSet(state.references, value, "visited");
38623
- return result;
38624
- }
38625
- function toJsonSafeValue(value) {
38626
- const state = {
38627
- nodes: 0,
38628
- propertyKeyBytes: 0,
38629
- serializedBytes: 0,
38630
- references: new WeakMapConstructor()
38631
- };
38632
- const converted = convertJsonValue(value, state, 0, false, "$");
38633
- if (converted === void 0) chargeBytes(state, 4);
38634
- const result = converted ?? null;
38635
- const serialized = propertyAccess(() => stringifyJson(result), "$");
38636
- if (typedArrayByteLength(encodeUtf8(serialized)) > JSON_SAFE_MAX_SERIALIZED_BYTES) {
38637
- fail(
38638
- "MAX_SERIALIZED_BYTES",
38639
- `JSON-safe value exceeds ${JSON_SAFE_MAX_SERIALIZED_BYTES} serialized bytes`
38640
- );
38641
- }
38642
- return result;
38643
- }
38644
-
38645
38849
  // src/services/TaskExecutionService.ts
38646
38850
  import { GraphInterrupt as GraphInterrupt2 } from "@langchain/langgraph";
38647
38851
  function persistedExecutionObservation(item, attempted) {
@@ -38690,10 +38894,26 @@ function createTaskExecutionService(deps) {
38690
38894
  const run = async (plan) => {
38691
38895
  const { tenantId: tenantId2, agentId, actor, parent, completedDependencies } = plan;
38692
38896
  let task = plan.task;
38693
- 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;
38897
+ 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;
38898
+ const storedRunId = typeof task.context?.run_id === "string" && task.context.run_id.trim() !== "" ? task.context.run_id : void 0;
38899
+ let reuseCurrentRun = false;
38900
+ if (task.status === "interrupted" && storedThreadId) {
38901
+ const currentKey = storedRunId ? `execution-result:${storedThreadId}:${storedRunId}` : `execution-result:${storedThreadId}`;
38902
+ try {
38903
+ reuseCurrentRun = await deps.workItemStore.findByEventKey(tenantId2, task.id, currentKey) === null;
38904
+ } catch {
38905
+ reuseCurrentRun = false;
38906
+ }
38907
+ }
38694
38908
  let threadId;
38909
+ let runId;
38695
38910
  try {
38696
- threadId = persistedThreadId ?? (deps.createThreadId ?? randomUUID8)();
38911
+ threadId = storedThreadId ?? (deps.createThreadId ?? randomUUID8)();
38912
+ if (task.status === "interrupted" && reuseCurrentRun) {
38913
+ runId = storedRunId;
38914
+ } else if (task.status === "interrupted" || task.status === "failed") {
38915
+ runId = (deps.createRunId ?? randomUUID8)();
38916
+ }
38697
38917
  } catch (error) {
38698
38918
  return {
38699
38919
  success: false,
@@ -38703,7 +38923,7 @@ function createTaskExecutionService(deps) {
38703
38923
  agentId
38704
38924
  };
38705
38925
  }
38706
- const eventKey = `execution-result:${threadId}`;
38926
+ const eventKey = runId ? `execution-result:${threadId}:${runId}` : `execution-result:${threadId}`;
38707
38927
  if (!isExecutionResultEventKey2(eventKey)) {
38708
38928
  return {
38709
38929
  success: false,
@@ -38737,7 +38957,10 @@ function createTaskExecutionService(deps) {
38737
38957
  tenantId: tenantId2,
38738
38958
  task,
38739
38959
  actor,
38740
- threadId
38960
+ threadId,
38961
+ ...runId ? { runId } : {},
38962
+ ...plan.callerThreadId ? { callerThreadId: plan.callerThreadId } : {},
38963
+ ...plan.callerAssistantId ? { callerAssistantId: plan.callerAssistantId } : {}
38741
38964
  });
38742
38965
  if (!begun.success) return { ...begun, taskId: task.id };
38743
38966
  if (!begun.mutated || !begun.transitioned) {
@@ -38751,38 +38974,120 @@ function createTaskExecutionService(deps) {
38751
38974
  task = begun.task;
38752
38975
  warnings.push(...begun.warnings);
38753
38976
  }
38754
- const invocation = {
38755
- tenantId: tenantId2,
38756
- workspaceId: task.workspaceId,
38757
- projectId: task.projectId,
38758
- taskId: task.id,
38759
- agentId,
38760
- threadId,
38761
- message: buildWorkerMessage(task, parent, completedDependencies),
38762
- delegatedTaskId: task.id,
38763
- taskExecutionRole: "worker"
38764
- };
38765
- let observation;
38977
+ taskRunRegistry.register(task.id);
38766
38978
  try {
38767
- observation = toJsonSafeValue(await deps.invokeAgent(invocation));
38768
- } catch (error) {
38769
- if (error instanceof GraphInterrupt2) {
38979
+ const invocation = {
38980
+ tenantId: tenantId2,
38981
+ workspaceId: task.workspaceId,
38982
+ projectId: task.projectId,
38983
+ taskId: task.id,
38984
+ agentId,
38985
+ threadId,
38986
+ message: buildWorkerMessage(task, parent, completedDependencies),
38987
+ delegatedTaskId: task.id,
38988
+ taskExecutionRole: "worker"
38989
+ };
38990
+ let observation;
38991
+ try {
38992
+ observation = toJsonSafeValue(await deps.invokeAgent(invocation));
38993
+ } catch (error) {
38994
+ if (error instanceof GraphInterrupt2) {
38995
+ try {
38996
+ await bridge.settleRun({
38997
+ tenantId: tenantId2,
38998
+ task,
38999
+ actor,
39000
+ threadId,
39001
+ outcome: { kind: "interrupted", summary: "Awaiting user input" }
39002
+ });
39003
+ } catch {
39004
+ }
39005
+ throw error;
39006
+ }
39007
+ const normalizationError = error instanceof JsonSafeValueError;
39008
+ const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
39009
+ const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
38770
39010
  try {
38771
- await bridge.settleRun({
39011
+ const settled = await bridge.settleRun({
38772
39012
  tenantId: tenantId2,
38773
39013
  task,
38774
39014
  actor,
38775
39015
  threadId,
38776
- outcome: { kind: "interrupted", summary: "Awaiting user input" }
39016
+ outcome: {
39017
+ kind: "failed",
39018
+ lifecycleHandled: false,
39019
+ error: message.trim() || "Agent invocation failed"
39020
+ }
38777
39021
  });
39022
+ if (!settled.success) {
39023
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
39024
+ }
38778
39025
  } catch {
39026
+ warnings.push({ code: "TASK_FAILED_SETTLE_FAILED", taskId: task.id });
39027
+ }
39028
+ const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
39029
+ try {
39030
+ const persisted = await deps.workItemStore.createIfAbsentByEventKey({
39031
+ taskId: task.id,
39032
+ tenantId: tenantId2,
39033
+ workspaceId: task.workspaceId,
39034
+ projectId: task.projectId,
39035
+ action: "execution_result",
39036
+ actor,
39037
+ threadId,
39038
+ summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
39039
+ detail: {
39040
+ agentId,
39041
+ threadId,
39042
+ observation: failedObservation,
39043
+ success: false
39044
+ },
39045
+ eventKey
39046
+ });
39047
+ const validated = persistedExecutionObservation(persisted, {
39048
+ tenantId: tenantId2,
39049
+ taskId: task.id,
39050
+ agentId,
39051
+ threadId,
39052
+ eventKey,
39053
+ success: false,
39054
+ observation: failedObservation
39055
+ });
39056
+ if (!validated.matches) {
39057
+ return {
39058
+ success: false,
39059
+ code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
39060
+ error: "The execution result identity is already bound to a different execution payload",
39061
+ ...!normalizationError ? { invocationError: message } : {},
39062
+ taskId: task.id,
39063
+ agentId,
39064
+ threadId,
39065
+ ...warnings.length > 0 ? { warnings } : {}
39066
+ };
39067
+ }
39068
+ return {
39069
+ success: false,
39070
+ code: failureCode,
39071
+ error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
39072
+ taskId: task.id,
39073
+ agentId,
39074
+ threadId,
39075
+ executionResultId: eventKey,
39076
+ ...warnings.length > 0 ? { warnings } : {}
39077
+ };
39078
+ } catch (persistenceError) {
39079
+ return {
39080
+ success: false,
39081
+ code: "EXECUTION_RESULT_WRITE_FAILED",
39082
+ error: errorMessage(persistenceError),
39083
+ ...!normalizationError ? { invocationError: message } : {},
39084
+ taskId: task.id,
39085
+ agentId,
39086
+ threadId,
39087
+ ...warnings.length > 0 ? { warnings } : {}
39088
+ };
38779
39089
  }
38780
- throw error;
38781
39090
  }
38782
- const normalizationError = error instanceof JsonSafeValueError;
38783
- const message = normalizationError ? `${error.code}: ${error.message}` : errorMessage(error);
38784
- const failureCode = normalizationError ? "EXECUTION_RESULT_NORMALIZATION_FAILED" : "AGENT_INVOCATION_FAILED";
38785
- const failedObservation = toJsonSafeValue(normalizationError ? { code: failureCode, error: message } : { error: message });
38786
39091
  try {
38787
39092
  const persisted = await deps.workItemStore.createIfAbsentByEventKey({
38788
39093
  taskId: task.id,
@@ -38792,13 +39097,8 @@ function createTaskExecutionService(deps) {
38792
39097
  action: "execution_result",
38793
39098
  actor,
38794
39099
  threadId,
38795
- summary: normalizationError ? `Agent ${agentId} returned an invalid execution observation` : `Agent ${agentId} invocation failed`,
38796
- detail: {
38797
- agentId,
38798
- threadId,
38799
- observation: failedObservation,
38800
- success: false
38801
- },
39100
+ summary: `Agent ${agentId} returned an execution observation`,
39101
+ detail: { agentId, threadId, observation, success: true },
38802
39102
  eventKey
38803
39103
  });
38804
39104
  const validated = persistedExecutionObservation(persisted, {
@@ -38807,15 +39107,14 @@ function createTaskExecutionService(deps) {
38807
39107
  agentId,
38808
39108
  threadId,
38809
39109
  eventKey,
38810
- success: false,
38811
- observation: failedObservation
39110
+ success: true,
39111
+ observation
38812
39112
  });
38813
39113
  if (!validated.matches) {
38814
39114
  return {
38815
39115
  success: false,
38816
39116
  code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
38817
39117
  error: "The execution result identity is already bound to a different execution payload",
38818
- ...!normalizationError ? { invocationError: message } : {},
38819
39118
  taskId: task.id,
38820
39119
  agentId,
38821
39120
  threadId,
@@ -38823,80 +39122,27 @@ function createTaskExecutionService(deps) {
38823
39122
  };
38824
39123
  }
38825
39124
  return {
38826
- success: false,
38827
- code: failureCode,
38828
- error: typeof validated.observation?.error === "string" ? validated.observation.error : message,
39125
+ success: true,
38829
39126
  taskId: task.id,
38830
39127
  agentId,
38831
39128
  threadId,
39129
+ observation: validated.observation,
38832
39130
  executionResultId: eventKey,
38833
39131
  ...warnings.length > 0 ? { warnings } : {}
38834
39132
  };
38835
- } catch (persistenceError) {
39133
+ } catch (error) {
38836
39134
  return {
38837
39135
  success: false,
38838
39136
  code: "EXECUTION_RESULT_WRITE_FAILED",
38839
- error: errorMessage(persistenceError),
38840
- ...!normalizationError ? { invocationError: message } : {},
38841
- taskId: task.id,
38842
- agentId,
38843
- threadId,
38844
- ...warnings.length > 0 ? { warnings } : {}
38845
- };
38846
- }
38847
- }
38848
- try {
38849
- const persisted = await deps.workItemStore.createIfAbsentByEventKey({
38850
- taskId: task.id,
38851
- tenantId: tenantId2,
38852
- workspaceId: task.workspaceId,
38853
- projectId: task.projectId,
38854
- action: "execution_result",
38855
- actor,
38856
- threadId,
38857
- summary: `Agent ${agentId} returned an execution observation`,
38858
- detail: { agentId, threadId, observation, success: true },
38859
- eventKey
38860
- });
38861
- const validated = persistedExecutionObservation(persisted, {
38862
- tenantId: tenantId2,
38863
- taskId: task.id,
38864
- agentId,
38865
- threadId,
38866
- eventKey,
38867
- success: true,
38868
- observation
38869
- });
38870
- if (!validated.matches) {
38871
- return {
38872
- success: false,
38873
- code: "EXECUTION_RESULT_IDENTITY_CONFLICT",
38874
- error: "The execution result identity is already bound to a different execution payload",
39137
+ error: errorMessage(error),
38875
39138
  taskId: task.id,
38876
39139
  agentId,
38877
39140
  threadId,
38878
39141
  ...warnings.length > 0 ? { warnings } : {}
38879
39142
  };
38880
39143
  }
38881
- return {
38882
- success: true,
38883
- taskId: task.id,
38884
- agentId,
38885
- threadId,
38886
- observation: validated.observation,
38887
- executionResultId: eventKey,
38888
- ...warnings.length > 0 ? { warnings } : {}
38889
- };
38890
- } catch (error) {
38891
- return {
38892
- success: false,
38893
- code: "EXECUTION_RESULT_WRITE_FAILED",
38894
- error: errorMessage(error),
38895
- taskId: task.id,
38896
- agentId,
38897
- threadId,
38898
- ...warnings.length > 0 ? { warnings } : {}
38899
- };
39144
+ } finally {
39145
+ taskRunRegistry.unregister(task.id);
38900
39146
  }
38901
39147
  };
38902
39148
  return {
@@ -38909,76 +39155,6 @@ function createTaskExecutionService(deps) {
38909
39155
  };
38910
39156
  }
38911
39157
 
38912
- // src/services/TaskRunRegistry.ts
38913
- var TaskRunRegistry = class {
38914
- constructor() {
38915
- this.live = /* @__PURE__ */ new Set();
38916
- }
38917
- /** Marks a task as currently held by a live run. */
38918
- register(taskId) {
38919
- this.live.add(taskId);
38920
- }
38921
- /** Removes a task once its run has ended. */
38922
- unregister(taskId) {
38923
- this.live.delete(taskId);
38924
- }
38925
- /** Reports whether a task is currently held by a live run. */
38926
- isLive(taskId) {
38927
- return this.live.has(taskId);
38928
- }
38929
- /** Returns a snapshot of the live task ids (diagnostics/tests). */
38930
- snapshot() {
38931
- return [...this.live];
38932
- }
38933
- /** Clears all live entries (tests / process teardown). */
38934
- clear() {
38935
- this.live.clear();
38936
- }
38937
- };
38938
- var taskRunRegistry = new TaskRunRegistry();
38939
- async function reconcileStaleTaskRuns(input) {
38940
- const registry4 = input.registry ?? taskRunRegistry;
38941
- const converged = [];
38942
- for (const task of input.tasks) {
38943
- if (task.status !== "in_progress" || registry4.isLive(task.id)) continue;
38944
- const result = await input.lifecycle.interruptTask({
38945
- tenantId: task.tenantId,
38946
- taskId: task.id,
38947
- actor: input.actor,
38948
- type: "missing_input",
38949
- summary: "Run is no longer executing this task (no_executor)"
38950
- });
38951
- if (result.success) converged.push(task.id);
38952
- }
38953
- return { converged };
38954
- }
38955
- async function reconcileTenantTaskRuns(input) {
38956
- const tasks = await input.taskStore.list({ tenantId: input.tenantId, status: "in_progress" });
38957
- const candidates = input.include ? tasks.filter(input.include) : tasks;
38958
- return reconcileStaleTaskRuns({
38959
- tasks: candidates,
38960
- actor: input.actor,
38961
- lifecycle: input.lifecycle,
38962
- ...input.registry ? { registry: input.registry } : {}
38963
- });
38964
- }
38965
- async function reconcileAllTenantTaskRuns(input) {
38966
- const tenants = await input.tenantStore.listTenants();
38967
- const converged = [];
38968
- for (const tenant of tenants) {
38969
- const result = await reconcileTenantTaskRuns({
38970
- tenantId: tenant.id,
38971
- actor: input.actor,
38972
- taskStore: input.taskStore,
38973
- lifecycle: input.lifecycle,
38974
- ...input.registry ? { registry: input.registry } : {},
38975
- ...input.include ? { include: input.include } : {}
38976
- });
38977
- converged.push(...result.converged);
38978
- }
38979
- return { converged };
38980
- }
38981
-
38982
39158
  // src/index.ts
38983
39159
  import * as Protocols from "@axiom-lattice/protocols";
38984
39160
 
@@ -41178,61 +41354,28 @@ var widgetPlugin = {
41178
41354
  import { createMiddleware as createMiddleware23, tool as tool64 } from "langchain";
41179
41355
  import { z as z70 } from "zod";
41180
41356
  import { GraphInterrupt as GraphInterrupt3, interrupt as interrupt4 } from "@langchain/langgraph";
41357
+ import { resolveRunScope as resolveRunScope2 } from "@axiom-lattice/protocols";
41181
41358
 
41182
- // src/util/truncateForJson.ts
41183
- var TRUNCATION_MARKER = "...[truncated]";
41184
- function truncateString(value, cap) {
41185
- if (value.length <= cap) return value;
41186
- const budget = Math.max(0, cap - TRUNCATION_MARKER.length);
41187
- return value.slice(0, budget) + TRUNCATION_MARKER;
41359
+ // src/services/taskWorkerRunConfig.ts
41360
+ import { firstNonEmptyString, resolveRunScope } from "@axiom-lattice/protocols";
41361
+ function resolveWorkerRunScope(input) {
41362
+ const caller = resolveRunScope(input.runConfig);
41363
+ return {
41364
+ workspaceId: firstNonEmptyString(input.invocation.workspaceId) ?? caller.workspaceId,
41365
+ projectId: firstNonEmptyString(input.invocation.projectId) ?? caller.projectId
41366
+ };
41188
41367
  }
41189
- function truncateValue(value, depth, maxDepth, maxEntries, maxStringLength, seen) {
41190
- if (typeof value === "string") return truncateString(value, maxStringLength);
41191
- if (value === null || typeof value !== "object") return value;
41192
- if (depth >= maxDepth) return "[truncated:max-depth]";
41193
- if (seen.has(value)) return "[Circular]";
41194
- seen.add(value);
41195
- try {
41196
- if (value instanceof Date) return value.toISOString();
41197
- if (Array.isArray(value)) {
41198
- const limit2 = Math.min(value.length, maxEntries);
41199
- const output2 = [];
41200
- for (let index = 0; index < limit2; index += 1) {
41201
- output2.push(truncateValue(value[index], depth + 1, maxDepth, maxEntries, maxStringLength, seen));
41202
- }
41203
- if (value.length > limit2) output2.push("[truncated:entries]");
41204
- return output2;
41205
- }
41206
- const record = value;
41207
- const output = {};
41208
- const keys = Object.keys(record);
41209
- const limit = Math.min(keys.length, maxEntries);
41210
- for (let index = 0; index < limit; index += 1) {
41211
- const key5 = keys[index];
41212
- output[truncateString(key5, maxStringLength)] = truncateValue(
41213
- record[key5],
41214
- depth + 1,
41215
- maxDepth,
41216
- maxEntries,
41217
- maxStringLength,
41218
- seen
41219
- );
41220
- }
41221
- if (keys.length > limit) output["[truncated]"] = true;
41222
- return output;
41223
- } finally {
41224
- seen.delete(value);
41368
+ function applyWorkerRunScope(runConfig, scope) {
41369
+ const next = { ...runConfig };
41370
+ if (scope.workspaceId !== void 0) {
41371
+ next.workspaceId = scope.workspaceId;
41372
+ next["x-workspace-id"] = scope.workspaceId;
41225
41373
  }
41226
- }
41227
- function truncateForJson(value, options = {}) {
41228
- return truncateValue(
41229
- value,
41230
- 0,
41231
- options.maxDepth ?? JSON_SAFE_MAX_DEPTH,
41232
- options.maxEntries ?? JSON_SAFE_MAX_COLLECTION_ENTRIES,
41233
- options.maxStringLength ?? JSON_SAFE_MAX_STRING_LENGTH,
41234
- /* @__PURE__ */ new WeakSet()
41235
- );
41374
+ if (scope.projectId !== void 0) {
41375
+ next.projectId = scope.projectId;
41376
+ next["x-project-id"] = scope.projectId;
41377
+ }
41378
+ return next;
41236
41379
  }
41237
41380
 
41238
41381
  // src/middlewares/taskMiddleware.ts
@@ -42077,7 +42220,7 @@ var manageTaskSchema = z70.object({
42077
42220
  parentId: z70.string().optional().describe("Parent task ID for grouping subtasks"),
42078
42221
  sourceId: z70.string().optional().describe("Source session/thread ID"),
42079
42222
  context: z70.record(z70.unknown()).optional().describe("Additional context data"),
42080
- ownerType: z70.enum(["user", "agent"]).optional().describe("Owner type. Defaults to 'user' if omitted"),
42223
+ ownerType: z70.enum(["user", "agent"]).optional().describe("Owner type. Defaults to the runtime actor: agent runtime (no user identity) -> 'agent', user runtime -> 'user'."),
42081
42224
  ownerId: z70.string().optional().describe("Owner ID. Auto-filled from current user/agent if omitted"),
42082
42225
  requireReview: z70.boolean().optional().describe("If true, agent completion pauses as interrupted(review_required) for HITL approval"),
42083
42226
  dependencies: z70.array(z70.string()).optional().describe("List of task IDs that must be completed before this task can start"),
@@ -42246,8 +42389,9 @@ function createTaskMiddleware(options = {}) {
42246
42389
  const trustedProject = authority.kind === "projectRoom" || authority.kind === "projectTask" ? authority.trusted : void 0;
42247
42390
  const trustedScope = trustedProject?.projectTask ?? trustedProject?.projectRoom;
42248
42391
  const tenantId2 = trustedScope?.tenantId ?? (rc.tenantId || "default");
42249
- const workspaceId = trustedScope?.workspaceId ?? rc.workspaceId;
42250
- const projectId = trustedScope?.projectId ?? rc.projectId;
42392
+ const runScope = resolveRunScope2(rc);
42393
+ const workspaceId = trustedScope?.workspaceId ?? runScope.workspaceId;
42394
+ const projectId = trustedScope?.projectId ?? runScope.projectId;
42251
42395
  const revalidateCaller = async () => {
42252
42396
  if (!trustedProject || trustedRosterExempt(trustedProject)) return void 0;
42253
42397
  try {
@@ -42264,7 +42408,9 @@ function createTaskMiddleware(options = {}) {
42264
42408
  return projectPolicyError(error);
42265
42409
  }
42266
42410
  }
42267
- const ownerId = input.ownerId || trustedScope?.assistantId || (input.ownerType === "agent" ? rc.assistant_id : null) || rc.user_id;
42411
+ const runtimeOwnerType = rc.user_id ? "user" : rc.assistant_id ? "agent" : "user";
42412
+ const requestedOwnerType = input.ownerType ?? runtimeOwnerType;
42413
+ const ownerId = input.ownerId || trustedScope?.assistantId || (requestedOwnerType === "agent" ? rc.assistant_id : null) || rc.user_id;
42268
42414
  const store = getTaskStore();
42269
42415
  const deleteOneTask = async (id) => {
42270
42416
  if (delegatedTaskId && id !== delegatedTaskId) {
@@ -42333,7 +42479,7 @@ function createTaskMiddleware(options = {}) {
42333
42479
  createScopeProjectId = createScopeProjectId ?? parentTask.projectId;
42334
42480
  }
42335
42481
  }
42336
- const effectiveOwnerType = delegatedTaskId ? "agent" : trustedProject ? "agent" : input.ownerType || "user";
42482
+ const effectiveOwnerType = delegatedTaskId ? "agent" : trustedProject ? "agent" : requestedOwnerType;
42337
42483
  const effectiveOwnerId = delegatedTaskId ? rc.assistant_id : ownerId;
42338
42484
  if (delegatedTaskId && !effectiveOwnerId) {
42339
42485
  return delegatedTaskScopeError(delegatedTaskId);
@@ -42359,6 +42505,14 @@ function createTaskMiddleware(options = {}) {
42359
42505
  }
42360
42506
  }
42361
42507
  }
42508
+ if (!delegatedTaskId && (typeof effectiveOwnerId !== "string" || effectiveOwnerId.length === 0)) {
42509
+ return JSON.stringify({
42510
+ success: false,
42511
+ code: "TASK_OWNER_REQUIRED",
42512
+ error: "Cannot resolve task owner: no user or agent identity in this run.",
42513
+ hint: 'Provide an explicit ownerId, or retry with ownerType:"agent" if this run has an agent identity.'
42514
+ });
42515
+ }
42362
42516
  if (effectiveOwnerType === "agent" && (input.result !== void 0 || input.failureReason !== void 0)) {
42363
42517
  return JSON.stringify({
42364
42518
  success: false,
@@ -43413,13 +43567,22 @@ function createTaskMiddleware(options = {}) {
43413
43567
  try {
43414
43568
  response = await handleManageTaskAction(input, config, validateExecutionResult, markMutation);
43415
43569
  } catch (error) {
43416
- if (!(error instanceof ExecutionResultNotPendingError)) throw error;
43570
+ if (error instanceof GraphInterrupt3) throw error;
43571
+ if (error instanceof ExecutionResultNotPendingError) {
43572
+ return JSON.stringify({
43573
+ success: false,
43574
+ code: "EXECUTION_RESULT_NOT_PENDING",
43575
+ taskId: error.taskId,
43576
+ executionResultId: error.executionResultId,
43577
+ error: error.message
43578
+ });
43579
+ }
43580
+ if (input.executionResultId) throw error;
43417
43581
  return JSON.stringify({
43418
43582
  success: false,
43419
- code: "EXECUTION_RESULT_NOT_PENDING",
43420
- taskId: error.taskId,
43421
- executionResultId: error.executionResultId,
43422
- error: error.message
43583
+ code: "TASK_ACTION_FAILED",
43584
+ error: error instanceof Error ? error.message : String(error),
43585
+ hint: "The action did not complete. Fix the input or retry; do not repeat the identical call."
43423
43586
  });
43424
43587
  }
43425
43588
  return reconcileExplicitExecutionResult(
@@ -43457,15 +43620,16 @@ function createTaskMiddleware(options = {}) {
43457
43620
  assistant_id: invocation.agentId,
43458
43621
  thread_id: invocation.threadId,
43459
43622
  input: { message: invocation.message },
43460
- runConfig: {
43461
- ...rc,
43462
- assistant_id: invocation.agentId,
43463
- thread_id: invocation.threadId,
43464
- taskId: invocation.taskId,
43465
- tenantId: invocation.tenantId,
43466
- workspaceId: invocation.workspaceId,
43467
- projectId: invocation.projectId
43468
- }
43623
+ runConfig: applyWorkerRunScope(
43624
+ {
43625
+ ...rc,
43626
+ assistant_id: invocation.agentId,
43627
+ thread_id: invocation.threadId,
43628
+ taskId: invocation.taskId,
43629
+ tenantId: invocation.tenantId
43630
+ },
43631
+ resolveWorkerRunScope({ invocation, runConfig: rc })
43632
+ )
43469
43633
  });
43470
43634
  const finalState = workerResult?.finalState;
43471
43635
  return boundedWorkerObservation(finalState, void 0);
@@ -43480,7 +43644,7 @@ function createTaskMiddleware(options = {}) {
43480
43644
  agentId,
43481
43645
  actor,
43482
43646
  callerThreadId: rc.thread_id,
43483
- ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : {}
43647
+ ...trustedCaller ? { callerMembershipId: trustedCaller.membershipId, callerAssistantId: trustedCaller.assistantId } : rc.assistant_id ? { callerAssistantId: rc.assistant_id } : {}
43484
43648
  }));
43485
43649
  };
43486
43650
  return createMiddleware23({
@@ -43540,7 +43704,14 @@ function createTaskMiddleware(options = {}) {
43540
43704
  task,
43541
43705
  actor: getRuntimeActor2(rc) ?? "system",
43542
43706
  ...threadId ? { threadId } : {},
43543
- outcome: { kind: "interrupted", summary: "Run ended without a task lifecycle transition" }
43707
+ // A run that ended without its own lifecycle transition is a mechanical
43708
+ // failure, NOT HITL. Human-in-the-loop pauses arrive as GraphInterrupt
43709
+ // and never reach afterAgent.
43710
+ outcome: {
43711
+ kind: "failed",
43712
+ lifecycleHandled: false,
43713
+ error: "Run ended without a task lifecycle transition"
43714
+ }
43544
43715
  });
43545
43716
  }
43546
43717
  taskRunRegistry.unregister(taskId);
@@ -43585,8 +43756,8 @@ changes only when acceptance criteria are truly met.
43585
43756
  ${TASK_CONVERGENCE_GUIDANCE}
43586
43757
 
43587
43758
  ### Ownership defaults
43588
- - No params: ownerType defaults to "user" with current user's ID
43589
- - ownerType="agent": auto-fills ownerId from current agent (subtask for yourself)
43759
+ - No params: ownerType defaults to the runtime actor (user runtime -> current user's ID; agent runtime -> current agent's ID)
43760
+ - ownerType="agent": auto-fills ownerId from the current agent (subtask for yourself)
43590
43761
  - Explicit ownerId: assign to a specific agent or user`;
43591
43762
  const boundTaskId = request.state?.taskId;
43592
43763
  const binding = typeof boundTaskId === "string" && boundTaskId ? renderTaskBinding(boundTaskId) : "";
@@ -43605,7 +43776,7 @@ ${TASK_CONVERGENCE_GUIDANCE}
43605
43776
  description: `Manage persistent tasks and their activity timelines for user and agent tasks.
43606
43777
 
43607
43778
  ## Owner defaults
43608
- - No ownerType/ownerId: auto-assigned to current user
43779
+ - No ownerType/ownerId: auto-assigned to the runtime actor (user runtime -> current user; agent runtime -> current agent)
43609
43780
  - ownerType="agent" without ownerId: auto-assigned to current agent
43610
43781
  - Explicit ownerId: assign to a specific agent (cross-agent delegation)
43611
43782
 
@@ -46689,6 +46860,7 @@ export {
46689
46860
  generateDirectHumanProjectId,
46690
46861
  generateToken,
46691
46862
  getAgentClient,
46863
+ getAgentClientAsync,
46692
46864
  getAgentConfig,
46693
46865
  getAllAgentConfigs,
46694
46866
  getAllBuiltInSkillMetas,