@agent-native/core 0.210.1-nightly-20261020124228 → 0.210.2
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/a2a/server.js +2 -1
- package/dist/agent/contain-principal.js +2 -3
- package/dist/agent/engine/ai-sdk-engine.js +29 -20
- package/dist/agent/engine/anthropic-engine.js +10 -1
- package/dist/agent/engine/builder-engine.js +28 -14
- package/dist/agent/engine/types.d.ts +11 -0
- package/dist/agent/engine/types.js +8 -0
- package/dist/agent/execution-fence.d.ts +5 -0
- package/dist/agent/execution-fence.js +15 -0
- package/dist/agent/harness/background.js +28 -7
- package/dist/agent/production-agent.d.ts +4 -3
- package/dist/agent/production-agent.js +20 -3
- package/dist/agent/run-manager.d.ts +8 -1
- package/dist/agent/run-manager.js +273 -34
- package/dist/agent/run-store.d.ts +3 -2
- package/dist/agent/run-store.fencing.worker.js +19 -1
- package/dist/agent/run-store.js +216 -67
- package/dist/client/use-agent-engine-configured.d.ts +2 -2
- package/dist/client/use-agent-engine-configured.js +3 -9
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/notifications/routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +4 -4
- package/dist/server/agent-chat-plugin.js +27 -11
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-engine-ollama-models-route.d.ts +2 -2
- package/dist/server/agent-teams.d.ts +3 -0
- package/dist/server/agent-teams.js +192 -30
- package/package.json +4 -4
|
@@ -27,39 +27,39 @@ export declare function createObservabilityHandler(): import("h3").EventHandlerW
|
|
|
27
27
|
thumbsUpRate: number;
|
|
28
28
|
avgEvalScore: number;
|
|
29
29
|
} | {
|
|
30
|
-
ok?: undefined;
|
|
31
30
|
error: string;
|
|
32
31
|
message: string;
|
|
33
32
|
summary?: undefined;
|
|
34
33
|
spans?: undefined;
|
|
34
|
+
ok?: undefined;
|
|
35
35
|
} | {
|
|
36
36
|
error?: undefined;
|
|
37
|
-
ok?: undefined;
|
|
38
37
|
message?: undefined;
|
|
39
38
|
summary: import("./types.js").TraceSummary;
|
|
40
39
|
spans: import("./types.js").TraceSpan[];
|
|
40
|
+
ok?: undefined;
|
|
41
41
|
} | {
|
|
42
42
|
error?: undefined;
|
|
43
|
-
ok?: undefined;
|
|
44
43
|
message?: undefined;
|
|
45
44
|
summary?: undefined;
|
|
46
45
|
spans?: undefined;
|
|
47
46
|
traceMissing: true;
|
|
48
47
|
id: string;
|
|
48
|
+
ok?: undefined;
|
|
49
49
|
} | {
|
|
50
50
|
error?: undefined;
|
|
51
|
-
ok?: undefined;
|
|
52
51
|
message?: undefined;
|
|
53
52
|
summary?: undefined;
|
|
54
53
|
spans?: undefined;
|
|
55
54
|
traceMissing?: undefined;
|
|
56
55
|
id: string;
|
|
57
|
-
} | {
|
|
58
56
|
ok?: undefined;
|
|
57
|
+
} | {
|
|
59
58
|
message?: undefined;
|
|
60
59
|
summary?: undefined;
|
|
61
60
|
spans?: undefined;
|
|
62
61
|
error: any;
|
|
62
|
+
ok?: undefined;
|
|
63
63
|
} | {
|
|
64
64
|
error?: undefined;
|
|
65
65
|
message?: undefined;
|
package/dist/secrets/routes.d.ts
CHANGED
|
@@ -57,31 +57,31 @@ export declare function createWriteSecretHandler(): import("h3").EventHandlerWit
|
|
|
57
57
|
} | {
|
|
58
58
|
error: string;
|
|
59
59
|
errorCode?: undefined;
|
|
60
|
-
ok?: undefined;
|
|
61
60
|
status?: undefined;
|
|
61
|
+
ok?: undefined;
|
|
62
62
|
} | {
|
|
63
63
|
error: string;
|
|
64
64
|
errorCode: string;
|
|
65
|
-
ok?: undefined;
|
|
66
65
|
status?: undefined;
|
|
66
|
+
ok?: undefined;
|
|
67
67
|
} | {
|
|
68
68
|
error?: undefined;
|
|
69
69
|
errorCode?: undefined;
|
|
70
70
|
ok: boolean;
|
|
71
71
|
status: string;
|
|
72
72
|
} | {
|
|
73
|
-
ok?: undefined;
|
|
74
73
|
error: string;
|
|
75
74
|
removed?: undefined;
|
|
75
|
+
ok?: undefined;
|
|
76
76
|
} | {
|
|
77
77
|
error?: undefined;
|
|
78
78
|
ok: boolean;
|
|
79
79
|
removed: boolean;
|
|
80
80
|
}>>;
|
|
81
81
|
export declare function createTestSecretHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
82
|
-
ok?: undefined;
|
|
83
82
|
error: string;
|
|
84
83
|
note?: undefined;
|
|
84
|
+
ok?: undefined;
|
|
85
85
|
} | {
|
|
86
86
|
error?: undefined;
|
|
87
87
|
ok: boolean;
|
|
@@ -20,7 +20,7 @@ import { SYSTEM_PROMPT_CACHE_SPLIT } from "../agent/engine/prompt-cache.js";
|
|
|
20
20
|
import { PROVIDER_TO_ENV } from "../agent/engine/provider-env-vars.js";
|
|
21
21
|
import { currentExecutionFence, withExecutionFence, } from "../agent/execution-fence.js";
|
|
22
22
|
import { hostedHarnessSystemPrompt } from "../agent/harness/hosted.js";
|
|
23
|
-
import { createProductionAgentHandler, endsAtContinuationBoundary, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, normalizeAgentActionSurfaceResolution, getActiveRunForThreadAsync, abortRunDurably, abortRunAtSafeBoundaryDurably, abortTurnByRefDurably, abortTurnDurably, subscribeToRun, } from "../agent/production-agent.js";
|
|
23
|
+
import { createProductionAgentHandler, endsAtContinuationBoundary, actionsToEngineTools, executeAgentToolCall, filterActionsByAllowedNames, normalizeAgentActionSurfaceResolution, getActiveRunForThreadAsync, abortRunDurably, abortRunAndTurnDurably, abortRunAtSafeBoundaryDurably, abortTurnByRefDurably, abortTurnDurably, subscribeToRun, } from "../agent/production-agent.js";
|
|
24
24
|
import { applyProviderModelSelection, providerForEngineName, resolveProviderModelSelectionAtScope, } from "../agent/provider-model-selection.js";
|
|
25
25
|
import { startRun } from "../agent/run-manager.js";
|
|
26
26
|
import { callerHasRunAccess, callerHasThreadAccess, } from "../agent/run-ownership.js";
|
|
@@ -420,7 +420,7 @@ export async function runA2AAgentLoopWithRunManager(runOptions, pluginOptions, t
|
|
|
420
420
|
model: runOptions.model,
|
|
421
421
|
engineName: runOptions.engine.name,
|
|
422
422
|
});
|
|
423
|
-
let cancellation = Promise.resolve(false);
|
|
423
|
+
let cancellation = Promise.resolve({ status: "fulfilled", aborted: false });
|
|
424
424
|
const abortFromTask = () => {
|
|
425
425
|
const reason = taskSignal?.reason;
|
|
426
426
|
const reasonCode = reason && typeof reason === "object" && "code" in reason
|
|
@@ -431,7 +431,7 @@ export async function runA2AAgentLoopWithRunManager(runOptions, pluginOptions, t
|
|
|
431
431
|
run.abort.abort("execution_lease_lost");
|
|
432
432
|
return;
|
|
433
433
|
}
|
|
434
|
-
cancellation = abortRunDurably(runId, clientAbortReason(reason));
|
|
434
|
+
cancellation = abortRunDurably(runId, clientAbortReason(reason)).then((aborted) => ({ status: "fulfilled", aborted }), (error) => ({ status: "rejected", error }));
|
|
435
435
|
};
|
|
436
436
|
if (taskSignal?.aborted) {
|
|
437
437
|
abortFromTask();
|
|
@@ -440,8 +440,17 @@ export async function runA2AAgentLoopWithRunManager(runOptions, pluginOptions, t
|
|
|
440
440
|
taskSignal?.addEventListener("abort", abortFromTask, { once: true });
|
|
441
441
|
}
|
|
442
442
|
try {
|
|
443
|
-
await run.finalized;
|
|
444
|
-
await cancellation;
|
|
443
|
+
const finalization = await run.finalized.then(() => ({ status: "fulfilled" }), (error) => ({ status: "rejected", error }));
|
|
444
|
+
const cancellationResult = await cancellation;
|
|
445
|
+
if (finalization.status === "rejected" &&
|
|
446
|
+
cancellationResult.status === "rejected") {
|
|
447
|
+
throw new AggregateError([finalization.error, cancellationResult.error], "A2A run finalization and durable cancellation both failed");
|
|
448
|
+
}
|
|
449
|
+
if (finalization.status === "rejected")
|
|
450
|
+
throw finalization.error;
|
|
451
|
+
if (cancellationResult.status === "rejected") {
|
|
452
|
+
throw cancellationResult.error;
|
|
453
|
+
}
|
|
445
454
|
}
|
|
446
455
|
finally {
|
|
447
456
|
taskSignal?.removeEventListener("abort", abortFromTask);
|
|
@@ -5262,10 +5271,15 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5262
5271
|
// Empty/invalid body — keep the default user abort reason.
|
|
5263
5272
|
}
|
|
5264
5273
|
if (safeBoundary) {
|
|
5265
|
-
const
|
|
5266
|
-
|
|
5267
|
-
|
|
5268
|
-
|
|
5274
|
+
const isUserStop = USER_STOP_ABORT_REASONS.has(reason);
|
|
5275
|
+
const aborted = isUserStop
|
|
5276
|
+
? await abortRunAndTurnDurably(runId, reason, {
|
|
5277
|
+
safeBoundary: true,
|
|
5278
|
+
})
|
|
5279
|
+
: await abortRunAtSafeBoundaryDurably(runId, reason);
|
|
5280
|
+
if (isUserStop && !aborted) {
|
|
5281
|
+
const latest = await getRunById(runId);
|
|
5282
|
+
if (latest?.status === "aborted") {
|
|
5269
5283
|
await abortTurnDurably(runId, reason);
|
|
5270
5284
|
}
|
|
5271
5285
|
}
|
|
@@ -5274,9 +5288,11 @@ Non-code requests are still fine on this surface: read data, navigate the UI, su
|
|
|
5274
5288
|
// Recovery starts as soon as this response resolves, so wait for
|
|
5275
5289
|
// the cross-isolate abort + terminal event to be durable. Returning
|
|
5276
5290
|
// early lets Retry collide with the still-running row.
|
|
5277
|
-
await abortRunDurably(runId, reason);
|
|
5278
5291
|
if (USER_STOP_ABORT_REASONS.has(reason)) {
|
|
5279
|
-
await
|
|
5292
|
+
await abortRunAndTurnDurably(runId, reason);
|
|
5293
|
+
}
|
|
5294
|
+
else {
|
|
5295
|
+
await abortRunDurably(runId, reason);
|
|
5280
5296
|
}
|
|
5281
5297
|
return { ok: true };
|
|
5282
5298
|
}
|
|
@@ -66,6 +66,7 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
|
|
|
66
66
|
error: any;
|
|
67
67
|
code: any;
|
|
68
68
|
} | {
|
|
69
|
+
error?: undefined;
|
|
69
70
|
errorCode?: undefined;
|
|
70
71
|
code?: undefined;
|
|
71
72
|
ok: boolean;
|
|
@@ -73,6 +74,5 @@ export declare function createAgentEngineApiKeyHandler(): import("h3").EventHand
|
|
|
73
74
|
baseUrlKey?: string;
|
|
74
75
|
scope: AgentEngineApiKeyScope;
|
|
75
76
|
defaultModel?: import("./agent-engine-default-model-route.js").SavedKeyDefaultModelOutcome;
|
|
76
|
-
error?: undefined;
|
|
77
77
|
}>>;
|
|
78
78
|
export {};
|
|
@@ -8,8 +8,8 @@ export declare const AGENT_ENGINE_API_KEY_ACTION_NAME = "agent-engine-api-key";
|
|
|
8
8
|
* resolveEngine's credential detection.
|
|
9
9
|
*/
|
|
10
10
|
export declare function createAgentEngineDisconnectHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
11
|
-
ok?: undefined;
|
|
12
11
|
error: string;
|
|
12
|
+
ok?: undefined;
|
|
13
13
|
scope?: undefined;
|
|
14
14
|
} | {
|
|
15
15
|
ok: boolean;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export declare function createAgentEngineOllamaModelsHandler(): import("h3").EventHandlerWithFetch<import("h3").EventHandlerRequest, Promise<{
|
|
2
2
|
error: string;
|
|
3
|
-
ok?: undefined;
|
|
4
3
|
models?: undefined;
|
|
4
|
+
ok?: undefined;
|
|
5
5
|
} | {
|
|
6
|
-
error?: undefined;
|
|
7
6
|
ok: boolean;
|
|
8
7
|
models: string[];
|
|
8
|
+
error?: undefined;
|
|
9
9
|
}>>;
|
|
@@ -44,6 +44,9 @@ export interface AgentTask {
|
|
|
44
44
|
terminalEffectsVersion?: 1;
|
|
45
45
|
terminalEffectsReconciled?: boolean;
|
|
46
46
|
terminalProgressStatus?: TerminalProgressStatus;
|
|
47
|
+
stopRequestedAt?: number;
|
|
48
|
+
stopRequestedRunId?: string;
|
|
49
|
+
stopRequestedReason?: string;
|
|
47
50
|
}
|
|
48
51
|
export interface AgentTeamOwnerScope {
|
|
49
52
|
ownerEmail: string | null;
|
|
@@ -5,7 +5,7 @@ import { resolveMainChatMaxOutputTokens } from "../agent/engine/output-tokens.js
|
|
|
5
5
|
import { currentExecutionFence, withExecutionFence, withFencedExecutionWrite, } from "../agent/execution-fence.js";
|
|
6
6
|
import { actionsToEngineTools, filterActionsByAllowedNames, filterInitialEngineTools, readPersistedAllowedActionNames, resolveAgentRequestReasoningEffort, } from "../agent/production-agent.js";
|
|
7
7
|
import { runAgentLoop, appendAgentLoopContinuation, } from "../agent/production-agent.js";
|
|
8
|
-
import { abortRun, getActiveRunForThreadAsync, getRun, startRun, subscribeToRun, } from "../agent/run-manager.js";
|
|
8
|
+
import { abortRun, abortRunDurably, getActiveRunForThreadAsync, getRun, startRun, subscribeToRun, } from "../agent/run-manager.js";
|
|
9
9
|
import { ensureRunTables, getRunEventsSince, lockTaskExecutionLease, revokeTaskExecutionLease, } from "../agent/run-store.js";
|
|
10
10
|
import { buildAssistantMessageFromRunJournal } from "../agent/run-thread-projector.js";
|
|
11
11
|
import { resolveMaxSubagentDelegationDepth } from "../agent/runtime-context.js";
|
|
@@ -466,6 +466,8 @@ async function failReconciledTask(task, ownerEmail, message, progressStatus = "f
|
|
|
466
466
|
? undefined
|
|
467
467
|
: structuredClone(currentTask);
|
|
468
468
|
Object.assign(task, currentTask);
|
|
469
|
+
if (task.stopRequestedAt !== undefined)
|
|
470
|
+
return false;
|
|
469
471
|
cancelled ||= isCancelledAgentTask(task);
|
|
470
472
|
terminalProgressStatus = cancelled ? "cancelled" : progressStatus;
|
|
471
473
|
task.status = "errored";
|
|
@@ -1407,6 +1409,9 @@ async function stopAgentTeamRunAfterActionPersistenceError(task, claimedAttempts
|
|
|
1407
1409
|
}
|
|
1408
1410
|
async function finalizeAgentTeamRun(task, run, ownerEmail, fullText, options) {
|
|
1409
1411
|
const result = await withCurrentAgentTeamRunAttempt(task.taskId, options.claimedAttempts, async () => {
|
|
1412
|
+
const currentTask = await loadTask(task.taskId);
|
|
1413
|
+
if (currentTask && currentTask.stopRequestedAt !== undefined)
|
|
1414
|
+
return null;
|
|
1410
1415
|
if (options.hitContinuationLimit) {
|
|
1411
1416
|
await bumpAgentTeamContinuation(task.taskId, options.claimedAttempts, {
|
|
1412
1417
|
requeue: false,
|
|
@@ -1573,6 +1578,13 @@ export async function processAgentTeamRun(opts) {
|
|
|
1573
1578
|
await completeAgentTeamRun(opts.taskId, task.status === "completed" ? "done" : "failed", claimed.attempts);
|
|
1574
1579
|
return { ok: true, skipped: "task-terminal" };
|
|
1575
1580
|
}
|
|
1581
|
+
if (task.stopRequestedAt !== undefined) {
|
|
1582
|
+
const stopped = await stopAgentTeamBackgroundRun(runId, task.stopRequestedReason ?? "user");
|
|
1583
|
+
if (!stopped.ok) {
|
|
1584
|
+
throw new Error("The persisted agent task stop could not be resumed.");
|
|
1585
|
+
}
|
|
1586
|
+
return { ok: true, skipped: "stop-reconciled" };
|
|
1587
|
+
}
|
|
1576
1588
|
const ownerEmail = claimed.ownerEmail ?? getRequestUserEmail() ?? "";
|
|
1577
1589
|
const orgId = claimed.orgId;
|
|
1578
1590
|
const turnId = payload.turnId || taskRunId(opts.taskId);
|
|
@@ -1591,6 +1603,11 @@ export async function processAgentTeamRun(opts) {
|
|
|
1591
1603
|
? `Failed to prepare sub-agent: ${err.message}`
|
|
1592
1604
|
: "Failed to prepare sub-agent.";
|
|
1593
1605
|
await failReconciledTask(task, ownerEmail || null, message, "failed", claimed, false);
|
|
1606
|
+
const latestTask = await loadTask(opts.taskId);
|
|
1607
|
+
if (latestTask?.stopRequestedAt !== undefined ||
|
|
1608
|
+
latestTask?.terminalProgressStatus === "cancelled") {
|
|
1609
|
+
return { ok: true, skipped: "stop-requested" };
|
|
1610
|
+
}
|
|
1594
1611
|
return { ok: false, skipped: "config-failed" };
|
|
1595
1612
|
}
|
|
1596
1613
|
const mode = opts.mode ?? (claimed.continuationCount > 0 ? "continue" : "start");
|
|
@@ -1630,19 +1647,54 @@ export async function processAgentTeamRun(opts) {
|
|
|
1630
1647
|
if (leaseLost)
|
|
1631
1648
|
return { ok: true, skipped: "superseded" };
|
|
1632
1649
|
const started = await withCurrentAgentTeamRunAttempt(opts.taskId, claimedAttempts, async () => {
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
:
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1650
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
1651
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1652
|
+
if (!currentTask || currentTask.status !== "running") {
|
|
1653
|
+
return { saved: false, task: currentTask };
|
|
1654
|
+
}
|
|
1655
|
+
if (currentTask.stopRequestedAt !== undefined) {
|
|
1656
|
+
return { saved: false, task: currentTask };
|
|
1657
|
+
}
|
|
1658
|
+
const expectedTask = structuredClone(currentTask);
|
|
1659
|
+
const transcriptRunIds = [
|
|
1660
|
+
...new Set([
|
|
1661
|
+
...(currentTask.transcriptRunIds ?? []),
|
|
1662
|
+
...(task.transcriptRunIds ?? []),
|
|
1663
|
+
]),
|
|
1664
|
+
];
|
|
1665
|
+
if (transcriptRunIds.length > 0) {
|
|
1666
|
+
currentTask.transcriptRunIds = transcriptRunIds;
|
|
1667
|
+
}
|
|
1668
|
+
currentTask.currentStep =
|
|
1669
|
+
mode === "continue"
|
|
1670
|
+
? "Continuing sub-agent"
|
|
1671
|
+
: "Working on response";
|
|
1672
|
+
currentTask.startedAt = currentTask.startedAt ?? Date.now();
|
|
1673
|
+
if (await saveTaskIfCurrent(currentTask, expectedTask)) {
|
|
1674
|
+
Object.assign(task, currentTask);
|
|
1675
|
+
if (ownerEmail) {
|
|
1676
|
+
await updateTaskProgressRun(currentTask, ownerEmail);
|
|
1677
|
+
}
|
|
1678
|
+
return { saved: true, task: currentTask };
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1681
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1682
|
+
return { saved: false, task: currentTask };
|
|
1641
1683
|
});
|
|
1642
1684
|
if (!started.current) {
|
|
1643
1685
|
markLeaseLost();
|
|
1644
1686
|
return { ok: true, skipped: "superseded" };
|
|
1645
1687
|
}
|
|
1688
|
+
if (!started.value?.saved) {
|
|
1689
|
+
const currentTask = started.value?.task;
|
|
1690
|
+
if (currentTask?.stopRequestedAt !== undefined) {
|
|
1691
|
+
return { ok: true, skipped: "stop-requested" };
|
|
1692
|
+
}
|
|
1693
|
+
if (currentTask?.status !== "running") {
|
|
1694
|
+
return { ok: true, skipped: "task-terminal" };
|
|
1695
|
+
}
|
|
1696
|
+
throw new Error("The agent task changed repeatedly before the worker could start.");
|
|
1697
|
+
}
|
|
1646
1698
|
let accumulatedText = "";
|
|
1647
1699
|
let lastProgressSent = 0;
|
|
1648
1700
|
const PROGRESS_INTERVAL_MS = 2000;
|
|
@@ -1651,21 +1703,28 @@ export async function processAgentTeamRun(opts) {
|
|
|
1651
1703
|
let progressWriteChain = Promise.resolve();
|
|
1652
1704
|
let continuationDispatch;
|
|
1653
1705
|
const scheduleProgressWrite = () => {
|
|
1654
|
-
const
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
? { transcriptRunIds: [...task.transcriptRunIds] }
|
|
1658
|
-
: {}),
|
|
1706
|
+
const progress = {
|
|
1707
|
+
preview: task.preview,
|
|
1708
|
+
currentStep: task.currentStep,
|
|
1659
1709
|
};
|
|
1660
1710
|
progressWriteChain = progressWriteChain
|
|
1661
1711
|
.then(async () => {
|
|
1662
1712
|
if (leaseLost)
|
|
1663
1713
|
return;
|
|
1664
1714
|
const result = await withCurrentAgentTeamRunAttempt(opts.taskId, claimedAttempts, async () => {
|
|
1665
|
-
await
|
|
1666
|
-
if (
|
|
1667
|
-
|
|
1715
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1716
|
+
if (!currentTask || currentTask.status !== "running") {
|
|
1717
|
+
return false;
|
|
1668
1718
|
}
|
|
1719
|
+
const expectedTask = structuredClone(currentTask);
|
|
1720
|
+
currentTask.preview = progress.preview;
|
|
1721
|
+
currentTask.currentStep = progress.currentStep;
|
|
1722
|
+
if (!(await saveTaskIfCurrent(currentTask, expectedTask))) {
|
|
1723
|
+
return false;
|
|
1724
|
+
}
|
|
1725
|
+
if (ownerEmail)
|
|
1726
|
+
await updateTaskProgressRun(currentTask, ownerEmail);
|
|
1727
|
+
return true;
|
|
1669
1728
|
});
|
|
1670
1729
|
if (!result.current)
|
|
1671
1730
|
markLeaseLost();
|
|
@@ -1677,6 +1736,25 @@ export async function processAgentTeamRun(opts) {
|
|
|
1677
1736
|
await new Promise((resolve) => {
|
|
1678
1737
|
const startedRun = startRun(runId, task.threadId, async (send, signal, control) => {
|
|
1679
1738
|
workerExecutionFence = currentExecutionFence();
|
|
1739
|
+
const dispatchReady = await withCurrentAgentTeamRunAttempt(opts.taskId, claimedAttempts, async () => {
|
|
1740
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1741
|
+
return {
|
|
1742
|
+
allowed: currentTask?.status === "running" &&
|
|
1743
|
+
currentTask.stopRequestedAt === undefined,
|
|
1744
|
+
stopRequested: currentTask?.stopRequestedAt !== undefined,
|
|
1745
|
+
stopReason: currentTask?.stopRequestedReason,
|
|
1746
|
+
};
|
|
1747
|
+
});
|
|
1748
|
+
if (!dispatchReady.current || !dispatchReady.value.allowed) {
|
|
1749
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1750
|
+
const reason = dispatchReady.current && dispatchReady.value.stopRequested
|
|
1751
|
+
? (dispatchReady.value.stopReason ?? "user")
|
|
1752
|
+
: currentTask && isCancelledAgentTask(currentTask)
|
|
1753
|
+
? (currentTask?.stopRequestedReason ?? "user")
|
|
1754
|
+
: "superseded";
|
|
1755
|
+
markLeaseLost(reason);
|
|
1756
|
+
return;
|
|
1757
|
+
}
|
|
1680
1758
|
const wrappedSend = (event) => {
|
|
1681
1759
|
if (leaseLost)
|
|
1682
1760
|
return Promise.resolve();
|
|
@@ -1730,6 +1808,34 @@ export async function processAgentTeamRun(opts) {
|
|
|
1730
1808
|
actions: messageAwareActions,
|
|
1731
1809
|
send: wrappedSend,
|
|
1732
1810
|
beforeWrite: control.flushEvents,
|
|
1811
|
+
beforeModelDispatch: async (dispatch) => {
|
|
1812
|
+
const current = await withCurrentAgentTeamRunAttempt(opts.taskId, claimedAttempts, async () => {
|
|
1813
|
+
const currentTask = await loadTask(opts.taskId);
|
|
1814
|
+
if (currentTask?.status === "running" &&
|
|
1815
|
+
currentTask.stopRequestedAt === undefined) {
|
|
1816
|
+
return {
|
|
1817
|
+
allowed: true,
|
|
1818
|
+
result: {
|
|
1819
|
+
started: true,
|
|
1820
|
+
value: dispatch(),
|
|
1821
|
+
},
|
|
1822
|
+
};
|
|
1823
|
+
}
|
|
1824
|
+
return { allowed: false, task: currentTask };
|
|
1825
|
+
});
|
|
1826
|
+
if (current.current && current.value.allowed)
|
|
1827
|
+
return current.value.result;
|
|
1828
|
+
const currentTask = current.current
|
|
1829
|
+
? current.value.task
|
|
1830
|
+
: await loadTask(opts.taskId);
|
|
1831
|
+
const reason = currentTask &&
|
|
1832
|
+
(currentTask.stopRequestedAt !== undefined ||
|
|
1833
|
+
isCancelledAgentTask(currentTask))
|
|
1834
|
+
? (currentTask.stopRequestedReason ?? "user")
|
|
1835
|
+
: "superseded";
|
|
1836
|
+
markLeaseLost(reason);
|
|
1837
|
+
return { started: false };
|
|
1838
|
+
},
|
|
1733
1839
|
signal,
|
|
1734
1840
|
finalResponseGuard: createTaskMessageFinalGuard(opts.taskId),
|
|
1735
1841
|
};
|
|
@@ -2146,10 +2252,13 @@ async function controlAgentTeamBackgroundAgentRun(input) {
|
|
|
2146
2252
|
export async function stopAgentTeamBackgroundRun(runId, reason = "user", scope) {
|
|
2147
2253
|
const taskId = await resolveTaskIdFromBackgroundRunId(runId);
|
|
2148
2254
|
const ownerScope = resolveOwnerScope(scope);
|
|
2149
|
-
const markStopped = (currentTask) => {
|
|
2255
|
+
const markStopped = (currentTask, stopReason) => {
|
|
2256
|
+
delete currentTask.stopRequestedAt;
|
|
2257
|
+
delete currentTask.stopRequestedRunId;
|
|
2258
|
+
delete currentTask.stopRequestedReason;
|
|
2150
2259
|
currentTask.status = "errored";
|
|
2151
2260
|
currentTask.summary =
|
|
2152
|
-
|
|
2261
|
+
stopReason === "user" ? "Task stopped." : `Task stopped: ${stopReason}`;
|
|
2153
2262
|
currentTask.error = currentTask.summary;
|
|
2154
2263
|
currentTask.currentStep = "";
|
|
2155
2264
|
currentTask.completedAt = Date.now();
|
|
@@ -2159,7 +2268,6 @@ export async function stopAgentTeamBackgroundRun(runId, reason = "user", scope)
|
|
|
2159
2268
|
currentTask.parentCompletionEnqueued = !currentTask.parentThreadId;
|
|
2160
2269
|
};
|
|
2161
2270
|
let stoppedTask = null;
|
|
2162
|
-
let stoppedDispatch = null;
|
|
2163
2271
|
for (let retry = 0; retry < 3 && !stoppedTask; retry += 1) {
|
|
2164
2272
|
const task = await loadTask(taskId);
|
|
2165
2273
|
if (!task || !taskMatchesOwnerScope(task, ownerScope)) {
|
|
@@ -2175,15 +2283,54 @@ export async function stopAgentTeamBackgroundRun(runId, reason = "user", scope)
|
|
|
2175
2283
|
return { ok: false, error: "Task is not running" };
|
|
2176
2284
|
}
|
|
2177
2285
|
if (dispatch) {
|
|
2286
|
+
const runId = taskRunChunkId(taskId, dispatch.continuationCount, dispatch.attempts);
|
|
2287
|
+
let stopRequestedAt;
|
|
2288
|
+
let stopRequestedRunId;
|
|
2289
|
+
let stopRequestedReason;
|
|
2290
|
+
const current = await withCurrentAgentTeamRunAttempt(taskId, dispatch.attempts, async () => {
|
|
2291
|
+
const currentTask = await loadTask(taskId);
|
|
2292
|
+
if (currentTask &&
|
|
2293
|
+
taskMatchesOwnerScope(currentTask, ownerScope) &&
|
|
2294
|
+
currentTask.status === "running") {
|
|
2295
|
+
const expectedTask = structuredClone(currentTask);
|
|
2296
|
+
currentTask.stopRequestedAt ??= Date.now();
|
|
2297
|
+
stopRequestedAt = currentTask.stopRequestedAt;
|
|
2298
|
+
currentTask.stopRequestedRunId ??= runId;
|
|
2299
|
+
stopRequestedRunId = currentTask.stopRequestedRunId;
|
|
2300
|
+
currentTask.stopRequestedReason ??= reason;
|
|
2301
|
+
stopRequestedReason = currentTask.stopRequestedReason;
|
|
2302
|
+
return saveTaskIfCurrent(currentTask, expectedTask);
|
|
2303
|
+
}
|
|
2304
|
+
return false;
|
|
2305
|
+
}, { statuses: ["queued", "running"] });
|
|
2306
|
+
if (!current.current ||
|
|
2307
|
+
!current.value ||
|
|
2308
|
+
stopRequestedAt === undefined ||
|
|
2309
|
+
stopRequestedRunId === undefined ||
|
|
2310
|
+
stopRequestedReason === undefined)
|
|
2311
|
+
continue;
|
|
2312
|
+
const requestedAt = stopRequestedAt;
|
|
2313
|
+
const requestedRunId = stopRequestedRunId;
|
|
2314
|
+
const requestedReason = stopRequestedReason;
|
|
2315
|
+
// Keep retries pointed at the original run after the queue attempt is reclaimed.
|
|
2316
|
+
await abortRunDurably(requestedRunId, requestedReason, {
|
|
2317
|
+
allowNotStarted: true,
|
|
2318
|
+
});
|
|
2178
2319
|
const result = await withCurrentAgentTeamRunAttempt(taskId, dispatch.attempts, async () => {
|
|
2179
2320
|
const currentTask = await loadTask(taskId);
|
|
2180
2321
|
if (!currentTask ||
|
|
2181
2322
|
!taskMatchesOwnerScope(currentTask, ownerScope) ||
|
|
2182
|
-
currentTask.status !== "running"
|
|
2323
|
+
currentTask.status !== "running" ||
|
|
2324
|
+
currentTask.stopRequestedAt !== requestedAt ||
|
|
2325
|
+
currentTask.stopRequestedRunId !== requestedRunId ||
|
|
2326
|
+
currentTask.stopRequestedReason !== requestedReason) {
|
|
2327
|
+
return null;
|
|
2328
|
+
}
|
|
2329
|
+
const expectedTask = structuredClone(currentTask);
|
|
2330
|
+
markStopped(currentTask, requestedReason);
|
|
2331
|
+
if (!(await saveTaskIfCurrent(currentTask, expectedTask))) {
|
|
2183
2332
|
return null;
|
|
2184
2333
|
}
|
|
2185
|
-
markStopped(currentTask);
|
|
2186
|
-
await saveTask(currentTask);
|
|
2187
2334
|
if (!(await completeAgentTeamRun(taskId, "failed", dispatch.attempts))) {
|
|
2188
2335
|
throw new Error("The agent task run changed before it could stop.");
|
|
2189
2336
|
}
|
|
@@ -2191,22 +2338,37 @@ export async function stopAgentTeamBackgroundRun(runId, reason = "user", scope)
|
|
|
2191
2338
|
}, { statuses: ["queued", "running"] });
|
|
2192
2339
|
if (result.current && result.value) {
|
|
2193
2340
|
stoppedTask = result.value;
|
|
2194
|
-
stoppedDispatch = dispatch;
|
|
2195
2341
|
}
|
|
2196
2342
|
continue;
|
|
2197
2343
|
}
|
|
2198
2344
|
const expectedTask = structuredClone(task);
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2345
|
+
const stopRequestedTask = {
|
|
2346
|
+
...task,
|
|
2347
|
+
stopRequestedAt: task.stopRequestedAt ?? Date.now(),
|
|
2348
|
+
stopRequestedRunId: task.stopRequestedRunId ?? runningInMemoryTaskRunId(taskId),
|
|
2349
|
+
stopRequestedReason: task.stopRequestedReason ?? reason,
|
|
2350
|
+
};
|
|
2351
|
+
if (!(await saveTaskIfCurrent(stopRequestedTask, expectedTask)))
|
|
2352
|
+
continue;
|
|
2353
|
+
await abortRunDurably(stopRequestedTask.stopRequestedRunId, stopRequestedTask.stopRequestedReason, { allowNotStarted: true });
|
|
2354
|
+
const currentTask = await loadTask(taskId);
|
|
2355
|
+
if (!currentTask ||
|
|
2356
|
+
!taskMatchesOwnerScope(currentTask, ownerScope) ||
|
|
2357
|
+
currentTask.status !== "running" ||
|
|
2358
|
+
currentTask.stopRequestedAt !== stopRequestedTask.stopRequestedAt ||
|
|
2359
|
+
currentTask.stopRequestedRunId !== stopRequestedTask.stopRequestedRunId ||
|
|
2360
|
+
currentTask.stopRequestedReason !== stopRequestedTask.stopRequestedReason) {
|
|
2361
|
+
return { ok: false, error: "Task is not running" };
|
|
2362
|
+
}
|
|
2363
|
+
const expectedStopRequestedTask = structuredClone(currentTask);
|
|
2364
|
+
markStopped(currentTask, stopRequestedTask.stopRequestedReason);
|
|
2365
|
+
if (await saveTaskIfCurrent(currentTask, expectedStopRequestedTask)) {
|
|
2366
|
+
stoppedTask = currentTask;
|
|
2202
2367
|
}
|
|
2203
2368
|
}
|
|
2204
2369
|
if (!stoppedTask) {
|
|
2205
2370
|
return { ok: false, error: "Task is not running" };
|
|
2206
2371
|
}
|
|
2207
|
-
abortRun(stoppedDispatch
|
|
2208
|
-
? taskRunChunkId(taskId, stoppedDispatch.continuationCount, stoppedDispatch.attempts)
|
|
2209
|
-
: runningInMemoryTaskRunId(taskId), reason);
|
|
2210
2372
|
const ownerEmail = getRequestUserEmail();
|
|
2211
2373
|
if (ownerEmail) {
|
|
2212
2374
|
await completeTaskProgressRun(stoppedTask, ownerEmail, "cancelled", stoppedTask.summary);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-native/core",
|
|
3
|
-
"version": "0.210.
|
|
3
|
+
"version": "0.210.2",
|
|
4
4
|
"description": "The agentic application framework for building autonomous agents with intuitive UIs",
|
|
5
5
|
"homepage": "https://github.com/BuilderIO/agent-native#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -711,8 +711,8 @@
|
|
|
711
711
|
"yaml": "^2.9.0",
|
|
712
712
|
"yjs": "^13.6.33",
|
|
713
713
|
"zod": "^4.3.6",
|
|
714
|
-
"@agent-native/agentkit": "^0.210.
|
|
715
|
-
"@agent-native/recap-cli": "^0.5.
|
|
714
|
+
"@agent-native/agentkit": "^0.210.2",
|
|
715
|
+
"@agent-native/recap-cli": "^0.5.77"
|
|
716
716
|
},
|
|
717
717
|
"devDependencies": {
|
|
718
718
|
"@ai-sdk/anthropic": "^3.0.71",
|
|
@@ -782,7 +782,7 @@
|
|
|
782
782
|
"xlsx": "^0.18.5"
|
|
783
783
|
},
|
|
784
784
|
"peerDependencies": {
|
|
785
|
-
"@agent-native/core-corpus": "0.
|
|
785
|
+
"@agent-native/core-corpus": ">=0.196.0",
|
|
786
786
|
"@ai-sdk/anthropic": ">=3",
|
|
787
787
|
"@ai-sdk/cohere": ">=3",
|
|
788
788
|
"@ai-sdk/google": ">=3",
|