@kortyx/agent 0.26.1 → 0.27.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 +31 -0
- package/dist/{browser-wjeg_MwV.d.ts → browser-EVWVR9BO.d.ts} +1 -0
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +1 -0
- package/dist/browser.js.map +1 -1
- package/dist/index.d.ts +87 -17
- package/dist/index.js +437 -208
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.js
CHANGED
|
@@ -61,7 +61,7 @@ var require_internal = __commonJS({
|
|
|
61
61
|
withSafeTraceSpan: () => withSafeTraceSpan2
|
|
62
62
|
});
|
|
63
63
|
module2.exports = __toCommonJS2(internal_exports);
|
|
64
|
-
var
|
|
64
|
+
var import_errors8 = require("@kortyx/core/errors");
|
|
65
65
|
var MAX_STACK_LENGTH = 32768;
|
|
66
66
|
var MAX_CAUSE_DEPTH = 4;
|
|
67
67
|
var projectDetails = (value, depth, seen) => {
|
|
@@ -71,16 +71,16 @@ var require_internal = __commonJS({
|
|
|
71
71
|
return { type: "Error", message: "Circular error cause." };
|
|
72
72
|
seen.add(objectValue);
|
|
73
73
|
}
|
|
74
|
-
const name = (0,
|
|
75
|
-
const message = (0,
|
|
76
|
-
const stack = (0,
|
|
74
|
+
const name = (0, import_errors8.errorProperty)(value, "name") ?? (value instanceof Error ? value.name : void 0);
|
|
75
|
+
const message = (0, import_errors8.errorProperty)(value, "message");
|
|
76
|
+
const stack = (0, import_errors8.errorProperty)(value, "stack") ?? (value instanceof Error ? (() => {
|
|
77
77
|
try {
|
|
78
78
|
return value.stack;
|
|
79
79
|
} catch {
|
|
80
80
|
return void 0;
|
|
81
81
|
}
|
|
82
82
|
})() : void 0);
|
|
83
|
-
const cause = depth < MAX_CAUSE_DEPTH ? (0,
|
|
83
|
+
const cause = depth < MAX_CAUSE_DEPTH ? (0, import_errors8.errorProperty)(value, "cause") : null;
|
|
84
84
|
return {
|
|
85
85
|
type: typeof name === "string" ? name.slice(0, 256) : "Error",
|
|
86
86
|
message: (typeof value === "string" ? value : typeof message === "string" ? message : "Execution reported a fault.").slice(0, 8192),
|
|
@@ -789,14 +789,14 @@ var require_dist = __commonJS({
|
|
|
789
789
|
workflowState: args.workflowState
|
|
790
790
|
}
|
|
791
791
|
});
|
|
792
|
-
var
|
|
792
|
+
var import_errors8 = require("@kortyx/core/errors");
|
|
793
793
|
var parseWithSchema = (schema, value, label) => {
|
|
794
794
|
if (!schema) return value;
|
|
795
795
|
const parsed = schema.safeParse(value);
|
|
796
796
|
if (parsed.success) return parsed.data;
|
|
797
797
|
const parsedError = "error" in parsed && parsed.error ? parsed.error : void 0;
|
|
798
798
|
const reason = typeof parsedError?.message === "string" && parsedError.message.length > 0 ? parsedError.message : "invalid payload";
|
|
799
|
-
throw new
|
|
799
|
+
throw new import_errors8.ValidationError(
|
|
800
800
|
label === "useReason output" ? "MODEL_OUTPUT_SCHEMA" : "SCHEMA_VALIDATION",
|
|
801
801
|
`${label} validation failed: ${reason}`,
|
|
802
802
|
parsedError
|
|
@@ -3532,6 +3532,7 @@ ${tryStringify2(args.response)}`
|
|
|
3532
3532
|
}
|
|
3533
3533
|
};
|
|
3534
3534
|
var shouldStreamReasonStructured = (args) => (args.emit ?? true) && shouldStreamStructured(args.structured);
|
|
3535
|
+
var usesNativeOutput = (schema) => schema?.["~kortyx"]?.nativeOutput === true;
|
|
3535
3536
|
var resolveEffectiveReasoningIncludeThoughts = (args) => args.reasoning?.includeThoughts ?? args.model.options?.reasoning?.includeThoughts ?? false;
|
|
3536
3537
|
var resolveEffectiveResponseFormatType = (args) => args.responseFormat?.type ?? args.model.options?.responseFormat?.type;
|
|
3537
3538
|
var assertReasoningThoughtsCompatibility = (args) => {
|
|
@@ -3677,7 +3678,7 @@ ${tryStringify2(args.response)}`
|
|
|
3677
3678
|
requestSchema: args.interrupt.requestSchema,
|
|
3678
3679
|
mode: args.interrupt.mode ?? "required",
|
|
3679
3680
|
...args.outputSchema ? { outputSchema: args.outputSchema } : {}
|
|
3680
|
-
}) : args.outputSchema ? withOutputGuardrails(
|
|
3681
|
+
}) : args.outputSchema ? usesNativeOutput(args.outputSchema) ? void 0 : withOutputGuardrails(
|
|
3681
3682
|
withStructuredStreamHints(args.input, {
|
|
3682
3683
|
...setFieldPaths.length > 0 ? { setFieldPaths } : {},
|
|
3683
3684
|
...appendFieldPaths.length > 0 ? { appendFieldPaths } : {},
|
|
@@ -3949,7 +3950,7 @@ ${tryStringify2(args.response)}`
|
|
|
3949
3950
|
return [getValue(), setValue];
|
|
3950
3951
|
}
|
|
3951
3952
|
var import_core7 = require("@kortyx/core");
|
|
3952
|
-
var
|
|
3953
|
+
var import_errors72 = require("@kortyx/core/errors");
|
|
3953
3954
|
var ParallelChildWaiting = class extends Error {
|
|
3954
3955
|
name = "ParallelChildWaiting";
|
|
3955
3956
|
};
|
|
@@ -3963,14 +3964,14 @@ ${tryStringify2(args.response)}`
|
|
|
3963
3964
|
);
|
|
3964
3965
|
this.results = results;
|
|
3965
3966
|
this.name = "ParallelError";
|
|
3966
|
-
this.failure = (0,
|
|
3967
|
+
this.failure = (0, import_errors72.serializeFailure)({
|
|
3967
3968
|
version: 1,
|
|
3968
3969
|
code: this.code,
|
|
3969
3970
|
category: "workflow",
|
|
3970
3971
|
message: this.message,
|
|
3971
3972
|
retryable: null,
|
|
3972
3973
|
results: results.map(
|
|
3973
|
-
(result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0,
|
|
3974
|
+
(result) => result.status === "fulfilled" ? { status: "fulfilled" } : { status: "rejected", failure: (0, import_errors72.serializeFailure)(result.reason) }
|
|
3974
3975
|
)
|
|
3975
3976
|
});
|
|
3976
3977
|
}
|
|
@@ -3978,7 +3979,7 @@ ${tryStringify2(args.response)}`
|
|
|
3978
3979
|
code = "PARALLEL_FAILED";
|
|
3979
3980
|
failure;
|
|
3980
3981
|
toJSON() {
|
|
3981
|
-
return (0,
|
|
3982
|
+
return (0, import_errors72.serializeFailure)(this);
|
|
3982
3983
|
}
|
|
3983
3984
|
};
|
|
3984
3985
|
function registerWorkflowTask(id) {
|
|
@@ -4123,11 +4124,11 @@ ${tryStringify2(args.response)}`
|
|
|
4123
4124
|
}
|
|
4124
4125
|
var import_node_crypto6 = require("crypto");
|
|
4125
4126
|
var import_core8 = require("@kortyx/core");
|
|
4126
|
-
var
|
|
4127
|
-
var WorkflowCallError = class extends
|
|
4127
|
+
var import_errors82 = require("@kortyx/core/errors");
|
|
4128
|
+
var WorkflowCallError = class extends import_errors82.KortyxError {
|
|
4128
4129
|
constructor(workflow, message, cause, failure) {
|
|
4129
|
-
const detail = (0,
|
|
4130
|
-
failure ?? cause ?? new
|
|
4130
|
+
const detail = (0, import_errors82.serializeFailure)(
|
|
4131
|
+
failure ?? cause ?? new import_errors82.WorkflowContractError(message)
|
|
4131
4132
|
);
|
|
4132
4133
|
super(detail.code, `Workflow '${workflow}': ${message}`, {
|
|
4133
4134
|
...detail,
|
|
@@ -4148,12 +4149,12 @@ ${tryStringify2(args.response)}`
|
|
|
4148
4149
|
if (v === null || typeof v === "string" || typeof v === "boolean") return v;
|
|
4149
4150
|
if (typeof v === "number" && Number.isFinite(v)) return v;
|
|
4150
4151
|
if (typeof v !== "object" || !v || seen.has(v)) {
|
|
4151
|
-
throw new
|
|
4152
|
+
throw new import_errors82.WorkflowContractError(
|
|
4152
4153
|
"Workflow input and output must be JSON serializable."
|
|
4153
4154
|
);
|
|
4154
4155
|
}
|
|
4155
4156
|
if (!Array.isArray(v) && Object.getPrototypeOf(v) !== Object.prototype) {
|
|
4156
|
-
throw new
|
|
4157
|
+
throw new import_errors82.WorkflowContractError(
|
|
4157
4158
|
"Workflow input and output must contain plain JSON objects."
|
|
4158
4159
|
);
|
|
4159
4160
|
}
|
|
@@ -4174,7 +4175,7 @@ ${tryStringify2(args.response)}`
|
|
|
4174
4175
|
useWorkflow: (args) => {
|
|
4175
4176
|
const workflow = workflows[args.workflow];
|
|
4176
4177
|
if (!workflow || workflow.id !== args.workflow)
|
|
4177
|
-
throw new
|
|
4178
|
+
throw new import_errors82.WorkflowContractError(
|
|
4178
4179
|
"Workflow registry keys must match definition ids."
|
|
4179
4180
|
);
|
|
4180
4181
|
return useWorkflow({ ...args, workflow });
|
|
@@ -4200,23 +4201,23 @@ ${tryStringify2(args.response)}`
|
|
|
4200
4201
|
(0, import_core8.throwIfExecutionAborted)(ctx.node.abortSignal);
|
|
4201
4202
|
const service = ctx.node.callWorkflow;
|
|
4202
4203
|
if (!service)
|
|
4203
|
-
throw new
|
|
4204
|
+
throw new import_errors82.WorkflowContractError(
|
|
4204
4205
|
"useWorkflow requires an agent workflow registry."
|
|
4205
4206
|
);
|
|
4206
4207
|
if (!args.id.trim())
|
|
4207
|
-
throw new
|
|
4208
|
+
throw new import_errors82.WorkflowContractError(
|
|
4208
4209
|
"useWorkflow requires a stable, nonempty id."
|
|
4209
4210
|
);
|
|
4210
4211
|
if (ctx.workflowCallActive && !task.group)
|
|
4211
|
-
throw new
|
|
4212
|
+
throw new import_errors82.WorkflowContractError(
|
|
4212
4213
|
"Concurrent workflow calls require parallel([...]); otherwise await each call."
|
|
4213
4214
|
);
|
|
4214
4215
|
if (ctx.workflowCallIds.has(args.id))
|
|
4215
|
-
throw new
|
|
4216
|
+
throw new import_errors82.WorkflowContractError(
|
|
4216
4217
|
`Duplicate workflow call id '${args.id}' in one node activation.`
|
|
4217
4218
|
);
|
|
4218
4219
|
if (ctx.workflowCallIds.size >= 64)
|
|
4219
|
-
throw new
|
|
4220
|
+
throw new import_errors82.WorkflowContractError(
|
|
4220
4221
|
"A node may call at most 64 child workflows per activation."
|
|
4221
4222
|
);
|
|
4222
4223
|
ctx.workflowCallIds.add(args.id);
|
|
@@ -4297,7 +4298,7 @@ ${tryStringify2(args.response)}`
|
|
|
4297
4298
|
workflow,
|
|
4298
4299
|
record.error ?? "child failed",
|
|
4299
4300
|
void 0,
|
|
4300
|
-
record.failure ?? (0,
|
|
4301
|
+
record.failure ?? (0, import_errors82.serializeFailure)(void 0)
|
|
4301
4302
|
);
|
|
4302
4303
|
if (task.group && record.status === "interrupted" && record.interrupts.at(-1)?.response === void 0)
|
|
4303
4304
|
throw new ParallelChildWaiting();
|
|
@@ -4333,7 +4334,7 @@ ${tryStringify2(args.response)}`
|
|
|
4333
4334
|
throw error;
|
|
4334
4335
|
}
|
|
4335
4336
|
record.status = "failed";
|
|
4336
|
-
record.failure = (0,
|
|
4337
|
+
record.failure = (0, import_errors82.serializeFailure)(error);
|
|
4337
4338
|
record.error = record.failure.message;
|
|
4338
4339
|
report("failed", { error: "Child workflow failed" });
|
|
4339
4340
|
throw new WorkflowCallError(
|
|
@@ -4394,6 +4395,7 @@ ${tryStringify2(args.response)}`
|
|
|
4394
4395
|
// src/index.ts
|
|
4395
4396
|
var index_exports = {};
|
|
4396
4397
|
__export(index_exports, {
|
|
4398
|
+
ChatLifecycleHookError: () => ChatLifecycleHookError,
|
|
4397
4399
|
ExecutionRequestError: () => ExecutionRequestError,
|
|
4398
4400
|
createAgent: () => createAgent,
|
|
4399
4401
|
createChatRouteHandler: () => createChatRouteHandler,
|
|
@@ -4416,183 +4418,29 @@ __export(index_exports, {
|
|
|
4416
4418
|
module.exports = __toCommonJS(index_exports);
|
|
4417
4419
|
|
|
4418
4420
|
// src/adapters/http.ts
|
|
4421
|
+
var import_errors5 = require("@kortyx/core/errors");
|
|
4422
|
+
var import_stream2 = require("@kortyx/stream");
|
|
4423
|
+
var import_zod2 = require("zod");
|
|
4424
|
+
|
|
4425
|
+
// src/chat/lifecycle.ts
|
|
4419
4426
|
var import_errors = require("@kortyx/core/errors");
|
|
4420
|
-
var
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
id: import_zod.z.string().optional(),
|
|
4427
|
-
timestamp: import_zod.z.number().refine(Number.isFinite).optional()
|
|
4428
|
-
}).strict();
|
|
4429
|
-
var chatRequestBodySchema = import_zod.z.looseObject({
|
|
4430
|
-
sessionId: import_zod.z.string().optional(),
|
|
4431
|
-
workflowId: import_zod.z.string().optional(),
|
|
4432
|
-
stream: import_zod.z.boolean().optional(),
|
|
4433
|
-
context: import_zod.z.record(import_zod.z.string(), import_zod.z.unknown()).optional(),
|
|
4434
|
-
messages: import_zod.z.array(chatMessageSchema)
|
|
4435
|
-
});
|
|
4436
|
-
var checkpointRequestBodySchema = import_zod.z.discriminatedUnion("action", [
|
|
4437
|
-
import_zod.z.object({
|
|
4438
|
-
action: import_zod.z.literal("list"),
|
|
4439
|
-
sessionId: import_zod.z.string().min(1)
|
|
4440
|
-
}).strict(),
|
|
4441
|
-
import_zod.z.object({
|
|
4442
|
-
action: import_zod.z.literal("get"),
|
|
4443
|
-
checkpointId: import_zod.z.string().min(1)
|
|
4444
|
-
}).strict(),
|
|
4445
|
-
import_zod.z.object({
|
|
4446
|
-
action: import_zod.z.literal("rollback"),
|
|
4447
|
-
checkpointId: import_zod.z.string().min(1)
|
|
4448
|
-
}).strict(),
|
|
4449
|
-
import_zod.z.object({
|
|
4450
|
-
action: import_zod.z.literal("fork"),
|
|
4451
|
-
checkpointId: import_zod.z.string().min(1),
|
|
4452
|
-
newSessionId: import_zod.z.string().min(1).optional()
|
|
4453
|
-
}).strict()
|
|
4454
|
-
]);
|
|
4455
|
-
async function readRequestJson(request) {
|
|
4456
|
-
try {
|
|
4457
|
-
const value = await request.json();
|
|
4458
|
-
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
4459
|
-
throw new Error("Expected a JSON object.");
|
|
4460
|
-
return value;
|
|
4461
|
-
} catch (cause) {
|
|
4462
|
-
throw new import_errors.KortyxError(
|
|
4463
|
-
"INVALID_REQUEST",
|
|
4464
|
-
"Request body is not valid JSON.",
|
|
4427
|
+
var ChatLifecycleHookError = class extends import_errors.KortyxError {
|
|
4428
|
+
phase;
|
|
4429
|
+
constructor(phase, cause) {
|
|
4430
|
+
super(
|
|
4431
|
+
"CHAT_LIFECYCLE_HOOK_FAILED",
|
|
4432
|
+
`Chat lifecycle hook failed: ${phase}`,
|
|
4465
4433
|
{
|
|
4466
|
-
category: "
|
|
4467
|
-
retryable:
|
|
4468
|
-
safeMessage: "
|
|
4434
|
+
category: "persistence",
|
|
4435
|
+
retryable: null,
|
|
4436
|
+
safeMessage: "Chat state could not be saved.",
|
|
4469
4437
|
cause
|
|
4470
4438
|
}
|
|
4471
4439
|
);
|
|
4440
|
+
this.name = "ChatLifecycleHookError";
|
|
4441
|
+
this.phase = phase;
|
|
4472
4442
|
}
|
|
4473
|
-
}
|
|
4474
|
-
function createFailureResponse(error, status) {
|
|
4475
|
-
const failure = (0, import_errors.serializeFailure)(error);
|
|
4476
|
-
return Response.json(
|
|
4477
|
-
{ error: failure.message, failure },
|
|
4478
|
-
{ status: status ?? (0, import_errors.failureHttpStatus)(failure) }
|
|
4479
|
-
);
|
|
4480
|
-
}
|
|
4481
|
-
function parseChatRequestBody(value) {
|
|
4482
|
-
const parsed = chatRequestBodySchema.safeParse(value);
|
|
4483
|
-
if (!parsed.success) {
|
|
4484
|
-
const [firstIssue] = parsed.error.issues;
|
|
4485
|
-
throw new import_errors.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
4486
|
-
category: "request",
|
|
4487
|
-
retryable: false,
|
|
4488
|
-
safeMessage: "The request body is invalid."
|
|
4489
|
-
});
|
|
4490
|
-
}
|
|
4491
|
-
const sessionId = parsed.data.sessionId?.trim();
|
|
4492
|
-
const workflowId = parsed.data.workflowId?.trim();
|
|
4493
|
-
return {
|
|
4494
|
-
...sessionId ? { sessionId } : {},
|
|
4495
|
-
...workflowId ? { workflowId } : {},
|
|
4496
|
-
...typeof parsed.data.stream === "boolean" ? { stream: parsed.data.stream } : {},
|
|
4497
|
-
...parsed.data.context ? { context: parsed.data.context } : {},
|
|
4498
|
-
messages: parsed.data.messages
|
|
4499
|
-
};
|
|
4500
|
-
}
|
|
4501
|
-
function parseCheckpointRequestBody(value) {
|
|
4502
|
-
const parsed = checkpointRequestBodySchema.safeParse(value);
|
|
4503
|
-
if (parsed.success) return parsed.data;
|
|
4504
|
-
const [firstIssue] = parsed.error.issues;
|
|
4505
|
-
throw new import_errors.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
4506
|
-
category: "request",
|
|
4507
|
-
retryable: false,
|
|
4508
|
-
safeMessage: "The request body is invalid."
|
|
4509
|
-
});
|
|
4510
|
-
}
|
|
4511
|
-
async function handleChatRequestBody(args) {
|
|
4512
|
-
const { agent, body } = args;
|
|
4513
|
-
const stream = await agent.streamChat(body.messages, {
|
|
4514
|
-
...args.onExecution ? { onExecution: args.onExecution } : {},
|
|
4515
|
-
...args.abortSignal ? { abortSignal: args.abortSignal } : {},
|
|
4516
|
-
sessionId: body.sessionId,
|
|
4517
|
-
workflowId: body.workflowId,
|
|
4518
|
-
context: body.context
|
|
4519
|
-
});
|
|
4520
|
-
if (body.stream === false) {
|
|
4521
|
-
const buffered = await (0, import_stream.collectBufferedStream)(stream);
|
|
4522
|
-
return new Response(JSON.stringify(buffered), {
|
|
4523
|
-
headers: {
|
|
4524
|
-
"content-type": "application/json"
|
|
4525
|
-
}
|
|
4526
|
-
});
|
|
4527
|
-
}
|
|
4528
|
-
return (0, import_stream.toSSE)(stream);
|
|
4529
|
-
}
|
|
4530
|
-
function createChatRouteHandler(args) {
|
|
4531
|
-
const { agent, errorStatus } = args;
|
|
4532
|
-
return async function POST(request) {
|
|
4533
|
-
try {
|
|
4534
|
-
const body = parseChatRequestBody(await readRequestJson(request));
|
|
4535
|
-
return await handleChatRequestBody({
|
|
4536
|
-
agent,
|
|
4537
|
-
body,
|
|
4538
|
-
abortSignal: request.signal,
|
|
4539
|
-
onExecution: args.onExecution
|
|
4540
|
-
});
|
|
4541
|
-
} catch (error) {
|
|
4542
|
-
return createFailureResponse(error, errorStatus);
|
|
4543
|
-
}
|
|
4544
|
-
};
|
|
4545
|
-
}
|
|
4546
|
-
async function handleCheckpointRequestBody(args) {
|
|
4547
|
-
const { agent, body } = args;
|
|
4548
|
-
const result = body.action === "list" ? await agent.listCheckpoints(body.sessionId) : body.action === "get" ? await agent.getCheckpoint(body.checkpointId) : body.action === "rollback" ? await agent.rollbackTo(body.checkpointId) : await agent.fork(body.checkpointId, {
|
|
4549
|
-
...body.newSessionId ? { newSessionId: body.newSessionId } : {}
|
|
4550
|
-
});
|
|
4551
|
-
return new Response(JSON.stringify(result), {
|
|
4552
|
-
headers: {
|
|
4553
|
-
"content-type": "application/json"
|
|
4554
|
-
}
|
|
4555
|
-
});
|
|
4556
|
-
}
|
|
4557
|
-
function createCheckpointRouteHandler(args) {
|
|
4558
|
-
const { agent, errorStatus } = args;
|
|
4559
|
-
return async function POST(request) {
|
|
4560
|
-
try {
|
|
4561
|
-
const body = parseCheckpointRequestBody(await readRequestJson(request));
|
|
4562
|
-
return await handleCheckpointRequestBody({ agent, body });
|
|
4563
|
-
} catch (error) {
|
|
4564
|
-
return createFailureResponse(error, errorStatus);
|
|
4565
|
-
}
|
|
4566
|
-
};
|
|
4567
|
-
}
|
|
4568
|
-
|
|
4569
|
-
// src/adapters/http-client.ts
|
|
4570
|
-
var import_browser = require("@kortyx/stream/browser");
|
|
4571
|
-
async function* streamChatFromRoute(args) {
|
|
4572
|
-
yield* (0, import_browser.streamFromRoute)({
|
|
4573
|
-
endpoint: args.endpoint,
|
|
4574
|
-
...args.fetchImpl ? { fetchImpl: args.fetchImpl } : {},
|
|
4575
|
-
...args.headers ? { headers: args.headers } : {},
|
|
4576
|
-
body: {
|
|
4577
|
-
sessionId: args.sessionId,
|
|
4578
|
-
workflowId: args.workflowId,
|
|
4579
|
-
messages: args.messages
|
|
4580
|
-
}
|
|
4581
|
-
});
|
|
4582
|
-
}
|
|
4583
|
-
|
|
4584
|
-
// src/chat/create-agent.ts
|
|
4585
|
-
var import_node_path = require("path");
|
|
4586
|
-
var import_core5 = require("@kortyx/core");
|
|
4587
|
-
var import_providers = require("@kortyx/providers");
|
|
4588
|
-
var import_runtime5 = require("@kortyx/runtime");
|
|
4589
|
-
var import_zod5 = require("zod");
|
|
4590
|
-
|
|
4591
|
-
// src/execution/execute.ts
|
|
4592
|
-
var import_core4 = require("@kortyx/core");
|
|
4593
|
-
var import_errors5 = require("@kortyx/core/errors");
|
|
4594
|
-
var import_runtime3 = require("@kortyx/runtime");
|
|
4595
|
-
var import_zod3 = require("zod");
|
|
4443
|
+
};
|
|
4596
4444
|
|
|
4597
4445
|
// src/interrupt/resume-handler.ts
|
|
4598
4446
|
var import_core3 = require("@kortyx/core");
|
|
@@ -4618,11 +4466,12 @@ var import_core2 = require("@kortyx/core");
|
|
|
4618
4466
|
var import_errors4 = require("@kortyx/core/errors");
|
|
4619
4467
|
var import_internal = __toESM(require_internal());
|
|
4620
4468
|
var import_runtime = require("@kortyx/runtime");
|
|
4469
|
+
var import_stream = require("@kortyx/stream");
|
|
4621
4470
|
var import_langgraph = require("@langchain/langgraph");
|
|
4622
4471
|
|
|
4623
4472
|
// src/execution/contracts.ts
|
|
4624
4473
|
var import_errors3 = require("@kortyx/core/errors");
|
|
4625
|
-
var
|
|
4474
|
+
var import_zod = require("zod");
|
|
4626
4475
|
async function resolveExecutionWorkflow(select, reference) {
|
|
4627
4476
|
const id = typeof reference === "string" ? reference : reference.id;
|
|
4628
4477
|
let workflow;
|
|
@@ -4654,12 +4503,12 @@ async function resolveExecutionWorkflow(select, reference) {
|
|
|
4654
4503
|
}
|
|
4655
4504
|
function parseExecutionInput(workflow, input) {
|
|
4656
4505
|
try {
|
|
4657
|
-
|
|
4506
|
+
import_zod.z.json().parse(input);
|
|
4658
4507
|
const parsed = workflow.inputSchema ? workflow.inputSchema.parse(input) : input;
|
|
4659
|
-
|
|
4508
|
+
import_zod.z.json().parse(parsed);
|
|
4660
4509
|
return parsed;
|
|
4661
4510
|
} catch (error) {
|
|
4662
|
-
if (!(error instanceof
|
|
4511
|
+
if (!(error instanceof import_zod.z.ZodError)) throw error;
|
|
4663
4512
|
throw new ExecutionRequestError("INVALID_INPUT", error.message, error);
|
|
4664
4513
|
}
|
|
4665
4514
|
}
|
|
@@ -4677,9 +4526,9 @@ async function validateExecutionOutput(state, select) {
|
|
|
4677
4526
|
for (const schema of /* @__PURE__ */ new Set([terminal.outputSchema, root.outputSchema])) {
|
|
4678
4527
|
if (schema) data = schema.parse(data);
|
|
4679
4528
|
}
|
|
4680
|
-
if (terminal.outputSchema || root.outputSchema)
|
|
4529
|
+
if (terminal.outputSchema || root.outputSchema) import_zod.z.json().parse(data);
|
|
4681
4530
|
} catch (error) {
|
|
4682
|
-
if (!(error instanceof
|
|
4531
|
+
if (!(error instanceof import_zod.z.ZodError)) throw error;
|
|
4683
4532
|
const failure = new import_errors3.ValidationError(
|
|
4684
4533
|
"INVALID_OUTPUT",
|
|
4685
4534
|
`Workflow output validation failed: ${error.message}`,
|
|
@@ -5090,6 +4939,9 @@ async function orchestrateGraphStream({
|
|
|
5090
4939
|
abortSignal: requestSignal,
|
|
5091
4940
|
executionSignal,
|
|
5092
4941
|
onExecution,
|
|
4942
|
+
clientTurnId,
|
|
4943
|
+
continueOnDisconnect = false,
|
|
4944
|
+
onResponseFinalized,
|
|
5093
4945
|
emitOutput = true,
|
|
5094
4946
|
onOutcome,
|
|
5095
4947
|
selectWorkflow,
|
|
@@ -5098,12 +4950,34 @@ async function orchestrateGraphStream({
|
|
|
5098
4950
|
executionLeaseRelease
|
|
5099
4951
|
}) {
|
|
5100
4952
|
const out = new import_node_stream.PassThrough({ objectMode: true });
|
|
4953
|
+
const visibleMessage = emitOutput && clientTurnId && onResponseFinalized && initialConfig.responseCompleted !== true ? (0, import_stream.createFinalizedChatMessageAccumulator)(clientTurnId) : void 0;
|
|
4954
|
+
let responseFinalized = false;
|
|
4955
|
+
const finalizeVisibleResponse = async (status) => {
|
|
4956
|
+
if (!visibleMessage || !onResponseFinalized || !clientTurnId || !sessionId || responseFinalized)
|
|
4957
|
+
return;
|
|
4958
|
+
responseFinalized = true;
|
|
4959
|
+
try {
|
|
4960
|
+
await onResponseFinalized({
|
|
4961
|
+
sessionId,
|
|
4962
|
+
runId,
|
|
4963
|
+
clientTurnId,
|
|
4964
|
+
status,
|
|
4965
|
+
message: visibleMessage.message(),
|
|
4966
|
+
...sessionCheckpointId ? { checkpointId: sessionCheckpointId } : {}
|
|
4967
|
+
});
|
|
4968
|
+
} catch (error) {
|
|
4969
|
+
console.error("[chat:onResponseFinalized]", (0, import_errors4.serializeFailure)(error));
|
|
4970
|
+
}
|
|
4971
|
+
};
|
|
5101
4972
|
const write = (chunk) => {
|
|
5102
4973
|
if (isRecord3(chunk) && chunk.type === "done" && isGraphState(chunk.data)) {
|
|
5103
4974
|
const { __kortyxParallelGraph: _journal, ...runtime } = chunk.data.runtime;
|
|
5104
4975
|
chunk = { ...chunk, data: { ...chunk.data, runtime } };
|
|
5105
4976
|
}
|
|
5106
|
-
if (emitOutput && !response.closed
|
|
4977
|
+
if (emitOutput && !response.closed) {
|
|
4978
|
+
visibleMessage?.apply(chunk);
|
|
4979
|
+
if (!out.destroyed) out.write(chunk);
|
|
4980
|
+
}
|
|
5107
4981
|
};
|
|
5108
4982
|
let outcomeState = state;
|
|
5109
4983
|
let outcomeError;
|
|
@@ -5118,7 +4992,7 @@ async function orchestrateGraphStream({
|
|
|
5118
4992
|
const response = createResponseLifecycle({
|
|
5119
4993
|
enabled: emitOutput,
|
|
5120
4994
|
restored: initialConfig.responseCompleted === true,
|
|
5121
|
-
requestSignal,
|
|
4995
|
+
requestSignal: continueOnDisconnect ? void 0 : requestSignal,
|
|
5122
4996
|
executionSignal: executionSignal ? AbortSignal.any([executionSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
5123
4997
|
onClosed: () => {
|
|
5124
4998
|
out.write({ type: "done" });
|
|
@@ -5182,11 +5056,12 @@ async function orchestrateGraphStream({
|
|
|
5182
5056
|
},
|
|
5183
5057
|
flush: true
|
|
5184
5058
|
});
|
|
5059
|
+
await finalizeVisibleResponse("completed");
|
|
5185
5060
|
}
|
|
5186
5061
|
});
|
|
5187
5062
|
const abortSignal = response.signal;
|
|
5188
5063
|
out.on("close", () => {
|
|
5189
|
-
if (!finished) response.disconnect();
|
|
5064
|
+
if (!finished && !continueOnDisconnect) response.disconnect();
|
|
5190
5065
|
});
|
|
5191
5066
|
let structuredSeq = 0;
|
|
5192
5067
|
const debugEnabled = Boolean(config?.features?.tracing);
|
|
@@ -5939,6 +5814,9 @@ async function orchestrateGraphStream({
|
|
|
5939
5814
|
);
|
|
5940
5815
|
}
|
|
5941
5816
|
}
|
|
5817
|
+
await finalizeVisibleResponse(
|
|
5818
|
+
outcomeError ? "failed" : shouldKeepFrameworkState ? "interrupted" : "completed"
|
|
5819
|
+
);
|
|
5942
5820
|
write({ type: "done", data: workflowFinalState });
|
|
5943
5821
|
out.end();
|
|
5944
5822
|
return;
|
|
@@ -6016,6 +5894,9 @@ async function orchestrateGraphStream({
|
|
|
6016
5894
|
});
|
|
6017
5895
|
finished = true;
|
|
6018
5896
|
runTraceSpan.end?.(runTraceEndArgs());
|
|
5897
|
+
await finalizeVisibleResponse(
|
|
5898
|
+
outcomeError ? "failed" : pendingRecordToken || naturalFinalState.awaitingHumanInput ? "interrupted" : "completed"
|
|
5899
|
+
);
|
|
6019
5900
|
write({ type: "done", data: naturalFinalState });
|
|
6020
5901
|
out.end();
|
|
6021
5902
|
return;
|
|
@@ -6076,6 +5957,7 @@ async function orchestrateGraphStream({
|
|
|
6076
5957
|
fallbackRunSpan?.setAttributes?.({ "kortyx.run.cancelled": true });
|
|
6077
5958
|
fallbackRunSpan?.end?.();
|
|
6078
5959
|
write({ type: "cancelled", runId, reason: "Execution cancelled." });
|
|
5960
|
+
await finalizeVisibleResponse("cancelled");
|
|
6079
5961
|
write({ type: "done" });
|
|
6080
5962
|
finished = true;
|
|
6081
5963
|
out.end();
|
|
@@ -6222,6 +6104,9 @@ async function orchestrateGraphStream({
|
|
|
6222
6104
|
console.error("[execution:releaseLease]", (0, import_errors4.serializeFailure)(error));
|
|
6223
6105
|
}
|
|
6224
6106
|
response.dispose();
|
|
6107
|
+
await finalizeVisibleResponse(
|
|
6108
|
+
outcomeError ? (0, import_core2.isExecutionCancelled)(outcomeError) ? "cancelled" : "failed" : pendingRecordToken || outcomeState.awaitingHumanInput ? "interrupted" : "completed"
|
|
6109
|
+
);
|
|
6225
6110
|
onOutcome?.({
|
|
6226
6111
|
state: outcomeState,
|
|
6227
6112
|
pending: pendingRecordToken ? activePendingRequests.get(pendingRecordToken) : void 0,
|
|
@@ -6271,6 +6156,9 @@ async function tryPrepareResumeStream({
|
|
|
6271
6156
|
abortSignal,
|
|
6272
6157
|
executionSignal,
|
|
6273
6158
|
onExecution,
|
|
6159
|
+
clientTurnId,
|
|
6160
|
+
continueOnDisconnect,
|
|
6161
|
+
onResponseFinalized,
|
|
6274
6162
|
lastMessage,
|
|
6275
6163
|
meta: suppliedMeta,
|
|
6276
6164
|
emitOutput,
|
|
@@ -6489,6 +6377,9 @@ async function tryPrepareResumeStream({
|
|
|
6489
6377
|
executionSignal: continuedSignal ? AbortSignal.any([continuedSignal, leaseAbort.signal]) : leaseAbort.signal,
|
|
6490
6378
|
executionLeaseRelease: releaseLease,
|
|
6491
6379
|
onExecution,
|
|
6380
|
+
clientTurnId,
|
|
6381
|
+
continueOnDisconnect,
|
|
6382
|
+
onResponseFinalized,
|
|
6492
6383
|
emitOutput,
|
|
6493
6384
|
onOutcome,
|
|
6494
6385
|
sessionId,
|
|
@@ -6525,7 +6416,316 @@ async function tryPrepareResumeStream({
|
|
|
6525
6416
|
}
|
|
6526
6417
|
}
|
|
6527
6418
|
|
|
6419
|
+
// src/adapters/http.ts
|
|
6420
|
+
var reportLifecycleError = async (callback, event) => {
|
|
6421
|
+
if (!callback) {
|
|
6422
|
+
console.error("[chat:lifecycle]", event.error);
|
|
6423
|
+
return;
|
|
6424
|
+
}
|
|
6425
|
+
try {
|
|
6426
|
+
await callback(event);
|
|
6427
|
+
} catch (error) {
|
|
6428
|
+
console.error("[chat:onLifecycleError]", (0, import_errors5.serializeFailure)(error));
|
|
6429
|
+
}
|
|
6430
|
+
};
|
|
6431
|
+
var chatMessageSchema = import_zod2.z.object({
|
|
6432
|
+
role: import_zod2.z.enum(["user", "assistant", "system"]),
|
|
6433
|
+
content: import_zod2.z.string(),
|
|
6434
|
+
metadata: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional(),
|
|
6435
|
+
id: import_zod2.z.string().optional(),
|
|
6436
|
+
timestamp: import_zod2.z.number().refine(Number.isFinite).optional()
|
|
6437
|
+
}).strict();
|
|
6438
|
+
var chatRequestBodySchema = import_zod2.z.looseObject({
|
|
6439
|
+
sessionId: import_zod2.z.string().optional(),
|
|
6440
|
+
clientTurnId: import_zod2.z.string().max(128).optional(),
|
|
6441
|
+
workflowId: import_zod2.z.string().optional(),
|
|
6442
|
+
stream: import_zod2.z.boolean().optional(),
|
|
6443
|
+
context: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.unknown()).optional(),
|
|
6444
|
+
messages: import_zod2.z.array(chatMessageSchema)
|
|
6445
|
+
});
|
|
6446
|
+
var checkpointRequestBodySchema = import_zod2.z.discriminatedUnion("action", [
|
|
6447
|
+
import_zod2.z.object({
|
|
6448
|
+
action: import_zod2.z.literal("list"),
|
|
6449
|
+
sessionId: import_zod2.z.string().min(1)
|
|
6450
|
+
}).strict(),
|
|
6451
|
+
import_zod2.z.object({
|
|
6452
|
+
action: import_zod2.z.literal("get"),
|
|
6453
|
+
checkpointId: import_zod2.z.string().min(1)
|
|
6454
|
+
}).strict(),
|
|
6455
|
+
import_zod2.z.object({
|
|
6456
|
+
action: import_zod2.z.literal("rollback"),
|
|
6457
|
+
checkpointId: import_zod2.z.string().min(1)
|
|
6458
|
+
}).strict(),
|
|
6459
|
+
import_zod2.z.object({
|
|
6460
|
+
action: import_zod2.z.literal("fork"),
|
|
6461
|
+
checkpointId: import_zod2.z.string().min(1),
|
|
6462
|
+
newSessionId: import_zod2.z.string().min(1).optional()
|
|
6463
|
+
}).strict()
|
|
6464
|
+
]);
|
|
6465
|
+
async function readRequestJson(request) {
|
|
6466
|
+
try {
|
|
6467
|
+
const value = await request.json();
|
|
6468
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
6469
|
+
throw new Error("Expected a JSON object.");
|
|
6470
|
+
return value;
|
|
6471
|
+
} catch (cause) {
|
|
6472
|
+
throw new import_errors5.KortyxError(
|
|
6473
|
+
"INVALID_REQUEST",
|
|
6474
|
+
"Request body is not valid JSON.",
|
|
6475
|
+
{
|
|
6476
|
+
category: "request",
|
|
6477
|
+
retryable: false,
|
|
6478
|
+
safeMessage: "The request body must contain a valid JSON object.",
|
|
6479
|
+
cause
|
|
6480
|
+
}
|
|
6481
|
+
);
|
|
6482
|
+
}
|
|
6483
|
+
}
|
|
6484
|
+
function createFailureResponse(error, status) {
|
|
6485
|
+
const failure = (0, import_errors5.serializeFailure)(error);
|
|
6486
|
+
return Response.json(
|
|
6487
|
+
{ error: failure.message, failure },
|
|
6488
|
+
{ status: status ?? (0, import_errors5.failureHttpStatus)(failure) }
|
|
6489
|
+
);
|
|
6490
|
+
}
|
|
6491
|
+
function parseChatRequestBody(value) {
|
|
6492
|
+
const parsed = chatRequestBodySchema.safeParse(value);
|
|
6493
|
+
if (!parsed.success) {
|
|
6494
|
+
const [firstIssue] = parsed.error.issues;
|
|
6495
|
+
throw new import_errors5.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
6496
|
+
category: "request",
|
|
6497
|
+
retryable: false,
|
|
6498
|
+
safeMessage: "The request body is invalid."
|
|
6499
|
+
});
|
|
6500
|
+
}
|
|
6501
|
+
const sessionId = parsed.data.sessionId?.trim();
|
|
6502
|
+
const workflowId = parsed.data.workflowId?.trim();
|
|
6503
|
+
const clientTurnId = parsed.data.clientTurnId?.trim();
|
|
6504
|
+
return {
|
|
6505
|
+
...sessionId ? { sessionId } : {},
|
|
6506
|
+
...workflowId ? { workflowId } : {},
|
|
6507
|
+
...clientTurnId ? { clientTurnId } : {},
|
|
6508
|
+
...typeof parsed.data.stream === "boolean" ? { stream: parsed.data.stream } : {},
|
|
6509
|
+
...parsed.data.context ? { context: parsed.data.context } : {},
|
|
6510
|
+
messages: parsed.data.messages
|
|
6511
|
+
};
|
|
6512
|
+
}
|
|
6513
|
+
function parseCheckpointRequestBody(value) {
|
|
6514
|
+
const parsed = checkpointRequestBodySchema.safeParse(value);
|
|
6515
|
+
if (parsed.success) return parsed.data;
|
|
6516
|
+
const [firstIssue] = parsed.error.issues;
|
|
6517
|
+
throw new import_errors5.KortyxError("INVALID_REQUEST", firstIssue.message, {
|
|
6518
|
+
category: "request",
|
|
6519
|
+
retryable: false,
|
|
6520
|
+
safeMessage: "The request body is invalid."
|
|
6521
|
+
});
|
|
6522
|
+
}
|
|
6523
|
+
async function handleChatRequestBody(args) {
|
|
6524
|
+
const { agent, body } = args;
|
|
6525
|
+
if (args.onResponseFinalized && (!body.sessionId || !body.clientTurnId)) {
|
|
6526
|
+
throw new import_errors5.KortyxError(
|
|
6527
|
+
"INVALID_REQUEST",
|
|
6528
|
+
"sessionId and clientTurnId are required with onResponseFinalized.",
|
|
6529
|
+
{
|
|
6530
|
+
category: "request",
|
|
6531
|
+
retryable: false,
|
|
6532
|
+
safeMessage: "This chat request needs a session and turn ID."
|
|
6533
|
+
}
|
|
6534
|
+
);
|
|
6535
|
+
}
|
|
6536
|
+
const stream = await agent.streamChat(body.messages, {
|
|
6537
|
+
...args.onExecution ? { onExecution: args.onExecution } : {},
|
|
6538
|
+
...body.clientTurnId ? { clientTurnId: body.clientTurnId } : {},
|
|
6539
|
+
...args.continueOnDisconnect ? { continueOnDisconnect: true } : {},
|
|
6540
|
+
...args.onResponseFinalized ? { onResponseFinalized: args.onResponseFinalized } : {},
|
|
6541
|
+
...args.abortSignal && !args.continueOnDisconnect ? { abortSignal: args.abortSignal } : {},
|
|
6542
|
+
sessionId: body.sessionId,
|
|
6543
|
+
workflowId: body.workflowId,
|
|
6544
|
+
context: body.context
|
|
6545
|
+
});
|
|
6546
|
+
if (body.stream === false) {
|
|
6547
|
+
const buffered = await (0, import_stream2.collectBufferedStream)(stream);
|
|
6548
|
+
return new Response(JSON.stringify(buffered), {
|
|
6549
|
+
headers: {
|
|
6550
|
+
"content-type": "application/json"
|
|
6551
|
+
}
|
|
6552
|
+
});
|
|
6553
|
+
}
|
|
6554
|
+
return (0, import_stream2.toSSE)(stream);
|
|
6555
|
+
}
|
|
6556
|
+
function createChatRouteHandler(args) {
|
|
6557
|
+
const { agent, errorStatus } = args;
|
|
6558
|
+
if (args.disconnect === "continue" && !args.onExecution) {
|
|
6559
|
+
throw new Error(
|
|
6560
|
+
'disconnect: "continue" requires onExecution to retain host lifetime.'
|
|
6561
|
+
);
|
|
6562
|
+
}
|
|
6563
|
+
return async function POST(request) {
|
|
6564
|
+
try {
|
|
6565
|
+
const body = parseChatRequestBody(await readRequestJson(request));
|
|
6566
|
+
if (args.onTurnAccepted || args.onResponseFinalized) {
|
|
6567
|
+
if (!body.sessionId || !body.clientTurnId) {
|
|
6568
|
+
throw new import_errors5.KortyxError(
|
|
6569
|
+
"INVALID_REQUEST",
|
|
6570
|
+
"sessionId and clientTurnId are required with chat lifecycle hooks.",
|
|
6571
|
+
{
|
|
6572
|
+
category: "request",
|
|
6573
|
+
retryable: false,
|
|
6574
|
+
safeMessage: "This chat request needs a session and turn ID."
|
|
6575
|
+
}
|
|
6576
|
+
);
|
|
6577
|
+
}
|
|
6578
|
+
const userMessage = body.messages.at(-1);
|
|
6579
|
+
if (!userMessage || userMessage.role !== "user") {
|
|
6580
|
+
throw new import_errors5.KortyxError(
|
|
6581
|
+
"INVALID_REQUEST",
|
|
6582
|
+
"The last chat message must be from the user.",
|
|
6583
|
+
{
|
|
6584
|
+
category: "request",
|
|
6585
|
+
retryable: false,
|
|
6586
|
+
safeMessage: "The chat request needs a user message."
|
|
6587
|
+
}
|
|
6588
|
+
);
|
|
6589
|
+
}
|
|
6590
|
+
if (args.onTurnAccepted) {
|
|
6591
|
+
try {
|
|
6592
|
+
await args.onTurnAccepted({
|
|
6593
|
+
request,
|
|
6594
|
+
sessionId: body.sessionId,
|
|
6595
|
+
clientTurnId: body.clientTurnId,
|
|
6596
|
+
userMessage: { ...userMessage, role: "user" },
|
|
6597
|
+
kind: parseResumeMeta(userMessage) ? "interrupt-response" : "prompt"
|
|
6598
|
+
});
|
|
6599
|
+
} catch (cause) {
|
|
6600
|
+
const error = new ChatLifecycleHookError("turn-accepted", cause);
|
|
6601
|
+
await reportLifecycleError(args.onLifecycleError, {
|
|
6602
|
+
phase: "turn-accepted",
|
|
6603
|
+
clientTurnId: body.clientTurnId,
|
|
6604
|
+
error
|
|
6605
|
+
});
|
|
6606
|
+
throw error;
|
|
6607
|
+
}
|
|
6608
|
+
}
|
|
6609
|
+
}
|
|
6610
|
+
return await handleChatRequestBody({
|
|
6611
|
+
agent,
|
|
6612
|
+
body,
|
|
6613
|
+
abortSignal: request.signal,
|
|
6614
|
+
onExecution: args.onExecution,
|
|
6615
|
+
continueOnDisconnect: args.disconnect === "continue",
|
|
6616
|
+
...args.onResponseFinalized ? {
|
|
6617
|
+
onResponseFinalized: async (event) => {
|
|
6618
|
+
try {
|
|
6619
|
+
await args.onResponseFinalized?.({ ...event, request });
|
|
6620
|
+
} catch (cause) {
|
|
6621
|
+
await reportLifecycleError(args.onLifecycleError, {
|
|
6622
|
+
phase: "response-finalized",
|
|
6623
|
+
clientTurnId: event.clientTurnId,
|
|
6624
|
+
error: new ChatLifecycleHookError(
|
|
6625
|
+
"response-finalized",
|
|
6626
|
+
cause
|
|
6627
|
+
)
|
|
6628
|
+
});
|
|
6629
|
+
}
|
|
6630
|
+
}
|
|
6631
|
+
} : {}
|
|
6632
|
+
});
|
|
6633
|
+
} catch (error) {
|
|
6634
|
+
return createFailureResponse(error, errorStatus);
|
|
6635
|
+
}
|
|
6636
|
+
};
|
|
6637
|
+
}
|
|
6638
|
+
async function handleCheckpointRequestBody(args) {
|
|
6639
|
+
const { agent, body } = args;
|
|
6640
|
+
const result = body.action === "list" ? await agent.listCheckpoints(body.sessionId) : body.action === "get" ? await agent.getCheckpoint(body.checkpointId) : body.action === "rollback" ? await agent.rollbackTo(body.checkpointId) : await agent.fork(body.checkpointId, {
|
|
6641
|
+
...body.newSessionId ? { newSessionId: body.newSessionId } : {}
|
|
6642
|
+
});
|
|
6643
|
+
if (args.request && body.action === "fork" && args.onForked) {
|
|
6644
|
+
const fork = result;
|
|
6645
|
+
try {
|
|
6646
|
+
await args.onForked({
|
|
6647
|
+
request: args.request,
|
|
6648
|
+
sourceSessionId: fork.parentSessionId,
|
|
6649
|
+
newSessionId: fork.sessionId,
|
|
6650
|
+
sourceCheckpointId: fork.forkedFrom,
|
|
6651
|
+
newCheckpointId: fork.checkpoint.id
|
|
6652
|
+
});
|
|
6653
|
+
} catch (cause) {
|
|
6654
|
+
await reportLifecycleError(args.onLifecycleError, {
|
|
6655
|
+
phase: "forked",
|
|
6656
|
+
error: new ChatLifecycleHookError("forked", cause)
|
|
6657
|
+
});
|
|
6658
|
+
}
|
|
6659
|
+
}
|
|
6660
|
+
if (args.request && body.action === "rollback" && args.onRolledBack) {
|
|
6661
|
+
const rollback = result;
|
|
6662
|
+
try {
|
|
6663
|
+
await args.onRolledBack({
|
|
6664
|
+
request: args.request,
|
|
6665
|
+
sessionId: rollback.sessionId,
|
|
6666
|
+
headCheckpointId: rollback.head,
|
|
6667
|
+
invalidatedStructuredStreamIds: rollback.invalidatedStructuredStreamIds
|
|
6668
|
+
});
|
|
6669
|
+
} catch (cause) {
|
|
6670
|
+
await reportLifecycleError(args.onLifecycleError, {
|
|
6671
|
+
phase: "rolled-back",
|
|
6672
|
+
error: new ChatLifecycleHookError("rolled-back", cause)
|
|
6673
|
+
});
|
|
6674
|
+
}
|
|
6675
|
+
}
|
|
6676
|
+
return new Response(JSON.stringify(result), {
|
|
6677
|
+
headers: {
|
|
6678
|
+
"content-type": "application/json"
|
|
6679
|
+
}
|
|
6680
|
+
});
|
|
6681
|
+
}
|
|
6682
|
+
function createCheckpointRouteHandler(args) {
|
|
6683
|
+
const { agent, errorStatus } = args;
|
|
6684
|
+
return async function POST(request) {
|
|
6685
|
+
try {
|
|
6686
|
+
const body = parseCheckpointRequestBody(await readRequestJson(request));
|
|
6687
|
+
return await handleCheckpointRequestBody({
|
|
6688
|
+
agent,
|
|
6689
|
+
body,
|
|
6690
|
+
request,
|
|
6691
|
+
onForked: args.onForked,
|
|
6692
|
+
onRolledBack: args.onRolledBack,
|
|
6693
|
+
onLifecycleError: args.onLifecycleError
|
|
6694
|
+
});
|
|
6695
|
+
} catch (error) {
|
|
6696
|
+
return createFailureResponse(error, errorStatus);
|
|
6697
|
+
}
|
|
6698
|
+
};
|
|
6699
|
+
}
|
|
6700
|
+
|
|
6701
|
+
// src/adapters/http-client.ts
|
|
6702
|
+
var import_browser = require("@kortyx/stream/browser");
|
|
6703
|
+
async function* streamChatFromRoute(args) {
|
|
6704
|
+
yield* (0, import_browser.streamFromRoute)({
|
|
6705
|
+
endpoint: args.endpoint,
|
|
6706
|
+
...args.fetchImpl ? { fetchImpl: args.fetchImpl } : {},
|
|
6707
|
+
...args.headers ? { headers: args.headers } : {},
|
|
6708
|
+
body: {
|
|
6709
|
+
sessionId: args.sessionId,
|
|
6710
|
+
clientTurnId: args.clientTurnId,
|
|
6711
|
+
workflowId: args.workflowId,
|
|
6712
|
+
messages: args.messages
|
|
6713
|
+
}
|
|
6714
|
+
});
|
|
6715
|
+
}
|
|
6716
|
+
|
|
6717
|
+
// src/chat/create-agent.ts
|
|
6718
|
+
var import_node_path = require("path");
|
|
6719
|
+
var import_core5 = require("@kortyx/core");
|
|
6720
|
+
var import_providers = require("@kortyx/providers");
|
|
6721
|
+
var import_runtime5 = require("@kortyx/runtime");
|
|
6722
|
+
var import_zod5 = require("zod");
|
|
6723
|
+
|
|
6528
6724
|
// src/execution/execute.ts
|
|
6725
|
+
var import_core4 = require("@kortyx/core");
|
|
6726
|
+
var import_errors6 = require("@kortyx/core/errors");
|
|
6727
|
+
var import_runtime3 = require("@kortyx/runtime");
|
|
6728
|
+
var import_zod3 = require("zod");
|
|
6529
6729
|
var handleSchema = import_zod3.z.object({
|
|
6530
6730
|
token: import_zod3.z.string().min(1),
|
|
6531
6731
|
requestId: import_zod3.z.string().min(1),
|
|
@@ -6556,7 +6756,7 @@ function resultFromOutcome(outcome, runId, sessionId) {
|
|
|
6556
6756
|
return {
|
|
6557
6757
|
...info,
|
|
6558
6758
|
status: "failed",
|
|
6559
|
-
error: (0,
|
|
6759
|
+
error: (0, import_errors6.serializeFailure)(error)
|
|
6560
6760
|
};
|
|
6561
6761
|
}
|
|
6562
6762
|
if (outcome.cancelled)
|
|
@@ -6737,7 +6937,7 @@ async function resumeWorkflow(services, args) {
|
|
|
6737
6937
|
);
|
|
6738
6938
|
}).catch(
|
|
6739
6939
|
(error) => reject(
|
|
6740
|
-
error instanceof Error ? error : new
|
|
6940
|
+
error instanceof Error ? error : new import_errors6.KortyxError("RESUME_FAILED", "Resume failed.", {
|
|
6741
6941
|
category: "persistence",
|
|
6742
6942
|
cause: error,
|
|
6743
6943
|
safeMessage: "The saved execution could not be resumed."
|
|
@@ -6940,6 +7140,7 @@ function restoreWorkflowCallBranch(requests, telemetry, sourceRunId) {
|
|
|
6940
7140
|
}
|
|
6941
7141
|
|
|
6942
7142
|
// src/chat/process-chat.ts
|
|
7143
|
+
var import_errors7 = require("@kortyx/core/errors");
|
|
6943
7144
|
var import_runtime4 = require("@kortyx/runtime");
|
|
6944
7145
|
|
|
6945
7146
|
// src/utils/extract-latest-message.ts
|
|
@@ -6960,6 +7161,9 @@ async function streamChat({
|
|
|
6960
7161
|
abortSignal,
|
|
6961
7162
|
executionSignal,
|
|
6962
7163
|
onExecution,
|
|
7164
|
+
clientTurnId,
|
|
7165
|
+
continueOnDisconnect,
|
|
7166
|
+
onResponseFinalized,
|
|
6963
7167
|
options,
|
|
6964
7168
|
sessionId,
|
|
6965
7169
|
defaultWorkflowId,
|
|
@@ -6971,6 +7175,18 @@ async function streamChat({
|
|
|
6971
7175
|
getProvider,
|
|
6972
7176
|
applyResumeSelection
|
|
6973
7177
|
}) {
|
|
7178
|
+
const suppliedSessionId = sessionId || options?.sessionId;
|
|
7179
|
+
if (onResponseFinalized && (!suppliedSessionId || !clientTurnId?.trim() || clientTurnId.length > 128)) {
|
|
7180
|
+
throw new import_errors7.KortyxError(
|
|
7181
|
+
"INVALID_REQUEST",
|
|
7182
|
+
"sessionId and clientTurnId are required with onResponseFinalized.",
|
|
7183
|
+
{
|
|
7184
|
+
category: "request",
|
|
7185
|
+
retryable: false,
|
|
7186
|
+
safeMessage: "This chat request needs a session and turn ID."
|
|
7187
|
+
}
|
|
7188
|
+
);
|
|
7189
|
+
}
|
|
6974
7190
|
const config = await loadRuntimeConfig(options);
|
|
6975
7191
|
let runtimeConfig2 = {
|
|
6976
7192
|
...config,
|
|
@@ -7009,6 +7225,9 @@ async function streamChat({
|
|
|
7009
7225
|
abortSignal,
|
|
7010
7226
|
executionSignal,
|
|
7011
7227
|
onExecution,
|
|
7228
|
+
clientTurnId,
|
|
7229
|
+
continueOnDisconnect,
|
|
7230
|
+
onResponseFinalized,
|
|
7012
7231
|
lastMessage: last,
|
|
7013
7232
|
sessionId: resolvedSessionId,
|
|
7014
7233
|
config: runtimeConfig2,
|
|
@@ -7082,6 +7301,9 @@ async function streamChat({
|
|
|
7082
7301
|
abortSignal,
|
|
7083
7302
|
executionSignal,
|
|
7084
7303
|
onExecution,
|
|
7304
|
+
clientTurnId,
|
|
7305
|
+
continueOnDisconnect,
|
|
7306
|
+
onResponseFinalized,
|
|
7085
7307
|
sessionId: resolvedSessionId,
|
|
7086
7308
|
runId,
|
|
7087
7309
|
graph,
|
|
@@ -7100,6 +7322,9 @@ var agentProcessOptionsSchema = import_zod5.z.object({
|
|
|
7100
7322
|
onExecution: import_zod5.z.custom(
|
|
7101
7323
|
(value) => typeof value === "function"
|
|
7102
7324
|
).optional(),
|
|
7325
|
+
clientTurnId: import_zod5.z.string().min(1).max(128).optional(),
|
|
7326
|
+
continueOnDisconnect: import_zod5.z.boolean().optional(),
|
|
7327
|
+
onResponseFinalized: import_zod5.z.custom((value) => typeof value === "function").optional(),
|
|
7103
7328
|
limits: import_core5.ExecutionLimitsSchema.optional(),
|
|
7104
7329
|
abortSignal: import_zod5.z.custom((value) => value instanceof AbortSignal).optional(),
|
|
7105
7330
|
sessionId: import_zod5.z.string().optional(),
|
|
@@ -7246,6 +7471,9 @@ function createAgent(args) {
|
|
|
7246
7471
|
abortSignal: parsedOptions?.abortSignal,
|
|
7247
7472
|
executionSignal: parsedOptions?.executionSignal,
|
|
7248
7473
|
onExecution: parsedOptions?.onExecution,
|
|
7474
|
+
clientTurnId: parsedOptions?.clientTurnId,
|
|
7475
|
+
continueOnDisconnect: parsedOptions?.continueOnDisconnect,
|
|
7476
|
+
onResponseFinalized: parsedOptions?.onResponseFinalized,
|
|
7249
7477
|
options: parsedOptions,
|
|
7250
7478
|
workflowRegistry: registry,
|
|
7251
7479
|
...knownWorkflowIds ? { knownWorkflowIds } : {},
|
|
@@ -7402,6 +7630,7 @@ function createAgent(args) {
|
|
|
7402
7630
|
}
|
|
7403
7631
|
// Annotate the CommonJS export names for ESM import in node:
|
|
7404
7632
|
0 && (module.exports = {
|
|
7633
|
+
ChatLifecycleHookError,
|
|
7405
7634
|
ExecutionRequestError,
|
|
7406
7635
|
createAgent,
|
|
7407
7636
|
createChatRouteHandler,
|