@kortyx/agent 0.23.0 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +129 -78
- package/dist/index.js.map +1 -1
- package/package.json +5 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.24.0](https://github.com/kortyx-io/kortyx/compare/agent-v0.23.0...agent-v0.24.0) (2026-09-16)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **runtime:** add PostgreSQL persistence, caching composition, and retention ([#207](https://github.com/kortyx-io/kortyx/issues/207)) ([6c1e7df](https://github.com/kortyx-io/kortyx/commit/6c1e7df22ffe8c792bf52b7dba5ae6ea04c1eb2a))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Dependencies
|
|
12
|
+
|
|
13
|
+
* The following workspace dependencies were updated
|
|
14
|
+
* dependencies
|
|
15
|
+
* @kortyx/runtime bumped to 0.19.0
|
|
16
|
+
* devDependencies
|
|
17
|
+
* @kortyx/hooks bumped to 0.25.3
|
|
18
|
+
|
|
3
19
|
## [0.23.0](https://github.com/kortyx-io/kortyx/compare/agent-v0.22.2...agent-v0.23.0) (2026-09-16)
|
|
4
20
|
|
|
5
21
|
|
package/dist/index.d.ts
CHANGED
|
@@ -254,6 +254,8 @@ type OrchestrationOutcome = {
|
|
|
254
254
|
error?: unknown;
|
|
255
255
|
};
|
|
256
256
|
interface OrchestrateArgs {
|
|
257
|
+
/** Resume owns the lease while restoring its snapshot, then transfers it to execution. */
|
|
258
|
+
executionLeaseRelease?: (() => Promise<void>) | undefined;
|
|
257
259
|
executionSignal?: AbortSignal | undefined;
|
|
258
260
|
onExecution?: ((completion: Promise<void>) => void) | undefined;
|
|
259
261
|
abortSignal?: AbortSignal | undefined;
|
|
@@ -272,7 +274,7 @@ interface OrchestrateArgs {
|
|
|
272
274
|
* Orchestrates runtime execution with mid-stream transitions emitted by
|
|
273
275
|
* runtime events.
|
|
274
276
|
*/
|
|
275
|
-
declare function orchestrateGraphStream({ sessionId, runId, graph, state, config: initialConfig, abortSignal: requestSignal, executionSignal, onExecution, emitOutput, onOutcome, selectWorkflow, knownWorkflowIds, frameworkAdapter, }: OrchestrateArgs): Promise<NodeJS.ReadableStream>;
|
|
277
|
+
declare function orchestrateGraphStream({ sessionId, runId, graph, state, config: initialConfig, abortSignal: requestSignal, executionSignal, onExecution, emitOutput, onOutcome, selectWorkflow, knownWorkflowIds, frameworkAdapter, executionLeaseRelease, }: OrchestrateArgs): Promise<NodeJS.ReadableStream>;
|
|
276
278
|
|
|
277
279
|
interface ResumeMeta {
|
|
278
280
|
token: string;
|
package/dist/index.js
CHANGED
|
@@ -3894,7 +3894,8 @@ async function orchestrateGraphStream({
|
|
|
3894
3894
|
onOutcome,
|
|
3895
3895
|
selectWorkflow,
|
|
3896
3896
|
knownWorkflowIds,
|
|
3897
|
-
frameworkAdapter
|
|
3897
|
+
frameworkAdapter,
|
|
3898
|
+
executionLeaseRelease
|
|
3898
3899
|
}) {
|
|
3899
3900
|
const out = new import_node_stream.PassThrough({ objectMode: true });
|
|
3900
3901
|
const write = (chunk) => {
|
|
@@ -3912,11 +3913,13 @@ async function orchestrateGraphStream({
|
|
|
3912
3913
|
let currentGraph = graph;
|
|
3913
3914
|
let currentState = state;
|
|
3914
3915
|
let finished = false;
|
|
3916
|
+
const leaseAbort = new AbortController();
|
|
3917
|
+
let releaseLease = executionLeaseRelease;
|
|
3915
3918
|
const response = createResponseLifecycle({
|
|
3916
3919
|
enabled: emitOutput,
|
|
3917
3920
|
restored: initialConfig.responseCompleted === true,
|
|
3918
3921
|
requestSignal,
|
|
3919
|
-
executionSignal,
|
|
3922
|
+
executionSignal: executionSignal ? AbortSignal.any([executionSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
3920
3923
|
onClosed: () => {
|
|
3921
3924
|
out.write({ type: "done" });
|
|
3922
3925
|
out.end();
|
|
@@ -4795,10 +4798,18 @@ async function orchestrateGraphStream({
|
|
|
4795
4798
|
if (!traceAdapter?.withSpan) {
|
|
4796
4799
|
emitTraceChunk();
|
|
4797
4800
|
}
|
|
4798
|
-
const
|
|
4801
|
+
const startRun = () => traceAdapter?.withSpan ? traceAdapter.withSpan(runSpanArgs, (runTraceSpan) => {
|
|
4799
4802
|
emitTraceChunk();
|
|
4800
4803
|
return runLoop(runTraceSpan);
|
|
4801
4804
|
}) : runLoop(fallbackRunSpan ?? {});
|
|
4805
|
+
const runPromise = frameworkAdapter?.acquireRunLease && !releaseLease ? frameworkAdapter.acquireRunLease({
|
|
4806
|
+
runId,
|
|
4807
|
+
...sessionId ? { sessionId } : {},
|
|
4808
|
+
onLost: (cause) => leaseAbort.abort(cause)
|
|
4809
|
+
}).then((release) => {
|
|
4810
|
+
releaseLease = release;
|
|
4811
|
+
return startRun();
|
|
4812
|
+
}) : startRun();
|
|
4802
4813
|
const finishCancelled = async () => {
|
|
4803
4814
|
emitTelemetryEvent({
|
|
4804
4815
|
config,
|
|
@@ -4962,7 +4973,12 @@ async function orchestrateGraphStream({
|
|
|
4962
4973
|
write({ type: "done" });
|
|
4963
4974
|
finished = true;
|
|
4964
4975
|
out.end();
|
|
4965
|
-
}).finally(() => {
|
|
4976
|
+
}).finally(async () => {
|
|
4977
|
+
try {
|
|
4978
|
+
await releaseLease?.();
|
|
4979
|
+
} catch (error) {
|
|
4980
|
+
console.error("[execution:releaseLease]", (0, import_errors4.serializeFailure)(error));
|
|
4981
|
+
}
|
|
4966
4982
|
response.dispose();
|
|
4967
4983
|
onOutcome?.({
|
|
4968
4984
|
state: outcomeState,
|
|
@@ -5023,7 +5039,7 @@ async function tryPrepareResumeStream({
|
|
|
5023
5039
|
if (!meta) return null;
|
|
5024
5040
|
const store = frameworkAdapter?.pendingRequests;
|
|
5025
5041
|
if (!store) return null;
|
|
5026
|
-
|
|
5042
|
+
let pending = await store.get(meta.token);
|
|
5027
5043
|
if (!pending || pending.requestId !== meta.requestId) {
|
|
5028
5044
|
throw new ExecutionRequestError(
|
|
5029
5045
|
"INVALID_RESUME",
|
|
@@ -5053,34 +5069,48 @@ async function tryPrepareResumeStream({
|
|
|
5053
5069
|
yield { type: "done" };
|
|
5054
5070
|
})();
|
|
5055
5071
|
}
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
"Interrupt has already been resumed or cancelled."
|
|
5060
|
-
);
|
|
5061
|
-
if (meta.cancel) {
|
|
5062
|
-
await store.delete(pending.token);
|
|
5063
|
-
emitTelemetryEvent({
|
|
5064
|
-
config,
|
|
5065
|
-
type: "interrupt.cancelled",
|
|
5066
|
-
correlation: {
|
|
5067
|
-
runId: pending.runId,
|
|
5068
|
-
sessionId,
|
|
5069
|
-
workflowId: pending.workflow,
|
|
5070
|
-
nodeId: pending.node
|
|
5071
|
-
},
|
|
5072
|
-
payload: {
|
|
5073
|
-
interruptId: pending.requestId,
|
|
5074
|
-
reason: "cancelled_by_client"
|
|
5075
|
-
},
|
|
5076
|
-
flush: true
|
|
5077
|
-
});
|
|
5078
|
-
onOutcome?.({ state: pending.state, cancelled: true });
|
|
5079
|
-
return (async function* () {
|
|
5080
|
-
yield { type: "done" };
|
|
5081
|
-
})();
|
|
5082
|
-
}
|
|
5072
|
+
const leaseAbort = new AbortController();
|
|
5073
|
+
let releaseLease;
|
|
5074
|
+
let consumed = false;
|
|
5083
5075
|
try {
|
|
5076
|
+
releaseLease = await frameworkAdapter?.acquireRunLease?.({
|
|
5077
|
+
runId: pending.runId,
|
|
5078
|
+
sessionId,
|
|
5079
|
+
onLost: (cause) => leaseAbort.abort(cause)
|
|
5080
|
+
});
|
|
5081
|
+
leaseAbort.signal.throwIfAborted();
|
|
5082
|
+
if (store.take) {
|
|
5083
|
+
const taken = await store.take(meta.token);
|
|
5084
|
+
if (!taken)
|
|
5085
|
+
throw new ExecutionRequestError(
|
|
5086
|
+
"INVALID_RESUME",
|
|
5087
|
+
"Interrupt has already been resumed or cancelled."
|
|
5088
|
+
);
|
|
5089
|
+
pending = taken;
|
|
5090
|
+
}
|
|
5091
|
+
consumed = true;
|
|
5092
|
+
if (meta.cancel) {
|
|
5093
|
+
await store.delete(pending.token);
|
|
5094
|
+
emitTelemetryEvent({
|
|
5095
|
+
config,
|
|
5096
|
+
type: "interrupt.cancelled",
|
|
5097
|
+
correlation: {
|
|
5098
|
+
runId: pending.runId,
|
|
5099
|
+
sessionId,
|
|
5100
|
+
workflowId: pending.workflow,
|
|
5101
|
+
nodeId: pending.node
|
|
5102
|
+
},
|
|
5103
|
+
payload: {
|
|
5104
|
+
interruptId: pending.requestId,
|
|
5105
|
+
reason: "cancelled_by_client"
|
|
5106
|
+
},
|
|
5107
|
+
flush: true
|
|
5108
|
+
});
|
|
5109
|
+
onOutcome?.({ state: pending.state, cancelled: true });
|
|
5110
|
+
return (async function* () {
|
|
5111
|
+
yield { type: "done" };
|
|
5112
|
+
})();
|
|
5113
|
+
}
|
|
5084
5114
|
const resumeData = isLimitPause ? {} : applyResumeSelection ? applyResumeSelection({ pending, selected: meta.selected }) : meta.selected?.length ? { coordinates: String(meta.selected[0]) } : {};
|
|
5085
5115
|
const resumeDataPatch = isRecord4(resumeData) ? resumeData : {};
|
|
5086
5116
|
const pendingMeta = isRecord4(pending.schema?.meta) ? pending.schema.meta : {};
|
|
@@ -5135,6 +5165,7 @@ async function tryPrepareResumeStream({
|
|
|
5135
5165
|
...resumeStatePatch
|
|
5136
5166
|
};
|
|
5137
5167
|
}
|
|
5168
|
+
leaseAbort.signal.throwIfAborted();
|
|
5138
5169
|
if (pending.graphSnapshot && frameworkAdapter)
|
|
5139
5170
|
await (0, import_runtime2.restoreGraphSnapshot)(
|
|
5140
5171
|
frameworkAdapter.checkpointer,
|
|
@@ -5184,9 +5215,11 @@ async function tryPrepareResumeStream({
|
|
|
5184
5215
|
},
|
|
5185
5216
|
flush: true
|
|
5186
5217
|
});
|
|
5218
|
+
const continuedSignal = pending.responseCompleted && emitOutput === false ? abortSignal : executionSignal;
|
|
5187
5219
|
const args = {
|
|
5188
5220
|
abortSignal,
|
|
5189
|
-
executionSignal:
|
|
5221
|
+
executionSignal: continuedSignal ? AbortSignal.any([continuedSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
5222
|
+
executionLeaseRelease: releaseLease,
|
|
5190
5223
|
onExecution,
|
|
5191
5224
|
emitOutput,
|
|
5192
5225
|
onOutcome,
|
|
@@ -5207,11 +5240,15 @@ async function tryPrepareResumeStream({
|
|
|
5207
5240
|
knownWorkflowIds,
|
|
5208
5241
|
frameworkAdapter
|
|
5209
5242
|
};
|
|
5243
|
+
leaseAbort.signal.throwIfAborted();
|
|
5210
5244
|
const stream = await orchestrateGraphStream(args);
|
|
5245
|
+
releaseLease = void 0;
|
|
5211
5246
|
return stream;
|
|
5212
5247
|
} catch (error) {
|
|
5213
|
-
await store.save(pending);
|
|
5248
|
+
if (consumed && !leaseAbort.signal.aborted) await store.save(pending);
|
|
5214
5249
|
throw error;
|
|
5250
|
+
} finally {
|
|
5251
|
+
await releaseLease?.();
|
|
5215
5252
|
}
|
|
5216
5253
|
}
|
|
5217
5254
|
|
|
@@ -5907,30 +5944,38 @@ function createAgent(args) {
|
|
|
5907
5944
|
const getCheckpoint = (id) => resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
5908
5945
|
const rollbackTo = async (id) => {
|
|
5909
5946
|
const target = await resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
5910
|
-
const
|
|
5911
|
-
const
|
|
5912
|
-
|
|
5913
|
-
|
|
5914
|
-
|
|
5915
|
-
|
|
5916
|
-
|
|
5917
|
-
activePendingRequests,
|
|
5918
|
-
telemetry,
|
|
5919
|
-
target?.runId ?? "unknown"
|
|
5920
|
-
);
|
|
5921
|
-
await Promise.all(
|
|
5922
|
-
activePendingRequests.map(
|
|
5923
|
-
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
5924
|
-
)
|
|
5947
|
+
const sourceRunId = target?.runId ?? "unknown";
|
|
5948
|
+
const managed = resolvedFrameworkAdapter.sessionCheckpoints.managesPendingRequests;
|
|
5949
|
+
const result = await resolvedFrameworkAdapter.sessionCheckpoints.rollbackTo(
|
|
5950
|
+
id,
|
|
5951
|
+
managed ? {
|
|
5952
|
+
preparePendingRequests: (requests) => restoreWorkflowCallBranch(requests, telemetry, sourceRunId)
|
|
5953
|
+
} : void 0
|
|
5925
5954
|
);
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5955
|
+
let activePendingRequests;
|
|
5956
|
+
if (managed) {
|
|
5957
|
+
activePendingRequests = result.activePendingRequests;
|
|
5958
|
+
} else {
|
|
5959
|
+
activePendingRequests = await Promise.all(
|
|
5960
|
+
result.activePendingRequests.map(
|
|
5961
|
+
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
5962
|
+
)
|
|
5963
|
+
);
|
|
5964
|
+
restoreWorkflowCallBranch(activePendingRequests, telemetry, sourceRunId);
|
|
5965
|
+
await Promise.all(
|
|
5966
|
+
activePendingRequests.map(
|
|
5967
|
+
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
5968
|
+
)
|
|
5969
|
+
);
|
|
5970
|
+
await Promise.all([
|
|
5971
|
+
...result.invalidatedInterruptTokens.map(
|
|
5972
|
+
(token) => resolvedFrameworkAdapter.pendingRequests.delete(token)
|
|
5973
|
+
),
|
|
5974
|
+
...activePendingRequests.map(
|
|
5975
|
+
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
5976
|
+
)
|
|
5977
|
+
]);
|
|
5978
|
+
}
|
|
5934
5979
|
if (target) {
|
|
5935
5980
|
emitTelemetryEvent({
|
|
5936
5981
|
config: { ...telemetry ? { telemetry } : {} },
|
|
@@ -5950,30 +5995,36 @@ function createAgent(args) {
|
|
|
5950
5995
|
};
|
|
5951
5996
|
const fork = async (id, options) => {
|
|
5952
5997
|
const source = await resolvedFrameworkAdapter.sessionCheckpoints.get(id);
|
|
5998
|
+
const sourceRunId = source?.runId ?? "unknown";
|
|
5999
|
+
const managed = resolvedFrameworkAdapter.sessionCheckpoints.managesPendingRequests;
|
|
5953
6000
|
const result = await resolvedFrameworkAdapter.sessionCheckpoints.fork(
|
|
5954
6001
|
id,
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
5960
|
-
)
|
|
5961
|
-
);
|
|
5962
|
-
restoreWorkflowCallBranch(
|
|
5963
|
-
activePendingRequests,
|
|
5964
|
-
telemetry,
|
|
5965
|
-
source?.runId ?? "unknown"
|
|
5966
|
-
);
|
|
5967
|
-
await Promise.all(
|
|
5968
|
-
activePendingRequests.map(
|
|
5969
|
-
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
5970
|
-
)
|
|
5971
|
-
);
|
|
5972
|
-
await Promise.all(
|
|
5973
|
-
activePendingRequests.map(
|
|
5974
|
-
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
5975
|
-
)
|
|
6002
|
+
managed ? {
|
|
6003
|
+
...options,
|
|
6004
|
+
preparePendingRequests: (requests) => restoreWorkflowCallBranch(requests, telemetry, sourceRunId)
|
|
6005
|
+
} : options
|
|
5976
6006
|
);
|
|
6007
|
+
let activePendingRequests;
|
|
6008
|
+
if (managed) {
|
|
6009
|
+
activePendingRequests = result.checkpoint.activePendingRequests;
|
|
6010
|
+
} else {
|
|
6011
|
+
activePendingRequests = await Promise.all(
|
|
6012
|
+
result.checkpoint.activePendingRequests.map(
|
|
6013
|
+
(request) => hydratePendingGraphCheckpoint(resolvedFrameworkAdapter, request)
|
|
6014
|
+
)
|
|
6015
|
+
);
|
|
6016
|
+
restoreWorkflowCallBranch(activePendingRequests, telemetry, sourceRunId);
|
|
6017
|
+
await Promise.all(
|
|
6018
|
+
activePendingRequests.map(
|
|
6019
|
+
(request) => clearPendingGraphWrites(resolvedFrameworkAdapter, request)
|
|
6020
|
+
)
|
|
6021
|
+
);
|
|
6022
|
+
await Promise.all(
|
|
6023
|
+
activePendingRequests.map(
|
|
6024
|
+
(request) => resolvedFrameworkAdapter.pendingRequests.save(request)
|
|
6025
|
+
)
|
|
6026
|
+
);
|
|
6027
|
+
}
|
|
5977
6028
|
emitTelemetryEvent({
|
|
5978
6029
|
config: { ...telemetry ? { telemetry } : {} },
|
|
5979
6030
|
type: "session.forked",
|