@zhivex-ai/core 1.5.0 → 1.7.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.
Files changed (119) hide show
  1. package/README.md +39 -0
  2. package/dist/agent-handoff-contracts.d.ts +12 -0
  3. package/dist/agent-handoff-contracts.d.ts.map +1 -0
  4. package/dist/agent-handoff-contracts.js +18 -0
  5. package/dist/agent-handoff-contracts.js.map +1 -0
  6. package/dist/agent-handoff.d.ts +2 -11
  7. package/dist/agent-handoff.d.ts.map +1 -1
  8. package/dist/agent-handoff.js +1 -18
  9. package/dist/agent-handoff.js.map +1 -1
  10. package/dist/agent-trace.d.ts +1 -5
  11. package/dist/agent-trace.d.ts.map +1 -1
  12. package/dist/agent-trace.js.map +1 -1
  13. package/dist/agent.d.ts +1 -0
  14. package/dist/agent.d.ts.map +1 -1
  15. package/dist/agent.js +358 -215
  16. package/dist/agent.js.map +1 -1
  17. package/dist/api-stability.d.ts.map +1 -1
  18. package/dist/api-stability.js +36 -25
  19. package/dist/api-stability.js.map +1 -1
  20. package/dist/artifact.d.ts +32 -9
  21. package/dist/artifact.d.ts.map +1 -1
  22. package/dist/artifact.js +428 -82
  23. package/dist/artifact.js.map +1 -1
  24. package/dist/catalog.d.ts +42 -3
  25. package/dist/catalog.d.ts.map +1 -1
  26. package/dist/catalog.js +269 -7
  27. package/dist/catalog.js.map +1 -1
  28. package/dist/contracts.d.ts +8 -0
  29. package/dist/contracts.d.ts.map +1 -0
  30. package/dist/contracts.js +2 -0
  31. package/dist/contracts.js.map +1 -0
  32. package/dist/generate-text.d.ts.map +1 -1
  33. package/dist/generate-text.js +6 -3
  34. package/dist/generate-text.js.map +1 -1
  35. package/dist/google.d.ts +1 -60
  36. package/dist/google.d.ts.map +1 -1
  37. package/dist/google.js +0 -198
  38. package/dist/google.js.map +1 -1
  39. package/dist/index.d.ts +13 -7
  40. package/dist/index.d.ts.map +1 -1
  41. package/dist/index.js +7 -4
  42. package/dist/index.js.map +1 -1
  43. package/dist/live-agent.js +1 -1
  44. package/dist/live-agent.js.map +1 -1
  45. package/dist/middleware.d.ts +16 -0
  46. package/dist/middleware.d.ts.map +1 -1
  47. package/dist/middleware.js +476 -110
  48. package/dist/middleware.js.map +1 -1
  49. package/dist/model-capabilities.d.ts +66 -0
  50. package/dist/model-capabilities.d.ts.map +1 -0
  51. package/dist/model-capabilities.js +136 -0
  52. package/dist/model-capabilities.js.map +1 -0
  53. package/dist/node.d.ts +8 -0
  54. package/dist/node.d.ts.map +1 -0
  55. package/dist/node.js +8 -0
  56. package/dist/node.js.map +1 -0
  57. package/dist/observability.d.ts +57 -10
  58. package/dist/observability.d.ts.map +1 -1
  59. package/dist/observability.js +535 -114
  60. package/dist/observability.js.map +1 -1
  61. package/dist/pricing.d.ts +7 -0
  62. package/dist/pricing.d.ts.map +1 -0
  63. package/dist/pricing.js +2 -0
  64. package/dist/pricing.js.map +1 -0
  65. package/dist/provider-resources.d.ts +61 -0
  66. package/dist/provider-resources.d.ts.map +1 -0
  67. package/dist/provider-resources.js +199 -0
  68. package/dist/provider-resources.js.map +1 -0
  69. package/dist/runner.js +1 -1
  70. package/dist/runner.js.map +1 -1
  71. package/dist/runtime-entry.d.ts +15 -0
  72. package/dist/runtime-entry.d.ts.map +1 -0
  73. package/dist/runtime-entry.js +14 -0
  74. package/dist/runtime-entry.js.map +1 -0
  75. package/dist/runtime.d.ts +9 -1
  76. package/dist/runtime.d.ts.map +1 -1
  77. package/dist/runtime.js +35 -8
  78. package/dist/runtime.js.map +1 -1
  79. package/dist/secure-id-node.d.ts +2 -0
  80. package/dist/secure-id-node.d.ts.map +1 -0
  81. package/dist/secure-id-node.js +3 -0
  82. package/dist/secure-id-node.js.map +1 -0
  83. package/dist/secure-id.d.ts.map +1 -1
  84. package/dist/secure-id.js +6 -2
  85. package/dist/secure-id.js.map +1 -1
  86. package/dist/testing.d.ts +4 -0
  87. package/dist/testing.d.ts.map +1 -0
  88. package/dist/testing.js +4 -0
  89. package/dist/testing.js.map +1 -0
  90. package/dist/types.d.ts +74 -6
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/ui-entry.d.ts +6 -0
  93. package/dist/ui-entry.d.ts.map +1 -0
  94. package/dist/ui-entry.js +5 -0
  95. package/dist/ui-entry.js.map +1 -0
  96. package/dist/ui.js +1 -1
  97. package/dist/ui.js.map +1 -1
  98. package/dist/workflow-observability.d.ts +13 -0
  99. package/dist/workflow-observability.d.ts.map +1 -0
  100. package/dist/workflow-observability.js +186 -0
  101. package/dist/workflow-observability.js.map +1 -0
  102. package/dist/workflow-state-contracts.d.ts +76 -0
  103. package/dist/workflow-state-contracts.d.ts.map +1 -0
  104. package/dist/workflow-state-contracts.js +49 -0
  105. package/dist/workflow-state-contracts.js.map +1 -0
  106. package/dist/workflow-state-service.d.ts +3 -34
  107. package/dist/workflow-state-service.d.ts.map +1 -1
  108. package/dist/workflow-state-service.js +2 -2
  109. package/dist/workflow-state-service.js.map +1 -1
  110. package/dist/workflow.d.ts +53 -42
  111. package/dist/workflow.d.ts.map +1 -1
  112. package/dist/workflow.js +258 -125
  113. package/dist/workflow.js.map +1 -1
  114. package/dist/workflows-entry.d.ts +9 -0
  115. package/dist/workflows-entry.d.ts.map +1 -0
  116. package/dist/workflows-entry.js +5 -0
  117. package/dist/workflows-entry.js.map +1 -0
  118. package/package.json +42 -1
  119. package/secure-id-internal.d.ts +1 -0
