@agent-native/core 0.214.0 → 0.217.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/action.js +54 -1
- package/dist/agent/actions/disconnect-chatgpt-subscription.js +5 -0
- package/dist/agent/actions/get-agentkit-capabilities.js +3 -3
- package/dist/agent/actions/manage-builder-connection.js +5 -0
- package/dist/agent/actions/manage-provider-key-policy.js +5 -0
- package/dist/agent/actions/manage-provider-models.js +5 -0
- package/dist/agent/actions/manage-service-providers.js +5 -0
- package/dist/agent/actions/select-chatgpt-subscription-account.js +5 -0
- package/dist/agent/context-xray/actions/context-evict.js +5 -0
- package/dist/agent/context-xray/actions/context-pin.js +5 -0
- package/dist/agent/context-xray/actions/context-report.js +5 -0
- package/dist/agent/context-xray/actions/context-restore.js +5 -0
- package/dist/agent/execution-fence.d.ts +1 -0
- package/dist/agent/execution-fence.js +5 -0
- package/dist/agent/production-agent.d.ts +35 -2
- package/dist/agent/production-agent.js +629 -32
- package/dist/agent/run-manager.d.ts +2 -0
- package/dist/agent/run-manager.js +397 -115
- package/dist/agent/run-slot-lock.d.ts +2 -0
- package/dist/agent/run-slot-lock.js +6 -0
- package/dist/agent/run-store.d.ts +5 -0
- package/dist/agent/run-store.js +423 -156
- package/dist/agent/thread-data-builder.js +27 -5
- package/dist/agent/types.d.ts +6 -12
- package/dist/agentkit/capabilities.d.ts +1 -1
- package/dist/app-config/analytics.js +1 -1
- package/dist/application-state/store.d.ts +5 -0
- package/dist/application-state/store.js +26 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/chat-threads/schema-migrations.js +17 -0
- package/dist/chat-threads/store.d.ts +21 -1
- package/dist/chat-threads/store.js +223 -41
- package/dist/cli/skills-content/turn-into-app-skill.d.ts +1 -1
- package/dist/cli/skills-content/turn-into-app-skill.js +20 -18
- package/dist/cli/templates-meta.js +14 -0
- package/dist/client/analytics-session.d.ts +7 -0
- package/dist/client/analytics-session.js +27 -1
- package/dist/client/analytics.js +276 -31
- package/dist/client/chat/agentkit-agent-native.js +79 -3
- package/dist/client/chat/agentkit-protocol.js +80 -42
- package/dist/client/chat/runtime.d.ts +5 -1
- package/dist/client/chat/runtime.js +46 -3
- package/dist/client/consent.d.ts +48 -0
- package/dist/client/consent.js +413 -0
- package/dist/client/onboarding/index.d.ts +1 -0
- package/dist/client/onboarding/index.js +1 -0
- package/dist/client/onboarding/use-onboarding-checklist.d.ts +23 -0
- package/dist/client/onboarding/use-onboarding-checklist.js +115 -0
- package/dist/client/review/use-review.d.ts +2 -0
- package/dist/client/review/use-review.js +28 -1
- package/dist/client/session-replay.d.ts +1 -1
- package/dist/client/session-replay.js +142 -3
- package/dist/client/sharing/useResourceAccessGate.d.ts +3 -2
- package/dist/client/sharing/useResourceAccessGate.js +9 -1
- package/dist/client/use-chat-thread-list.d.ts +2 -0
- package/dist/client/use-chat-thread-list.js +12 -2
- package/dist/client/use-chat-threads.d.ts +1 -0
- package/dist/client/use-chat-threads.js +2 -0
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/connections/catalog.d.ts +5 -5
- package/dist/connections/catalog.js +22 -3
- package/dist/data-widgets/index.d.ts +36 -2
- package/dist/data-widgets/index.js +94 -6
- package/dist/db/migrations.js +4 -1
- package/dist/db/schema-snapshot.generated.js +8 -1
- package/dist/feature-flags/actions/set-feature-flag.js +5 -0
- package/dist/feature-flags/index.d.ts +1 -1
- package/dist/feature-flags/index.js +1 -1
- package/dist/feature-flags/store.d.ts +12 -0
- package/dist/feature-flags/store.js +79 -7
- package/dist/file-upload/actions/manage-file-storage.js +5 -0
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/file-upload/actions/upload-image.js +5 -0
- package/dist/history/actions/create-resource-version.js +5 -0
- package/dist/history/actions/restore-resource-version.js +5 -0
- package/dist/ingestion/index.d.ts +1 -1
- package/dist/ingestion/index.js +1 -1
- package/dist/ingestion/pptx.d.ts +11 -0
- package/dist/ingestion/pptx.js +81 -1
- package/dist/integrations/actions/manage-messaging-channel.js +5 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/jobs/scheduler.js +17 -1
- package/dist/labs/actions/set-lab.js +5 -0
- package/dist/localization/actions/set-localization-preference.js +5 -0
- package/dist/localization/consent-banner-messages.d.ts +16 -0
- package/dist/localization/consent-banner-messages.js +149 -0
- package/dist/localization/core-messages.js +4 -0
- package/dist/localization/default-messages.d.ts +1 -0
- package/dist/localization/default-messages.js +2 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/actions/save-observability-instruction-update.js +5 -0
- package/dist/observability/actions/save-observability-review-summary.js +5 -0
- package/dist/observability/routes.d.ts +6 -6
- package/dist/onboarding/index.d.ts +2 -1
- package/dist/onboarding/index.js +1 -0
- package/dist/onboarding/plugin.js +55 -46
- package/dist/onboarding/status.d.ts +15 -0
- package/dist/onboarding/status.js +59 -0
- package/dist/onboarding/types.d.ts +12 -0
- package/dist/onboarding/types.js +2 -1
- package/dist/org/workspace-app-access.js +19 -9
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +16 -16
- package/dist/provider-api/actions/provider-api.d.ts +11 -11
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.js +9 -2
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/review/actions/consume-review-feedback.js +5 -0
- package/dist/review/actions/create-review-comment.js +5 -0
- package/dist/review/actions/delete-review-comment.js +5 -0
- package/dist/review/actions/react-to-review-comment.js +5 -0
- package/dist/review/actions/reply-review-comment.js +5 -0
- package/dist/review/actions/resolve-review-thread.js +5 -0
- package/dist/review/actions/send-review-thread-to-agent.js +5 -0
- package/dist/review/actions/set-review-status.js +5 -0
- package/dist/review/actions/set-review-thread-muted.js +5 -0
- package/dist/review/actions/set-review-thread-unread.js +5 -0
- package/dist/review/actions/set-review-threads-unread.js +5 -0
- package/dist/review/actions/update-review-comment-anchor.js +5 -0
- package/dist/review/actions/update-review-comment.js +5 -0
- package/dist/review/suggestions/actions.js +60 -21
- package/dist/review/suggestions/store.d.ts +2 -0
- package/dist/review/suggestions/store.js +28 -0
- package/dist/secrets/actions/delete-api-key.js +5 -0
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-capabilities.js +13 -6
- package/dist/server/agent-chat/context-tools.js +63 -2
- package/dist/server/agent-chat-plugin.d.ts +2 -0
- package/dist/server/agent-chat-plugin.js +242 -54
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +1 -1
- package/dist/server/analytics.d.ts +0 -1
- package/dist/server/analytics.js +81 -20
- package/dist/server/application-state-maintenance.d.ts +2 -0
- package/dist/server/application-state-maintenance.js +2 -0
- package/dist/server/attribution.d.ts +14 -0
- package/dist/server/attribution.js +62 -2
- package/dist/server/auth.js +7 -0
- package/dist/server/builder-api-auth.d.ts +7 -0
- package/dist/server/builder-api-auth.js +24 -0
- package/dist/server/builder-oauth.d.ts +5 -1
- package/dist/server/builder-oauth.js +5 -0
- package/dist/server/consent-route.d.ts +41 -0
- package/dist/server/consent-route.js +102 -0
- package/dist/server/core-routes-plugin.d.ts +1 -1
- package/dist/server/first-touch-route.d.ts +39 -0
- package/dist/server/first-touch-route.js +115 -0
- package/dist/server/index.d.ts +2 -1
- package/dist/server/index.js +2 -1
- package/dist/server/queued-submission-inbox-drain.d.ts +9 -0
- package/dist/server/queued-submission-inbox-drain.js +12 -0
- package/dist/server/request-origin.d.ts +6 -0
- package/dist/server/request-origin.js +12 -0
- package/dist/settings/org-settings.d.ts +2 -1
- package/dist/settings/org-settings.js +4 -1
- package/dist/settings/store.d.ts +8 -0
- package/dist/settings/store.js +14 -5
- package/dist/shared/consent.d.ts +33 -0
- package/dist/shared/consent.js +149 -0
- package/dist/shared/first-touch-persistence.d.ts +31 -0
- package/dist/shared/first-touch-persistence.js +53 -0
- package/dist/sharing/actions/set-resource-visibility.js +5 -0
- package/dist/sharing/actions/share-resource.js +5 -0
- package/dist/sharing/actions/unshare-resource.js +5 -0
- package/dist/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/dist/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/dist/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
- package/dist/triggers/actions/manage-automation.d.ts +4 -4
- package/dist/usage/actions/get-usage-metrics.js +27 -4
- package/dist/usage/actions/manage-usage-alert.js +5 -0
- package/dist/vite/client.js +8 -6
- package/dist/workspace-connections/actions/bulk-update-workspace-user-groups.js +5 -0
- package/dist/workspace-connections/actions/delete-workspace-user-group.js +5 -0
- package/dist/workspace-connections/actions/upsert-workspace-user-group.js +5 -0
- package/docs/content/actions-access-control.mdx +8 -8
- package/docs/content/actions-defining.mdx +9 -8
- package/docs/content/deployment-environment-variables.mdx +1 -1
- package/docs/content/environment-variables.mdx +1 -1
- package/docs/content/template-design-developers.mdx +9 -9
- package/docs/content/template-design-features.mdx +1 -3
- package/docs/content/turn-into-app.mdx +4 -0
- package/package.json +6 -3
- package/src/templates/chat/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/default/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/factory/.agents/skills/review-latest-feedback/SKILL.md +36 -80
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/channel-inventory.md +54 -16
- package/src/templates/factory/.agents/skills/review-latest-feedback/references/slack-reaction-replies.md +50 -73
- package/src/templates/headless/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/actions/references/action-fields.md +1 -1
- package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +20 -18
|
@@ -12,7 +12,7 @@ import { getAgentEngineEntry } from "./engine/registry.js";
|
|
|
12
12
|
import { EngineError } from "./engine/types.js";
|
|
13
13
|
import { currentExecutionFence, MissingExecutionFenceError, StaleExecutionFenceError, withExecutionFence, withExecutionLeaseRequested, } from "./execution-fence.js";
|
|
14
14
|
import { AgentRunEventNotPersistedError, insertRun, insertRunEvent, insertRunEvents, updateRunStatusIfRunning, markRunAborted, markRunAbortedAtSafeBoundary, getRunAbortState, getRunStatus, getRunEventsSince, getCurrentTurnRunEventsForThread, getRunById, getRunByThread, getRunTurnRef, listRunsForThread, markTurnAborted, cleanupOldRuns, updateRunHeartbeat, bumpRunProgress, setRunInFlightMarker, reapIfStale, reapUnclaimedBackgroundRun, shouldRedispatchUnclaimedBackgroundRun, reconcileTerminalRunFromEvents, ensureTerminalRunEvent, getLastTerminalRunEvent, resolveErroredRunTerminalEvent, setRunError, setRunTerminalReason, persistRunCheckpointEvent, recordRunDiagnostic, RUN_DIAG_STAGE, claimTurnExecutionLease, renewTurnExecutionLease, releaseTurnExecutionLease, TurnExecutionLeaseBusyError, terminalEventForAbortReason, RUN_RECORD_MISSING_ERROR_EVENT, RUN_RECORD_MISSING_GRACE_MS, RUN_TERMINAL_LOOKUP_FAILED_ERROR_EVENT, UNKNOWN_RUN_STATUS_ERROR_EVENT, } from "./run-store.js";
|
|
15
|
-
import { isContinuationTerminalReason } from "./types.js";
|
|
15
|
+
import { CONTINUATION_REASONS, isContinuationTerminalReason } from "./types.js";
|
|
16
16
|
const activeRuns = new Map();
|
|
17
17
|
const threadToRun = new Map();
|
|
18
18
|
function peekRunEventSeq(run) {
|
|
@@ -107,6 +107,13 @@ const RECONNECTABLE_TERMINAL_RUN_STATUSES = new Set([
|
|
|
107
107
|
"errored",
|
|
108
108
|
"aborted",
|
|
109
109
|
]);
|
|
110
|
+
function isKnownRunStatus(status) {
|
|
111
|
+
return (status === "running" ||
|
|
112
|
+
status === "completed" ||
|
|
113
|
+
status === "truncated" ||
|
|
114
|
+
status === "errored" ||
|
|
115
|
+
status === "aborted");
|
|
116
|
+
}
|
|
110
117
|
function isDuplicateSubmissionMarker(run) {
|
|
111
118
|
return (run.status === "aborted" &&
|
|
112
119
|
run.terminalReason === "aborted:duplicate_submission");
|
|
@@ -371,6 +378,8 @@ function terminalReasonForRun(finalStatus, terminalEvent, abortReason, completio
|
|
|
371
378
|
if (terminalEvent?.type === "error") {
|
|
372
379
|
return `error:${terminalEvent.errorCode || "unknown"}`;
|
|
373
380
|
}
|
|
381
|
+
if (finalStatus === "truncated")
|
|
382
|
+
return "stream_ended";
|
|
374
383
|
if (finalStatus === "aborted")
|
|
375
384
|
return `aborted:${abortReason ?? "user"}`;
|
|
376
385
|
if (completionError)
|
|
@@ -584,6 +593,7 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
584
593
|
},
|
|
585
594
|
};
|
|
586
595
|
let softTimedOut = false;
|
|
596
|
+
let checkpointBoundaryStarted = false;
|
|
587
597
|
let resolveFinalized = () => { };
|
|
588
598
|
let rejectFinalized = () => { };
|
|
589
599
|
const finalized = new Promise((resolve, reject) => {
|
|
@@ -652,12 +662,16 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
652
662
|
: undefined;
|
|
653
663
|
const servicePrincipalRunStart = Boolean(options?.turnInitiator &&
|
|
654
664
|
parseServiceIdentityEmail(options.turnInitiator.email));
|
|
665
|
+
let servicePrincipalStartRefused = false;
|
|
655
666
|
const insertRunPromise = (options?.runRowAlreadyInserted && !servicePrincipalRunStart
|
|
656
667
|
? Promise.resolve()
|
|
657
668
|
: insertOptions
|
|
658
669
|
? insertRun(runId, threadId, options?.turnId, insertOptions)
|
|
659
670
|
: insertRun(runId, threadId, options?.turnId)).catch((error) => {
|
|
660
671
|
captureRunPersistenceError(error, "insert-run");
|
|
672
|
+
if (error instanceof ServicePrincipalRefusedError) {
|
|
673
|
+
servicePrincipalStartRefused = true;
|
|
674
|
+
}
|
|
661
675
|
if (options?.executionLease ||
|
|
662
676
|
error instanceof ServicePrincipalRefusedError)
|
|
663
677
|
throw error;
|
|
@@ -983,24 +997,140 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
983
997
|
mirrorInFlightMarker(false);
|
|
984
998
|
}
|
|
985
999
|
};
|
|
1000
|
+
let checkpointRunBoundaryTask = Promise.resolve();
|
|
986
1001
|
let checkpointAbortInFlight = false;
|
|
987
|
-
|
|
1002
|
+
let checkpointPersistenceFailed = false;
|
|
1003
|
+
let checkpointStatusReadFailed = false;
|
|
1004
|
+
let checkpointUnknownStatus = null;
|
|
1005
|
+
let checkpointObservedTerminalStatus = null;
|
|
1006
|
+
const observeCheckpointRunStatus = (persistedRun, context) => {
|
|
1007
|
+
if (!persistedRun) {
|
|
1008
|
+
checkpointStatusReadFailed = true;
|
|
1009
|
+
console.error(`[run-manager] run row missing ${context}`, runId);
|
|
1010
|
+
return "missing";
|
|
1011
|
+
}
|
|
1012
|
+
if (!isKnownRunStatus(persistedRun.status)) {
|
|
1013
|
+
checkpointUnknownStatus = persistedRun.status;
|
|
1014
|
+
return "unknown";
|
|
1015
|
+
}
|
|
1016
|
+
if (persistedRun.status === "running")
|
|
1017
|
+
return "running";
|
|
1018
|
+
checkpointObservedTerminalStatus = persistedRun.status;
|
|
1019
|
+
run.status = persistedRun.status;
|
|
1020
|
+
if (persistedRun.status === "aborted") {
|
|
1021
|
+
run.abortReason = persistedRun.terminalReason?.startsWith("aborted:")
|
|
1022
|
+
? persistedRun.terminalReason.slice("aborted:".length)
|
|
1023
|
+
: undefined;
|
|
1024
|
+
}
|
|
1025
|
+
return "terminal";
|
|
1026
|
+
};
|
|
1027
|
+
let runDriverSettled = false;
|
|
1028
|
+
let pendingTerminalEvent = null;
|
|
1029
|
+
let persistedCheckpointTerminalEvent = null;
|
|
1030
|
+
const rememberPersistedCheckpointTerminalEvent = (persistedRun, checkpointEvent) => {
|
|
1031
|
+
if (persistedRun?.status !== "truncated")
|
|
1032
|
+
return;
|
|
1033
|
+
const persistedReason = persistedRun.terminalReason;
|
|
1034
|
+
const persistedContinuationReason = CONTINUATION_REASONS.find((reason) => reason === persistedReason);
|
|
1035
|
+
const reason = persistedContinuationReason ??
|
|
1036
|
+
(checkpointEvent.type === "auto_continue"
|
|
1037
|
+
? checkpointEvent.reason
|
|
1038
|
+
: "stream_ended");
|
|
1039
|
+
persistedCheckpointTerminalEvent = {
|
|
1040
|
+
seq: peekRunEventSeq(run),
|
|
1041
|
+
event: { type: "auto_continue", reason },
|
|
1042
|
+
};
|
|
1043
|
+
};
|
|
1044
|
+
const checkpointRunBoundary = (event, terminalReason, diagnostic) => {
|
|
988
1045
|
if (checkpointAbortInFlight ||
|
|
989
1046
|
run.status !== "running" ||
|
|
990
1047
|
abort.signal.aborted)
|
|
991
|
-
return;
|
|
1048
|
+
return checkpointRunBoundaryTask;
|
|
992
1049
|
checkpointAbortInFlight = true;
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1050
|
+
checkpointBoundaryStarted = true;
|
|
1051
|
+
const task = (async () => {
|
|
1052
|
+
let checkpointPersisted = false;
|
|
1053
|
+
try {
|
|
1054
|
+
await withWorkerFence(() => persistRunCheckpointEvent(runId, event, terminalReason));
|
|
1055
|
+
checkpointPersisted = true;
|
|
1056
|
+
let persistedRun;
|
|
1057
|
+
try {
|
|
1058
|
+
persistedRun = await getRunById(runId);
|
|
1059
|
+
}
|
|
1060
|
+
catch (error) {
|
|
1061
|
+
checkpointStatusReadFailed = true;
|
|
1062
|
+
console.error("[run-manager] could not confirm run status after checkpoint persistence", runId, error instanceof Error ? error.message : error);
|
|
1063
|
+
return;
|
|
1064
|
+
}
|
|
1065
|
+
const checkpointStatus = observeCheckpointRunStatus(persistedRun, "after checkpoint persistence");
|
|
1066
|
+
if (checkpointStatus !== "running") {
|
|
1067
|
+
rememberPersistedCheckpointTerminalEvent(persistedRun, event);
|
|
1068
|
+
return;
|
|
1069
|
+
}
|
|
1070
|
+
softTimedOut = true;
|
|
1071
|
+
recordRunBoundaryDiagnostic(terminalReason, diagnostic, "terminal");
|
|
1072
|
+
emitRunBoundaryTrackingEvent({
|
|
1073
|
+
runId,
|
|
1074
|
+
threadId,
|
|
1075
|
+
reason: terminalReason,
|
|
1076
|
+
recovered: false,
|
|
1077
|
+
boundaryIndex: recoveredChunkBoundaries + 1,
|
|
1078
|
+
dispatchMode: options?.dispatchMode,
|
|
1079
|
+
model: options?.model,
|
|
1080
|
+
engineName: options?.engineName,
|
|
1081
|
+
userId: options?.userId,
|
|
1082
|
+
});
|
|
1083
|
+
if (!pendingTerminalEvent && run.status === "running") {
|
|
1084
|
+
send(event);
|
|
1085
|
+
persistedCheckpointTerminalEvent = pendingTerminalEvent;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
catch (error) {
|
|
1089
|
+
let persistedCheckpointStatus = "running";
|
|
1090
|
+
if (error instanceof AgentRunEventNotPersistedError &&
|
|
1091
|
+
error.terminalRun) {
|
|
1092
|
+
try {
|
|
1093
|
+
const persistedRun = await getRunById(runId);
|
|
1094
|
+
persistedCheckpointStatus = observeCheckpointRunStatus(persistedRun, "after checkpoint rejection");
|
|
1095
|
+
rememberPersistedCheckpointTerminalEvent(persistedRun, event);
|
|
1096
|
+
}
|
|
1097
|
+
catch (statusError) {
|
|
1098
|
+
checkpointStatusReadFailed = true;
|
|
1099
|
+
console.error("[run-manager] could not confirm run status after checkpoint rejection", runId, statusError instanceof Error ? statusError.message : statusError);
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
1102
|
+
if (!checkpointStatusReadFailed &&
|
|
1103
|
+
(persistedCheckpointStatus === "terminal" ||
|
|
1104
|
+
(pendingTerminalEvent && !checkpointPersisted))) {
|
|
1105
|
+
softTimedOut = true;
|
|
1106
|
+
}
|
|
1107
|
+
else if (!checkpointStatusReadFailed &&
|
|
1108
|
+
persistedCheckpointStatus !== "unknown") {
|
|
1109
|
+
checkpointPersistenceFailed = true;
|
|
1110
|
+
}
|
|
1111
|
+
if (persistedCheckpointStatus !== "terminal" &&
|
|
1112
|
+
persistedCheckpointStatus !== "unknown" &&
|
|
1113
|
+
!checkpointStatusReadFailed) {
|
|
1114
|
+
console.error("[run-manager] could not persist run boundary checkpoint", runId, error instanceof Error ? error.message : error);
|
|
1115
|
+
}
|
|
1116
|
+
if (!pendingTerminalEvent &&
|
|
1117
|
+
persistedCheckpointStatus !== "terminal" &&
|
|
1118
|
+
persistedCheckpointStatus !== "unknown" &&
|
|
1119
|
+
!checkpointStatusReadFailed) {
|
|
1120
|
+
send({
|
|
1121
|
+
type: "error",
|
|
1122
|
+
error: "The agent could not save its continuation checkpoint.",
|
|
1123
|
+
errorCode: "run_checkpoint_persistence_failed",
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
}
|
|
1127
|
+
finally {
|
|
1128
|
+
abort.abort(run.abortReason ?? terminalReason);
|
|
1129
|
+
checkpointAbortInFlight = false;
|
|
1130
|
+
}
|
|
1131
|
+
})();
|
|
1132
|
+
checkpointRunBoundaryTask = task;
|
|
1133
|
+
return task;
|
|
1004
1134
|
};
|
|
1005
1135
|
const recordRunBoundaryDiagnostic = (reason, diagnostic, disposition) => {
|
|
1006
1136
|
if (getCurrentRequestDbPoolScope()?.closing)
|
|
@@ -1016,7 +1146,7 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1016
1146
|
})).catch(() => { }))).catch(() => { });
|
|
1017
1147
|
};
|
|
1018
1148
|
const reachRunBoundary = (reason, diagnostic = {}) => {
|
|
1019
|
-
if (run.status !== "running" || abort.signal.aborted)
|
|
1149
|
+
if (runDriverSettled || run.status !== "running" || abort.signal.aborted)
|
|
1020
1150
|
return;
|
|
1021
1151
|
const activeChunkAbort = chunkAbort;
|
|
1022
1152
|
const canRecoverChunk = activeChunkAbort !== null &&
|
|
@@ -1034,22 +1164,8 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1034
1164
|
}
|
|
1035
1165
|
if (chunkAbort)
|
|
1036
1166
|
chunkBoundaryReason = reason;
|
|
1037
|
-
softTimedOut = true;
|
|
1038
|
-
recordRunBoundaryDiagnostic(reason, diagnostic, "terminal");
|
|
1039
|
-
emitRunBoundaryTrackingEvent({
|
|
1040
|
-
runId,
|
|
1041
|
-
threadId,
|
|
1042
|
-
reason,
|
|
1043
|
-
recovered: false,
|
|
1044
|
-
boundaryIndex: recoveredChunkBoundaries + 1,
|
|
1045
|
-
dispatchMode: options?.dispatchMode,
|
|
1046
|
-
model: options?.model,
|
|
1047
|
-
engineName: options?.engineName,
|
|
1048
|
-
userId: options?.userId,
|
|
1049
|
-
});
|
|
1050
1167
|
const event = { type: "auto_continue", reason };
|
|
1051
|
-
|
|
1052
|
-
void checkpointRunBoundary(event, reason);
|
|
1168
|
+
void checkpointRunBoundary(event, reason, diagnostic);
|
|
1053
1169
|
};
|
|
1054
1170
|
const checkNoProgressBackstop = () => {
|
|
1055
1171
|
if (noProgressTimeoutMs <= 0)
|
|
@@ -1204,7 +1320,6 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1204
1320
|
};
|
|
1205
1321
|
armChunkSoftTimeout();
|
|
1206
1322
|
}
|
|
1207
|
-
let pendingTerminalEvent = null;
|
|
1208
1323
|
const captureRunError = (error, phase) => {
|
|
1209
1324
|
const errorCode = getRunErrorCode(error);
|
|
1210
1325
|
const engineError = error instanceof EngineError ? error : null;
|
|
@@ -1249,18 +1364,22 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1249
1364
|
};
|
|
1250
1365
|
const persistEventHook = options?.persistEvent;
|
|
1251
1366
|
const persistRunEvent = async (runEvent, eventData, eventAt) => {
|
|
1252
|
-
|
|
1367
|
+
const terminal = isTerminalRunEvent(runEvent.event);
|
|
1368
|
+
const requireInserted = runEvent.event.type === "tool_start" ||
|
|
1369
|
+
(terminal && !servicePrincipalStartRefused);
|
|
1370
|
+
if (requireInserted)
|
|
1253
1371
|
await insertRunPromise;
|
|
1254
|
-
const write = () => runEvent.
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
toolInputSource: "execution"
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1372
|
+
const write = () => insertRunEvent(runId, runEvent.seq, eventData, {
|
|
1373
|
+
eventAt,
|
|
1374
|
+
...(runEvent.event.type === "tool_start" ||
|
|
1375
|
+
runEvent.event.type === "tool_done"
|
|
1376
|
+
? { toolInputSource: "execution" }
|
|
1377
|
+
: {}),
|
|
1378
|
+
...(requireInserted ? { requireInserted: true } : {}),
|
|
1379
|
+
...(runEvent.event.type === "auto_continue"
|
|
1380
|
+
? { allowContinuationTerminal: true }
|
|
1381
|
+
: {}),
|
|
1382
|
+
});
|
|
1264
1383
|
return withWorkerFence(() => options?.persistEvent
|
|
1265
1384
|
? options.persistEvent(write, {
|
|
1266
1385
|
terminal: isTerminalRunEvent(runEvent.event),
|
|
@@ -1381,6 +1500,14 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1381
1500
|
event: normalizedEvent,
|
|
1382
1501
|
};
|
|
1383
1502
|
if (isTerminalRunEvent(event)) {
|
|
1503
|
+
if (persistedCheckpointTerminalEvent)
|
|
1504
|
+
return Promise.resolve();
|
|
1505
|
+
if (checkpointPersistenceFailed &&
|
|
1506
|
+
pendingTerminalEvent?.event.type === "error" &&
|
|
1507
|
+
pendingTerminalEvent.event.errorCode ===
|
|
1508
|
+
"run_checkpoint_persistence_failed") {
|
|
1509
|
+
return Promise.resolve();
|
|
1510
|
+
}
|
|
1384
1511
|
pendingTerminalEvent = runEvent;
|
|
1385
1512
|
return Promise.resolve();
|
|
1386
1513
|
}
|
|
@@ -1406,18 +1533,40 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1406
1533
|
await runFn(send, runControl.chunkSignal, runControl);
|
|
1407
1534
|
};
|
|
1408
1535
|
const runPromise = startDriver()
|
|
1409
|
-
.then(() => {
|
|
1536
|
+
.then(async () => {
|
|
1537
|
+
runDriverSettled = true;
|
|
1538
|
+
if (checkpointAbortInFlight)
|
|
1539
|
+
await checkpointRunBoundaryTask;
|
|
1410
1540
|
settleBoundary(false);
|
|
1411
1541
|
if (abort.signal.aborted) {
|
|
1412
|
-
run.status
|
|
1542
|
+
if (run.status !== "aborted") {
|
|
1543
|
+
run.status =
|
|
1544
|
+
checkpointObservedTerminalStatus ??
|
|
1545
|
+
(checkpointPersistenceFailed
|
|
1546
|
+
? "errored"
|
|
1547
|
+
: softTimedOut
|
|
1548
|
+
? "completed"
|
|
1549
|
+
: "aborted");
|
|
1550
|
+
}
|
|
1413
1551
|
return;
|
|
1414
1552
|
}
|
|
1415
1553
|
run.status = "completed";
|
|
1416
1554
|
})
|
|
1417
|
-
.catch((err) => {
|
|
1555
|
+
.catch(async (err) => {
|
|
1556
|
+
runDriverSettled = true;
|
|
1557
|
+
if (checkpointAbortInFlight)
|
|
1558
|
+
await checkpointRunBoundaryTask;
|
|
1418
1559
|
settleBoundary(false);
|
|
1419
1560
|
if (abort.signal.aborted) {
|
|
1420
|
-
run.status
|
|
1561
|
+
if (run.status !== "aborted") {
|
|
1562
|
+
run.status =
|
|
1563
|
+
checkpointObservedTerminalStatus ??
|
|
1564
|
+
(checkpointPersistenceFailed
|
|
1565
|
+
? "errored"
|
|
1566
|
+
: softTimedOut
|
|
1567
|
+
? "completed"
|
|
1568
|
+
: "aborted");
|
|
1569
|
+
}
|
|
1421
1570
|
return;
|
|
1422
1571
|
}
|
|
1423
1572
|
run.status = "errored";
|
|
@@ -1450,8 +1599,11 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1450
1599
|
let eventPersistenceError = null;
|
|
1451
1600
|
let runTerminalErrorCode;
|
|
1452
1601
|
let terminalPersistenceEstablished = false;
|
|
1602
|
+
let continuationStatusPersistedBeforeEvent = false;
|
|
1603
|
+
let suppressContinuationEvent = false;
|
|
1453
1604
|
try {
|
|
1454
1605
|
await persistenceChain;
|
|
1606
|
+
await run.abortPersistencePromise;
|
|
1455
1607
|
}
|
|
1456
1608
|
catch (error) {
|
|
1457
1609
|
eventPersistenceError = error;
|
|
@@ -1467,14 +1619,43 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1467
1619
|
};
|
|
1468
1620
|
}
|
|
1469
1621
|
}
|
|
1622
|
+
if (checkpointStatusReadFailed || checkpointUnknownStatus !== null) {
|
|
1623
|
+
const event = checkpointStatusReadFailed
|
|
1624
|
+
? RUN_TERMINAL_LOOKUP_FAILED_ERROR_EVENT
|
|
1625
|
+
: UNKNOWN_RUN_STATUS_ERROR_EVENT;
|
|
1626
|
+
const abortAlreadyWon = run.status === "aborted" && run.abortReason !== undefined;
|
|
1627
|
+
if (!abortAlreadyWon) {
|
|
1628
|
+
run.status = "errored";
|
|
1629
|
+
if (!eventPersistenceError) {
|
|
1630
|
+
pendingTerminalEvent = {
|
|
1631
|
+
seq: peekRunEventSeq(run),
|
|
1632
|
+
event: { ...event },
|
|
1633
|
+
};
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
if (checkpointUnknownStatus !== null) {
|
|
1637
|
+
console.error("[run-manager] checkpoint observed an unknown persisted run status", runId, checkpointUnknownStatus);
|
|
1638
|
+
}
|
|
1639
|
+
}
|
|
1470
1640
|
const resolveTerminalEventForCompletion = () => {
|
|
1471
|
-
if (run.status === "aborted")
|
|
1641
|
+
if (run.status === "aborted" && run.abortReason !== undefined)
|
|
1472
1642
|
return null;
|
|
1473
1643
|
if (eventPersistenceError) {
|
|
1474
1644
|
return pendingTerminalEvent
|
|
1475
1645
|
? { ...pendingTerminalEvent, seq: run.events.length }
|
|
1476
1646
|
: null;
|
|
1477
1647
|
}
|
|
1648
|
+
if (checkpointStatusReadFailed || checkpointUnknownStatus !== null) {
|
|
1649
|
+
return pendingTerminalEvent
|
|
1650
|
+
? { ...pendingTerminalEvent, seq: peekRunEventSeq(run) }
|
|
1651
|
+
: null;
|
|
1652
|
+
}
|
|
1653
|
+
if (persistedCheckpointTerminalEvent) {
|
|
1654
|
+
return {
|
|
1655
|
+
...persistedCheckpointTerminalEvent,
|
|
1656
|
+
seq: peekRunEventSeq(run),
|
|
1657
|
+
};
|
|
1658
|
+
}
|
|
1478
1659
|
const continuationTerminalEvent = run.continuationTerminalEvent
|
|
1479
1660
|
? {
|
|
1480
1661
|
seq: peekRunEventSeq(run),
|
|
@@ -1489,7 +1670,9 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1489
1670
|
};
|
|
1490
1671
|
let terminalEventForCompletion = resolveTerminalEventForCompletion();
|
|
1491
1672
|
let terminalEvent = terminalEventForCompletion?.event ?? null;
|
|
1492
|
-
if (onComplete
|
|
1673
|
+
if (onComplete &&
|
|
1674
|
+
!checkpointStatusReadFailed &&
|
|
1675
|
+
checkpointUnknownStatus === null) {
|
|
1493
1676
|
try {
|
|
1494
1677
|
const completionStatus = run.status !== "aborted" &&
|
|
1495
1678
|
terminalEventForcesErroredStatus(terminalEvent)
|
|
@@ -1524,9 +1707,13 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1524
1707
|
completionError ||
|
|
1525
1708
|
terminalEventForcesErroredStatus(terminalEvent)
|
|
1526
1709
|
? "errored"
|
|
1527
|
-
: "
|
|
1710
|
+
: run.status === "truncated"
|
|
1711
|
+
? "truncated"
|
|
1712
|
+
: "completed";
|
|
1528
1713
|
run.status = finalStatus;
|
|
1529
1714
|
const shouldAutoContinueAfterUnfinishedTurn = finalStatus === "completed" &&
|
|
1715
|
+
!checkpointStatusReadFailed &&
|
|
1716
|
+
checkpointUnknownStatus === null &&
|
|
1530
1717
|
(endsAfterToolResultWithoutAssistantFinal(run) ||
|
|
1531
1718
|
endsDuringActionPreparation(run)) &&
|
|
1532
1719
|
(!terminalEventForCompletion ||
|
|
@@ -1549,16 +1736,36 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1549
1736
|
? "truncated"
|
|
1550
1737
|
: finalStatus;
|
|
1551
1738
|
let volatileTerminalEvent = null;
|
|
1552
|
-
const
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
:
|
|
1557
|
-
|
|
1739
|
+
const threadProjectionPending = Boolean(completionError ||
|
|
1740
|
+
(onComplete &&
|
|
1741
|
+
(checkpointStatusReadFailed || checkpointUnknownStatus !== null)));
|
|
1742
|
+
const terminalStatusOptions = {
|
|
1743
|
+
...(threadProjectionPending ? { threadProjectionPending: true } : {}),
|
|
1744
|
+
...(checkpointBoundaryStarted || persistedStatus === "truncated"
|
|
1745
|
+
? { terminalReason }
|
|
1746
|
+
: {}),
|
|
1747
|
+
};
|
|
1748
|
+
const persistTerminalStatus = () => Object.keys(terminalStatusOptions).length === 0
|
|
1749
|
+
? updateRunStatusIfRunning(runId, persistedStatus)
|
|
1750
|
+
: updateRunStatusIfRunning(runId, persistedStatus, terminalStatusOptions);
|
|
1751
|
+
const reconcileTerminalRun = () => threadProjectionPending
|
|
1558
1752
|
? reconcileTerminalRunFromEvents(runId, {
|
|
1559
1753
|
threadProjectionPending: true,
|
|
1560
1754
|
})
|
|
1561
1755
|
: reconcileTerminalRunFromEvents(runId);
|
|
1756
|
+
const reportTerminalStatusPersistenceError = (error) => {
|
|
1757
|
+
captureError(error, {
|
|
1758
|
+
route: "/_agent-native/agent-chat",
|
|
1759
|
+
aiTraceId: runId,
|
|
1760
|
+
tags: {
|
|
1761
|
+
source: "agent-run-manager",
|
|
1762
|
+
phase: "terminal-status-persistence",
|
|
1763
|
+
errorCode: "run_terminal_status_persistence_failed",
|
|
1764
|
+
},
|
|
1765
|
+
extra: { runId, threadId, turnId: run.turnId },
|
|
1766
|
+
});
|
|
1767
|
+
console.error("[run-manager] terminal status persistence error:", error instanceof Error ? error.message : error);
|
|
1768
|
+
};
|
|
1562
1769
|
if (finalStatus === "completed" || finalStatus === "errored") {
|
|
1563
1770
|
const terminalEventToEmit = eventPersistenceError
|
|
1564
1771
|
? {
|
|
@@ -1581,8 +1788,37 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1581
1788
|
? "Agent response could not be saved."
|
|
1582
1789
|
: "Agent run ended unexpectedly",
|
|
1583
1790
|
};
|
|
1791
|
+
if (terminalEventToEmit.type === "auto_continue") {
|
|
1792
|
+
if (persistedStatus !== "truncated") {
|
|
1793
|
+
suppressContinuationEvent = true;
|
|
1794
|
+
}
|
|
1795
|
+
else {
|
|
1796
|
+
try {
|
|
1797
|
+
await insertRunPromise;
|
|
1798
|
+
continuationStatusPersistedBeforeEvent = await withWorkerFence(persistTerminalStatus);
|
|
1799
|
+
if (!continuationStatusPersistedBeforeEvent) {
|
|
1800
|
+
await withWorkerFence(reconcileTerminalRun);
|
|
1801
|
+
const persistedRun = await getRunById(runId);
|
|
1802
|
+
continuationStatusPersistedBeforeEvent =
|
|
1803
|
+
persistedRun?.status === "truncated" &&
|
|
1804
|
+
persistedRun.terminalReason === terminalReason;
|
|
1805
|
+
}
|
|
1806
|
+
if (continuationStatusPersistedBeforeEvent) {
|
|
1807
|
+
terminalPersistenceEstablished = true;
|
|
1808
|
+
}
|
|
1809
|
+
else {
|
|
1810
|
+
suppressContinuationEvent = true;
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
catch (error) {
|
|
1814
|
+
suppressContinuationEvent = true;
|
|
1815
|
+
reportTerminalStatusPersistenceError(error);
|
|
1816
|
+
}
|
|
1817
|
+
}
|
|
1818
|
+
}
|
|
1584
1819
|
const last = run.events[run.events.length - 1];
|
|
1585
|
-
if (!last || !isTerminalRunEvent(last.event))
|
|
1820
|
+
if ((!last || !isTerminalRunEvent(last.event)) &&
|
|
1821
|
+
!suppressContinuationEvent) {
|
|
1586
1822
|
const terminal = {
|
|
1587
1823
|
seq: terminalEventForCompletion?.seq ?? allocateRunEventSeq(run),
|
|
1588
1824
|
event: terminalEventToEmit,
|
|
@@ -1621,27 +1857,40 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1621
1857
|
if (!executionLeaseClaimFailed)
|
|
1622
1858
|
mirrorInFlightMarker(false);
|
|
1623
1859
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1860
|
+
if (executionLeaseClaimFailed || finalStatus === "aborted") {
|
|
1861
|
+
if (!executionLeaseClaimFailed && run.abortPersistenceManaged) {
|
|
1862
|
+
terminalPersistenceEstablished = true;
|
|
1863
|
+
}
|
|
1864
|
+
else if (!executionLeaseClaimFailed &&
|
|
1865
|
+
(run.abortReason === "superseded" ||
|
|
1866
|
+
run.abortReason === "execution_lease_lost")) {
|
|
1867
|
+
terminalPersistenceEstablished = false;
|
|
1868
|
+
}
|
|
1869
|
+
else {
|
|
1870
|
+
try {
|
|
1871
|
+
await insertRunPromise;
|
|
1872
|
+
const persistAtomicAbort = () => markRunAborted(runId, run.abortReason ?? "execution-lease-claim-failed");
|
|
1873
|
+
const aborted = executionLeaseClaimFailed
|
|
1874
|
+
? await persistAtomicAbort()
|
|
1875
|
+
: await withWorkerFence(persistAtomicAbort);
|
|
1876
|
+
terminalPersistenceEstablished = aborted
|
|
1877
|
+
? true
|
|
1878
|
+
: await withWorkerFence(reconcileTerminalRun);
|
|
1879
|
+
}
|
|
1880
|
+
catch (error) {
|
|
1881
|
+
terminalPersistenceEstablished = false;
|
|
1882
|
+
reportTerminalStatusPersistenceError(error);
|
|
1883
|
+
throw error;
|
|
1884
|
+
}
|
|
1885
|
+
}
|
|
1640
1886
|
}
|
|
1641
1887
|
else {
|
|
1642
1888
|
try {
|
|
1643
|
-
|
|
1644
|
-
|
|
1889
|
+
if (!continuationStatusPersistedBeforeEvent) {
|
|
1890
|
+
await insertRunPromise;
|
|
1891
|
+
}
|
|
1892
|
+
if (!continuationStatusPersistedBeforeEvent &&
|
|
1893
|
+
(!terminalPersistenceError || eventPersistenceError)) {
|
|
1645
1894
|
let statusUpdated = false;
|
|
1646
1895
|
try {
|
|
1647
1896
|
statusUpdated = await withWorkerFence(persistTerminalStatus);
|
|
@@ -1650,8 +1899,10 @@ export function startRun(runId, threadId, runFn, onComplete, options) {
|
|
|
1650
1899
|
reportTerminalStatusPersistenceError(error);
|
|
1651
1900
|
}
|
|
1652
1901
|
if (statusUpdated) {
|
|
1902
|
+
if (!checkpointBoundaryStarted) {
|
|
1903
|
+
await withWorkerFence(() => setRunTerminalReason(runId, terminalReason));
|
|
1904
|
+
}
|
|
1653
1905
|
terminalPersistenceEstablished = !terminalPersistenceError;
|
|
1654
|
-
await withWorkerFence(() => setRunTerminalReason(runId, terminalReason));
|
|
1655
1906
|
}
|
|
1656
1907
|
else {
|
|
1657
1908
|
terminalPersistenceEstablished =
|
|
@@ -2102,14 +2353,15 @@ function subscribeFromSQL(runId, fromSeq) {
|
|
|
2102
2353
|
return;
|
|
2103
2354
|
if (run?.status === "aborted") {
|
|
2104
2355
|
const existing = await getLastTerminalRunEvent(runId).catch(() => null);
|
|
2356
|
+
const persistedTerminal = existing?.event.type === "auto_continue" ? null : existing;
|
|
2105
2357
|
const abortReason = run.terminalReason?.startsWith("aborted:")
|
|
2106
2358
|
? run.terminalReason.slice("aborted:".length)
|
|
2107
2359
|
: undefined;
|
|
2108
|
-
const terminalEvent =
|
|
2109
|
-
?
|
|
2360
|
+
const terminalEvent = persistedTerminal
|
|
2361
|
+
? persistedTerminal.event
|
|
2110
2362
|
: terminalEventForAbortReason(abortReason);
|
|
2111
2363
|
try {
|
|
2112
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(streamEventWithIdentity(runId, terminalEvent,
|
|
2364
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(streamEventWithIdentity(runId, terminalEvent, persistedTerminal?.seq ?? lastSeq))}\n\n`));
|
|
2113
2365
|
}
|
|
2114
2366
|
catch {
|
|
2115
2367
|
cancelled = true;
|
|
@@ -2497,9 +2749,15 @@ export function abortRun(runId, reason = "user") {
|
|
|
2497
2749
|
const run = activeRuns.get(runId);
|
|
2498
2750
|
const abortedInMemory = abortRunInMemory(runId, reason);
|
|
2499
2751
|
const markAborted = () => markRunAborted(runId, reason);
|
|
2500
|
-
|
|
2752
|
+
const abortPersistence = flushRunEventsBeforeAbort(run)
|
|
2501
2753
|
.then(markAborted, markAborted)
|
|
2502
|
-
.
|
|
2754
|
+
.then((persisted) => {
|
|
2755
|
+
if (run)
|
|
2756
|
+
run.abortPersistenceManaged = persisted;
|
|
2757
|
+
return persisted;
|
|
2758
|
+
}, (error) => {
|
|
2759
|
+
if (run)
|
|
2760
|
+
run.abortPersistenceManaged = false;
|
|
2503
2761
|
captureError(error, {
|
|
2504
2762
|
route: "/_agent-native/agent-chat/runs/:id/abort",
|
|
2505
2763
|
aiTraceId: runId,
|
|
@@ -2507,7 +2765,10 @@ export function abortRun(runId, reason = "user") {
|
|
|
2507
2765
|
extra: { runId, threadId: run?.threadId, reason },
|
|
2508
2766
|
});
|
|
2509
2767
|
console.error("[run-manager] durable abort status write failed:", error instanceof Error ? error.message : error);
|
|
2768
|
+
return false;
|
|
2510
2769
|
});
|
|
2770
|
+
if (run)
|
|
2771
|
+
run.abortPersistencePromise = abortPersistence;
|
|
2511
2772
|
return abortedInMemory;
|
|
2512
2773
|
}
|
|
2513
2774
|
/**
|
|
@@ -2519,44 +2780,65 @@ export function abortRun(runId, reason = "user") {
|
|
|
2519
2780
|
export async function abortRunDurably(runId, reason = "user", options) {
|
|
2520
2781
|
const run = activeRuns.get(runId);
|
|
2521
2782
|
const abortedInMemory = abortRunInMemory(runId, reason);
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2783
|
+
const persistence = (async () => {
|
|
2784
|
+
let eventFlushFailure;
|
|
2785
|
+
try {
|
|
2786
|
+
eventFlushFailure = await flushRunEventsBeforeAbort(run);
|
|
2787
|
+
}
|
|
2788
|
+
catch (error) {
|
|
2789
|
+
if (run)
|
|
2790
|
+
run.abortPersistenceManaged = false;
|
|
2791
|
+
throw error;
|
|
2792
|
+
}
|
|
2793
|
+
let abortPersistedDurably = false;
|
|
2794
|
+
try {
|
|
2795
|
+
const abortPersisted = await markRunAborted(runId, reason);
|
|
2796
|
+
abortPersistedDurably = abortPersisted;
|
|
2797
|
+
if (!abortPersisted || eventFlushFailure) {
|
|
2798
|
+
const persistedStatus = await getRunStatus(runId);
|
|
2799
|
+
abortPersistedDurably ||= persistedStatus === "aborted";
|
|
2800
|
+
if (persistedStatus === null) {
|
|
2801
|
+
// Agent Teams persists Stop intent before run registration.
|
|
2802
|
+
// Workers recheck it before dispatch.
|
|
2803
|
+
if (options?.allowNotStarted && !run && !eventFlushFailure)
|
|
2804
|
+
return false;
|
|
2805
|
+
throw new Error(`Cannot confirm durable abort for missing run ${runId}`);
|
|
2806
|
+
}
|
|
2807
|
+
if (!abortPersisted && persistedStatus === "running") {
|
|
2808
|
+
throw new Error(`Durable abort did not transition run ${runId}`);
|
|
2809
|
+
}
|
|
2536
2810
|
}
|
|
2811
|
+
if (run)
|
|
2812
|
+
run.abortPersistenceManaged = abortPersistedDurably;
|
|
2813
|
+
if (eventFlushFailure)
|
|
2814
|
+
throw eventFlushFailure;
|
|
2537
2815
|
}
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
}
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2816
|
+
catch (error) {
|
|
2817
|
+
if (run)
|
|
2818
|
+
run.abortPersistenceManaged = abortPersistedDurably;
|
|
2819
|
+
captureError(error, {
|
|
2820
|
+
route: "/_agent-native/agent-chat/runs/:id/abort",
|
|
2821
|
+
aiTraceId: runId,
|
|
2822
|
+
tags: {
|
|
2823
|
+
source: "agent-run-manager",
|
|
2824
|
+
phase: "abort-run",
|
|
2825
|
+
},
|
|
2826
|
+
extra: {
|
|
2827
|
+
runId,
|
|
2828
|
+
threadId: activeRuns.get(runId)?.threadId,
|
|
2829
|
+
reason,
|
|
2830
|
+
abortedInMemory,
|
|
2831
|
+
},
|
|
2832
|
+
});
|
|
2833
|
+
console.error("[run-manager] durable abort persistence failed:", error instanceof Error ? error.message : error);
|
|
2834
|
+
throw error;
|
|
2835
|
+
}
|
|
2836
|
+
return abortedInMemory;
|
|
2837
|
+
})();
|
|
2838
|
+
if (run) {
|
|
2839
|
+
run.abortPersistencePromise = persistence.then(() => run.abortPersistenceManaged ?? false, () => run.abortPersistenceManaged ?? false);
|
|
2558
2840
|
}
|
|
2559
|
-
return
|
|
2841
|
+
return persistence;
|
|
2560
2842
|
}
|
|
2561
2843
|
async function abortRunAtSafeBoundaryDurablyResult(runId, reason = "user") {
|
|
2562
2844
|
const run = activeRuns.get(runId);
|