@fevex/core 0.1.0-alpha.3 → 0.1.0-alpha.5
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/README.md +183 -2
- package/dist/agents/index.d.mts +1 -1
- package/dist/artifacts/index.d.mts +2 -0
- package/dist/artifacts/index.mjs +2 -0
- package/dist/artifacts-gUzemET7.mjs +440 -0
- package/dist/channels/index.d.mts +2 -2
- package/dist/channels/index.mjs +70 -28
- package/dist/evals/index.d.mts +4 -4
- package/dist/{fevex-Ddyi6z6L.d.mts → fevex-B5NxFKcV.d.mts} +41 -11
- package/dist/http/index.d.mts +65 -5
- package/dist/http/index.mjs +236 -16
- package/dist/{index-Bgcxgy66.d.mts → index--_LdSEuF.d.mts} +31 -10
- package/dist/{index-CrOId2px.d.mts → index-BFnWUu7j.d.mts} +1 -1
- package/dist/{index-CTIwrVf9.d.mts → index-BPwkgdo3.d.mts} +1 -1
- package/dist/{index-DviHtsLo.d.mts → index-Br-zPxZH.d.mts} +2 -2
- package/dist/{index-Dx_LotWZ.d.mts → index-CGmHXV31.d.mts} +38 -3
- package/dist/{index-CqOjvtQ9.d.mts → index-CKQCNvJz.d.mts} +4 -2
- package/dist/{index-dkFyTNh4.d.mts → index-Cb3AB98n.d.mts} +2 -2
- package/dist/{index-B4PIkqOU.d.mts → index-D6lnI92z.d.mts} +3 -3
- package/dist/{index-Bg9rr8Qe.d.mts → index-Dsulk-n6.d.mts} +3 -3
- package/dist/{index-DeXUtyd9.d.mts → index-aayvtf0J.d.mts} +2 -2
- package/dist/index.d.mts +13 -13
- package/dist/index.mjs +464 -103
- package/dist/knowledge/index.d.mts +1 -1
- package/dist/model-stream-JQdHDDcj.mjs +131 -0
- package/dist/models/index.d.mts +1 -1
- package/dist/observability/index.d.mts +1 -1
- package/dist/policies/index.d.mts +1 -1
- package/dist/{model-stream-u2xMsEaf.mjs → run-support-CmZ6Xo6H.mjs} +41 -130
- package/dist/runtime/index.d.mts +2 -2
- package/dist/runtime/index.mjs +43 -1
- package/dist/sandbox/index.d.mts +1 -1
- package/dist/sandbox/index.mjs +42 -17
- package/dist/teams/index.d.mts +1 -1
- package/dist/testing/index.d.mts +13 -7
- package/dist/testing/index.mjs +98 -2
- package/dist/tools/index.d.mts +2 -2
- package/dist/types-BDVUoAU6.d.mts +559 -0
- package/dist/workflows/index.d.mts +1 -1
- package/package.json +6 -2
- package/dist/types-CuoRx12Q.d.mts +0 -333
package/dist/index.mjs
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { defineAgent } from "./agents/index.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as CatalogedArtifactStore, c as assertArtifactId, i as FileSystemArtifactStore, n as InMemoryArtifactStore, o as ArtifactError, r as InMemoryArtifactCatalog, s as artifactTenantId, t as S3ArtifactStore } from "./artifacts-gUzemET7.mjs";
|
|
3
|
+
import { n as RunPausedError, t as FevexRunError } from "./run-error-Cr17wPGH.mjs";
|
|
4
|
+
import { ChannelError, deliverChannelRun, handleChannelInput } from "./channels/index.mjs";
|
|
3
5
|
import { InMemoryMemoryStore, createMemoryContextProvider, defineContextProvider, defineSkill } from "./knowledge/index.mjs";
|
|
4
6
|
import { n as teamAsWorkflow, t as defineTeam } from "./teams-Ctz676G4.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { InMemoryRunStore, isDurableRunStore, validateListEventsOptions } from "./runtime/index.mjs";
|
|
7
|
+
import { InMemoryRunStore, isDurableRunStore, isRetainableRunStore, validateListEventsOptions, validatePurgeRunsOptions } from "./runtime/index.mjs";
|
|
7
8
|
import { FEVEX_JSON_SCHEMA_PROFILE_VERSION, IntegrationError, compileFevexJsonSchema, defineConnection, defineTool, toToolSpec, validateFevexJsonSchemaProfile } from "./tools/index.mjs";
|
|
8
|
-
import { a as assertTokenBudget, c as
|
|
9
|
+
import { _ as serializeValue, a as assertTokenBudget, c as eventUsage, d as remainingDeadlineMs, f as remainingOutputTokens, g as serializeJsonValue, h as toErrorMessage, i as assertContinuationBudget, l as isTimeoutError, m as runSignal, n as abortable, o as cancellationReason, p as resumeDeadlineSignal, r as addUsage, s as deadlineAtFromMs, u as minDeadline, v as toJsonValue } from "./run-support-CmZ6Xo6H.mjs";
|
|
10
|
+
import { t as readModelStream } from "./model-stream-JQdHDDcj.mjs";
|
|
9
11
|
import "./models/index.mjs";
|
|
10
12
|
import { definePolicy } from "./policies/index.mjs";
|
|
11
13
|
import { SandboxError, createLocalSandbox, sandboxResultToJson } from "./sandbox/index.mjs";
|
|
@@ -103,6 +105,9 @@ function isRunStore(value) {
|
|
|
103
105
|
function isSandbox(value) {
|
|
104
106
|
return isRecord(value) && typeof value.run === "function";
|
|
105
107
|
}
|
|
108
|
+
function isArtifactStore(value) {
|
|
109
|
+
return (typeof value === "object" && value !== null || typeof value === "function") && typeof value.put === "function" && typeof value.get === "function";
|
|
110
|
+
}
|
|
106
111
|
function isJsonObject(value) {
|
|
107
112
|
return isRecord(value);
|
|
108
113
|
}
|
|
@@ -300,7 +305,21 @@ function createComposition(config) {
|
|
|
300
305
|
assertConfiguration(config.runStore === void 0 || isRunStore(config.runStore), "INVALID_CONFIG", "Fevex config \"runStore\" must implement RunStore");
|
|
301
306
|
assertConfiguration(config.credentialStore === void 0 || typeof config.credentialStore?.resolve === "function", "INVALID_CONFIG", "Fevex config \"credentialStore\" must implement resolve");
|
|
302
307
|
assertConfiguration(config.sandbox === void 0 || isSandbox(config.sandbox), "INVALID_CONFIG", "Fevex config \"sandbox\" must implement Sandbox");
|
|
308
|
+
assertConfiguration(config.artifacts === void 0 || isArtifactStore(config.artifacts), "INVALID_CONFIG", "Fevex config \"artifacts\" must implement ArtifactStore");
|
|
303
309
|
assertConfiguration(config.policies === void 0 || Array.isArray(config.policies), "INVALID_CONFIG", "Fevex config \"policies\" must be an array");
|
|
310
|
+
if (config.admission !== void 0) {
|
|
311
|
+
assertConfiguration(isRecord(config.admission), "INVALID_CONFIG", "Fevex config \"admission\" must be an object");
|
|
312
|
+
for (const name of ["maxActiveRuns", "maxActiveRunsPerTenant"]) {
|
|
313
|
+
const value = config.admission[name];
|
|
314
|
+
assertConfiguration(value === void 0 || typeof value === "number" && Number.isSafeInteger(value) && value > 0, "INVALID_CONFIG", `Fevex config "admission.${name}" must be a positive safe integer`);
|
|
315
|
+
}
|
|
316
|
+
assertConfiguration(config.admission.tenantKey === void 0 || typeof config.admission.tenantKey === "function", "INVALID_CONFIG", "Fevex config \"admission.tenantKey\" must be a function");
|
|
317
|
+
assertConfiguration(config.admission.authorize === void 0 || typeof config.admission.authorize === "function", "INVALID_CONFIG", "Fevex config \"admission.authorize\" must be a function");
|
|
318
|
+
}
|
|
319
|
+
if (config.limits !== void 0) {
|
|
320
|
+
assertConfiguration(isRecord(config.limits), "INVALID_CONFIG", "Fevex config \"limits\" must be an object");
|
|
321
|
+
assertConfiguration(config.limits.maxEventsPerRun === void 0 || typeof config.limits.maxEventsPerRun === "number" && Number.isSafeInteger(config.limits.maxEventsPerRun) && config.limits.maxEventsPerRun > 0, "INVALID_CONFIG", "Fevex config \"limits.maxEventsPerRun\" must be a positive safe integer");
|
|
322
|
+
}
|
|
304
323
|
if (config.observability !== void 0) {
|
|
305
324
|
assertConfiguration(isRecord(config.observability), "INVALID_CONFIG", "Fevex config \"observability\" must be an object");
|
|
306
325
|
assertConfiguration(Array.isArray(config.observability.exporters) && config.observability.exporters.every((exporter) => isRecord(exporter) && typeof exporter.export === "function"), "INVALID_CONFIG", "Fevex config \"observability.exporters\" must contain TraceExporters");
|
|
@@ -594,8 +613,11 @@ function createComposition(config) {
|
|
|
594
613
|
runStore: config.runStore ?? new InMemoryRunStore(),
|
|
595
614
|
credentialStore: config.credentialStore,
|
|
596
615
|
sandbox: config.sandbox,
|
|
616
|
+
artifacts: config.artifacts,
|
|
597
617
|
policies,
|
|
598
618
|
onEvent: config.onEvent,
|
|
619
|
+
admission: config.admission === void 0 ? void 0 : { ...config.admission },
|
|
620
|
+
limits: config.limits === void 0 ? void 0 : { ...config.limits },
|
|
599
621
|
observability: config.observability === void 0 ? void 0 : {
|
|
600
622
|
exporters: [...config.observability.exporters],
|
|
601
623
|
...config.observability.calculateCost ? { calculateCost: config.observability.calculateCost } : {},
|
|
@@ -732,6 +754,7 @@ const toolErrorPayload = (tool, error) => ({
|
|
|
732
754
|
} : {}
|
|
733
755
|
});
|
|
734
756
|
const runErrorPayload = (error) => {
|
|
757
|
+
if (error instanceof FevexRunError) return { errorCode: error.code };
|
|
735
758
|
if (!(error instanceof IntegrationError)) return {};
|
|
736
759
|
return {
|
|
737
760
|
errorCode: error.code,
|
|
@@ -866,12 +889,12 @@ function addWorkflowBudget(first, second) {
|
|
|
866
889
|
* engine — that direction is what keeps the two separable.
|
|
867
890
|
*/
|
|
868
891
|
function createAgentEngine(composition, core) {
|
|
869
|
-
const { models, agents, tools, contextProviders, memoryStore, runStore, credentialStore, sandbox, policies } = composition;
|
|
870
|
-
const { activeRuns, activeSessions, runtimeOwner, resolveModel, resolveCheckpointModel, notifyObserver, createEvent, emitEvent, releaseExecution, commit, startLease, cancelExecution, authorize } = core;
|
|
871
|
-
const
|
|
892
|
+
const { models, agents, tools, contextProviders, memoryStore, runStore, credentialStore, sandbox, artifacts, policies } = composition;
|
|
893
|
+
const { activeRuns, activeSessions, runtimeOwner, admitStart, markInternalRun, resolveModel, resolveCheckpointModel, notifyObserver, createEvent, emitEvent, releaseExecution, commit, startLease, cancelExecution, authorize } = core;
|
|
894
|
+
const prepareExecutionBody = async (name, request, internal = false) => {
|
|
872
895
|
const agent = agents.get(name);
|
|
873
896
|
if (!agent) throw new FevexRunError("AGENT_NOT_FOUND", `Agent "${name}" is not registered`);
|
|
874
|
-
const { modelName } = resolveModel(agent, request.model);
|
|
897
|
+
const { modelName, model } = resolveModel(agent, request.model);
|
|
875
898
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
876
899
|
let session;
|
|
877
900
|
const newSession = request.sessionId === void 0;
|
|
@@ -887,18 +910,23 @@ function createAgentEngine(composition, core) {
|
|
|
887
910
|
session = stored;
|
|
888
911
|
}
|
|
889
912
|
if (activeSessions.has(session.id)) throw new FevexRunError("RUN_CONFLICT", `Session "${session.id}" already has an active run`);
|
|
890
|
-
activeSessions.add(session.id);
|
|
891
913
|
const controller = new AbortController();
|
|
892
|
-
const signal =
|
|
914
|
+
const signal = runSignal(controller, request);
|
|
915
|
+
const deadlineAt = deadlineAtFromMs(request.deadlineMs);
|
|
916
|
+
activeSessions.add(session.id);
|
|
893
917
|
const run = {
|
|
894
918
|
id: crypto.randomUUID(),
|
|
895
919
|
sessionId: session.id,
|
|
896
920
|
agentName: name,
|
|
921
|
+
modelName,
|
|
922
|
+
...model.metadata === void 0 ? {} : { modelMetadata: structuredClone(model.metadata) },
|
|
897
923
|
status: "running",
|
|
898
924
|
revision: 0,
|
|
899
925
|
createdAt: now,
|
|
900
|
-
updatedAt: now
|
|
926
|
+
updatedAt: now,
|
|
927
|
+
...deadlineAt === void 0 ? {} : { deadlineAt }
|
|
901
928
|
};
|
|
929
|
+
if (internal) markInternalRun(run.id);
|
|
902
930
|
const state = {
|
|
903
931
|
run,
|
|
904
932
|
session,
|
|
@@ -979,6 +1007,14 @@ function createAgentEngine(composition, core) {
|
|
|
979
1007
|
activeRuns.set(run.id, state);
|
|
980
1008
|
return state;
|
|
981
1009
|
};
|
|
1010
|
+
const prepareExecution = async (name, request, options = {}) => {
|
|
1011
|
+
const release = options.admit === false ? void 0 : await admitStart("agent", name, request);
|
|
1012
|
+
try {
|
|
1013
|
+
return await prepareExecutionBody(name, request, options.admit === false);
|
|
1014
|
+
} finally {
|
|
1015
|
+
release?.();
|
|
1016
|
+
}
|
|
1017
|
+
};
|
|
982
1018
|
const durableCheckpoint = async (state, model, modelName, messages, inputContent, usage, providerState, step, toolCallCount, seenToolCallIds, pendingTools, pendingIndex) => {
|
|
983
1019
|
const agent = agents.get(state.run.agentName);
|
|
984
1020
|
if (agent.model !== void 0 && typeof agent.model !== "string") throw new FevexRunError("RUN_NOT_RESUMABLE", "Durable continuation requires a named model", state.run.id);
|
|
@@ -1517,6 +1553,20 @@ function createAgentEngine(composition, core) {
|
|
|
1517
1553
|
}
|
|
1518
1554
|
events.push(started);
|
|
1519
1555
|
yield started;
|
|
1556
|
+
const createdArtifacts = [];
|
|
1557
|
+
const toolArtifacts = artifacts === void 0 ? void 0 : scopedArtifacts(artifacts, {
|
|
1558
|
+
runId: state.run.id,
|
|
1559
|
+
sessionId: state.session.id,
|
|
1560
|
+
request,
|
|
1561
|
+
emit: async (descriptor) => {
|
|
1562
|
+
createdArtifacts.push(await emit("artifact.created", {
|
|
1563
|
+
descriptor,
|
|
1564
|
+
toolCallId: pending.call.id,
|
|
1565
|
+
toolName: pending.call.name,
|
|
1566
|
+
...toolSourcePayload(tool)
|
|
1567
|
+
}));
|
|
1568
|
+
}
|
|
1569
|
+
});
|
|
1520
1570
|
try {
|
|
1521
1571
|
const raw = await abortable(() => tool.execute(pending.input, {
|
|
1522
1572
|
runId: state.run.id,
|
|
@@ -1525,9 +1575,11 @@ function createAgentEngine(composition, core) {
|
|
|
1525
1575
|
idempotencyKey: pending.idempotencyKey,
|
|
1526
1576
|
getCredential,
|
|
1527
1577
|
...scopedSandbox === void 0 ? {} : { sandbox: scopedSandbox },
|
|
1578
|
+
...toolArtifacts === void 0 ? {} : { artifacts: toolArtifacts },
|
|
1528
1579
|
context: request.context,
|
|
1529
1580
|
signal: request.signal
|
|
1530
1581
|
}), request.signal);
|
|
1582
|
+
for (const event of createdArtifacts.splice(0)) yield event;
|
|
1531
1583
|
output = toJsonValue(tool.outputSchema === void 0 ? raw : await validateSchema(tool.outputSchema, raw, `Output from tool "${tool.name}" does not match outputSchema`), `Output from tool "${tool.name}" must be JSON-serializable`);
|
|
1532
1584
|
if (containsSecret(output, secrets)) throw new Error(`Output from tool "${tool.name}" contains a credential`);
|
|
1533
1585
|
record = {
|
|
@@ -1555,6 +1607,7 @@ function createAgentEngine(composition, core) {
|
|
|
1555
1607
|
yield completed;
|
|
1556
1608
|
break;
|
|
1557
1609
|
} catch (error) {
|
|
1610
|
+
for (const event of createdArtifacts.splice(0)) yield event;
|
|
1558
1611
|
if (request.signal.aborted) throw error;
|
|
1559
1612
|
const safeError = redact(toErrorMessage(error), secrets);
|
|
1560
1613
|
record = {
|
|
@@ -1662,7 +1715,7 @@ function createAgentEngine(composition, core) {
|
|
|
1662
1715
|
}
|
|
1663
1716
|
}
|
|
1664
1717
|
};
|
|
1665
|
-
const
|
|
1718
|
+
const resumeAgentBody = async (runId, resolution, waitForCompletion = false, recoveryActor) => {
|
|
1666
1719
|
if (resolution?.type === "timer" || resolution?.type === "event") throw new FevexRunError("RUN_NOT_RESUMABLE", `Run "${runId}" cannot be resumed`, runId);
|
|
1667
1720
|
if (!isDurableRunStore(runStore)) throw new FevexRunError("DURABLE_STORE_REQUIRED", "resumeRun requires DurableRunStore", runId);
|
|
1668
1721
|
const run = await runStore.getRun(runId);
|
|
@@ -1670,11 +1723,20 @@ function createAgentEngine(composition, core) {
|
|
|
1670
1723
|
if (!run || !checkpoint) throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" cannot be ${resolution ? "resumed" : "recovered"}`, runId);
|
|
1671
1724
|
if (checkpoint.version !== 2) throw new FevexRunError("CHECKPOINT_UNSUPPORTED", `Checkpoint for run "${runId}" is unsupported`, runId);
|
|
1672
1725
|
if (resolution && run.status !== "paused" && run.status !== "running" || !resolution && run.status !== "running") throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" is not ${resolution ? "resumable" : "recoverable"}`, runId);
|
|
1726
|
+
if (run.deadlineAt !== void 0 && Date.parse(run.deadlineAt) <= Date.now()) {
|
|
1727
|
+
if (!await cancelStoredAgent(runId, "timeout")) throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" deadline has passed`, runId);
|
|
1728
|
+
return await runStore.getRun(runId);
|
|
1729
|
+
}
|
|
1730
|
+
const deadlineSignal = resumeDeadlineSignal(run.deadlineAt, runId, resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE");
|
|
1673
1731
|
const agent = agents.get(run.agentName);
|
|
1674
1732
|
if (!agent) throw new FevexRunError("RUN_DEFINITION_CHANGED", `Agent "${run.agentName}" is unavailable`, runId);
|
|
1675
1733
|
const checkpointModel = await resolveCheckpointModel(run.agentName, agent, checkpoint);
|
|
1676
1734
|
if (!checkpointModel) throw new FevexRunError("RUN_DEFINITION_CHANGED", `Definition for agent "${run.agentName}" changed`, runId);
|
|
1677
1735
|
const { modelName, model } = checkpointModel;
|
|
1736
|
+
if (run.modelName === void 0) {
|
|
1737
|
+
run.modelName = modelName;
|
|
1738
|
+
run.modelMetadata = model.metadata === void 0 ? void 0 : structuredClone(model.metadata);
|
|
1739
|
+
}
|
|
1678
1740
|
if (checkpoint.providerState !== void 0 && !model.stateCodec) throw new FevexRunError("RUN_NOT_RESUMABLE", "ModelGateway no longer provides its stateCodec", runId);
|
|
1679
1741
|
const session = await runStore.getSession(run.sessionId);
|
|
1680
1742
|
if (!session) throw new Error(`Session "${run.sessionId}" does not exist`);
|
|
@@ -1689,6 +1751,7 @@ function createAgentEngine(composition, core) {
|
|
|
1689
1751
|
if (!await runStore.acquireLease(lease)) throw new FevexRunError("RUN_CONFLICT", `Run "${runId}" is leased`, runId);
|
|
1690
1752
|
try {
|
|
1691
1753
|
const controller = new AbortController();
|
|
1754
|
+
const signal = deadlineSignal ? AbortSignal.any([controller.signal, deadlineSignal]) : controller.signal;
|
|
1692
1755
|
const state = {
|
|
1693
1756
|
run,
|
|
1694
1757
|
session,
|
|
@@ -1699,7 +1762,7 @@ function createAgentEngine(composition, core) {
|
|
|
1699
1762
|
sessionId: session.id,
|
|
1700
1763
|
context: checkpoint.context,
|
|
1701
1764
|
limits: checkpoint.limits,
|
|
1702
|
-
signal
|
|
1765
|
+
signal
|
|
1703
1766
|
},
|
|
1704
1767
|
controller,
|
|
1705
1768
|
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
@@ -1868,10 +1931,27 @@ function createAgentEngine(composition, core) {
|
|
|
1868
1931
|
throw error;
|
|
1869
1932
|
}
|
|
1870
1933
|
};
|
|
1871
|
-
const
|
|
1934
|
+
const resumeAgent = async (runId, resolution, waitForCompletion = false, recoveryActor, options = {}) => {
|
|
1935
|
+
let release;
|
|
1936
|
+
if (options.admit !== false) {
|
|
1937
|
+
const run = await runStore.getRun(runId);
|
|
1938
|
+
const checkpoint = isDurableRunStore(runStore) ? await runStore.getCheckpoint(runId) : void 0;
|
|
1939
|
+
if (run && checkpoint && (run.status === "paused" || run.status === "running")) release = await admitStart("agent", run.agentName, {
|
|
1940
|
+
input: "",
|
|
1941
|
+
...checkpoint.context === void 0 ? {} : { context: checkpoint.context }
|
|
1942
|
+
});
|
|
1943
|
+
}
|
|
1944
|
+
try {
|
|
1945
|
+
if (options.internal) markInternalRun(runId);
|
|
1946
|
+
return await resumeAgentBody(runId, resolution, waitForCompletion, recoveryActor);
|
|
1947
|
+
} finally {
|
|
1948
|
+
release?.();
|
|
1949
|
+
}
|
|
1950
|
+
};
|
|
1951
|
+
const cancelStoredAgent = async (runId, reason = "aborted") => {
|
|
1872
1952
|
const active = activeRuns.get(runId);
|
|
1873
1953
|
if (active && !active.request.signal.aborted) {
|
|
1874
|
-
active.controller.abort(new DOMException("Run cancelled", "AbortError"));
|
|
1954
|
+
active.controller.abort(new DOMException(reason === "timeout" ? "Run deadline exceeded" : "Run cancelled", reason === "timeout" ? "TimeoutError" : "AbortError"));
|
|
1875
1955
|
if (!active.advancing) {
|
|
1876
1956
|
await cancelExecution(active);
|
|
1877
1957
|
return true;
|
|
@@ -1914,8 +1994,8 @@ function createAgentEngine(composition, core) {
|
|
|
1914
1994
|
};
|
|
1915
1995
|
run.status = "cancelled";
|
|
1916
1996
|
run.pause = void 0;
|
|
1917
|
-
run.error =
|
|
1918
|
-
const cancelled = createEvent(state, "run.cancelled", { reason
|
|
1997
|
+
run.error = reason;
|
|
1998
|
+
const cancelled = createEvent(state, "run.cancelled", { reason });
|
|
1919
1999
|
await commit(state, {
|
|
1920
2000
|
checkpoint: null,
|
|
1921
2001
|
events: [cancelled]
|
|
@@ -1937,6 +2017,37 @@ function createAgentEngine(composition, core) {
|
|
|
1937
2017
|
cancelStoredAgent
|
|
1938
2018
|
};
|
|
1939
2019
|
}
|
|
2020
|
+
function scopedArtifacts(store, options) {
|
|
2021
|
+
const scopedContext = (value) => {
|
|
2022
|
+
const contextTenant = options.request.context?.attributes?.tenantId;
|
|
2023
|
+
const tenantId = typeof contextTenant === "string" ? contextTenant : value?.tenantId;
|
|
2024
|
+
const actor = options.request.context?.actor;
|
|
2025
|
+
return {
|
|
2026
|
+
...value,
|
|
2027
|
+
runId: options.runId,
|
|
2028
|
+
sessionId: options.sessionId,
|
|
2029
|
+
...tenantId === void 0 ? {} : { tenantId },
|
|
2030
|
+
...actor === void 0 ? {} : { actor },
|
|
2031
|
+
signal: options.request.signal
|
|
2032
|
+
};
|
|
2033
|
+
};
|
|
2034
|
+
return {
|
|
2035
|
+
async put(input, context) {
|
|
2036
|
+
const descriptor = await store.put(input, scopedContext(context));
|
|
2037
|
+
await options.emit(descriptor);
|
|
2038
|
+
return descriptor;
|
|
2039
|
+
},
|
|
2040
|
+
get(artifactId, context) {
|
|
2041
|
+
return store.get(artifactId, scopedContext(context));
|
|
2042
|
+
},
|
|
2043
|
+
...store.head === void 0 ? {} : { head(artifactId, context) {
|
|
2044
|
+
return store.head(artifactId, scopedContext(context));
|
|
2045
|
+
} },
|
|
2046
|
+
...store.delete === void 0 ? {} : { delete(artifactId, context) {
|
|
2047
|
+
return store.delete(artifactId, scopedContext(context));
|
|
2048
|
+
} }
|
|
2049
|
+
};
|
|
2050
|
+
}
|
|
1940
2051
|
//#endregion
|
|
1941
2052
|
//#region src/internal/observability.ts
|
|
1942
2053
|
const TERMINAL_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -2230,14 +2341,103 @@ function buildRunTrace(run, rawEvents, modelRegistryName, model, options) {
|
|
|
2230
2341
|
* the lease table, so a second instance would corrupt event ordering and lease
|
|
2231
2342
|
* ownership without raising an error.
|
|
2232
2343
|
*/
|
|
2233
|
-
function createRunCore({ models, agents, tools, runStore, policies, onEvent, observability }) {
|
|
2344
|
+
function createRunCore({ models, agents, tools, runStore, policies, onEvent, observability, admission, limits }) {
|
|
2234
2345
|
const activeRuns = /* @__PURE__ */ new Map();
|
|
2235
2346
|
const activeWorkflowRuns = /* @__PURE__ */ new Map();
|
|
2236
2347
|
const activeSessions = /* @__PURE__ */ new Set();
|
|
2348
|
+
const internalRuns = /* @__PURE__ */ new Set();
|
|
2349
|
+
const pendingTenantStarts = /* @__PURE__ */ new Map();
|
|
2350
|
+
let pendingStarts = 0;
|
|
2237
2351
|
const pendingExports = /* @__PURE__ */ new Set();
|
|
2238
2352
|
const exportFailures = [];
|
|
2239
2353
|
const exportedRuns = /* @__PURE__ */ new Set();
|
|
2240
2354
|
const runtimeOwner = crypto.randomUUID();
|
|
2355
|
+
const unboundedEvents = /* @__PURE__ */ new Set([
|
|
2356
|
+
"run.started",
|
|
2357
|
+
"run.recovered",
|
|
2358
|
+
"run.paused",
|
|
2359
|
+
"run.resumed",
|
|
2360
|
+
"elicitation.requested",
|
|
2361
|
+
"elicitation.resolved",
|
|
2362
|
+
"approval.requested",
|
|
2363
|
+
"approval.resolved",
|
|
2364
|
+
"tool.execution_unknown",
|
|
2365
|
+
"run.completed",
|
|
2366
|
+
"run.failed",
|
|
2367
|
+
"run.cancelled",
|
|
2368
|
+
"workflow.run.started",
|
|
2369
|
+
"workflow.run.recovered",
|
|
2370
|
+
"workflow.run.paused",
|
|
2371
|
+
"workflow.run.resumed",
|
|
2372
|
+
"workflow.wait.started",
|
|
2373
|
+
"workflow.wait.completed",
|
|
2374
|
+
"workflow.run.completed",
|
|
2375
|
+
"workflow.run.failed",
|
|
2376
|
+
"workflow.run.cancelled",
|
|
2377
|
+
"team.run.started",
|
|
2378
|
+
"team.run.recovered",
|
|
2379
|
+
"team.run.paused",
|
|
2380
|
+
"team.run.resumed",
|
|
2381
|
+
"team.run.completed",
|
|
2382
|
+
"team.run.failed",
|
|
2383
|
+
"team.run.cancelled"
|
|
2384
|
+
]);
|
|
2385
|
+
const tenantOf = (context) => {
|
|
2386
|
+
const configured = admission?.tenantKey?.(context);
|
|
2387
|
+
if (configured !== void 0) return configured;
|
|
2388
|
+
const tenantId = context?.attributes?.tenantId;
|
|
2389
|
+
if (typeof tenantId !== "string") return void 0;
|
|
2390
|
+
return tenantId.trim() || void 0;
|
|
2391
|
+
};
|
|
2392
|
+
const countsForAdmission = (runId, state) => !internalRuns.has(runId) && !state.request.signal?.aborted;
|
|
2393
|
+
const activeTopLevelRuns = () => {
|
|
2394
|
+
let count = 0;
|
|
2395
|
+
for (const [runId, state] of activeRuns) if (countsForAdmission(runId, state)) count += 1;
|
|
2396
|
+
for (const [runId, state] of activeWorkflowRuns) if (countsForAdmission(runId, state)) count += 1;
|
|
2397
|
+
return count;
|
|
2398
|
+
};
|
|
2399
|
+
const activeTenantRuns = (tenant) => {
|
|
2400
|
+
let count = 0;
|
|
2401
|
+
for (const [runId, state] of activeRuns) if (countsForAdmission(runId, state) && tenantOf(state.request.context) === tenant) count += 1;
|
|
2402
|
+
for (const [runId, state] of activeWorkflowRuns) if (countsForAdmission(runId, state) && tenantOf(state.request.context) === tenant) count += 1;
|
|
2403
|
+
return count;
|
|
2404
|
+
};
|
|
2405
|
+
const admitStart = async (kind, name, request) => {
|
|
2406
|
+
if (!admission) return () => {};
|
|
2407
|
+
const running = activeTopLevelRuns() + pendingStarts;
|
|
2408
|
+
const tenant = tenantOf(request.context);
|
|
2409
|
+
const tenantRuns = tenant === void 0 ? 0 : activeTenantRuns(tenant) + (pendingTenantStarts.get(tenant) ?? 0);
|
|
2410
|
+
if (admission.maxActiveRuns !== void 0 && running >= admission.maxActiveRuns) throw new FevexRunError("ADMISSION_DENIED", `Runtime reached maxActiveRuns limit of ${admission.maxActiveRuns}`);
|
|
2411
|
+
if (admission.maxActiveRunsPerTenant !== void 0 && tenant !== void 0 && tenantRuns >= admission.maxActiveRunsPerTenant) throw new FevexRunError("ADMISSION_DENIED", `Tenant "${tenant}" reached maxActiveRunsPerTenant limit of ${admission.maxActiveRunsPerTenant}`);
|
|
2412
|
+
pendingStarts += 1;
|
|
2413
|
+
if (tenant !== void 0) pendingTenantStarts.set(tenant, (pendingTenantStarts.get(tenant) ?? 0) + 1);
|
|
2414
|
+
let released = false;
|
|
2415
|
+
const release = () => {
|
|
2416
|
+
if (released) return;
|
|
2417
|
+
released = true;
|
|
2418
|
+
pendingStarts = Math.max(0, pendingStarts - 1);
|
|
2419
|
+
if (tenant === void 0) return;
|
|
2420
|
+
const next = (pendingTenantStarts.get(tenant) ?? 1) - 1;
|
|
2421
|
+
if (next <= 0) pendingTenantStarts.delete(tenant);
|
|
2422
|
+
else pendingTenantStarts.set(tenant, next);
|
|
2423
|
+
};
|
|
2424
|
+
try {
|
|
2425
|
+
if (admission.authorize && !await admission.authorize({
|
|
2426
|
+
kind,
|
|
2427
|
+
name,
|
|
2428
|
+
request,
|
|
2429
|
+
activeRuns: running,
|
|
2430
|
+
activeTenantRuns: tenantRuns
|
|
2431
|
+
})) throw new FevexRunError("ADMISSION_DENIED", "Run admission was denied by the host");
|
|
2432
|
+
} catch (error) {
|
|
2433
|
+
release();
|
|
2434
|
+
throw error;
|
|
2435
|
+
}
|
|
2436
|
+
return release;
|
|
2437
|
+
};
|
|
2438
|
+
const markInternalRun = (runId) => {
|
|
2439
|
+
internalRuns.add(runId);
|
|
2440
|
+
};
|
|
2241
2441
|
const resolveModel = (agent, requestedModel) => {
|
|
2242
2442
|
const modelName = requestedModel ?? (typeof agent.model === "string" ? agent.model : "default");
|
|
2243
2443
|
if (!modelName.trim()) throw new FevexRunError("MODEL_NOT_FOUND", "Model name cannot be empty");
|
|
@@ -2271,11 +2471,17 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2271
2471
|
if (!run) throw new Error(`Run "${event.runId}" does not exist`);
|
|
2272
2472
|
if (isCoordinatorRun(run)) return;
|
|
2273
2473
|
const agentRun = run;
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2474
|
+
let modelRegistryName = agentRun.modelName;
|
|
2475
|
+
let modelMetadata = agentRun.modelMetadata;
|
|
2476
|
+
if (modelRegistryName === void 0) {
|
|
2477
|
+
const agent = agents.get(agentRun.agentName);
|
|
2478
|
+
if (!agent) throw new Error(`Agent "${agentRun.agentName}" is not registered`);
|
|
2479
|
+
const checkpoint = isDurableRunStore(runStore) ? await runStore.getCheckpoint(agentRun.id) : void 0;
|
|
2480
|
+
const resolved = resolveModel(agent, checkpoint?.modelName);
|
|
2481
|
+
modelRegistryName = resolved.modelName;
|
|
2482
|
+
modelMetadata = resolved.model.metadata;
|
|
2483
|
+
}
|
|
2484
|
+
const trace = buildRunTrace(agentRun, await runStore.listEvents(agentRun.id), modelRegistryName, modelMetadata, observability);
|
|
2279
2485
|
const failures = (await Promise.allSettled(observability.exporters.map((exporter) => Promise.resolve().then(() => exporter.export(trace))))).filter((result) => result.status === "rejected").map(({ reason }) => reason);
|
|
2280
2486
|
if (failures.length) throw new AggregateError(failures, "Trace export failed");
|
|
2281
2487
|
})().catch((error) => {
|
|
@@ -2290,14 +2496,17 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2290
2496
|
Promise.resolve(onEvent(event)).catch(() => {});
|
|
2291
2497
|
} catch {}
|
|
2292
2498
|
};
|
|
2293
|
-
const createEvent = (state, type, payload) =>
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2499
|
+
const createEvent = (state, type, payload) => {
|
|
2500
|
+
if (limits?.maxEventsPerRun !== void 0 && !unboundedEvents.has(type) && state.eventSequence >= limits.maxEventsPerRun) throw new FevexRunError("EVENT_LIMIT_EXCEEDED", `Run exceeded maxEventsPerRun limit of ${limits.maxEventsPerRun}`, state.run.id);
|
|
2501
|
+
return {
|
|
2502
|
+
id: crypto.randomUUID(),
|
|
2503
|
+
sequence: state.eventSequence += 1,
|
|
2504
|
+
type,
|
|
2505
|
+
runId: state.run.id,
|
|
2506
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2507
|
+
...payload === void 0 ? {} : { payload }
|
|
2508
|
+
};
|
|
2509
|
+
};
|
|
2301
2510
|
const createCoordinatorEvent = (state, workflowType, workflowPayload, teamType, teamPayload = workflowPayload) => createEvent(state, isTeamRun(state.run) ? teamType : workflowType, isTeamRun(state.run) ? teamPayload : workflowPayload);
|
|
2302
2511
|
const emitEvent = async (state, type, payload) => {
|
|
2303
2512
|
const event = createEvent(state, type, payload);
|
|
@@ -2311,6 +2520,7 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2311
2520
|
const releaseExecution = async (state) => {
|
|
2312
2521
|
activeRuns.delete(state.run.id);
|
|
2313
2522
|
activeSessions.delete(state.session.id);
|
|
2523
|
+
internalRuns.delete(state.run.id);
|
|
2314
2524
|
if (state.leaseTimer) clearInterval(state.leaseTimer);
|
|
2315
2525
|
if (state.leaseExpiryTimer) clearTimeout(state.leaseExpiryTimer);
|
|
2316
2526
|
state.leaseTimer = void 0;
|
|
@@ -2399,6 +2609,7 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2399
2609
|
const releaseWorkflowExecution = async (state) => {
|
|
2400
2610
|
activeWorkflowRuns.delete(state.run.id);
|
|
2401
2611
|
activeSessions.delete(state.session.id);
|
|
2612
|
+
internalRuns.delete(state.run.id);
|
|
2402
2613
|
if (state.leaseTimer) clearInterval(state.leaseTimer);
|
|
2403
2614
|
if (state.leaseExpiryTimer) clearTimeout(state.leaseExpiryTimer);
|
|
2404
2615
|
state.leaseTimer = void 0;
|
|
@@ -2440,6 +2651,8 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2440
2651
|
pendingExports,
|
|
2441
2652
|
exportFailures,
|
|
2442
2653
|
runtimeOwner,
|
|
2654
|
+
admitStart,
|
|
2655
|
+
markInternalRun,
|
|
2443
2656
|
resolveModel,
|
|
2444
2657
|
resolveCheckpointModel,
|
|
2445
2658
|
notifyObserver,
|
|
@@ -2467,7 +2680,7 @@ function createRunCore({ models, agents, tools, runStore, policies, onEvent, obs
|
|
|
2467
2680
|
*/
|
|
2468
2681
|
function createWorkflowEngine(composition, core, agentEngine) {
|
|
2469
2682
|
const { models, agents, workflows, teams, runStore } = composition;
|
|
2470
|
-
const { activeRuns, activeWorkflowRuns, activeSessions, runtimeOwner, createEvent, createCoordinatorEvent, notifyObserver, commit, startLease, releaseWorkflowExecution, commitWorkflow } = core;
|
|
2683
|
+
const { activeRuns, activeWorkflowRuns, activeSessions, runtimeOwner, admitStart, createEvent, createCoordinatorEvent, notifyObserver, commit, startLease, releaseWorkflowExecution, commitWorkflow } = core;
|
|
2471
2684
|
const { prepareExecution, executeAgent, nextEvent, resumeAgent, cancelStoredAgent } = agentEngine;
|
|
2472
2685
|
const cancelWorkflowExecution = async (state, reason = cancellationReason(state.request.signal)) => {
|
|
2473
2686
|
if (state.leaseLost) {
|
|
@@ -2476,7 +2689,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2476
2689
|
}
|
|
2477
2690
|
if (state.run.status === "completed" || state.run.status === "failed" || state.run.status === "cancelled") return;
|
|
2478
2691
|
const childRunIds = Object.values(state.checkpoint.steps).filter((record) => record.type === "agent" && record.status === "running").map(({ childRunId }) => childRunId);
|
|
2479
|
-
for (const childRunId of childRunIds) if (!await cancelStoredAgent(childRunId)) throw new FevexRunError("RUN_CONFLICT", `Workflow child "${childRunId}" could not be cancelled`, state.run.id);
|
|
2692
|
+
for (const childRunId of childRunIds) if (!await cancelStoredAgent(childRunId, reason === "timeout" ? "timeout" : "aborted")) throw new FevexRunError("RUN_CONFLICT", `Workflow child "${childRunId}" could not be cancelled`, state.run.id);
|
|
2480
2693
|
state.run.status = "cancelled";
|
|
2481
2694
|
state.run.pause = void 0;
|
|
2482
2695
|
state.run.error = reason;
|
|
@@ -2489,7 +2702,76 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2489
2702
|
await releaseWorkflowExecution(state);
|
|
2490
2703
|
return event;
|
|
2491
2704
|
};
|
|
2492
|
-
const
|
|
2705
|
+
const cancelStoredWorkflow = async (runId, reason = "aborted") => {
|
|
2706
|
+
const active = activeWorkflowRuns.get(runId);
|
|
2707
|
+
if (active && !active.request.signal.aborted) {
|
|
2708
|
+
active.controller.abort(new DOMException(reason === "timeout" ? "Run deadline exceeded" : "Run cancelled", reason === "timeout" ? "TimeoutError" : "AbortError"));
|
|
2709
|
+
if (!active.advancing) {
|
|
2710
|
+
await cancelWorkflowExecution(active);
|
|
2711
|
+
return true;
|
|
2712
|
+
}
|
|
2713
|
+
for (let attempt = 0; attempt < 100; attempt += 1) {
|
|
2714
|
+
const current = await runStore.getRun(runId);
|
|
2715
|
+
if (current?.status === "cancelled" || current?.status === "completed" || current?.status === "failed") return true;
|
|
2716
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
2717
|
+
}
|
|
2718
|
+
return false;
|
|
2719
|
+
}
|
|
2720
|
+
if (!isDurableRunStore(runStore)) return false;
|
|
2721
|
+
const run = await runStore.getRun(runId);
|
|
2722
|
+
if (!run) return false;
|
|
2723
|
+
if (run.status === "completed" || run.status === "failed" || run.status === "cancelled") return true;
|
|
2724
|
+
const session = await runStore.getSession(run.sessionId);
|
|
2725
|
+
const checkpoint = await runStore.getCheckpoint(runId);
|
|
2726
|
+
if (!session || !checkpoint) return false;
|
|
2727
|
+
const ownerId = `${runtimeOwner}:${crypto.randomUUID()}`;
|
|
2728
|
+
const lease = {
|
|
2729
|
+
generation: 0,
|
|
2730
|
+
runId,
|
|
2731
|
+
ownerId,
|
|
2732
|
+
expiresAt: new Date(Date.now() + LEASE_MS).toISOString()
|
|
2733
|
+
};
|
|
2734
|
+
if (!await runStore.acquireLease(lease)) return false;
|
|
2735
|
+
try {
|
|
2736
|
+
const childRunIds = Object.values(checkpoint.steps).filter((record) => record.type === "agent" && record.status === "running").map(({ childRunId }) => childRunId);
|
|
2737
|
+
for (const childRunId of childRunIds) if (!await cancelStoredAgent(childRunId, reason)) return false;
|
|
2738
|
+
const state = {
|
|
2739
|
+
run,
|
|
2740
|
+
session,
|
|
2741
|
+
request: {
|
|
2742
|
+
input: checkpoint.input,
|
|
2743
|
+
...checkpoint.model === void 0 ? {} : { model: checkpoint.model },
|
|
2744
|
+
...checkpoint.reasoning === void 0 ? {} : { reasoning: checkpoint.reasoning },
|
|
2745
|
+
sessionId: session.id,
|
|
2746
|
+
context: checkpoint.context,
|
|
2747
|
+
limits: checkpoint.limits,
|
|
2748
|
+
signal: new AbortController().signal
|
|
2749
|
+
},
|
|
2750
|
+
controller: new AbortController(),
|
|
2751
|
+
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
2752
|
+
checkpoint,
|
|
2753
|
+
advancing: false,
|
|
2754
|
+
lease,
|
|
2755
|
+
commitQueue: Promise.resolve()
|
|
2756
|
+
};
|
|
2757
|
+
run.status = "cancelled";
|
|
2758
|
+
run.pause = void 0;
|
|
2759
|
+
run.error = reason;
|
|
2760
|
+
run.usage = checkpoint.budget?.usage;
|
|
2761
|
+
const cancelled = createCoordinatorEvent(state, "workflow.run.cancelled", { reason }, "team.run.cancelled");
|
|
2762
|
+
await commit(state, {
|
|
2763
|
+
checkpoint: null,
|
|
2764
|
+
events: [cancelled]
|
|
2765
|
+
});
|
|
2766
|
+
return true;
|
|
2767
|
+
} catch (error) {
|
|
2768
|
+
if (error instanceof FevexRunError && error.code === "RUN_CONFLICT" && (await runStore.getRun(runId))?.status !== "paused") return false;
|
|
2769
|
+
throw error;
|
|
2770
|
+
} finally {
|
|
2771
|
+
await runStore.releaseLease(runId, ownerId, lease.generation).catch(() => {});
|
|
2772
|
+
}
|
|
2773
|
+
};
|
|
2774
|
+
const prepareWorkflowExecutionBody = async (name, request, kind = "workflow") => {
|
|
2493
2775
|
const workflow = workflows.get(name);
|
|
2494
2776
|
const team = kind === "team" ? teams.get(name) : void 0;
|
|
2495
2777
|
if (!workflow || kind === "team" && !team || kind === "workflow" && teams.has(name)) throw new FevexRunError(kind === "team" ? "TEAM_NOT_FOUND" : "WORKFLOW_NOT_FOUND", `${kind === "team" ? "Team" : "Workflow"} "${name}" is not registered`);
|
|
@@ -2508,9 +2790,9 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2508
2790
|
session = stored;
|
|
2509
2791
|
}
|
|
2510
2792
|
if (activeSessions.has(session.id)) throw new FevexRunError("RUN_CONFLICT", `Session "${session.id}" already has an active run`);
|
|
2511
|
-
activeSessions.add(session.id);
|
|
2512
2793
|
const controller = new AbortController();
|
|
2513
|
-
const signal =
|
|
2794
|
+
const signal = runSignal(controller, request);
|
|
2795
|
+
const deadlineAt = deadlineAtFromMs(request.deadlineMs);
|
|
2514
2796
|
const input = toJsonValue(workflow.inputSchema === void 0 ? request.input : await abortable(() => validateSchema(workflow.inputSchema, request.input, `Input for ${kind} "${name}" does not match inputSchema`), signal), `${kind === "team" ? "Team" : "Workflow"} input must be a string or JSON-serializable value`);
|
|
2515
2797
|
const id = crypto.randomUUID();
|
|
2516
2798
|
const run = kind === "team" ? {
|
|
@@ -2521,7 +2803,8 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2521
2803
|
status: "running",
|
|
2522
2804
|
revision: 0,
|
|
2523
2805
|
createdAt: now,
|
|
2524
|
-
updatedAt: now
|
|
2806
|
+
updatedAt: now,
|
|
2807
|
+
...deadlineAt === void 0 ? {} : { deadlineAt }
|
|
2525
2808
|
} : {
|
|
2526
2809
|
kind: "workflow",
|
|
2527
2810
|
id,
|
|
@@ -2530,7 +2813,8 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2530
2813
|
status: "running",
|
|
2531
2814
|
revision: 0,
|
|
2532
2815
|
createdAt: now,
|
|
2533
|
-
updatedAt: now
|
|
2816
|
+
updatedAt: now,
|
|
2817
|
+
...deadlineAt === void 0 ? {} : { deadlineAt }
|
|
2534
2818
|
};
|
|
2535
2819
|
const checkpoint = kind === "team" ? {
|
|
2536
2820
|
version: 2,
|
|
@@ -2557,6 +2841,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2557
2841
|
steps: {},
|
|
2558
2842
|
limits: combineLimits(workflow.limits, request.limits)
|
|
2559
2843
|
};
|
|
2844
|
+
activeSessions.add(session.id);
|
|
2560
2845
|
const state = {
|
|
2561
2846
|
run,
|
|
2562
2847
|
session,
|
|
@@ -2598,6 +2883,14 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2598
2883
|
activeWorkflowRuns.set(run.id, state);
|
|
2599
2884
|
return state;
|
|
2600
2885
|
};
|
|
2886
|
+
const prepareWorkflowExecution = async (name, request, kind = "workflow") => {
|
|
2887
|
+
const release = await admitStart(kind, name, request);
|
|
2888
|
+
try {
|
|
2889
|
+
return await prepareWorkflowExecutionBody(name, request, kind);
|
|
2890
|
+
} finally {
|
|
2891
|
+
release();
|
|
2892
|
+
}
|
|
2893
|
+
};
|
|
2601
2894
|
async function* executeWorkflow(name, state) {
|
|
2602
2895
|
const workflow = workflows.get(name);
|
|
2603
2896
|
const events = [];
|
|
@@ -2759,7 +3052,10 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2759
3052
|
if (!child) throw new Error(`Child run "${existing.childRunId}" does not exist`);
|
|
2760
3053
|
if (child.status === "running") {
|
|
2761
3054
|
if (!state.recoveryActor) throw new FevexRunError("RUN_NOT_RECOVERABLE", `Child run "${child.id}" is still running`, state.run.id);
|
|
2762
|
-
child = await resumeAgent(child.id, void 0, true, state.recoveryActor
|
|
3055
|
+
child = await resumeAgent(child.id, void 0, true, state.recoveryActor, {
|
|
3056
|
+
admit: false,
|
|
3057
|
+
internal: true
|
|
3058
|
+
});
|
|
2763
3059
|
}
|
|
2764
3060
|
if (child.status === "completed") return completeAgentStep(stepId, existing.agentName, existing.childRunId, toJsonValue(child.output, "Child agent output must be JSON-serializable"), options);
|
|
2765
3061
|
if (child.status === "paused" && child.pause) return pauseForChild(stepId, new RunPausedError(child.id, child.pause));
|
|
@@ -2770,12 +3066,13 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
2770
3066
|
const childSignal = request.signal ? AbortSignal.any([state.request.signal, request.signal]) : state.request.signal;
|
|
2771
3067
|
const childState = await prepareExecution(agentName, {
|
|
2772
3068
|
...request,
|
|
3069
|
+
deadlineMs: minDeadline(remainingDeadlineMs(state.run.deadlineAt, state.run.id), request.deadlineMs),
|
|
2773
3070
|
model: request.model ?? state.request.model,
|
|
2774
3071
|
reasoning: request.reasoning ?? state.request.reasoning,
|
|
2775
3072
|
context: mergeExecutionContext(state.request.context, request.context),
|
|
2776
3073
|
limits: combineLimits(request.limits, remainingWorkflowLimits(state.checkpoint.limits, state.checkpoint.budget)),
|
|
2777
3074
|
signal: childSignal
|
|
2778
|
-
});
|
|
3075
|
+
}, { admit: false });
|
|
2779
3076
|
const action = options?.metadata?.teamAction === "handoff" ? "handoff" : "delegate";
|
|
2780
3077
|
const lifecycleEvents = [];
|
|
2781
3078
|
if (isTeamRun(state.run) && action === "handoff") lifecycleEvents.push(createEvent(state, "team.handoff.created", {
|
|
@@ -3109,8 +3406,10 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3109
3406
|
};
|
|
3110
3407
|
} catch (error) {
|
|
3111
3408
|
let thrown = error;
|
|
3112
|
-
|
|
3113
|
-
|
|
3409
|
+
const parentDeadline = state.run.deadlineAt === void 0 ? void 0 : Date.parse(state.run.deadlineAt);
|
|
3410
|
+
const parentTimedOut = isTimeoutError(error) && parentDeadline !== void 0 && Date.now() >= parentDeadline - 10;
|
|
3411
|
+
if (state.request.signal.aborted || parentTimedOut) try {
|
|
3412
|
+
const event = await cancelWorkflowExecution(state, parentTimedOut ? "timeout" : void 0);
|
|
3114
3413
|
if (event) {
|
|
3115
3414
|
events.push(event);
|
|
3116
3415
|
yield event;
|
|
@@ -3172,13 +3471,18 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3172
3471
|
}
|
|
3173
3472
|
}
|
|
3174
3473
|
};
|
|
3175
|
-
const
|
|
3474
|
+
const resumeWorkflowBody = async (runId, resolution, recoveryActor) => {
|
|
3176
3475
|
if (!isDurableRunStore(runStore)) throw new FevexRunError("DURABLE_STORE_REQUIRED", "resumeRun requires DurableRunStore", runId);
|
|
3177
3476
|
const run = await runStore.getRun(runId);
|
|
3178
3477
|
const checkpoint = await runStore.getCheckpoint(runId);
|
|
3179
3478
|
if (!run || !checkpoint) throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" cannot be ${resolution ? "resumed" : "recovered"}`, runId);
|
|
3180
3479
|
if (checkpoint.version !== 2) throw new FevexRunError("CHECKPOINT_UNSUPPORTED", `Checkpoint for run "${runId}" is unsupported`, runId);
|
|
3181
3480
|
if (resolution && run.status !== "paused" && run.status !== "running" || !resolution && run.status !== "running") throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" is not ${resolution ? "resumable" : "recoverable"}`, runId);
|
|
3481
|
+
if (run.deadlineAt !== void 0 && Date.parse(run.deadlineAt) <= Date.now()) {
|
|
3482
|
+
if (!await cancelStoredWorkflow(runId, "timeout")) throw new FevexRunError(resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE", `Run "${runId}" deadline has passed`, runId);
|
|
3483
|
+
return await runStore.getRun(runId);
|
|
3484
|
+
}
|
|
3485
|
+
const deadlineSignal = resumeDeadlineSignal(run.deadlineAt, runId, resolution ? "RUN_NOT_RESUMABLE" : "RUN_NOT_RECOVERABLE");
|
|
3182
3486
|
const name = coordinatorName(run);
|
|
3183
3487
|
const workflow = workflows.get(name);
|
|
3184
3488
|
const team = isTeamRun(run) ? teams.get(name) : void 0;
|
|
@@ -3201,6 +3505,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3201
3505
|
if (!resolution) {
|
|
3202
3506
|
if (!recoveryActor?.id.trim()) throw new FevexRunError("RUN_NOT_RECOVERABLE", "Recovery actor is required", runId);
|
|
3203
3507
|
const controller = new AbortController();
|
|
3508
|
+
const signal = deadlineSignal ? AbortSignal.any([controller.signal, deadlineSignal]) : controller.signal;
|
|
3204
3509
|
const state = {
|
|
3205
3510
|
run,
|
|
3206
3511
|
session,
|
|
@@ -3211,7 +3516,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3211
3516
|
sessionId: session.id,
|
|
3212
3517
|
context: checkpoint.context,
|
|
3213
3518
|
limits: checkpoint.limits,
|
|
3214
|
-
signal
|
|
3519
|
+
signal
|
|
3215
3520
|
},
|
|
3216
3521
|
controller,
|
|
3217
3522
|
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
@@ -3254,6 +3559,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3254
3559
|
if (validatedPayload !== void 0) eventPayload = toJsonValue(validatedPayload, "Workflow event payload must be JSON-serializable");
|
|
3255
3560
|
}
|
|
3256
3561
|
const controller = new AbortController();
|
|
3562
|
+
const signal = deadlineSignal ? AbortSignal.any([controller.signal, deadlineSignal]) : controller.signal;
|
|
3257
3563
|
const state = {
|
|
3258
3564
|
run,
|
|
3259
3565
|
session,
|
|
@@ -3264,7 +3570,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3264
3570
|
sessionId: session.id,
|
|
3265
3571
|
context: checkpoint.context,
|
|
3266
3572
|
limits: checkpoint.limits,
|
|
3267
|
-
signal
|
|
3573
|
+
signal
|
|
3268
3574
|
},
|
|
3269
3575
|
controller,
|
|
3270
3576
|
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
@@ -3302,8 +3608,93 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3302
3608
|
if (resolution.type === "timer" || resolution.type === "event") throw new FevexRunError("RUN_NOT_RESUMABLE", `Run "${runId}" cannot be resumed`, runId);
|
|
3303
3609
|
const childRunId = workflowPause.type === "workflow_children" ? workflowPause.children.find(({ childPause }) => pauseMatchesResolution(childPause, resolution))?.childRunId : workflowPause.childRunId;
|
|
3304
3610
|
if (!childRunId) throw new FevexRunError("RUN_NOT_RESUMABLE", "Resolution does not match a paused child run", runId);
|
|
3305
|
-
|
|
3611
|
+
let childRun;
|
|
3612
|
+
try {
|
|
3613
|
+
childRun = await resumeAgent(childRunId, resolution, true, void 0, {
|
|
3614
|
+
admit: false,
|
|
3615
|
+
internal: true
|
|
3616
|
+
});
|
|
3617
|
+
} catch (error) {
|
|
3618
|
+
const parentDeadline = run.deadlineAt === void 0 ? void 0 : Date.parse(run.deadlineAt);
|
|
3619
|
+
const child = await runStore.getRun(childRunId);
|
|
3620
|
+
const childDeadline = child?.deadlineAt === void 0 ? void 0 : Date.parse(child.deadlineAt);
|
|
3621
|
+
if (isTimeoutError(error) && parentDeadline !== void 0 && childDeadline !== void 0 && Math.abs(childDeadline - parentDeadline) <= 5) {
|
|
3622
|
+
const pausedChildIds = workflowPause.type === "workflow_children" ? workflowPause.children.map(({ childRunId }) => childRunId) : [workflowPause.childRunId];
|
|
3623
|
+
for (const pausedChildId of pausedChildIds) if (!await cancelStoredAgent(pausedChildId, "timeout")) throw error;
|
|
3624
|
+
const cancelController = new AbortController();
|
|
3625
|
+
const cancelState = {
|
|
3626
|
+
run,
|
|
3627
|
+
session,
|
|
3628
|
+
request: {
|
|
3629
|
+
input: checkpoint.input,
|
|
3630
|
+
...checkpoint.model === void 0 ? {} : { model: checkpoint.model },
|
|
3631
|
+
...checkpoint.reasoning === void 0 ? {} : { reasoning: checkpoint.reasoning },
|
|
3632
|
+
sessionId: session.id,
|
|
3633
|
+
context: checkpoint.context,
|
|
3634
|
+
limits: checkpoint.limits,
|
|
3635
|
+
signal: cancelController.signal
|
|
3636
|
+
},
|
|
3637
|
+
controller: cancelController,
|
|
3638
|
+
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
3639
|
+
checkpoint,
|
|
3640
|
+
advancing: false,
|
|
3641
|
+
lease,
|
|
3642
|
+
commitQueue: Promise.resolve()
|
|
3643
|
+
};
|
|
3644
|
+
run.status = "cancelled";
|
|
3645
|
+
run.pause = void 0;
|
|
3646
|
+
run.error = "timeout";
|
|
3647
|
+
run.usage = checkpoint.budget?.usage;
|
|
3648
|
+
const cancelled = createCoordinatorEvent(cancelState, "workflow.run.cancelled", { reason: "timeout" }, "team.run.cancelled");
|
|
3649
|
+
await commit(cancelState, {
|
|
3650
|
+
checkpoint: null,
|
|
3651
|
+
events: [cancelled]
|
|
3652
|
+
});
|
|
3653
|
+
await runStore.releaseLease(runId, ownerId, lease.generation).catch(() => {});
|
|
3654
|
+
return structuredClone(run);
|
|
3655
|
+
}
|
|
3656
|
+
if (isTimeoutError(error)) {
|
|
3657
|
+
const pausedChildIds = workflowPause.type === "workflow_children" ? workflowPause.children.map(({ childRunId }) => childRunId) : [workflowPause.childRunId];
|
|
3658
|
+
for (const pausedChildId of pausedChildIds) if (!await cancelStoredAgent(pausedChildId, "aborted")) throw error;
|
|
3659
|
+
const failController = new AbortController();
|
|
3660
|
+
const failState = {
|
|
3661
|
+
run,
|
|
3662
|
+
session,
|
|
3663
|
+
request: {
|
|
3664
|
+
input: checkpoint.input,
|
|
3665
|
+
...checkpoint.model === void 0 ? {} : { model: checkpoint.model },
|
|
3666
|
+
...checkpoint.reasoning === void 0 ? {} : { reasoning: checkpoint.reasoning },
|
|
3667
|
+
sessionId: session.id,
|
|
3668
|
+
context: checkpoint.context,
|
|
3669
|
+
limits: checkpoint.limits,
|
|
3670
|
+
signal: failController.signal
|
|
3671
|
+
},
|
|
3672
|
+
controller: failController,
|
|
3673
|
+
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
3674
|
+
checkpoint,
|
|
3675
|
+
advancing: false,
|
|
3676
|
+
lease,
|
|
3677
|
+
commitQueue: Promise.resolve()
|
|
3678
|
+
};
|
|
3679
|
+
run.status = "failed";
|
|
3680
|
+
run.pause = void 0;
|
|
3681
|
+
run.error = toErrorMessage(error);
|
|
3682
|
+
run.usage = checkpoint.budget?.usage;
|
|
3683
|
+
const failed = createCoordinatorEvent(failState, "workflow.run.failed", {
|
|
3684
|
+
error: toErrorMessage(error),
|
|
3685
|
+
...runErrorPayload(error)
|
|
3686
|
+
}, "team.run.failed");
|
|
3687
|
+
await commit(failState, {
|
|
3688
|
+
checkpoint: null,
|
|
3689
|
+
events: [failed]
|
|
3690
|
+
});
|
|
3691
|
+
await runStore.releaseLease(runId, ownerId, lease.generation).catch(() => {});
|
|
3692
|
+
return structuredClone(run);
|
|
3693
|
+
}
|
|
3694
|
+
throw error;
|
|
3695
|
+
}
|
|
3306
3696
|
const controller = new AbortController();
|
|
3697
|
+
const signal = deadlineSignal ? AbortSignal.any([controller.signal, deadlineSignal]) : controller.signal;
|
|
3307
3698
|
const state = {
|
|
3308
3699
|
run,
|
|
3309
3700
|
session,
|
|
@@ -3314,7 +3705,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3314
3705
|
sessionId: session.id,
|
|
3315
3706
|
context: checkpoint.context,
|
|
3316
3707
|
limits: checkpoint.limits,
|
|
3317
|
-
signal
|
|
3708
|
+
signal
|
|
3318
3709
|
},
|
|
3319
3710
|
controller,
|
|
3320
3711
|
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
@@ -3327,7 +3718,7 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3327
3718
|
run.status = "cancelled";
|
|
3328
3719
|
run.pause = void 0;
|
|
3329
3720
|
run.error = childRun.error ?? "aborted";
|
|
3330
|
-
const reason = childRun.error === "approval_rejected" ? "approval_rejected" : "aborted";
|
|
3721
|
+
const reason = childRun.error === "approval_rejected" ? "approval_rejected" : childRun.error === "timeout" ? "timeout" : "aborted";
|
|
3331
3722
|
const cancelled = createCoordinatorEvent(state, "workflow.run.cancelled", { reason }, "team.run.cancelled");
|
|
3332
3723
|
await commit(state, {
|
|
3333
3724
|
checkpoint: null,
|
|
@@ -3353,13 +3744,30 @@ function createWorkflowEngine(composition, core, agentEngine) {
|
|
|
3353
3744
|
throw error;
|
|
3354
3745
|
}
|
|
3355
3746
|
};
|
|
3747
|
+
const resumeWorkflow = async (runId, resolution, recoveryActor, options = {}) => {
|
|
3748
|
+
let release;
|
|
3749
|
+
if (options.admit !== false) {
|
|
3750
|
+
const run = await runStore.getRun(runId);
|
|
3751
|
+
const checkpoint = isDurableRunStore(runStore) ? await runStore.getCheckpoint(runId) : void 0;
|
|
3752
|
+
if (run && checkpoint && (run.status === "paused" || run.status === "running")) release = await admitStart(isTeamRun(run) ? "team" : "workflow", coordinatorName(run), {
|
|
3753
|
+
input: "",
|
|
3754
|
+
...checkpoint.context === void 0 ? {} : { context: checkpoint.context }
|
|
3755
|
+
});
|
|
3756
|
+
}
|
|
3757
|
+
try {
|
|
3758
|
+
return await resumeWorkflowBody(runId, resolution, recoveryActor);
|
|
3759
|
+
} finally {
|
|
3760
|
+
release?.();
|
|
3761
|
+
}
|
|
3762
|
+
};
|
|
3356
3763
|
return {
|
|
3357
3764
|
prepareWorkflowExecution,
|
|
3358
3765
|
executeWorkflow,
|
|
3359
3766
|
nextWorkflowEvent,
|
|
3360
3767
|
drainWorkflowExecution,
|
|
3361
3768
|
resumeWorkflow,
|
|
3362
|
-
cancelWorkflowExecution
|
|
3769
|
+
cancelWorkflowExecution,
|
|
3770
|
+
cancelStoredWorkflow
|
|
3363
3771
|
};
|
|
3364
3772
|
}
|
|
3365
3773
|
//#endregion
|
|
@@ -3370,7 +3778,7 @@ function createRuntime(composition) {
|
|
|
3370
3778
|
const { activeRuns, activeWorkflowRuns, activeSessions, pendingExports, exportFailures, runtimeOwner, createEvent, createCoordinatorEvent, notifyObserver, commit, startLease, cancelExecution, releaseWorkflowExecution, commitWorkflow } = core;
|
|
3371
3779
|
const agentEngine = createAgentEngine(composition, core);
|
|
3372
3780
|
const { prepareExecution, executeAgent, nextEvent, drainExecution, resumeAgent, cancelStoredAgent } = agentEngine;
|
|
3373
|
-
const { prepareWorkflowExecution, executeWorkflow, nextWorkflowEvent, drainWorkflowExecution, resumeWorkflow, cancelWorkflowExecution } = createWorkflowEngine(composition, core, agentEngine);
|
|
3781
|
+
const { prepareWorkflowExecution, executeWorkflow, nextWorkflowEvent, drainWorkflowExecution, resumeWorkflow, cancelWorkflowExecution, cancelStoredWorkflow } = createWorkflowEngine(composition, core, agentEngine);
|
|
3374
3782
|
const resumeRun = async (runId, resolution) => {
|
|
3375
3783
|
const run = await runStore.getRun(runId);
|
|
3376
3784
|
if (run && isCoordinatorRun(run)) return resumeWorkflow(runId, resolution);
|
|
@@ -3487,58 +3895,7 @@ function createRuntime(composition) {
|
|
|
3487
3895
|
}
|
|
3488
3896
|
const run = await runStore.getRun(runId);
|
|
3489
3897
|
if (!run || run.status !== "paused" && run.status !== "running") return false;
|
|
3490
|
-
if (
|
|
3491
|
-
const session = await runStore.getSession(run.sessionId);
|
|
3492
|
-
if (!session) return false;
|
|
3493
|
-
if (isCoordinatorRun(run)) {
|
|
3494
|
-
const checkpoint = await runStore.getCheckpoint(runId);
|
|
3495
|
-
if (!checkpoint) return false;
|
|
3496
|
-
const ownerId = `${runtimeOwner}:${crypto.randomUUID()}`;
|
|
3497
|
-
const lease = {
|
|
3498
|
-
generation: 0,
|
|
3499
|
-
runId,
|
|
3500
|
-
ownerId,
|
|
3501
|
-
expiresAt: new Date(Date.now() + LEASE_MS).toISOString()
|
|
3502
|
-
};
|
|
3503
|
-
if (!await runStore.acquireLease(lease)) return false;
|
|
3504
|
-
try {
|
|
3505
|
-
const childRunIds = Object.values(checkpoint.steps).filter((record) => record.type === "agent" && record.status === "running").map(({ childRunId }) => childRunId);
|
|
3506
|
-
for (const childRunId of childRunIds) if (!await cancelStoredAgent(childRunId)) return false;
|
|
3507
|
-
const state = {
|
|
3508
|
-
run,
|
|
3509
|
-
session,
|
|
3510
|
-
request: {
|
|
3511
|
-
input: checkpoint.input,
|
|
3512
|
-
...checkpoint.reasoning === void 0 ? {} : { reasoning: checkpoint.reasoning },
|
|
3513
|
-
sessionId: session.id,
|
|
3514
|
-
context: checkpoint.context,
|
|
3515
|
-
limits: checkpoint.limits,
|
|
3516
|
-
signal: new AbortController().signal
|
|
3517
|
-
},
|
|
3518
|
-
controller: new AbortController(),
|
|
3519
|
-
eventSequence: (await runStore.listEvents(runId)).at(-1)?.sequence ?? 0,
|
|
3520
|
-
checkpoint,
|
|
3521
|
-
advancing: false,
|
|
3522
|
-
lease,
|
|
3523
|
-
commitQueue: Promise.resolve()
|
|
3524
|
-
};
|
|
3525
|
-
run.status = "cancelled";
|
|
3526
|
-
run.pause = void 0;
|
|
3527
|
-
run.error = "aborted";
|
|
3528
|
-
run.usage = checkpoint.budget?.usage;
|
|
3529
|
-
const cancelled = createCoordinatorEvent(state, "workflow.run.cancelled", { reason: "aborted" }, "team.run.cancelled");
|
|
3530
|
-
await commit(state, {
|
|
3531
|
-
checkpoint: null,
|
|
3532
|
-
events: [cancelled]
|
|
3533
|
-
});
|
|
3534
|
-
return true;
|
|
3535
|
-
} catch (error) {
|
|
3536
|
-
if (error instanceof FevexRunError && error.code === "RUN_CONFLICT" && (await runStore.getRun(runId))?.status !== "paused") return false;
|
|
3537
|
-
throw error;
|
|
3538
|
-
} finally {
|
|
3539
|
-
await runStore.releaseLease(runId, ownerId, lease.generation).catch(() => {});
|
|
3540
|
-
}
|
|
3541
|
-
}
|
|
3898
|
+
if (isCoordinatorRun(run)) return cancelStoredWorkflow(runId);
|
|
3542
3899
|
return cancelStoredAgent(runId);
|
|
3543
3900
|
},
|
|
3544
3901
|
resumeRun(runId, resolution) {
|
|
@@ -3547,6 +3904,10 @@ function createRuntime(composition) {
|
|
|
3547
3904
|
recoverRun(runId, options) {
|
|
3548
3905
|
return recoverRun(runId, options.actor);
|
|
3549
3906
|
},
|
|
3907
|
+
async purgeRuns(options) {
|
|
3908
|
+
if (!isRetainableRunStore(runStore)) throw new FevexRunError("RETENTION_UNSUPPORTED", "The configured run store does not support purgeRuns");
|
|
3909
|
+
return runStore.purgeRuns(options);
|
|
3910
|
+
},
|
|
3550
3911
|
async compactSession(sessionId, summary) {
|
|
3551
3912
|
if (typeof summary !== "string" || !summary.trim()) throw new Error("Session summary must be a non-empty string");
|
|
3552
3913
|
if (activeSessions.has(sessionId)) throw new Error(`Session "${sessionId}" has an active run`);
|
|
@@ -3581,4 +3942,4 @@ function createFevex(config) {
|
|
|
3581
3942
|
return createRuntime(createComposition(config));
|
|
3582
3943
|
}
|
|
3583
3944
|
//#endregion
|
|
3584
|
-
export { ChannelError, FEVEX_JSON_SCHEMA_PROFILE_VERSION, FevexConfigurationError, FevexRunError, InMemoryMemoryStore, InMemoryRunStore, IntegrationError, PROVIDER_REASONING_UNSUPPORTED, PROVIDER_SCHEMA_UNSUPPORTED, RunPausedError, SCHEMA_NOT_TRANSPORTABLE, SandboxError, compileFevexJsonSchema, createFevex, createLocalSandbox, createMemoryContextProvider, defineAgent, defineConnection, defineContextProvider, definePolicy, defineSkill, defineTeam, defineTool, defineWorkflow, handleChannelInput, isDurableRunStore, sandboxResultToJson, toToolSpec, validateFevexJsonSchemaProfile, validateListEventsOptions };
|
|
3945
|
+
export { ArtifactError, CatalogedArtifactStore, ChannelError, FEVEX_JSON_SCHEMA_PROFILE_VERSION, FevexConfigurationError, FevexRunError, FileSystemArtifactStore, InMemoryArtifactCatalog, InMemoryArtifactStore, InMemoryMemoryStore, InMemoryRunStore, IntegrationError, PROVIDER_REASONING_UNSUPPORTED, PROVIDER_SCHEMA_UNSUPPORTED, RunPausedError, S3ArtifactStore, SCHEMA_NOT_TRANSPORTABLE, SandboxError, artifactTenantId, assertArtifactId, compileFevexJsonSchema, createFevex, createLocalSandbox, createMemoryContextProvider, defineAgent, defineConnection, defineContextProvider, definePolicy, defineSkill, defineTeam, defineTool, defineWorkflow, deliverChannelRun, handleChannelInput, isDurableRunStore, isRetainableRunStore, sandboxResultToJson, toToolSpec, validateFevexJsonSchemaProfile, validateListEventsOptions, validatePurgeRunsOptions };
|