package/dist/agent.js CHANGED
@@ -1,15 +1,15 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { createAgentApprovalMessage, getAgentApprovalRequests } from "./agent-approval.js";
3
- import { createAgentHandoffMessage } from "./agent-handoff.js";
3
+ import { createAgentHandoffMessage } from "./agent-handoff-contracts.js";
4
4
  import { createAgentExecutionEnvironmentBinding, fingerprintAgentHarness } from "./agent-harness.js";
5
5
  import { AGENT_RUN_STATE_SCHEMA_VERSION, normalizeAgentRunState } from "./agent-state.js";
6
6
  import { BoundedReplayBroadcast } from "./bounded-broadcast.js";
7
7
  import { ConflictError, GuardrailTriggeredError, UnsupportedFeatureError, ValidationError } from "./errors.js";
8
8
  import { aggregateTokenUsage, generateText, getGenerateTextStepTiming, normalizeMessages, streamText } from "./generate-text.js";
9
9
  import { createTextMessage, isCallableToolDefinition, serializeJsonValue } from "./messages.js";
10
- import { mergeAbortSignals } from "./runtime.js";
10
+ import { createMergedAbortSignal } from "./runtime.js";
11
11
  import { evaluateAgentBudgetPreflight, getAgentBudgetStatus } from "./safety-policy.js";
12
- import { createSecureId } from "./secure-id.js";
12
+ import { createSecureId } from "#secure-id";
13
13
  import { createStructuredOutputPrompt } from "./structured-output-prompt.js";
14
14
  import { ToolExecutionSuspendedError } from "./tool-execution-suspension.js";
15
15
  import { toToolSet } from "./tool-registry.js";
