@agent-native/core 0.204.0 → 0.204.1-nightly-20261008034100
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 +5 -6
- package/dist/agent/auto-continue.d.ts +35 -0
- package/dist/agent/auto-continue.js +38 -0
- package/dist/agent/connection-required-note.d.ts +52 -0
- package/dist/agent/connection-required-note.js +187 -0
- package/dist/agent/jev-tool-prefetch.d.ts +5 -1
- package/dist/agent/jev-tool-prefetch.js +19 -6
- package/dist/agent/previous-turn-note.d.ts +9 -0
- package/dist/agent/previous-turn-note.js +48 -0
- package/dist/agent/production-agent.d.ts +17 -13
- package/dist/agent/production-agent.js +185 -43
- package/dist/agent/reaped-run-thread.d.ts +13 -0
- package/dist/agent/reaped-run-thread.js +45 -0
- package/dist/agent/run-store.d.ts +29 -5
- package/dist/agent/run-store.js +144 -30
- package/dist/agent/thread-data-builder.d.ts +16 -0
- package/dist/agent/thread-data-builder.js +30 -8
- package/dist/agent/thread-message-projection.js +5 -3
- package/dist/agent/tool-search.js +5 -1
- package/dist/agent/types.d.ts +3 -0
- package/dist/audit/config.d.ts +6 -0
- package/dist/audit/config.js +12 -1
- package/dist/audit/index.d.ts +1 -1
- package/dist/audit/index.js +1 -1
- package/dist/audit/store.js +39 -4
- package/dist/cli/skills.d.ts +1 -0
- package/dist/cli/skills.js +1 -1
- package/dist/client/chat/agentkit-agent-native.js +83 -7
- package/dist/client/chat/agentkit-protocol.js +140 -67
- package/dist/client/chat/runtime.js +5 -3
- package/dist/client/use-run-stuck-detection.d.ts +18 -1
- package/dist/client/use-run-stuck-detection.js +115 -75
- package/dist/db/request-telemetry.d.ts +7 -1
- package/dist/db/request-telemetry.js +20 -1
- package/dist/deploy/build.d.ts +25 -1
- package/dist/deploy/build.js +176 -3
- package/dist/deploy/workspace-deploy.js +8 -3
- package/dist/extensions/fetch-tool.js +50 -14
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/integrations/adapters/email.js +11 -3
- package/dist/integrations/adapters/telegram.js +4 -2
- package/dist/jobs/actions/automation-no-op.d.ts +12 -0
- package/dist/jobs/actions/automation-no-op.js +20 -0
- package/dist/jobs/actions/manage-recurring-job.d.ts +1 -1
- package/dist/jobs/background-automation-runner.d.ts +8 -1
- package/dist/jobs/background-automation-runner.js +102 -19
- package/dist/jobs/run-history.d.ts +1 -1
- package/dist/jobs/run-history.js +8 -4
- package/dist/jobs/scheduler.js +25 -12
- package/dist/localization/automation-outcome-messages.d.ts +22 -0
- package/dist/localization/automation-outcome-messages.js +90 -0
- package/dist/localization/default-messages.d.ts +2 -0
- package/dist/localization/default-messages.js +4 -2
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/metrics.d.ts +3 -0
- package/dist/observability/metrics.js +10 -0
- package/dist/observability/migrations.js +22 -0
- package/dist/observability/routes.d.ts +13 -8
- package/dist/observability/routes.js +88 -14
- package/dist/observability/sentiment.d.ts +5 -0
- package/dist/observability/sentiment.js +75 -25
- package/dist/observability/store.d.ts +28 -0
- package/dist/observability/store.js +58 -0
- package/dist/observability/traces.js +37 -5
- package/dist/org/index.d.ts +2 -2
- package/dist/progress/actions.js +1 -0
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +7 -7
- package/dist/provider-api/actions/provider-api.js +6 -2
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/provider-api/index.d.ts +1 -0
- package/dist/provider-api/index.js +18 -0
- package/dist/provider-api/result-outcome.d.ts +1 -0
- package/dist/provider-api/result-outcome.js +20 -0
- package/dist/provider-api/staging.js +10 -9
- package/dist/server/agent-chat/prompt-resources.d.ts +8 -2
- package/dist/server/agent-chat/prompt-resources.js +30 -7
- package/dist/server/agent-chat/recurring-jobs-runtime.d.ts +19 -4
- package/dist/server/agent-chat/recurring-jobs-runtime.js +52 -16
- package/dist/server/agent-chat/sweep-trigger-auth.d.ts +18 -0
- package/dist/server/agent-chat/sweep-trigger-auth.js +36 -0
- package/dist/server/agent-chat-plugin.js +20 -13
- package/dist/server/agent-engine-default-model-route.d.ts +2 -2
- package/dist/server/auth.js +4 -4
- package/dist/server/framework-request-handler.js +19 -0
- package/dist/server/http-response-telemetry.js +4 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/request-context.d.ts +6 -0
- package/dist/shared/context-status.d.ts +21 -0
- package/dist/shared/context-status.js +54 -0
- package/dist/templates/chat/app/components/chat/ChatRouteContent.tsx +8 -1
- package/dist/templates/workspace-core/.agents/skills/automations/SKILL.md +8 -1
- package/dist/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +3 -1
- package/dist/triggers/actions/manage-automation.d.ts +7 -7
- package/dist/triggers/dispatcher.js +10 -7
- package/docs/content/audit-log.mdx +3 -3
- package/docs/content/cloudflare.mdx +27 -0
- package/docs/content/deployment-environment-variables.mdx +2 -0
- package/docs/content/durable-resume.mdx +3 -1
- package/docs/content/environment-variables.mdx +2 -0
- package/docs/content/recurring-jobs.mdx +29 -9
- package/docs/content/vercel.mdx +30 -0
- package/package.json +3 -3
- package/src/templates/chat/app/components/chat/ChatRouteContent.tsx +8 -1
- package/src/templates/workspace-core/.agents/skills/automations/SKILL.md +8 -1
- package/src/templates/workspace-core/.agents/skills/recurring-jobs/SKILL.md +3 -1
|
@@ -365,6 +365,31 @@ function durableRunFailures(messages) {
|
|
|
365
365
|
];
|
|
366
366
|
}));
|
|
367
367
|
}
|
|
368
|
+
/** The turn each durable prompt started, keyed by the run it was submitted to. */
|
|
369
|
+
function durableSubmittedTurns(messages) {
|
|
370
|
+
return new Map(messages.flatMap((message) => {
|
|
371
|
+
const custom = asRecord(asRecord(message.metadata)?.custom);
|
|
372
|
+
return message.role === "user" &&
|
|
373
|
+
typeof custom?.submittedRunId === "string" &&
|
|
374
|
+
typeof custom.submittedTurnId === "string"
|
|
375
|
+
? [[custom.submittedRunId, custom.submittedTurnId]]
|
|
376
|
+
: [];
|
|
377
|
+
}));
|
|
378
|
+
}
|
|
379
|
+
/** The runs that left a durable reply on each turn. */
|
|
380
|
+
function durableReplyRunsByTurn(messages) {
|
|
381
|
+
const result = new Map();
|
|
382
|
+
for (const message of messages) {
|
|
383
|
+
const turnId = asRecord(asRecord(message.metadata)?.custom)?.turnId;
|
|
384
|
+
if (message.role !== "assistant" || typeof turnId !== "string")
|
|
385
|
+
continue;
|
|
386
|
+
const runIds = result.get(turnId) ?? new Set();
|
|
387
|
+
for (const runId of durableRunIds(message))
|
|
388
|
+
runIds.add(runId);
|
|
389
|
+
result.set(turnId, runIds);
|
|
390
|
+
}
|
|
391
|
+
return result;
|
|
392
|
+
}
|
|
368
393
|
/** A durable reply's terminal run plus every continuation run folded into it. */
|
|
369
394
|
function durableRunIds(message) {
|
|
370
395
|
const metadata = asRecord(message.metadata);
|
|
@@ -561,6 +586,38 @@ function reconcileDurableMessages(messages, durable, events, runs, toolCalls) {
|
|
|
561
586
|
durableByFoldedRun.set(runId, durableByFoldedRun.has(runId) ? null : message);
|
|
562
587
|
}
|
|
563
588
|
}
|
|
589
|
+
const textOf = (parts) => parts
|
|
590
|
+
.filter((part) => part.type === "text")
|
|
591
|
+
.map((part) => part.text)
|
|
592
|
+
.join("");
|
|
593
|
+
// A run that recovered an interrupted turn records only itself on its reply,
|
|
594
|
+
// while an open page streamed it into the run the prompt was submitted to.
|
|
595
|
+
// The recovering run's events open their own message, so the reply is on
|
|
596
|
+
// screen only when one of that run's messages is exactly it; anything less
|
|
597
|
+
// keeps the saved reply, so the answer is never dropped.
|
|
598
|
+
const submittedRunByTurn = new Map();
|
|
599
|
+
for (const stored of submittedUsers) {
|
|
600
|
+
const turnId = asRecord(asRecord(stored.metadata)?.custom)?.submittedTurnId;
|
|
601
|
+
if (typeof turnId !== "string")
|
|
602
|
+
continue;
|
|
603
|
+
submittedRunByTurn.set(turnId, submittedRunByTurn.has(turnId) ? null : submittedRunId(stored));
|
|
604
|
+
}
|
|
605
|
+
const shownByInterruptedRun = (reply) => {
|
|
606
|
+
const turnId = asRecord(asRecord(reply.metadata)?.custom)?.turnId;
|
|
607
|
+
const submitted = typeof turnId === "string" ? submittedRunByTurn.get(turnId) : undefined;
|
|
608
|
+
if (!submitted ||
|
|
609
|
+
durableRunIds(reply).includes(submitted) ||
|
|
610
|
+
durableByRun.has(submitted)) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
const ids = assistantIdsByRun.get(submitted);
|
|
614
|
+
const replyText = textOf(reply.parts);
|
|
615
|
+
if (!ids || !replyText)
|
|
616
|
+
return false;
|
|
617
|
+
return messages.some((message) => message.role === "assistant" &&
|
|
618
|
+
ids.has(message.id) &&
|
|
619
|
+
textOf(message.parts) === replyText);
|
|
620
|
+
};
|
|
564
621
|
const rootAssistantProjection = projectRootAssistantMessages({
|
|
565
622
|
rootMessages: durable,
|
|
566
623
|
snapshotMessages: messages,
|
|
@@ -676,6 +733,8 @@ function reconcileDurableMessages(messages, durable, events, runs, toolCalls) {
|
|
|
676
733
|
if (typeof runId !== "string" || !recoverableAssistantRunIds.has(runId)) {
|
|
677
734
|
continue;
|
|
678
735
|
}
|
|
736
|
+
if (shownByInterruptedRun(message))
|
|
737
|
+
continue;
|
|
679
738
|
missingMessages.push(message);
|
|
680
739
|
representedAssistantIds.add(message.id);
|
|
681
740
|
}
|
|
@@ -694,10 +753,6 @@ function reconcileDurableMessages(messages, durable, events, runs, toolCalls) {
|
|
|
694
753
|
snapshotRunIdsByMessageId.get(message.id) ??
|
|
695
754
|
(typeof metadataRunId === "string" ? metadataRunId : undefined));
|
|
696
755
|
};
|
|
697
|
-
const textOf = (parts) => parts
|
|
698
|
-
.filter((part) => part.type === "text")
|
|
699
|
-
.map((part) => part.text)
|
|
700
|
-
.join("");
|
|
701
756
|
const reconciledMessages = projectedMessages.map((message) => {
|
|
702
757
|
if (message.role === "user") {
|
|
703
758
|
const stored = storedUserBySnapshotId.get(message.id);
|
|
@@ -1652,8 +1707,7 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1652
1707
|
}
|
|
1653
1708
|
return value;
|
|
1654
1709
|
}
|
|
1655
|
-
async function activeRunSnapshot(threadId) {
|
|
1656
|
-
const value = await activeRunStatus(threadId);
|
|
1710
|
+
async function activeRunSnapshot(threadId, value) {
|
|
1657
1711
|
const status = value.status;
|
|
1658
1712
|
if (typeof value.active !== "boolean")
|
|
1659
1713
|
return undefined;
|
|
@@ -1775,7 +1829,8 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1775
1829
|
const completedRunIds = completedDurableRunIds(durableMessages);
|
|
1776
1830
|
const userStoppedRunIds = userStoppedDurableRunIds(durableMessages);
|
|
1777
1831
|
const durableFailures = durableRunFailures(durableMessages);
|
|
1778
|
-
const
|
|
1832
|
+
const activeStatus = await activeRunStatus(threadId);
|
|
1833
|
+
const activeRun = await activeRunSnapshot(threadId, activeStatus);
|
|
1779
1834
|
if (activeRun === undefined)
|
|
1780
1835
|
return thread;
|
|
1781
1836
|
let discoveredRun = activeRun;
|
|
@@ -1792,9 +1847,30 @@ export function createAgentNativeAgentKitTransport(options = {}) {
|
|
|
1792
1847
|
!["completed", "failed", "cancelled"].includes(discoveredRun.status)
|
|
1793
1848
|
? discoveredRun.id
|
|
1794
1849
|
: undefined;
|
|
1850
|
+
const submittedTurns = durableSubmittedTurns(durableMessages);
|
|
1851
|
+
const replyRunsByTurn = durableReplyRunsByTurn(durableMessages);
|
|
1852
|
+
const discoveredTurnId = typeof activeStatus.turnId === "string" ? activeStatus.turnId : undefined;
|
|
1853
|
+
// The stale-run reaper hands an interrupted turn to a successor run, which
|
|
1854
|
+
// then owns the turn's outcome: the server reports it, or it completed a
|
|
1855
|
+
// reply. A successor that failed or was stopped leaves the failure showing.
|
|
1856
|
+
const carriedOnByNewerRun = (runId) => {
|
|
1857
|
+
const turnId = submittedTurns.get(runId);
|
|
1858
|
+
if (!turnId)
|
|
1859
|
+
return false;
|
|
1860
|
+
if (discoveredRun && discoveredTurnId === turnId)
|
|
1861
|
+
return true;
|
|
1862
|
+
return [...(replyRunsByTurn.get(turnId) ?? [])].some((id) => id !== runId && completedRunIds.has(id));
|
|
1863
|
+
};
|
|
1795
1864
|
const runs = (thread.runs ?? [])
|
|
1796
1865
|
.filter((entry) => entry.id !== discoveredRun?.id)
|
|
1797
1866
|
.map((run) => {
|
|
1867
|
+
if ((["queued", "running"].includes(run.status) ||
|
|
1868
|
+
(run.status === "failed" &&
|
|
1869
|
+
runOutcomeForCode(run.error?.code) === "interrupted")) &&
|
|
1870
|
+
carriedOnByNewerRun(run.id)) {
|
|
1871
|
+
const { error: _error, ...attempt } = run;
|
|
1872
|
+
return { ...attempt, status: "completed" };
|
|
1873
|
+
}
|
|
1798
1874
|
if (activeRun === null &&
|
|
1799
1875
|
run.status === "running" &&
|
|
1800
1876
|
userStoppedRunIds.has(run.id)) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AGENT_TOOL_CALL_HISTORY_MEDIA_TYPE, AGENT_TOOL_RESULT_HISTORY_MEDIA_TYPE, AGENTKIT_PROTOCOL_VERSION, AgentProtocolValidationError, approvalResponseFromResume, createCapabilityUnavailableError, createCapabilityUnsupportedError, inferAgentActivityKind, negotiateAgentKitProtocolVersion, resumeEntryFromApproval, resumeOptionId, } from "@agent-native/agentkit/protocol";
|
|
2
|
-
import { AUTO_CONTINUE_OF_RUN_METADATA_KEY, AUTO_CONTINUE_PROMPT, AUTO_CONTINUE_REFUSAL_CODES, } from "../../agent/auto-continue.js";
|
|
2
|
+
import { AUTO_CONTINUE_OF_RUN_METADATA_KEY, AUTO_CONTINUE_PROMPT, AUTO_CONTINUE_REFUSAL_CODES, CONTINUE_OF_RUN_METADATA_KEY, CONTINUE_UNAVAILABLE_CODE, } from "../../agent/auto-continue.js";
|
|
3
3
|
import { emitChatFirstOpenApp, emitChatFirstOpenBrowser, } from "../chat-first-state.js";
|
|
4
4
|
import { decideAfterStreamClosed, runOutcomeForCode, } from "./run-outcome.js";
|
|
5
5
|
function isTerminalRunStatus(status) {
|
|
@@ -1104,6 +1104,67 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
1104
1104
|
ensurePump(run);
|
|
1105
1105
|
return run;
|
|
1106
1106
|
}
|
|
1107
|
+
/**
|
|
1108
|
+
* Registers a run the runtime just started and begins reading it. A disposed
|
|
1109
|
+
* adapter keeps no run it can no longer read.
|
|
1110
|
+
*/
|
|
1111
|
+
async function openStartedRun(threadId, session, turn, turnMetadata, observability) {
|
|
1112
|
+
const runId = turn.runId ?? turn.id ?? createId("run");
|
|
1113
|
+
const runMetadata = mergeTrustedProtocolMetadata(options.metadata, turnMetadata, turn.metadata, {
|
|
1114
|
+
[AGENT_NATIVE_PROTOCOL_METADATA_KEY]: {
|
|
1115
|
+
observability: {
|
|
1116
|
+
protocolRunId: runId,
|
|
1117
|
+
...(turn.runId === undefined ? {} : { runtimeRunId: turn.runId }),
|
|
1118
|
+
runtimeId: runtime.id,
|
|
1119
|
+
sessionId: session.id,
|
|
1120
|
+
turnId: turn.id,
|
|
1121
|
+
threadId,
|
|
1122
|
+
...observability,
|
|
1123
|
+
},
|
|
1124
|
+
},
|
|
1125
|
+
});
|
|
1126
|
+
setRuntimeRunIdMetadata(runMetadata, turn.runId);
|
|
1127
|
+
const run = {
|
|
1128
|
+
runId,
|
|
1129
|
+
threadId,
|
|
1130
|
+
session,
|
|
1131
|
+
turn,
|
|
1132
|
+
events: [],
|
|
1133
|
+
firstRetainedSequence: 1,
|
|
1134
|
+
sequence: 0,
|
|
1135
|
+
status: "queued",
|
|
1136
|
+
lastAccessedAtMs: timeMs(),
|
|
1137
|
+
activeReaders: 0,
|
|
1138
|
+
metadata: runMetadata,
|
|
1139
|
+
activeMessageCompleted: false,
|
|
1140
|
+
pendingWidgets: new Map(),
|
|
1141
|
+
actions: new Map(),
|
|
1142
|
+
activeTools: new Map(),
|
|
1143
|
+
pendingToolMessageAssociations: new Map(),
|
|
1144
|
+
activeActivities: new Map(),
|
|
1145
|
+
terminalAppendDepth: 0,
|
|
1146
|
+
pumpPromise: null,
|
|
1147
|
+
continuationPromise: null,
|
|
1148
|
+
streamClosed: false,
|
|
1149
|
+
terminal: false,
|
|
1150
|
+
waitingForContinuation: false,
|
|
1151
|
+
listeners: new Set(),
|
|
1152
|
+
};
|
|
1153
|
+
if (disposed) {
|
|
1154
|
+
await disposeSession(session).catch(() => undefined);
|
|
1155
|
+
throw new Error("The AgentKit adapter was disposed during turn creation.");
|
|
1156
|
+
}
|
|
1157
|
+
pruneRetainedRuns(run.lastAccessedAtMs);
|
|
1158
|
+
indexRun(run, turn.runId);
|
|
1159
|
+
append(run, {
|
|
1160
|
+
type: "run.started",
|
|
1161
|
+
agentId: runtime.id,
|
|
1162
|
+
metadata: runMetadata,
|
|
1163
|
+
});
|
|
1164
|
+
append(run, { type: "run.status", status: "running" });
|
|
1165
|
+
ensurePump(run);
|
|
1166
|
+
return runId;
|
|
1167
|
+
}
|
|
1107
1168
|
async function disposeSession(session) {
|
|
1108
1169
|
if (disposedSessions.has(session))
|
|
1109
1170
|
return;
|
|
@@ -2012,21 +2073,26 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2012
2073
|
payload: run.usage,
|
|
2013
2074
|
},
|
|
2014
2075
|
];
|
|
2015
|
-
case "error":
|
|
2076
|
+
case "error": {
|
|
2077
|
+
const error = {
|
|
2078
|
+
code: event.code ?? "runtime_error",
|
|
2079
|
+
message: event.error,
|
|
2080
|
+
retryable: event.retryable ?? event.recoverable,
|
|
2081
|
+
details: event.details ?? event.cause,
|
|
2082
|
+
};
|
|
2083
|
+
// An interruption ends this runtime run, not necessarily the turn.
|
|
2084
|
+
if (runAuthority &&
|
|
2085
|
+
capabilities.resumableRuns === true &&
|
|
2086
|
+
runOutcomeForCode(error.code) === "interrupted") {
|
|
2087
|
+
run.heldInterruption = error;
|
|
2088
|
+
return [];
|
|
2089
|
+
}
|
|
2016
2090
|
run.terminal = true;
|
|
2017
2091
|
return [
|
|
2018
2092
|
{ type: "run.status", ...base, status: "failed" },
|
|
2019
|
-
{
|
|
2020
|
-
type: "run.failed",
|
|
2021
|
-
...base,
|
|
2022
|
-
error: {
|
|
2023
|
-
code: event.code ?? "runtime_error",
|
|
2024
|
-
message: event.error,
|
|
2025
|
-
retryable: event.retryable ?? event.recoverable,
|
|
2026
|
-
details: event.details ?? event.cause,
|
|
2027
|
-
},
|
|
2028
|
-
},
|
|
2093
|
+
{ type: "run.failed", ...base, error },
|
|
2029
2094
|
];
|
|
2095
|
+
}
|
|
2030
2096
|
case "done":
|
|
2031
2097
|
if (!isTerminalReason(event.reason)) {
|
|
2032
2098
|
run.waitingForContinuation = true;
|
|
@@ -2256,6 +2322,18 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2256
2322
|
}
|
|
2257
2323
|
if (stopped())
|
|
2258
2324
|
return null;
|
|
2325
|
+
// An unreachable server says nothing about a successor; keep holding
|
|
2326
|
+
// through the usual backoff until it answers.
|
|
2327
|
+
if (run.heldInterruption && read.kind !== "unreachable") {
|
|
2328
|
+
const successor = read.kind === "read" &&
|
|
2329
|
+
read.state.status !== "missing" &&
|
|
2330
|
+
read.state.runId !== runtimeRunId;
|
|
2331
|
+
if (!successor) {
|
|
2332
|
+
appendHeldInterruption(run);
|
|
2333
|
+
return null;
|
|
2334
|
+
}
|
|
2335
|
+
run.heldInterruption = undefined;
|
|
2336
|
+
}
|
|
2259
2337
|
const decision = decideAfterStreamClosed(read, {
|
|
2260
2338
|
runId: runtimeRunId,
|
|
2261
2339
|
drain: run.terminalDrain,
|
|
@@ -2406,6 +2484,14 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2406
2484
|
append(run, { type: "run.cancelled" });
|
|
2407
2485
|
}
|
|
2408
2486
|
}
|
|
2487
|
+
/** The runtime run's own interruption, once no newer run carries the turn. */
|
|
2488
|
+
function appendHeldInterruption(run) {
|
|
2489
|
+
const error = run.heldInterruption;
|
|
2490
|
+
run.heldInterruption = undefined;
|
|
2491
|
+
run.terminal = true;
|
|
2492
|
+
append(run, { type: "run.status", status: "failed" });
|
|
2493
|
+
append(run, { type: "run.failed", error });
|
|
2494
|
+
}
|
|
2409
2495
|
function setResumedRuntimeTurn(run, resumed) {
|
|
2410
2496
|
const runtimeRunId = run.turn.runId ?? run.runId;
|
|
2411
2497
|
if (resumed.runId && resumed.runId !== runtimeRunId) {
|
|
@@ -2439,8 +2525,11 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2439
2525
|
for (const protocolEvent of runtimeEventToProtocolEvents(run, event)) {
|
|
2440
2526
|
append(run, protocolEvent);
|
|
2441
2527
|
}
|
|
2442
|
-
if (run.waitingForContinuation ||
|
|
2528
|
+
if (run.waitingForContinuation ||
|
|
2529
|
+
run.terminal ||
|
|
2530
|
+
run.heldInterruption) {
|
|
2443
2531
|
break;
|
|
2532
|
+
}
|
|
2444
2533
|
}
|
|
2445
2534
|
}
|
|
2446
2535
|
catch (error) {
|
|
@@ -2452,7 +2541,7 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2452
2541
|
}
|
|
2453
2542
|
if (run.restoredWithoutStream)
|
|
2454
2543
|
run.restoredWithoutStream = false;
|
|
2455
|
-
else
|
|
2544
|
+
else if (!run.heldInterruption)
|
|
2456
2545
|
run.pipeClosedBeforeTerminal = true;
|
|
2457
2546
|
const resumed = runAuthority && capabilities.resumableRuns === true
|
|
2458
2547
|
? await followRunAuthority(run, runAuthority, stream)
|
|
@@ -2578,59 +2667,7 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2578
2667
|
metadata: turnMetadata,
|
|
2579
2668
|
abortSignal: readers.signal,
|
|
2580
2669
|
});
|
|
2581
|
-
const runId =
|
|
2582
|
-
const runMetadata = mergeTrustedProtocolMetadata(options.metadata, turnMetadata, turn.metadata, {
|
|
2583
|
-
[AGENT_NATIVE_PROTOCOL_METADATA_KEY]: {
|
|
2584
|
-
observability: {
|
|
2585
|
-
protocolRunId: runId,
|
|
2586
|
-
...(turn.runId === undefined ? {} : { runtimeRunId: turn.runId }),
|
|
2587
|
-
runtimeId: runtime.id,
|
|
2588
|
-
sessionId: session.id,
|
|
2589
|
-
turnId: turn.id,
|
|
2590
|
-
threadId: input.threadId,
|
|
2591
|
-
},
|
|
2592
|
-
},
|
|
2593
|
-
});
|
|
2594
|
-
setRuntimeRunIdMetadata(runMetadata, turn.runId);
|
|
2595
|
-
const run = {
|
|
2596
|
-
runId,
|
|
2597
|
-
threadId: input.threadId,
|
|
2598
|
-
session,
|
|
2599
|
-
turn,
|
|
2600
|
-
events: [],
|
|
2601
|
-
firstRetainedSequence: 1,
|
|
2602
|
-
sequence: 0,
|
|
2603
|
-
status: "queued",
|
|
2604
|
-
lastAccessedAtMs: timeMs(),
|
|
2605
|
-
activeReaders: 0,
|
|
2606
|
-
metadata: runMetadata,
|
|
2607
|
-
activeMessageCompleted: false,
|
|
2608
|
-
pendingWidgets: new Map(),
|
|
2609
|
-
actions: new Map(),
|
|
2610
|
-
activeTools: new Map(),
|
|
2611
|
-
pendingToolMessageAssociations: new Map(),
|
|
2612
|
-
activeActivities: new Map(),
|
|
2613
|
-
terminalAppendDepth: 0,
|
|
2614
|
-
pumpPromise: null,
|
|
2615
|
-
continuationPromise: null,
|
|
2616
|
-
streamClosed: false,
|
|
2617
|
-
terminal: false,
|
|
2618
|
-
waitingForContinuation: false,
|
|
2619
|
-
listeners: new Set(),
|
|
2620
|
-
};
|
|
2621
|
-
if (disposed) {
|
|
2622
|
-
await disposeSession(session).catch(() => undefined);
|
|
2623
|
-
throw new Error("The AgentKit adapter was disposed during turn creation.");
|
|
2624
|
-
}
|
|
2625
|
-
pruneRetainedRuns(run.lastAccessedAtMs);
|
|
2626
|
-
indexRun(run, turn.runId);
|
|
2627
|
-
append(run, {
|
|
2628
|
-
type: "run.started",
|
|
2629
|
-
agentId: runtime.id,
|
|
2630
|
-
metadata: runMetadata,
|
|
2631
|
-
});
|
|
2632
|
-
append(run, { type: "run.status", status: "running" });
|
|
2633
|
-
ensurePump(run);
|
|
2670
|
+
const runId = await openStartedRun(input.threadId, session, turn, turnMetadata);
|
|
2634
2671
|
return { runId, capabilities };
|
|
2635
2672
|
},
|
|
2636
2673
|
async *subscribeToRun(input) {
|
|
@@ -2984,6 +3021,42 @@ export function createAgentKitProtocolAdapter(runtime, options = {}) {
|
|
|
2984
3021
|
});
|
|
2985
3022
|
};
|
|
2986
3023
|
}
|
|
3024
|
+
if (runAuthority) {
|
|
3025
|
+
const authority = runAuthority;
|
|
3026
|
+
// Continues the turn a stopped run belonged to rather than starting a new
|
|
3027
|
+
// one, so the turn's journal still blocks repeating a finished write. The
|
|
3028
|
+
// server reads which run ended the turn; this page may know only the one
|
|
3029
|
+
// it watched, or none after a reload.
|
|
3030
|
+
transport.continueRun = async (input) => {
|
|
3031
|
+
if (disposed)
|
|
3032
|
+
throw new Error("The AgentKit adapter is disposed.");
|
|
3033
|
+
pruneRetainedRuns();
|
|
3034
|
+
const local = runs.get(input.runId);
|
|
3035
|
+
if (local && local.threadId !== input.threadId) {
|
|
3036
|
+
throw new Error(`Unknown AgentKit run: ${input.runId}`);
|
|
3037
|
+
}
|
|
3038
|
+
const session = local?.session ?? (await getSession(input.threadId));
|
|
3039
|
+
if (!session.continueTurn) {
|
|
3040
|
+
throw new Error("The Core runtime does not support run continuation.");
|
|
3041
|
+
}
|
|
3042
|
+
const state = await authority.readRunState({
|
|
3043
|
+
sessionId: session.id,
|
|
3044
|
+
runId: local?.turn.runId ?? input.runId,
|
|
3045
|
+
abortSignal: readers.signal,
|
|
3046
|
+
});
|
|
3047
|
+
if (state.status === "missing" || !state.turnId) {
|
|
3048
|
+
throw Object.assign(new Error(`Agent run ${input.runId} cannot be continued.`), { code: CONTINUE_UNAVAILABLE_CODE, retryable: false });
|
|
3049
|
+
}
|
|
3050
|
+
const turn = await session.continueTurn({
|
|
3051
|
+
turnId: state.turnId,
|
|
3052
|
+
prompt: AUTO_CONTINUE_PROMPT,
|
|
3053
|
+
metadata: { [CONTINUE_OF_RUN_METADATA_KEY]: state.runId },
|
|
3054
|
+
abortSignal: readers.signal,
|
|
3055
|
+
});
|
|
3056
|
+
const runId = await openStartedRun(input.threadId, session, turn, undefined, { continuedRunId: input.runId });
|
|
3057
|
+
return { runId, capabilities };
|
|
3058
|
+
};
|
|
3059
|
+
}
|
|
2987
3060
|
if (runtime.capabilities.rich?.connectionRequests) {
|
|
2988
3061
|
transport.resolveConnectionRequest = async (input) => {
|
|
2989
3062
|
pruneRetainedRuns();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AgentKitRunSlotBusyError } from "@agent-native/agentkit/client";
|
|
2
|
-
import { AUTO_CONTINUE_OF_RUN_METADATA_KEY } from "../../agent/auto-continue.js";
|
|
2
|
+
import { AUTO_CONTINUE_OF_RUN_METADATA_KEY, CONTINUE_OF_RUN_METADATA_KEY, } from "../../agent/auto-continue.js";
|
|
3
3
|
import { agentChatStreamingUrl, agentNativePath } from "../api-path.js";
|
|
4
4
|
import { CHAT_REQUEST_TOO_LARGE_MESSAGE } from "../error-format.js";
|
|
5
5
|
import { appendMissingFinalResponseWarning, } from "../sse-event-processor.js";
|
|
@@ -2449,6 +2449,7 @@ export function createAgentNativeChatRuntime(options = {}) {
|
|
|
2449
2449
|
const approvedToolCalls = metadataStringList(turn.metadata, AGENT_NATIVE_APPROVED_TOOL_CALLS_METADATA_KEY);
|
|
2450
2450
|
const continuationTurnId = metadataString(turn.metadata, AGENT_NATIVE_CONTINUATION_TURN_ID_METADATA_KEY);
|
|
2451
2451
|
const autoContinueOfRunId = metadataString(turn.metadata, AUTO_CONTINUE_OF_RUN_METADATA_KEY);
|
|
2452
|
+
const continueOfRunId = metadataString(turn.metadata, CONTINUE_OF_RUN_METADATA_KEY);
|
|
2452
2453
|
const continuationMessageState = continuationTurnId
|
|
2453
2454
|
? messageStates.get(continuationTurnId)
|
|
2454
2455
|
: undefined;
|
|
@@ -2481,6 +2482,7 @@ export function createAgentNativeChatRuntime(options = {}) {
|
|
|
2481
2482
|
? { internalContinuation: true }
|
|
2482
2483
|
: {}),
|
|
2483
2484
|
...(autoContinueOfRunId ? { autoContinueOfRunId } : {}),
|
|
2485
|
+
...(continueOfRunId ? { continueOfRunId } : {}),
|
|
2484
2486
|
...(turn.metadata?.agentNativeSkipPendingSelectionContext === true
|
|
2485
2487
|
? { skipPendingSelectionContext: true }
|
|
2486
2488
|
: {}),
|
|
@@ -2527,8 +2529,8 @@ export function createAgentNativeChatRuntime(options = {}) {
|
|
|
2527
2529
|
},
|
|
2528
2530
|
continueTurn: ({ session, continuation, previousTurn, startTurn }) => {
|
|
2529
2531
|
// Only the continuation that names a stopped run continues it; an approval
|
|
2530
|
-
// or connection answered later is not another
|
|
2531
|
-
const { [AUTO_CONTINUE_OF_RUN_METADATA_KEY]: _autoContinueOf, ...previousMetadata } = previousTurn?.metadata ?? {};
|
|
2532
|
+
// or connection answered later is not another continuation of that run.
|
|
2533
|
+
const { [AUTO_CONTINUE_OF_RUN_METADATA_KEY]: _autoContinueOf, [CONTINUE_OF_RUN_METADATA_KEY]: _continueOf, ...previousMetadata } = previousTurn?.metadata ?? {};
|
|
2532
2534
|
const approval = continuation.approval;
|
|
2533
2535
|
const connection = continuation.connection;
|
|
2534
2536
|
const messageStateKey = continuation.turnId ?? session.id;
|
|
@@ -9,10 +9,27 @@ export interface RunStuckState {
|
|
|
9
9
|
heartbeatSinceMs: number | null;
|
|
10
10
|
dispatchMode: string | null;
|
|
11
11
|
hasInFlightWork: boolean | null;
|
|
12
|
+
/**
|
|
13
|
+
* The server reported no run in flight on this thread on two polls in a row.
|
|
14
|
+
* A chat still showing "running" at that point has lost the run's ending and
|
|
15
|
+
* should reload the thread, not keep waiting.
|
|
16
|
+
*/
|
|
17
|
+
serverSettled: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* The last polls failed, so nothing here says whether the run is alive.
|
|
20
|
+
* Distinct from "no run": the other fields are the last answer, not a fresh one.
|
|
21
|
+
*/
|
|
22
|
+
statusUnreadable: boolean;
|
|
12
23
|
}
|
|
13
24
|
export interface UseRunStuckDetectionOptions {
|
|
14
25
|
threadId: string | null | undefined;
|
|
15
26
|
enabled?: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* Whether the chat is showing a run in progress. Each time it turns on, the
|
|
29
|
+
* hook starts over, so `serverSettled` only ever reflects polls taken after
|
|
30
|
+
* the chat began waiting, never an idle answer from before the user sent.
|
|
31
|
+
*/
|
|
32
|
+
awaitingResponse?: boolean;
|
|
16
33
|
stuckThresholdMs?: number;
|
|
17
34
|
/**
|
|
18
35
|
* Threshold for BACKGROUND-dispatched runs (dispatchMode starts with
|
|
@@ -29,5 +46,5 @@ export interface UseRunStuckDetectionOptions {
|
|
|
29
46
|
}
|
|
30
47
|
export declare const DEFAULT_BACKGROUND_STUCK_THRESHOLD_MS = 180000;
|
|
31
48
|
export declare const DEFAULT_LIVE_BACKGROUND_STUCK_THRESHOLD_MS: number;
|
|
32
|
-
export declare function useRunStuckDetection({ threadId, enabled, stuckThresholdMs, backgroundStuckThresholdMs, liveBackgroundStuckThresholdMs, pollIntervalMs, apiUrl, }: UseRunStuckDetectionOptions): RunStuckState;
|
|
49
|
+
export declare function useRunStuckDetection({ threadId, enabled, awaitingResponse, stuckThresholdMs, backgroundStuckThresholdMs, liveBackgroundStuckThresholdMs, pollIntervalMs, apiUrl, }: UseRunStuckDetectionOptions): RunStuckState;
|
|
33
50
|
export declare function useAbortRun(apiUrl?: string): (runId: string, reason?: string) => Promise<string | null>;
|