@@ -416,6 +416,71 @@ const finalizeState = (agent, state, result, newSteps, newToolResults) => {
416
416
  const emitTelemetryEvent = async (agent, event) => {
417
417
  await invokeOperationalHook(agent, "telemetry", event.type, event.runId, agent.onTelemetryEvent ? () => agent.onTelemetryEvent(event) : undefined, undefined);
418
418
  };
419
+ const emitInvocationStartTelemetry = async (agent, runId, startedAt, maxSteps) => {
420
+ try {
421
+ await agent.onTelemetryEvent?.startInvocation?.({
422
+ runId,
423
+ agentId: agent.id,
424
+ agentName: agent.name,
425
+ provider: agent.model.provider,
426
+ modelId: agent.model.modelId,
427
+ maxSteps,
428
+ startedAt
429
+ });
430
+ }
431
+ catch {
432
+ // Invocation telemetry is best-effort and cannot replace setup/business errors.
433
+ }
434
+ };
435
+ const emitInvocationFinishTelemetry = async (agent, runId, status, error) => {
436
+ try {
437
+ await agent.onTelemetryEvent?.finishInvocation?.({
438
+ runId,
439
+ agentId: agent.id,
440
+ agentName: agent.name,
441
+ status,
442
+ error,
443
+ finishedAt: Date.now()
444
+ });
445
+ }
446
+ catch {
447
+ // Invocation telemetry is best-effort and cannot replace setup/business errors.
448
+ }
449
+ };
450
+ const withAgentTelemetryRunContext = (agent, runId, callback) => {
451
+ const telemetryObserver = agent.onTelemetryEvent;
452
+ const wrapper = telemetryObserver?.withRunContext;
453
+ if (!wrapper)
454
+ return Promise.resolve().then(callback);
455
+ let execution;
456
+ let callbackError;
457
+ let callbackFailed = false;
458
+ const executeOnce = () => {
459
+ execution ??= Promise.resolve()
460
+ .then(callback)
461
+ .catch((error) => {
462
+ callbackFailed = true;
463
+ callbackError = error;
464
+ throw error;
465
+ });
466
+ return execution;
467
+ };
468
+ return Promise.resolve()
469
+ .then(async () => {
470
+ await wrapper.call(telemetryObserver, runId, executeOnce);
471
+ return executeOnce();
472
+ })
473
+ .catch(async (wrapperError) => {
474
+ if (callbackFailed)
475
+ throw callbackError;
476
+ try {
477
+ return await executeOnce();
478
+ }
479
+ catch (executionError) {
480
+ throw callbackFailed ? callbackError : executionError ?? wrapperError;
481
+ }
482
+ });
483
+ };
419
484
  const subAgentToolInputSchema = z.object({
420
485
  prompt: z.string().min(1),
421
486
  system: z.string().optional()
@@ -1171,6 +1236,7 @@ const createGenerateOptions = (agent, state, input, messages, maxSteps, context,
1171
1236
  context,
1172
1237
  runId: state.runId,
1173
1238
  agentId: state.agentId,
1239
+ agentName: agent.name,
1174
1240
  scope: state.scope,
1175
1241
  metadata: state.metadata,
1176
1242
  executionEnvironment: executionEnvironmentSession
@@ -1206,19 +1272,27 @@ const createGenerateOptions = (agent, state, input, messages, maxSteps, context,
1206
1272
  return compacted.messages;
1207
1273
  }
1208
1274
  : undefined,
1209
- onBeforeModelStep: ({ step }) => {
1210
- if (!budget)
1211
- return;
1212
- const trigger = evaluateAgentBudgetPreflight(state, budget, {
1213
- operation: "model",
1214
- requiredSteps: Math.max(1, step - state.currentStep),
1215
- requestedOutputTokens: maxTokens
1216
- });
1217
- if (trigger) {
1218
- throw new GuardrailTriggeredError("input", trigger.reason ?? "Agent model budget preflight failed.", {
1219
- metadata: trigger.metadata
1275
+ onBeforeModelStep: async ({ step }) => {
1276
+ if (budget) {
1277
+ const trigger = evaluateAgentBudgetPreflight(state, budget, {
1278
+ operation: "model",
1279
+ requiredSteps: Math.max(1, step - state.currentStep),
1280
+ requestedOutputTokens: maxTokens
1220
1281
  });
1282
+ if (trigger) {
1283
+ throw new GuardrailTriggeredError("input", trigger.reason ?? "Agent model budget preflight failed.", {
1284
+ metadata: trigger.metadata
1285
+ });
1286
+ }
1221
1287
  }
1288
+ await emitTelemetryEvent(agent, {
1289
+ type: "step-start",
1290
+ runId: state.runId,
1291
+ agentId: state.agentId,
1292
+ agentName: agent.name,
1293
+ stepIndex: step,
1294
+ startedAt: Date.now()
1295
+ });
1222
1296
  },
1223
1297
  onModelStep: async ({ request, response, step, toolCalls, approvalRequests }) => {
1224
1298
  if (!agent.store)
@@ -1285,17 +1359,28 @@ const createGenerateOptions = (agent, state, input, messages, maxSteps, context,
1285
1359
  state.revision = checkpointState.revision;
1286
1360
  },
1287
1361
  stepOffset: state.currentStep,
1288
- onBeforeToolExecution: ({ toolCalls }) => {
1289
- if (!budget)
1290
- return;
1291
- reservedToolCalls += toolCalls.length;
1292
- const trigger = evaluateAgentBudgetPreflight(state, budget, {
1293
- operation: "tool",
1294
- requiredToolCalls: reservedToolCalls
1295
- });
1296
- if (trigger) {
1297
- throw new GuardrailTriggeredError("input", trigger.reason ?? "Agent tool budget preflight failed.", {
1298
- metadata: trigger.metadata
1362
+ onBeforeToolExecution: async ({ step, toolCalls }) => {
1363
+ if (budget) {
1364
+ reservedToolCalls += toolCalls.length;
1365
+ const trigger = evaluateAgentBudgetPreflight(state, budget, {
1366
+ operation: "tool",
1367
+ requiredToolCalls: reservedToolCalls
1368
+ });
1369
+ if (trigger) {
1370
+ throw new GuardrailTriggeredError("input", trigger.reason ?? "Agent tool budget preflight failed.", {
1371
+ metadata: trigger.metadata
1372
+ });
1373
+ }
1374
+ }
1375
+ for (const toolCall of toolCalls) {
1376
+ await emitTelemetryEvent(agent, {
1377
+ type: "tool-start",
1378
+ runId: state.runId,
1379
+ agentId: state.agentId,
1380
+ agentName: agent.name,
1381
+ stepIndex: step,
1382
+ toolCall,
1383
+ startedAt: Date.now()
1299
1384
  });
1300
1385
  }
1301
1386
  },
@@ -1347,22 +1432,22 @@ const resolveRunPolicy = (agent, input) => {
1347
1432
  return Object.keys(policy).length ? policy : undefined;
1348
1433
  };
1349
1434
  const withAgentPolicyTimeout = async (operation, timeout) => {
1350
- if (!timeout.timeoutPromise) {
1351
- return operation;
1352
- }
1353
1435
  try {
1354
- return await Promise.race([operation, timeout.timeoutPromise]);
1436
+ return timeout.timeoutPromise
1437
+ ? await Promise.race([operation, timeout.timeoutPromise])
1438
+ : await operation;
1355
1439
  }
1356
1440
  finally {
1357
1441
  timeout.cleanup();
1358
1442
  }
1359
1443
  };
1360
- const createAgentAbortContext = (inputAbortSignal, policy) => {
1444
+ const createAgentAbortContext = (inputAbortSignal, policy, ...additionalSignals) => {
1361
1445
  if (!policy?.timeoutMs) {
1446
+ const merged = createMergedAbortSignal(inputAbortSignal, ...additionalSignals);
1362
1447
  return {
1363
- signal: inputAbortSignal,
1448
+ signal: merged.signal,
1364
1449
  timeoutPromise: undefined,
1365
- cleanup: () => undefined,
1450
+ cleanup: merged.cleanup,
1366
1451
  isTimedOut: () => false
1367
1452
  };
1368
1453
  }
@@ -1376,10 +1461,12 @@ const createAgentAbortContext = (inputAbortSignal, policy) => {
1376
1461
  reject(new AgentPolicyTimeoutError(policy.timeoutMs));
1377
1462
  }, policy.timeoutMs);
1378
1463
  });
1464
+ const merged = createMergedAbortSignal(inputAbortSignal, ...additionalSignals, controller.signal);
1379
1465
  return {
1380
- signal: mergeAbortSignals(inputAbortSignal, controller.signal),
1466
+ signal: merged.signal,
1381
1467
  timeoutPromise,
1382
1468
  cleanup: () => {
1469
+ merged.cleanup();
1383
1470
  if (timeout) {
1384
1471
  clearTimeout(timeout);
1385
1472
  }
@@ -1500,14 +1587,16 @@ const acquireAgentExecutionLease = async (agent, state, policy) => {
1500
1587
  }
1501
1588
  };
1502
1589
  };
1503
- const emitRunStartTelemetry = async (agent, state, memoryMessages, approvals) => {
1590
+ const emitRunStartTelemetry = async (agent, state, memoryMessages, approvals, invocationStartedAt) => {
1504
1591
  await emitTelemetryEvent(agent, {
1505
1592
  type: "run-start",
1506
1593
  runId: state.runId,
1507
1594
  agentId: state.agentId,
1595
+ agentName: agent.name,
1508
1596
  provider: state.provider,
1509
1597
  modelId: state.modelId,
1510
- maxSteps: state.maxSteps
1598
+ maxSteps: state.maxSteps,
1599
+ startedAt: invocationStartedAt
1511
1600
  });
1512
1601
  if (state.handoff) {
1513
1602
  await emitTelemetryEvent(agent, {
@@ -1539,8 +1628,10 @@ const emitRunFinishTelemetry = async (agent, state) => {
1539
1628
  type: "run-finish",
1540
1629
  runId: state.runId,
1541
1630
  agentId: state.agentId,
1631
+ agentName: agent.name,
1542
1632
  status: state.status,
1543
- state: cloneState(state)
1633
+ state: cloneState(state),
1634
+ finishedAt: Date.now()
1544
1635
  });
1545
1636
  };
1546
1637
  export const createAgent = (definition) => ({
@@ -1549,6 +1640,7 @@ export const createAgent = (definition) => ({
1549
1640
  });
1550
1641
  export class Agent {
1551
1642
  id;
1643
+ name;
1552
1644
  model;
1553
1645
  instructions;
1554
1646
  contextSchema;
@@ -1584,6 +1676,7 @@ export class Agent {
1584
1676
  toDefinition() {
1585
1677
  return createAgent({
1586
1678
  id: this.id,
1679
+ name: this.name,
1587
1680
  model: this.model,
1588
1681
  instructions: this.instructions,
1589
1682
  contextSchema: this.contextSchema,
@@ -1671,16 +1764,17 @@ export const runAgentGroup = async (agents, input = {}) => {
1671
1764
  });
1672
1765
  };
1673
1766
  const runs = agents.map(async (member, index) => {
1674
- const runInput = {
1675
- ...sharedInput,
1676
- ...(member.input ?? {}),
1677
- parentRunId: member.input?.parentRunId ?? parentRunId,
1678
- abortSignal: mergeAbortSignals(input.abortSignal, member.input?.abortSignal, controllers[index].signal),
1679
- metadata: cloneMetadata(input.metadata, member.input?.metadata, {
1680
- ...(member.name ? { agentGroupMember: member.name } : {})
1681
- })
1682
- };
1767
+ const merged = createMergedAbortSignal(input.abortSignal, member.input?.abortSignal, controllers[index].signal);
1683
1768
  try {
1769
+ const runInput = {
1770
+ ...sharedInput,
1771
+ ...(member.input ?? {}),
1772
+ parentRunId: member.input?.parentRunId ?? parentRunId,
1773
+ abortSignal: merged.signal,
1774
+ metadata: cloneMetadata(input.metadata, member.input?.metadata, {
1775
+ ...(member.name ? { agentGroupMember: member.name } : {})
1776
+ })
1777
+ };
1684
1778
  const output = await runAgent(member.agent, runInput);
1685
1779
  if (isFailingOutput(output)) {
1686
1780
  abortPending(index);
@@ -1691,6 +1785,9 @@ export const runAgentGroup = async (agents, input = {}) => {
1691
1785
  abortPending(index);
1692
1786
  throw error;
1693
1787
  }
1788
+ finally {
1789
+ merged.cleanup();
1790
+ }
1694
1791
  });
1695
1792
  const settled = await Promise.allSettled(runs);
1696
1793
  const outputs = settled.map((result, index) => {
@@ -1788,175 +1885,204 @@ export const cancelAgentRunTree = async (store, runId, options = {}) => {
1788
1885
  };
1789
1886
  };
1790
1887
  export const runAgent = async (agent, input = {}) => {
1791
- const context = await resolveContext(agent, input);
1792
- const currentStatus = normalizeApprovalStatus(context.state.status);
1793
- const policy = resolveRunPolicy(agent, input);
1794
- if (currentStatus === "completed" ||
1795
- currentStatus === "cancelled" ||
1796
- currentStatus === "cancel_requested" ||
1797
- currentStatus === "timed_out") {
1798
- context.state.status = currentStatus;
1799
- return toOutput(context.state);
1800
- }
1801
- if (currentStatus === "waiting_approval" && context.state.pendingApprovals.length > 0) {
1802
- context.state.status = currentStatus;
1803
- return toOutput(context.state);
1804
- }
1805
- const supportsLeases = Boolean(agent.store?.acquireLease && agent.store.renewLease && agent.store.releaseLease);
1806
- if (!context.fresh && currentStatus === "running" && !supportsLeases) {
1807
- return toOutput(context.state);
1808
- }
1809
- const freshRequiresExistingClaim = context.fresh && Boolean(context.state.idempotencyKey);
1810
- if (context.fresh && !freshRequiresExistingClaim) {
1811
- await claimAgentExecution(agent, context.state);
1812
- }
1813
- const executionLease = await acquireAgentExecutionLease(agent, context.state, policy);
1814
- if (!executionLease) {
1815
- if (input.state) {
1816
- throw new ConflictError(`Agent run "${context.state.runId}" is already owned by another worker.`);
1888
+ const invocationStartedAt = Date.now();
1889
+ const telemetryRunId = input.runId ?? input.state?.runId ?? randomId("run");
1890
+ const invocationInput = input.runId || input.state
1891
+ ? input
1892
+ : { ...input, runId: telemetryRunId };
1893
+ let invocationStatus = "completed";
1894
+ let invocationError;
1895
+ const returnInvocationOutput = (output) => {
1896
+ invocationStatus = output.status;
1897
+ if (output.status === "failed" || output.status === "timed_out") {
1898
+ invocationError = new Error(output.error?.message ?? `Agent invocation ${output.status}.`);
1899
+ if (output.status === "timed_out")
1900
+ invocationError.name = "TimeoutError";
1817
1901
  }
1818
- const activeState = await agent.store?.load(context.state.runId, context.state.scope);
1819
- return toOutput(activeState ? normalizeAgentRunState(activeState) : context.state);
1820
- }
1902
+ else {
1903
+ invocationError = undefined;
1904
+ }
1905
+ return output;
1906
+ };
1907
+ await emitInvocationStartTelemetry(agent, telemetryRunId, invocationStartedAt, Math.max(1, input.maxSteps ?? input.state?.maxSteps ?? agent.maxSteps ?? 1));
1821
1908
  try {
1822
- if (!context.fresh || freshRequiresExistingClaim) {
1909
+ const context = await resolveContext(agent, invocationInput);
1910
+ const currentStatus = normalizeApprovalStatus(context.state.status);
1911
+ const policy = resolveRunPolicy(agent, input);
1912
+ if (currentStatus === "completed" ||
1913
+ currentStatus === "cancelled" ||
1914
+ currentStatus === "cancel_requested" ||
1915
+ currentStatus === "timed_out") {
1916
+ context.state.status = currentStatus;
1917
+ invocationStatus = currentStatus;
1918
+ return returnInvocationOutput(toOutput(context.state));
1919
+ }
1920
+ if (currentStatus === "waiting_approval" && context.state.pendingApprovals.length > 0) {
1921
+ context.state.status = currentStatus;
1922
+ invocationStatus = currentStatus;
1923
+ return returnInvocationOutput(toOutput(context.state));
1924
+ }
1925
+ const supportsLeases = Boolean(agent.store?.acquireLease && agent.store.renewLease && agent.store.releaseLease);
1926
+ if (!context.fresh && currentStatus === "running" && !supportsLeases) {
1927
+ invocationStatus = currentStatus;
1928
+ return returnInvocationOutput(toOutput(context.state));
1929
+ }
1930
+ const freshRequiresExistingClaim = context.fresh && Boolean(context.state.idempotencyKey);
1931
+ if (context.fresh && !freshRequiresExistingClaim) {
1823
1932
  await claimAgentExecution(agent, context.state);
1824
1933
  }
1825
- await emitRunStartTelemetry(agent, context.state, context.memoryMessages, input.approvals);
1826
- }
1827
- catch (error) {
1828
- await executionLease.release();
1829
- throw error;
1830
- }
1831
- if (context.remainingSteps === 0) {
1832
- const state = createFailedState(context.state, "Agent exhausted maxSteps before reaching a terminal response.");
1833
- await persistState(agent, state, policy);
1834
- await emitRunFinishTelemetry(agent, state);
1835
- await executionLease.release();
1836
- return toOutput(state);
1837
- }
1838
- let inputGuardrail;
1839
- try {
1840
- inputGuardrail = await runGuardrails(agent, context.state, "input", agent.inputGuardrails, () => ({
1841
- runId: context.state.runId,
1842
- agentId: context.state.agentId,
1843
- context: context.context,
1844
- state: cloneState(context.state),
1845
- messages: context.messages,
1846
- metadata: context.state.metadata
1847
- }));
1848
- }
1849
- catch (error) {
1850
- await executionLease.release();
1851
- throw error;
1852
- }
1853
- if (inputGuardrail) {
1854
- const failedState = applyGuardrailFailure(context.state, "input", inputGuardrail);
1855
- await persistState(agent, failedState, policy);
1856
- await emitRunFinishTelemetry(agent, failedState);
1857
- await executionLease.release();
1858
- return toOutput(failedState);
1859
- }
1860
- try {
1861
- await emitTelemetryEvent(agent, {
1862
- type: "step-start",
1863
- runId: context.state.runId,
1864
- agentId: context.state.agentId,
1865
- stepIndex: context.state.currentStep + 1
1866
- });
1867
- }
1868
- catch (error) {
1869
- await executionLease.release();
1870
- throw error;
1871
- }
1872
- const abortContext = createAgentAbortContext(mergeAbortSignals(input.abortSignal, executionLease.signal), policy);
1873
- let executionEnvironmentSession;
1874
- let executionEnvironmentStatus = "failed";
1875
- let executionEnvironmentError;
1876
- try {
1877
- executionEnvironmentSession = await acquireExecutionEnvironment(context.executionEnvironment, context.state, context.context, abortContext.signal);
1878
- }
1879
- catch (error) {
1880
- await executionLease.release();
1881
- throw error;
1882
- }
1883
- try {
1884
- const result = await withAgentPolicyTimeout(generateText(createGenerateOptions(agent, context.state, input, context.messages, context.remainingSteps, context.context, executionEnvironmentSession, abortContext.signal)), abortContext);
1885
- const cancelled = executionLease.cancelledState();
1886
- if (cancelled) {
1887
- executionEnvironmentStatus = cancelled.status;
1888
- await emitRunFinishTelemetry(agent, cancelled);
1889
- return toOutput(cancelled);
1890
- }
1891
- if (executionLease.leaseLost()) {
1892
- throw new ConflictError(`Agent run "${context.state.runId}" lost its worker lease.`);
1893
- }
1894
- const newSteps = mapSteps(result.steps, context.state.currentStep, result.toolResults);
1895
- let output = finalizeState(agent, context.state, result, newSteps, result.toolResults);
1896
- const outputGuardrail = await runGuardrails(agent, output.state, "output", agent.outputGuardrails, () => ({
1897
- runId: output.state.runId,
1898
- agentId: output.state.agentId,
1899
- context: context.context,
1900
- state: cloneState(output.state),
1901
- output,
1902
- metadata: output.state.metadata
1903
- }));
1904
- if (outputGuardrail) {
1905
- output = toOutput(applyGuardrailFailure(output.state, "output", outputGuardrail));
1906
- }
1907
- await emitFinalizedStepTelemetry(agent, output.state, newSteps);
1908
- await emitApprovalTelemetry(agent, output.state, [
1909
- ...(result.approvalRequests ?? []),
1910
- ...approvalsFromEvents(newSteps.flatMap((step) => step.response?.messages ?? []))
1911
- ]);
1912
- await persistState(agent, output.state, policy);
1913
- await emitRunFinishTelemetry(agent, output.state);
1914
- executionEnvironmentStatus = output.status;
1915
- return output;
1916
- }
1917
- catch (error) {
1918
- executionEnvironmentError = {
1919
- message: error instanceof Error ? error.message : String(error)
1920
- };
1921
- const cancelled = executionLease.cancelledState();
1922
- if (cancelled) {
1923
- executionEnvironmentStatus = cancelled.status;
1924
- await emitRunFinishTelemetry(agent, cancelled);
1925
- return toOutput(cancelled);
1926
- }
1927
- if (executionLease.leaseLost()) {
1928
- throw new ConflictError(`Agent run "${context.state.runId}" lost its worker lease.`);
1929
- }
1930
- if (error instanceof AgentPolicyTimeoutError || abortContext.isTimedOut()) {
1931
- const status = policy?.onTimeout === "cancel-requested" ? "cancel_requested" : "timed_out";
1932
- const message = error instanceof Error ? error.message : `Agent run timed out after ${policy?.timeoutMs}ms.`;
1934
+ const executionLease = await acquireAgentExecutionLease(agent, context.state, policy);
1935
+ if (!executionLease) {
1936
+ if (input.state) {
1937
+ throw new ConflictError(`Agent run "${context.state.runId}" is already owned by another worker.`);
1938
+ }
1939
+ const activeState = await agent.store?.load(context.state.runId, context.state.scope);
1940
+ const outputState = activeState ? normalizeAgentRunState(activeState) : context.state;
1941
+ invocationStatus = outputState.status;
1942
+ return returnInvocationOutput(toOutput(outputState));
1943
+ }
1944
+ try {
1945
+ if (!context.fresh || freshRequiresExistingClaim) {
1946
+ await claimAgentExecution(agent, context.state);
1947
+ }
1948
+ await emitRunStartTelemetry(agent, context.state, context.memoryMessages, input.approvals, invocationStartedAt);
1949
+ }
1950
+ catch (error) {
1951
+ await executionLease.release();
1952
+ throw error;
1953
+ }
1954
+ if (context.remainingSteps === 0) {
1955
+ const state = createFailedState(context.state, "Agent exhausted maxSteps before reaching a terminal response.");
1956
+ await persistState(agent, state, policy);
1957
+ await emitRunFinishTelemetry(agent, state);
1958
+ await executionLease.release();
1959
+ return returnInvocationOutput(toOutput(state));
1960
+ }
1961
+ let inputGuardrail;
1962
+ try {
1963
+ inputGuardrail = await runGuardrails(agent, context.state, "input", agent.inputGuardrails, () => ({
1964
+ runId: context.state.runId,
1965
+ agentId: context.state.agentId,
1966
+ context: context.context,
1967
+ state: cloneState(context.state),
1968
+ messages: context.messages,
1969
+ metadata: context.state.metadata
1970
+ }));
1971
+ }
1972
+ catch (error) {
1973
+ await executionLease.release();
1974
+ throw error;
1975
+ }
1976
+ if (inputGuardrail) {
1977
+ const failedState = applyGuardrailFailure(context.state, "input", inputGuardrail);
1978
+ await persistState(agent, failedState, policy);
1979
+ await emitRunFinishTelemetry(agent, failedState);
1980
+ await executionLease.release();
1981
+ return returnInvocationOutput(toOutput(failedState));
1982
+ }
1983
+ const abortContext = createAgentAbortContext(input.abortSignal, policy, executionLease.signal);
1984
+ let executionEnvironmentSession;
1985
+ let executionEnvironmentStatus = "failed";
1986
+ let executionEnvironmentError;
1987
+ try {
1988
+ executionEnvironmentSession = await acquireExecutionEnvironment(context.executionEnvironment, context.state, context.context, abortContext.signal);
1989
+ }
1990
+ catch (error) {
1991
+ abortContext.cleanup();
1992
+ await executionLease.release();
1993
+ throw error;
1994
+ }
1995
+ try {
1996
+ const result = await withAgentTelemetryRunContext(agent, context.state.runId, () => withAgentPolicyTimeout(generateText(createGenerateOptions(agent, context.state, input, context.messages, context.remainingSteps, context.context, executionEnvironmentSession, abortContext.signal)), abortContext));
1997
+ const cancelled = executionLease.cancelledState();
1998
+ if (cancelled) {
1999
+ executionEnvironmentStatus = cancelled.status;
2000
+ await emitRunFinishTelemetry(agent, cancelled);
2001
+ return returnInvocationOutput(toOutput(cancelled));
2002
+ }
2003
+ if (executionLease.leaseLost()) {
2004
+ throw new ConflictError(`Agent run "${context.state.runId}" lost its worker lease.`);
2005
+ }
2006
+ const newSteps = mapSteps(result.steps, context.state.currentStep, result.toolResults);
2007
+ let output = finalizeState(agent, context.state, result, newSteps, result.toolResults);
2008
+ const outputGuardrail = await runGuardrails(agent, output.state, "output", agent.outputGuardrails, () => ({
2009
+ runId: output.state.runId,
2010
+ agentId: output.state.agentId,
2011
+ context: context.context,
2012
+ state: cloneState(output.state),
2013
+ output,
2014
+ metadata: output.state.metadata
2015
+ }));
2016
+ if (outputGuardrail) {
2017
+ output = toOutput(applyGuardrailFailure(output.state, "output", outputGuardrail));
2018
+ }
2019
+ await emitFinalizedStepTelemetry(agent, output.state, newSteps);
2020
+ await emitApprovalTelemetry(agent, output.state, [
2021
+ ...(result.approvalRequests ?? []),
2022
+ ...approvalsFromEvents(newSteps.flatMap((step) => step.response?.messages ?? []))
2023
+ ]);
2024
+ await persistState(agent, output.state, policy);
2025
+ await emitRunFinishTelemetry(agent, output.state);
2026
+ executionEnvironmentStatus = output.status;
2027
+ return returnInvocationOutput(output);
2028
+ }
2029
+ catch (error) {
2030
+ executionEnvironmentError = {
2031
+ message: error instanceof Error ? error.message : String(error)
2032
+ };
2033
+ const cancelled = executionLease.cancelledState();
2034
+ if (cancelled) {
2035
+ executionEnvironmentStatus = cancelled.status;
2036
+ await emitRunFinishTelemetry(agent, cancelled);
2037
+ return returnInvocationOutput(toOutput(cancelled));
2038
+ }
2039
+ if (executionLease.leaseLost()) {
2040
+ throw new ConflictError(`Agent run "${context.state.runId}" lost its worker lease.`);
2041
+ }
2042
+ if (error instanceof AgentPolicyTimeoutError || abortContext.isTimedOut()) {
2043
+ const status = policy?.onTimeout === "cancel-requested" ? "cancel_requested" : "timed_out";
2044
+ const message = error instanceof Error ? error.message : `Agent run timed out after ${policy?.timeoutMs}ms.`;
2045
+ const durableState = agent.store
2046
+ ? normalizeAgentRunState((await agent.store.load(context.state.runId, context.state.scope)) ?? context.state)
2047
+ : context.state;
2048
+ const timedOutState = createTerminalState(durableState, status, message);
2049
+ await persistState(agent, timedOutState, policy);
2050
+ await emitRunFinishTelemetry(agent, timedOutState);
2051
+ executionEnvironmentStatus = timedOutState.status;
2052
+ return returnInvocationOutput(toOutput(timedOutState));
2053
+ }
1933
2054
  const durableState = agent.store
1934
2055
  ? normalizeAgentRunState((await agent.store.load(context.state.runId, context.state.scope)) ?? context.state)
1935
2056
  : context.state;
1936
- const timedOutState = createTerminalState(durableState, status, message);
1937
- await persistState(agent, timedOutState, policy);
1938
- await emitRunFinishTelemetry(agent, timedOutState);
1939
- executionEnvironmentStatus = timedOutState.status;
1940
- return toOutput(timedOutState);
1941
- }
1942
- const durableState = agent.store
1943
- ? normalizeAgentRunState((await agent.store.load(context.state.runId, context.state.scope)) ?? context.state)
1944
- : context.state;
1945
- const failedState = createFailedState(durableState, error instanceof Error ? error.message : String(error));
1946
- await persistState(agent, failedState, policy);
1947
- await emitRunFinishTelemetry(agent, failedState);
1948
- executionEnvironmentStatus = failedState.status;
2057
+ const failedState = createFailedState(durableState, error instanceof Error ? error.message : String(error));
2058
+ await persistState(agent, failedState, policy);
2059
+ await emitRunFinishTelemetry(agent, failedState);
2060
+ executionEnvironmentStatus = failedState.status;
2061
+ throw error;
2062
+ }
2063
+ finally {
2064
+ await executionEnvironmentSession?.release?.({
2065
+ status: executionEnvironmentStatus,
2066
+ error: executionEnvironmentError
2067
+ });
2068
+ await executionLease.release();
2069
+ }
2070
+ }
2071
+ catch (error) {
2072
+ invocationStatus = "failed";
2073
+ invocationError = error instanceof Error ? error : new Error(String(error));
1949
2074
  throw error;
1950
2075
  }
1951
2076
  finally {
1952
- await executionEnvironmentSession?.release?.({
1953
- status: executionEnvironmentStatus,
1954
- error: executionEnvironmentError
1955
- });
1956
- await executionLease.release();
2077
+ await emitInvocationFinishTelemetry(agent, telemetryRunId, invocationStatus, invocationError);
1957
2078
  }
1958
2079
  };
1959
2080
  export const streamAgent = (agent, input = {}) => {
2081
+ const invocationStartedAt = Date.now();
2082
+ const telemetryRunId = input.runId ?? input.state?.runId ?? randomId("run");
2083
+ const invocationInput = input.runId || input.state
2084
+ ? input
2085
+ : { ...input, runId: telemetryRunId };
1960
2086
  const policy = resolveRunPolicy(agent, input);
1961
2087
  const broadcast = new BoundedReplayBroadcast({
1962
2088
  maxHistory: policy?.maxStreamEvents ?? 4096
@@ -1964,12 +2090,19 @@ export const streamAgent = (agent, input = {}) => {
1964
2090
  const publish = (event, terminal = false) => broadcast.publish(event, { terminal });
1965
2091
  let activeLease;
1966
2092
  let activeExecutionEnvironment;
2093
+ let invocationFinishPromise;
2094
+ const finishInvocation = (status, error) => {
2095
+ invocationFinishPromise ??= emitInvocationFinishTelemetry(agent, telemetryRunId, status, error);
2096
+ return invocationFinishPromise;
2097
+ };
1967
2098
  const runner = (async () => {
1968
- const context = await resolveContext(agent, input);
2099
+ await emitInvocationStartTelemetry(agent, telemetryRunId, invocationStartedAt, Math.max(1, input.maxSteps ?? input.state?.maxSteps ?? agent.maxSteps ?? 1));
2100
+ const context = await resolveContext(agent, invocationInput);
1969
2101
  const currentStatus = normalizeApprovalStatus(context.state.status);
1970
2102
  const supportsLeases = Boolean(agent.store?.acquireLease && agent.store.renewLease && agent.store.releaseLease);
1971
2103
  if (!context.fresh && currentStatus === "running" && !supportsLeases) {
1972
2104
  broadcast.close();
2105
+ await finishInvocation(currentStatus);
1973
2106
  return {
1974
2107
  output: toOutput(context.state),
1975
2108
  textStream: emptyAsyncIterable()
@@ -1981,6 +2114,7 @@ export const streamAgent = (agent, input = {}) => {
1981
2114
  currentStatus === "timed_out") {
1982
2115
  context.state.status = currentStatus;
1983
2116
  broadcast.close();
2117
+ await finishInvocation(currentStatus);
1984
2118
  return {
1985
2119
  output: toOutput(context.state),
1986
2120
  textStream: emptyAsyncIterable()
@@ -1989,6 +2123,7 @@ export const streamAgent = (agent, input = {}) => {
1989
2123
  if (currentStatus === "waiting_approval" && context.state.pendingApprovals.length > 0) {
1990
2124
  context.state.status = currentStatus;
1991
2125
  broadcast.close();
2126
+ await finishInvocation(currentStatus);
1992
2127
  return {
1993
2128
  output: toOutput(context.state),
1994
2129
  textStream: emptyAsyncIterable()
@@ -2005,8 +2140,10 @@ export const streamAgent = (agent, input = {}) => {
2005
2140
  }
2006
2141
  const activeState = await agent.store?.load(context.state.runId, context.state.scope);
2007
2142
  broadcast.close();
2143
+ const outputState = activeState ? normalizeAgentRunState(activeState) : context.state;
2144
+ await finishInvocation(outputState.status);
2008
2145
  return {
2009
- output: toOutput(activeState ? normalizeAgentRunState(activeState) : context.state),
2146
+ output: toOutput(outputState),
2010
2147
  textStream: emptyAsyncIterable()
2011
2148
  };
2012
2149
  }
@@ -2015,7 +2152,7 @@ export const streamAgent = (agent, input = {}) => {
2015
2152
  if (!context.fresh || freshRequiresExistingClaim) {
2016
2153
  await claimAgentExecution(agent, context.state);
2017
2154
  }
2018
- await emitRunStartTelemetry(agent, context.state, context.memoryMessages, input.approvals);
2155
+ await emitRunStartTelemetry(agent, context.state, context.memoryMessages, input.approvals, invocationStartedAt);
2019
2156
  }
2020
2157
  catch (error) {
2021
2158
  await executionLease.release();
@@ -2027,6 +2164,7 @@ export const streamAgent = (agent, input = {}) => {
2027
2164
  await emitRunFinishTelemetry(agent, state);
2028
2165
  await executionLease.release();
2029
2166
  broadcast.close();
2167
+ await finishInvocation(state.status);
2030
2168
  return {
2031
2169
  output: toOutput(state),
2032
2170
  textStream: emptyAsyncIterable()
@@ -2064,6 +2202,7 @@ export const streamAgent = (agent, input = {}) => {
2064
2202
  }, true);
2065
2203
  broadcast.close();
2066
2204
  await executionLease.release();
2205
+ await finishInvocation(failedState.status);
2067
2206
  return {
2068
2207
  output: toOutput(failedState),
2069
2208
  textStream: emptyAsyncIterable()
@@ -2084,14 +2223,16 @@ export const streamAgent = (agent, input = {}) => {
2084
2223
  type: "agent-step-start",
2085
2224
  stepIndex: context.state.currentStep + 1
2086
2225
  });
2087
- await emitTelemetryEvent(agent, {
2088
- type: "step-start",
2089
- runId: context.state.runId,
2090
- agentId: context.state.agentId,
2091
- stepIndex: context.state.currentStep + 1
2092
- });
2093
- const abortContext = createAgentAbortContext(mergeAbortSignals(input.abortSignal, executionLease.signal), policy);
2094
- const executionEnvironmentSession = await acquireExecutionEnvironment(context.executionEnvironment, context.state, context.context, abortContext.signal);
2226
+ const abortContext = createAgentAbortContext(input.abortSignal, policy, executionLease.signal);
2227
+ let executionEnvironmentSession;
2228
+ try {
2229
+ executionEnvironmentSession = await acquireExecutionEnvironment(context.executionEnvironment, context.state, context.context, abortContext.signal);
2230
+ }
2231
+ catch (error) {
2232
+ abortContext.cleanup();
2233
+ await executionLease.release();
2234
+ throw error;
2235
+ }
2095
2236
  activeExecutionEnvironment = executionEnvironmentSession;
2096
2237
  let executionEnvironmentStatus = "failed";
2097
2238
  let executionEnvironmentError;
@@ -2105,6 +2246,7 @@ export const streamAgent = (agent, input = {}) => {
2105
2246
  }));
2106
2247
  }
2107
2248
  catch (error) {
2249
+ abortContext.cleanup();
2108
2250
  executionEnvironmentError = {
2109
2251
  message: error instanceof Error ? error.message : String(error)
2110
2252
  };
@@ -2117,7 +2259,7 @@ export const streamAgent = (agent, input = {}) => {
2117
2259
  throw error;
2118
2260
  }
2119
2261
  const approvalRequests = [];
2120
- const eventRelay = (async () => {
2262
+ const eventRelay = withAgentTelemetryRunContext(agent, context.state.runId, async () => {
2121
2263
  for await (const event of streamResult.eventStream) {
2122
2264
  await publish(event);
2123
2265
  if (event.type === "tool-approval-request") {
@@ -2162,7 +2304,7 @@ export const streamAgent = (agent, input = {}) => {
2162
2304
  });
2163
2305
  }
2164
2306
  }
2165
- })();
2307
+ });
2166
2308
  const output = (async () => {
2167
2309
  try {
2168
2310
  const final = await withAgentPolicyTimeout(eventRelay.then(() => streamResult.collect()), abortContext);
@@ -2291,12 +2433,13 @@ export const streamAgent = (agent, input = {}) => {
2291
2433
  activeExecutionEnvironment = undefined;
2292
2434
  await executionLease.release();
2293
2435
  }
2294
- })();
2436
+ })().finally(() => finishInvocation(executionEnvironmentStatus, executionEnvironmentError ? new Error(executionEnvironmentError.message) : undefined));
2295
2437
  return {
2296
2438
  output,
2297
2439
  textStream: streamResult.textStream
2298
2440
  };
2299
2441
  })().catch(async (error) => {
2442
+ await finishInvocation("failed", error instanceof Error ? error : new Error(String(error)));
2300
2443
  await activeExecutionEnvironment?.release?.({
2301
2444
  status: "failed",
2302
2445
  error: { message: error instanceof Error ? error.message : String(error) }