@kortyx/agent 0.4.0 → 0.5.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 +23 -0
- package/dist/adapters/http-client.d.ts +12 -0
- package/dist/adapters/http-client.d.ts.map +1 -0
- package/dist/adapters/http-client.js +16 -0
- package/dist/adapters/http.d.ts +17 -0
- package/dist/adapters/http.d.ts.map +1 -0
- package/dist/adapters/http.js +66 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +5 -0
- package/dist/chat/create-agent.d.ts +27 -10
- package/dist/chat/create-agent.d.ts.map +1 -1
- package/dist/chat/create-agent.js +102 -35
- package/dist/chat/process-chat.d.ts +9 -8
- package/dist/chat/process-chat.d.ts.map +1 -1
- package/dist/chat/process-chat.js +1 -7
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -1
- package/dist/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator.js +89 -185
- package/dist/stream/transform-graph-stream-for-ui.d.ts +1 -2
- package/dist/stream/transform-graph-stream-for-ui.d.ts.map +1 -1
- package/dist/stream/transform-graph-stream-for-ui.js +11 -145
- package/package.json +7 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.5.0](https://github.com/kortyx-io/kortyx/compare/agent-v0.4.1...agent-v0.5.0) (2026-02-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **agent:** strict createAgent and unify useReason streaming ([6725f97](https://github.com/kortyx-io/kortyx/commit/6725f976fc32083fb7d2590f1353d16a99afb46f))
|
|
9
|
+
* **kortyx:** add browser-safe chat streaming adapters ([c7eb98e](https://github.com/kortyx-io/kortyx/commit/c7eb98e06781a708c79f143ba725efb69d35709e))
|
|
10
|
+
* make createAgent strict/declarative and split providers ([1d252f2](https://github.com/kortyx-io/kortyx/commit/1d252f2dcd51622f821715c0fffb13733aeb3cae))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **agent:** remove eager provider registration guard ([8da4059](https://github.com/kortyx-io/kortyx/commit/8da40592d55bb31800a4d85edcd49795ddf09a29))
|
|
16
|
+
* **agent:** simplify stream transformer and interrupt orchestration ([d0b5847](https://github.com/kortyx-io/kortyx/commit/d0b58475e139e070fd9ca1a68b71395642ac32d5))
|
|
17
|
+
|
|
18
|
+
## [0.4.1](https://github.com/kortyx-io/kortyx/compare/agent-v0.4.0...agent-v0.4.1) (2026-02-15)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Bug Fixes
|
|
22
|
+
|
|
23
|
+
* remove kortyx.config support and update docs ([ecb3f8d](https://github.com/kortyx-io/kortyx/commit/ecb3f8d53a017cc84bf8db3e125a6f711f5d4013))
|
|
24
|
+
* remove kortyx.config support and update docs ([aa4a70a](https://github.com/kortyx-io/kortyx/commit/aa4a70a034dfec7bca829793f1729c51be018ae2))
|
|
25
|
+
|
|
3
26
|
## [0.4.0](https://github.com/kortyx-io/Kortyx/compare/agent-v0.3.0...agent-v0.4.0) (2026-02-07)
|
|
4
27
|
|
|
5
28
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type StreamChunk } from "@kortyx/stream/browser";
|
|
2
|
+
import type { ChatMessage } from "../types/chat-message";
|
|
3
|
+
export interface StreamChatFromRouteArgs {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
sessionId: string;
|
|
6
|
+
workflowId?: string | undefined;
|
|
7
|
+
messages: ChatMessage[];
|
|
8
|
+
fetchImpl?: typeof fetch;
|
|
9
|
+
headers?: Record<string, string> | undefined;
|
|
10
|
+
}
|
|
11
|
+
export declare function streamChatFromRoute(args: StreamChatFromRouteArgs): AsyncGenerator<StreamChunk, void, void>;
|
|
12
|
+
//# sourceMappingURL=http-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/adapters/http-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAmB,MAAM,wBAAwB,CAAC;AAC3E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAAC;CAC9C;AAED,wBAAuB,mBAAmB,CACxC,IAAI,EAAE,uBAAuB,GAC5B,cAAc,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAWzC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.streamChatFromRoute = streamChatFromRoute;
|
|
4
|
+
const browser_1 = require("@kortyx/stream/browser");
|
|
5
|
+
async function* streamChatFromRoute(args) {
|
|
6
|
+
yield* (0, browser_1.streamFromRoute)({
|
|
7
|
+
endpoint: args.endpoint,
|
|
8
|
+
...(args.fetchImpl ? { fetchImpl: args.fetchImpl } : {}),
|
|
9
|
+
...(args.headers ? { headers: args.headers } : {}),
|
|
10
|
+
body: {
|
|
11
|
+
sessionId: args.sessionId,
|
|
12
|
+
...(args.workflowId ? { workflowId: args.workflowId } : {}),
|
|
13
|
+
messages: args.messages,
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Agent } from "../chat/create-agent";
|
|
2
|
+
import type { ChatMessage } from "../types/chat-message";
|
|
3
|
+
export type ChatRequestBody = {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
workflowId?: string | undefined;
|
|
6
|
+
messages: ChatMessage[];
|
|
7
|
+
};
|
|
8
|
+
export declare function parseChatRequestBody(value: unknown): ChatRequestBody;
|
|
9
|
+
export declare function processChatRequestBody(args: {
|
|
10
|
+
agent: Agent;
|
|
11
|
+
body: ChatRequestBody;
|
|
12
|
+
}): Promise<Response>;
|
|
13
|
+
export declare function createChatRouteHandler(args: {
|
|
14
|
+
agent: Agent;
|
|
15
|
+
errorStatus?: number | undefined;
|
|
16
|
+
}): (request: Request) => Promise<Response>;
|
|
17
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/adapters/http.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,EAAE,WAAW,EAAE,CAAC;CACzB,CAAC;AA4BF,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAapE;AAED,wBAAsB,sBAAsB,CAAC,IAAI,EAAE;IACjD,KAAK,EAAE,KAAK,CAAC;IACb,IAAI,EAAE,eAAe,CAAC;CACvB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAMpB;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE;IAC3C,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAClC,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAqB1C"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseChatRequestBody = parseChatRequestBody;
|
|
4
|
+
exports.processChatRequestBody = processChatRequestBody;
|
|
5
|
+
exports.createChatRouteHandler = createChatRouteHandler;
|
|
6
|
+
const zod_1 = require("zod");
|
|
7
|
+
const chatMessageSchema = zod_1.z
|
|
8
|
+
.object({
|
|
9
|
+
role: zod_1.z.enum(["user", "assistant", "system"]),
|
|
10
|
+
content: zod_1.z.string(),
|
|
11
|
+
metadata: zod_1.z.record(zod_1.z.unknown()).optional(),
|
|
12
|
+
id: zod_1.z.string().optional(),
|
|
13
|
+
timestamp: zod_1.z.number().finite().optional(),
|
|
14
|
+
})
|
|
15
|
+
.strict();
|
|
16
|
+
const chatRequestBodySchema = zod_1.z
|
|
17
|
+
.object({
|
|
18
|
+
sessionId: zod_1.z
|
|
19
|
+
.string()
|
|
20
|
+
.transform((value) => value.trim())
|
|
21
|
+
.refine((value) => value.length > 0, {
|
|
22
|
+
message: "`sessionId` is required.",
|
|
23
|
+
}),
|
|
24
|
+
workflowId: zod_1.z.string().optional(),
|
|
25
|
+
messages: zod_1.z.array(chatMessageSchema),
|
|
26
|
+
})
|
|
27
|
+
.strict();
|
|
28
|
+
const toErrorMessage = (error) => error instanceof Error ? error.message : String(error);
|
|
29
|
+
function parseChatRequestBody(value) {
|
|
30
|
+
const parsed = chatRequestBodySchema.safeParse(value);
|
|
31
|
+
if (!parsed.success) {
|
|
32
|
+
throw new Error(parsed.error.issues[0]?.message ?? "Invalid chat request.");
|
|
33
|
+
}
|
|
34
|
+
const workflowId = parsed.data.workflowId?.trim();
|
|
35
|
+
return {
|
|
36
|
+
sessionId: parsed.data.sessionId,
|
|
37
|
+
...(workflowId ? { workflowId } : {}),
|
|
38
|
+
messages: parsed.data.messages,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function processChatRequestBody(args) {
|
|
42
|
+
const { agent, body } = args;
|
|
43
|
+
return agent.processChat(body.messages, {
|
|
44
|
+
sessionId: body.sessionId,
|
|
45
|
+
...(body.workflowId ? { workflowId: body.workflowId } : {}),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
function createChatRouteHandler(args) {
|
|
49
|
+
const { agent, errorStatus = 400 } = args;
|
|
50
|
+
return async function POST(request) {
|
|
51
|
+
try {
|
|
52
|
+
const body = parseChatRequestBody(await request.json());
|
|
53
|
+
return await processChatRequestBody({ agent, body });
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
return new Response(JSON.stringify({
|
|
57
|
+
error: toErrorMessage(error),
|
|
58
|
+
}), {
|
|
59
|
+
status: errorStatus,
|
|
60
|
+
headers: {
|
|
61
|
+
"content-type": "application/json",
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAGA,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.streamChatFromRoute = void 0;
|
|
4
|
+
var http_client_1 = require("./adapters/http-client");
|
|
5
|
+
Object.defineProperty(exports, "streamChatFromRoute", { enumerable: true, get: function () { return http_client_1.streamChatFromRoute; } });
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type
|
|
1
|
+
import type { WorkflowDefinition } from "@kortyx/core";
|
|
2
|
+
import { type GetProviderFn } from "@kortyx/providers";
|
|
3
|
+
import type { FrameworkAdapter, WorkflowRegistry } from "@kortyx/runtime";
|
|
3
4
|
import type { ChatMessage } from "../types/chat-message";
|
|
4
|
-
|
|
5
|
-
|
|
5
|
+
export interface AgentSessionConfig {
|
|
6
|
+
id?: string | undefined;
|
|
7
|
+
}
|
|
8
|
+
export interface AgentMemoryConfig {
|
|
9
|
+
enabled?: boolean | undefined;
|
|
10
|
+
namespace?: string | undefined;
|
|
11
|
+
ttlMs?: number | undefined;
|
|
12
|
+
}
|
|
13
|
+
export interface AgentProcessOptions {
|
|
14
|
+
sessionId?: string | undefined;
|
|
15
|
+
workflowId?: string | undefined;
|
|
16
|
+
workflow?: string | undefined;
|
|
17
|
+
}
|
|
18
|
+
export interface CreateAgentArgs {
|
|
19
|
+
getProvider?: GetProviderFn | undefined;
|
|
20
|
+
workflows?: WorkflowDefinition[];
|
|
6
21
|
workflowsDir?: string;
|
|
7
22
|
workflowRegistry?: WorkflowRegistry;
|
|
8
|
-
selectWorkflow?: SelectWorkflowFn;
|
|
9
23
|
fallbackWorkflowId?: string;
|
|
10
|
-
|
|
11
|
-
|
|
24
|
+
defaultWorkflowId?: string;
|
|
25
|
+
frameworkAdapter?: FrameworkAdapter;
|
|
26
|
+
session?: AgentSessionConfig;
|
|
27
|
+
memory?: AgentMemoryConfig;
|
|
28
|
+
}
|
|
29
|
+
export interface Agent {
|
|
30
|
+
processChat: (messages: ChatMessage[], options?: AgentProcessOptions) => Promise<Response>;
|
|
12
31
|
}
|
|
13
|
-
export declare function createAgent
|
|
14
|
-
processChat: (messages: ChatMessage[], options?: Options) => Promise<Response>;
|
|
15
|
-
};
|
|
32
|
+
export declare function createAgent(args: CreateAgentArgs): Agent;
|
|
16
33
|
//# sourceMappingURL=create-agent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-agent.d.ts","sourceRoot":"","sources":["../../src/chat/create-agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"create-agent.d.ts","sourceRoot":"","sources":["../../src/chat/create-agent.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,OAAO,EACL,KAAK,aAAa,EAEnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAO1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACzB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IACxC,SAAS,CAAC,EAAE,kBAAkB,EAAE,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,KAAK;IACpB,WAAW,EAAE,CACX,QAAQ,EAAE,WAAW,EAAE,EACvB,OAAO,CAAC,EAAE,mBAAmB,KAC1B,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxB;AA6FD,wBAAgB,WAAW,CAAC,IAAI,EAAE,eAAe,GAAG,KAAK,CA6ExD"}
|
|
@@ -2,69 +2,136 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createAgent = createAgent;
|
|
4
4
|
const node_path_1 = require("node:path");
|
|
5
|
+
const memory_1 = require("@kortyx/memory");
|
|
6
|
+
const providers_1 = require("@kortyx/providers");
|
|
5
7
|
const runtime_1 = require("@kortyx/runtime");
|
|
8
|
+
const zod_1 = require("zod");
|
|
6
9
|
const process_chat_1 = require("./process-chat");
|
|
10
|
+
const agentProcessOptionsSchema = zod_1.z
|
|
11
|
+
.object({
|
|
12
|
+
sessionId: zod_1.z.string().optional(),
|
|
13
|
+
workflowId: zod_1.z.string().optional(),
|
|
14
|
+
workflow: zod_1.z.string().optional(),
|
|
15
|
+
})
|
|
16
|
+
.strict();
|
|
17
|
+
const createAgentArgsBaseSchema = zod_1.z
|
|
18
|
+
.object({
|
|
19
|
+
getProvider: zod_1.z.unknown().optional(),
|
|
20
|
+
workflows: zod_1.z.array(zod_1.z.unknown()).optional(),
|
|
21
|
+
workflowsDir: zod_1.z.string().optional(),
|
|
22
|
+
workflowRegistry: zod_1.z.unknown().optional(),
|
|
23
|
+
fallbackWorkflowId: zod_1.z.string().optional(),
|
|
24
|
+
defaultWorkflowId: zod_1.z.string().optional(),
|
|
25
|
+
frameworkAdapter: zod_1.z.unknown().optional(),
|
|
26
|
+
session: zod_1.z
|
|
27
|
+
.object({
|
|
28
|
+
id: zod_1.z.string().optional(),
|
|
29
|
+
})
|
|
30
|
+
.strict()
|
|
31
|
+
.optional(),
|
|
32
|
+
memory: zod_1.z
|
|
33
|
+
.object({
|
|
34
|
+
enabled: zod_1.z.boolean().optional(),
|
|
35
|
+
namespace: zod_1.z.string().optional(),
|
|
36
|
+
ttlMs: zod_1.z.number().finite().positive().optional(),
|
|
37
|
+
})
|
|
38
|
+
.strict()
|
|
39
|
+
.optional(),
|
|
40
|
+
})
|
|
41
|
+
.strict();
|
|
42
|
+
const createAgentArgsSchema = createAgentArgsBaseSchema.superRefine((value, ctx) => {
|
|
43
|
+
if (value.getProvider !== undefined &&
|
|
44
|
+
typeof value.getProvider !== "function") {
|
|
45
|
+
ctx.addIssue({
|
|
46
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
47
|
+
message: "Expected `args.getProvider` to be a function.",
|
|
48
|
+
path: ["getProvider"],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
const workflowSources = [
|
|
52
|
+
value.workflows !== undefined,
|
|
53
|
+
value.workflowsDir !== undefined,
|
|
54
|
+
value.workflowRegistry !== undefined,
|
|
55
|
+
].filter(Boolean).length;
|
|
56
|
+
if (workflowSources > 1) {
|
|
57
|
+
ctx.addIssue({
|
|
58
|
+
code: zod_1.z.ZodIssueCode.custom,
|
|
59
|
+
message: "Use only one workflow source: `workflows`, `workflowsDir`, or `workflowRegistry`.",
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const parseSchema = (schema, value) => {
|
|
64
|
+
const parsed = schema.safeParse(value);
|
|
65
|
+
if (parsed.success)
|
|
66
|
+
return parsed.data;
|
|
67
|
+
const firstIssue = parsed.error.issues[0];
|
|
68
|
+
throw new Error(firstIssue?.message ?? "Invalid configuration.");
|
|
69
|
+
};
|
|
70
|
+
const parseCreateAgentArgs = (value) => parseSchema(createAgentArgsSchema, value);
|
|
71
|
+
const parseAgentProcessOptions = (value) => {
|
|
72
|
+
if (value === undefined)
|
|
73
|
+
return undefined;
|
|
74
|
+
return parseSchema(agentProcessOptionsSchema, value);
|
|
75
|
+
};
|
|
76
|
+
const resolveMemoryAdapter = (memory) => {
|
|
77
|
+
if (memory?.enabled === false)
|
|
78
|
+
return undefined;
|
|
79
|
+
return (0, memory_1.createInMemoryAdapter)({
|
|
80
|
+
namespace: memory?.namespace ?? "kortyx-agent",
|
|
81
|
+
ttlMs: memory?.ttlMs ?? 1000 * 60 * 60,
|
|
82
|
+
});
|
|
83
|
+
};
|
|
7
84
|
function createAgent(args) {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
85
|
+
const parsedArgs = parseCreateAgentArgs(args);
|
|
86
|
+
const { getProvider, workflows, workflowsDir, workflowRegistry, fallbackWorkflowId, defaultWorkflowId, frameworkAdapter, session, memory, } = parsedArgs;
|
|
87
|
+
const resolvedDefaultWorkflowId = defaultWorkflowId ?? fallbackWorkflowId;
|
|
10
88
|
const resolvedFrameworkAdapter = frameworkAdapter ?? (0, runtime_1.createFrameworkAdapterFromEnv)();
|
|
89
|
+
const defaultSessionId = session?.id ?? "anonymous-session";
|
|
90
|
+
const memoryAdapter = resolveMemoryAdapter(memory);
|
|
91
|
+
const resolvedGetProvider = getProvider ?? providers_1.getProvider;
|
|
11
92
|
const resolvedCwd = process.cwd();
|
|
12
93
|
const registryPromise = (async () => {
|
|
13
94
|
if (workflowRegistry)
|
|
14
95
|
return workflowRegistry;
|
|
96
|
+
if (workflows) {
|
|
97
|
+
return (0, runtime_1.createInMemoryWorkflowRegistry)(workflows, {
|
|
98
|
+
fallbackId: fallbackWorkflowId ?? "general-chat",
|
|
99
|
+
});
|
|
100
|
+
}
|
|
15
101
|
if (workflowsDir) {
|
|
16
102
|
return (0, runtime_1.createFileWorkflowRegistry)({
|
|
17
103
|
workflowsDir,
|
|
18
104
|
fallbackId: fallbackWorkflowId ?? "general-chat",
|
|
19
105
|
});
|
|
20
106
|
}
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
...(configPath ? { configPath } : {}),
|
|
24
|
-
};
|
|
25
|
-
const loadedConfig = config ?? (await (0, runtime_1.loadKortyxConfig)(loadConfigArgs));
|
|
26
|
-
const resolvedWorkflowsDir = loadedConfig?.workflowsDir ?? (0, node_path_1.resolve)(resolvedCwd, "src", "workflows");
|
|
27
|
-
const registryOptions = {
|
|
107
|
+
const resolvedWorkflowsDir = (0, node_path_1.resolve)(resolvedCwd, "src", "workflows");
|
|
108
|
+
return (0, runtime_1.createFileWorkflowRegistry)({
|
|
28
109
|
workflowsDir: resolvedWorkflowsDir,
|
|
29
|
-
fallbackId:
|
|
30
|
-
|
|
31
|
-
"general-chat",
|
|
32
|
-
...(loadedConfig?.registry?.cache !== undefined
|
|
33
|
-
? { cache: loadedConfig.registry.cache }
|
|
34
|
-
: {}),
|
|
35
|
-
...(loadedConfig?.registry?.extensions
|
|
36
|
-
? { extensions: loadedConfig.registry.extensions }
|
|
37
|
-
: {}),
|
|
38
|
-
};
|
|
39
|
-
return (0, runtime_1.createFileWorkflowRegistry)(registryOptions);
|
|
110
|
+
fallbackId: fallbackWorkflowId ?? "general-chat",
|
|
111
|
+
});
|
|
40
112
|
})();
|
|
41
113
|
return {
|
|
42
114
|
processChat: async (messages, options) => {
|
|
43
|
-
|
|
44
|
-
return (0, process_chat_1.processChat)({
|
|
45
|
-
...baseArgs,
|
|
46
|
-
...(resolvedDefaultWorkflowId
|
|
47
|
-
? { defaultWorkflowId: resolvedDefaultWorkflowId }
|
|
48
|
-
: {}),
|
|
49
|
-
messages,
|
|
50
|
-
options,
|
|
51
|
-
selectWorkflow,
|
|
52
|
-
frameworkAdapter: resolvedFrameworkAdapter,
|
|
53
|
-
});
|
|
54
|
-
}
|
|
115
|
+
const parsedOptions = parseAgentProcessOptions(options);
|
|
55
116
|
const registry = await registryPromise;
|
|
56
117
|
if (!registry) {
|
|
57
|
-
throw new Error("createAgent requires
|
|
118
|
+
throw new Error("createAgent requires workflows, workflowsDir, or workflowRegistry.");
|
|
58
119
|
}
|
|
59
120
|
return (0, process_chat_1.processChat)({
|
|
60
|
-
...baseArgs,
|
|
61
121
|
...(resolvedDefaultWorkflowId
|
|
62
122
|
? { defaultWorkflowId: resolvedDefaultWorkflowId }
|
|
63
123
|
: {}),
|
|
64
124
|
messages,
|
|
65
|
-
options,
|
|
125
|
+
options: parsedOptions,
|
|
66
126
|
workflowRegistry: registry,
|
|
67
127
|
frameworkAdapter: resolvedFrameworkAdapter,
|
|
128
|
+
getProvider: resolvedGetProvider,
|
|
129
|
+
...(memoryAdapter ? { memoryAdapter } : {}),
|
|
130
|
+
loadRuntimeConfig: (runtimeOptions) => ({
|
|
131
|
+
session: {
|
|
132
|
+
id: runtimeOptions?.sessionId ?? defaultSessionId,
|
|
133
|
+
},
|
|
134
|
+
}),
|
|
68
135
|
});
|
|
69
136
|
},
|
|
70
137
|
};
|
|
@@ -4,23 +4,24 @@ import type { FrameworkAdapter, WorkflowRegistry } from "@kortyx/runtime";
|
|
|
4
4
|
import type { ApplyResumeSelection } from "../interrupt/resume-handler";
|
|
5
5
|
import type { SelectWorkflowFn } from "../orchestrator";
|
|
6
6
|
import type { ChatMessage } from "../types/chat-message";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
export interface RuntimeConfig {
|
|
8
|
+
session?: {
|
|
9
|
+
id?: string;
|
|
10
|
+
};
|
|
11
|
+
[key: string]: unknown;
|
|
12
|
+
}
|
|
13
|
+
export interface ProcessChatArgs<Options> {
|
|
11
14
|
messages: ChatMessage[];
|
|
12
15
|
options?: Options | undefined;
|
|
13
16
|
sessionId?: string;
|
|
14
17
|
defaultWorkflowId?: string;
|
|
15
|
-
loadRuntimeConfig: (options?: Options) =>
|
|
18
|
+
loadRuntimeConfig: (options?: Options) => RuntimeConfig | Promise<RuntimeConfig>;
|
|
16
19
|
selectWorkflow?: SelectWorkflowFn;
|
|
17
20
|
workflowRegistry?: WorkflowRegistry;
|
|
18
21
|
frameworkAdapter?: FrameworkAdapter;
|
|
19
22
|
getProvider: GetProviderFn;
|
|
20
|
-
initializeProviders?: InitializeProvidersFn<Config>;
|
|
21
23
|
memoryAdapter?: MemoryAdapter;
|
|
22
24
|
applyResumeSelection?: ApplyResumeSelection;
|
|
23
25
|
}
|
|
24
|
-
export declare function processChat<
|
|
25
|
-
export {};
|
|
26
|
+
export declare function processChat<Options = unknown>({ messages, options, sessionId, defaultWorkflowId, loadRuntimeConfig, selectWorkflow, workflowRegistry, frameworkAdapter, getProvider, memoryAdapter, applyResumeSelection, }: ProcessChatArgs<Options>): Promise<Response>;
|
|
26
27
|
//# sourceMappingURL=process-chat.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"process-chat.d.ts","sourceRoot":"","sources":["../../src/chat/process-chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAO1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAKxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,
|
|
1
|
+
{"version":3,"file":"process-chat.d.ts","sourceRoot":"","sources":["../../src/chat/process-chat.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAO1E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAKxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,eAAe,CAAC,OAAO;IACtC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,CACjB,OAAO,CAAC,EAAE,OAAO,KACd,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;IAC5C,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,WAAW,EAAE,aAAa,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,oBAAoB,CAAC;CAC7C;AAED,wBAAsB,WAAW,CAAC,OAAO,GAAG,OAAO,EAAE,EACnD,QAAQ,EACR,OAAO,EACP,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,WAAW,EACX,aAAa,EACb,oBAAoB,GACrB,EAAE,eAAe,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqF9C"}
|
|
@@ -6,14 +6,8 @@ const stream_1 = require("@kortyx/stream");
|
|
|
6
6
|
const resume_handler_1 = require("../interrupt/resume-handler");
|
|
7
7
|
const orchestrator_1 = require("../orchestrator");
|
|
8
8
|
const extract_latest_message_1 = require("../utils/extract-latest-message");
|
|
9
|
-
async function processChat({ messages, options, sessionId, defaultWorkflowId, loadRuntimeConfig, selectWorkflow, workflowRegistry, frameworkAdapter, getProvider,
|
|
9
|
+
async function processChat({ messages, options, sessionId, defaultWorkflowId, loadRuntimeConfig, selectWorkflow, workflowRegistry, frameworkAdapter, getProvider, memoryAdapter, applyResumeSelection, }) {
|
|
10
10
|
const config = await loadRuntimeConfig(options);
|
|
11
|
-
if (initializeProviders) {
|
|
12
|
-
const ai = config.ai;
|
|
13
|
-
initializeProviders((ai && typeof ai === "object" && !Array.isArray(ai)
|
|
14
|
-
? ai
|
|
15
|
-
: {}));
|
|
16
|
-
}
|
|
17
11
|
const runtimeConfig = {
|
|
18
12
|
...config,
|
|
19
13
|
getProvider,
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
export type {
|
|
1
|
+
export type { ChatRequestBody } from "./adapters/http";
|
|
2
|
+
export { createChatRouteHandler, parseChatRequestBody, processChatRequestBody, } from "./adapters/http";
|
|
3
|
+
export type { StreamChatFromRouteArgs } from "./adapters/http-client";
|
|
4
|
+
export { streamChatFromRoute } from "./adapters/http-client";
|
|
5
|
+
export type { Agent, AgentMemoryConfig, AgentProcessOptions, AgentSessionConfig, CreateAgentArgs, } from "./chat/create-agent";
|
|
2
6
|
export { createAgent } from "./chat/create-agent";
|
|
3
7
|
export type { ProcessChatArgs } from "./chat/process-chat";
|
|
4
8
|
export { processChat } from "./chat/process-chat";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAC7D,YAAY,EACV,KAAK,EACL,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,YAAY,EACV,oBAAoB,EACpB,UAAU,GACX,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,eAAe,EACf,sBAAsB,GACvB,MAAM,4BAA4B,CAAC;AACpC,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,sBAAsB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gCAAgC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.extractLatestUserMessage = exports.transformGraphStreamForUI = exports.orchestrateGraphStream = exports.tryPrepareResumeStream = exports.parseResumeMeta = exports.processChat = exports.createAgent = void 0;
|
|
3
|
+
exports.extractLatestUserMessage = exports.transformGraphStreamForUI = exports.orchestrateGraphStream = exports.tryPrepareResumeStream = exports.parseResumeMeta = exports.processChat = exports.createAgent = exports.streamChatFromRoute = exports.processChatRequestBody = exports.parseChatRequestBody = exports.createChatRouteHandler = void 0;
|
|
4
|
+
var http_1 = require("./adapters/http");
|
|
5
|
+
Object.defineProperty(exports, "createChatRouteHandler", { enumerable: true, get: function () { return http_1.createChatRouteHandler; } });
|
|
6
|
+
Object.defineProperty(exports, "parseChatRequestBody", { enumerable: true, get: function () { return http_1.parseChatRequestBody; } });
|
|
7
|
+
Object.defineProperty(exports, "processChatRequestBody", { enumerable: true, get: function () { return http_1.processChatRequestBody; } });
|
|
8
|
+
var http_client_1 = require("./adapters/http-client");
|
|
9
|
+
Object.defineProperty(exports, "streamChatFromRoute", { enumerable: true, get: function () { return http_client_1.streamChatFromRoute; } });
|
|
4
10
|
var create_agent_1 = require("./chat/create-agent");
|
|
5
11
|
Object.defineProperty(exports, "createAgent", { enumerable: true, get: function () { return create_agent_1.createAgent; } });
|
|
6
12
|
var process_chat_1 = require("./chat/process-chat");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAc,MAAM,cAAc,CAAC;AAC/E,OAAO,EAEL,KAAK,gBAAgB,EAKtB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,gBAAgB,GAAG,CAC7B,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEjC,MAAM,MAAM,YAAY,GAAG,CACzB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,CACZ,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACnE,aAAa,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,cAAc,EAAE,gBAAgB,CAAC;IACjC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../src/orchestrator.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,kBAAkB,EAAc,MAAM,cAAc,CAAC;AAC/E,OAAO,EAEL,KAAK,gBAAgB,EAKtB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,gBAAgB,GAAG,CAC7B,UAAU,EAAE,MAAM,KACf,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAEjC,MAAM,MAAM,YAAY,GAAG,CACzB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,UAAU,KACd,OAAO,CAAC,IAAI,CAAC,CAAC;AAEnB,MAAM,WAAW,iBAAiB;IAChC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,YAAY,EAAE,CACZ,KAAK,EAAE,UAAU,EACjB,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,KACnE,aAAa,CAAC,OAAO,CAAC,GAAG,cAAc,CAAC,OAAO,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,iBAAiB,CAAC;IACzB,KAAK,EAAE,UAAU,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,cAAc,EAAE,gBAAgB,CAAC;IACjC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAMD,wBAAsB,sBAAsB,CAAC,EAC3C,SAAS,EACT,KAAK,EACL,KAAK,EACL,KAAK,EACL,MAAM,EACN,cAAc,EACd,gBAAgB,GACjB,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,CAgZlD"}
|
package/dist/orchestrator.js
CHANGED
|
@@ -10,6 +10,7 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
10
10
|
let currentGraph = graph;
|
|
11
11
|
let currentState = state;
|
|
12
12
|
let finished = false;
|
|
13
|
+
const debugEnabled = Boolean(config?.features?.tracing);
|
|
13
14
|
const namespacesUsed = new Set();
|
|
14
15
|
try {
|
|
15
16
|
const sid = config?.session?.id;
|
|
@@ -22,7 +23,6 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
22
23
|
to: null,
|
|
23
24
|
payload: {},
|
|
24
25
|
};
|
|
25
|
-
const streamedNodes = new Set();
|
|
26
26
|
let lastStatusMsg = "";
|
|
27
27
|
let lastStatusAt = 0;
|
|
28
28
|
let pendingRecordToken = null;
|
|
@@ -30,6 +30,70 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
30
30
|
let wroteHumanInput = false;
|
|
31
31
|
const pendingStore = frameworkAdapter?.pendingRequests;
|
|
32
32
|
const pendingTtlMs = frameworkAdapter?.ttlMs ?? 15 * 60 * 1000;
|
|
33
|
+
const persistAndEmitInterrupt = async (payload) => {
|
|
34
|
+
if (activeIsResume || wroteHumanInput)
|
|
35
|
+
return;
|
|
36
|
+
const token = (0, runtime_1.makeResumeToken)();
|
|
37
|
+
const requestId = (0, runtime_1.makeRequestId)("human");
|
|
38
|
+
pendingRecordToken = token;
|
|
39
|
+
const input = payload.input ?? {};
|
|
40
|
+
const optionsList = Array.isArray(input.options) ? input.options : [];
|
|
41
|
+
const kind = input.kind || (input.multiple ? "multi-choice" : "choice");
|
|
42
|
+
const isText = kind === "text";
|
|
43
|
+
const record = {
|
|
44
|
+
token,
|
|
45
|
+
requestId,
|
|
46
|
+
sessionId,
|
|
47
|
+
runId,
|
|
48
|
+
workflow: payload.workflow || currentState.currentWorkflow,
|
|
49
|
+
node: payload.node || "",
|
|
50
|
+
state: { ...currentState, awaitingHumanInput: true },
|
|
51
|
+
schema: isText
|
|
52
|
+
? {
|
|
53
|
+
kind: kind,
|
|
54
|
+
multiple: Boolean(input.multiple),
|
|
55
|
+
...(input.question ? { question: input.question } : {}),
|
|
56
|
+
}
|
|
57
|
+
: {
|
|
58
|
+
kind: kind,
|
|
59
|
+
multiple: Boolean(input.multiple),
|
|
60
|
+
question: String(input.question || "Please choose an option."),
|
|
61
|
+
},
|
|
62
|
+
options: optionsList.map((option) => ({
|
|
63
|
+
id: String(option.id),
|
|
64
|
+
label: String(option.label),
|
|
65
|
+
description: typeof option.description === "string"
|
|
66
|
+
? option.description
|
|
67
|
+
: undefined,
|
|
68
|
+
value: option.value,
|
|
69
|
+
})),
|
|
70
|
+
createdAt: Date.now(),
|
|
71
|
+
ttlMs: pendingTtlMs,
|
|
72
|
+
};
|
|
73
|
+
if (pendingStore) {
|
|
74
|
+
pendingStore.save(record).catch((error) => {
|
|
75
|
+
console.error("[orchestrator] failed to save pending request", error);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
out.write({
|
|
79
|
+
type: "interrupt",
|
|
80
|
+
requestId: record.requestId,
|
|
81
|
+
resumeToken: record.token,
|
|
82
|
+
workflow: record.workflow,
|
|
83
|
+
node: record.node,
|
|
84
|
+
input: {
|
|
85
|
+
kind: record.schema.kind,
|
|
86
|
+
multiple: record.schema.multiple,
|
|
87
|
+
question: record.schema.question,
|
|
88
|
+
options: record.options.map((option) => ({
|
|
89
|
+
id: option.id,
|
|
90
|
+
label: option.label,
|
|
91
|
+
description: option.description,
|
|
92
|
+
})),
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
wroteHumanInput = true;
|
|
96
|
+
};
|
|
33
97
|
const forwardEmit = (event, payload) => {
|
|
34
98
|
if (event === "error") {
|
|
35
99
|
const msg = String(payload?.message ?? "Unexpected error");
|
|
@@ -40,6 +104,8 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
40
104
|
return;
|
|
41
105
|
}
|
|
42
106
|
if (event === "status") {
|
|
107
|
+
if (!debugEnabled)
|
|
108
|
+
return;
|
|
43
109
|
const msg = String(payload?.message ?? "");
|
|
44
110
|
const now = Date.now();
|
|
45
111
|
if (msg && msg === lastStatusMsg && now - lastStatusAt < 250)
|
|
@@ -54,7 +120,6 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
54
120
|
if (!node)
|
|
55
121
|
return;
|
|
56
122
|
out.write({ type: "text-start", node });
|
|
57
|
-
streamedNodes.add(node);
|
|
58
123
|
return;
|
|
59
124
|
}
|
|
60
125
|
if (event === "text-delta") {
|
|
@@ -63,7 +128,6 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
63
128
|
if (!node || !delta)
|
|
64
129
|
return;
|
|
65
130
|
out.write({ type: "text-delta", delta, node });
|
|
66
|
-
streamedNodes.add(node);
|
|
67
131
|
return;
|
|
68
132
|
}
|
|
69
133
|
if (event === "text-end") {
|
|
@@ -100,81 +164,15 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
100
164
|
return;
|
|
101
165
|
}
|
|
102
166
|
if (event === "interrupt") {
|
|
103
|
-
if (activeIsResume)
|
|
104
|
-
return;
|
|
105
|
-
try {
|
|
106
|
-
const p = payload;
|
|
107
|
-
console.log(`[orchestrator] interrupt node=${p?.node} workflow=${p?.workflow} options=${Array.isArray(p?.input?.options) ? p.input.options.length : 0}`);
|
|
108
|
-
}
|
|
109
|
-
catch { }
|
|
110
167
|
const p = payload;
|
|
111
168
|
const local = {
|
|
112
169
|
node: p?.node,
|
|
113
170
|
workflow: p?.workflow,
|
|
114
171
|
input: p?.input,
|
|
115
172
|
};
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
pendingRecordToken = token;
|
|
119
|
-
const options = Array.isArray(local.input?.options)
|
|
120
|
-
? local.input.options
|
|
121
|
-
: [];
|
|
122
|
-
const kind = local.input?.kind ||
|
|
123
|
-
(local.input?.multiple ? "multi-choice" : "choice");
|
|
124
|
-
const isText = kind === "text";
|
|
125
|
-
const record = {
|
|
126
|
-
token,
|
|
127
|
-
requestId,
|
|
128
|
-
sessionId: sessionId,
|
|
129
|
-
runId,
|
|
130
|
-
workflow: local.workflow || currentState.currentWorkflow,
|
|
131
|
-
node: local.node || "",
|
|
132
|
-
state: { ...currentState, awaitingHumanInput: true },
|
|
133
|
-
schema: isText
|
|
134
|
-
? {
|
|
135
|
-
kind: kind,
|
|
136
|
-
multiple: Boolean(local.input?.multiple),
|
|
137
|
-
...(local.input?.question
|
|
138
|
-
? { question: local.input.question }
|
|
139
|
-
: {}),
|
|
140
|
-
}
|
|
141
|
-
: {
|
|
142
|
-
kind: kind,
|
|
143
|
-
multiple: Boolean(local.input?.multiple),
|
|
144
|
-
question: String(local.input?.question || "Please choose an option."),
|
|
145
|
-
},
|
|
146
|
-
options: options.map((o) => ({
|
|
147
|
-
id: String(o.id),
|
|
148
|
-
label: String(o.label),
|
|
149
|
-
description: typeof o.description === "string" ? o.description : undefined,
|
|
150
|
-
value: o.value,
|
|
151
|
-
})),
|
|
152
|
-
createdAt: Date.now(),
|
|
153
|
-
ttlMs: pendingTtlMs,
|
|
154
|
-
};
|
|
155
|
-
if (pendingStore) {
|
|
156
|
-
pendingStore.save(record).catch((e) => {
|
|
157
|
-
console.error("[orchestrator] failed to save pending request", e);
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
out.write({
|
|
161
|
-
type: "interrupt",
|
|
162
|
-
requestId: record.requestId,
|
|
163
|
-
resumeToken: record.token,
|
|
164
|
-
workflow: record.workflow,
|
|
165
|
-
node: record.node,
|
|
166
|
-
input: {
|
|
167
|
-
kind: record.schema.kind,
|
|
168
|
-
multiple: record.schema.multiple,
|
|
169
|
-
question: record.schema.question,
|
|
170
|
-
options: record.options.map((o) => ({
|
|
171
|
-
id: o.id,
|
|
172
|
-
label: o.label,
|
|
173
|
-
description: o.description,
|
|
174
|
-
})),
|
|
175
|
-
},
|
|
173
|
+
void persistAndEmitInterrupt(local).catch((error) => {
|
|
174
|
+
console.error("[orchestrator] failed to emit interrupt", error);
|
|
176
175
|
});
|
|
177
|
-
wroteHumanInput = true;
|
|
178
176
|
return;
|
|
179
177
|
}
|
|
180
178
|
};
|
|
@@ -188,10 +186,12 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
188
186
|
"anonymous-session";
|
|
189
187
|
const checkpointNs = String(currentState.currentWorkflow || "default");
|
|
190
188
|
namespacesUsed.add(checkpointNs);
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
189
|
+
if (debugEnabled) {
|
|
190
|
+
out.write({
|
|
191
|
+
type: "status",
|
|
192
|
+
message: `🧵 thread_id=${threadId} run_id=${runId} workflow=${currentState.currentWorkflow}`,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
195
|
const isResume = Boolean(currentGraph.config?.resume);
|
|
196
196
|
activeIsResume = isResume;
|
|
197
197
|
const resumeUpdate = currentGraph.config?.resumeUpdate;
|
|
@@ -210,119 +210,20 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
210
210
|
checkpoint_ns: checkpointNs,
|
|
211
211
|
},
|
|
212
212
|
});
|
|
213
|
-
|
|
213
|
+
if (debugEnabled) {
|
|
214
214
|
out.write({
|
|
215
215
|
type: "status",
|
|
216
216
|
message: `▶️ streamEvents invoke: resume=${Boolean(currentGraph.config?.resume)} thread_id=${threadId} run_id=${runId} ns=${String(currentState.currentWorkflow || "default")}`,
|
|
217
217
|
});
|
|
218
218
|
}
|
|
219
|
-
catch { }
|
|
220
219
|
const uiStream = (0, transform_graph_stream_for_ui_1.transformGraphStreamForUI)(runtimeStream, {
|
|
221
|
-
debug:
|
|
220
|
+
debug: debugEnabled,
|
|
221
|
+
emitStatus: debugEnabled,
|
|
222
222
|
});
|
|
223
|
-
let loopTransitionTo = null;
|
|
224
|
-
let loopTransitionPayload = {};
|
|
225
223
|
for await (const chunk of uiStream) {
|
|
226
224
|
if (finished)
|
|
227
225
|
break;
|
|
228
|
-
|
|
229
|
-
if (chunk.type === "interrupt" &&
|
|
230
|
-
(!chunk.resumeToken || !chunk.requestId)) {
|
|
231
|
-
if (wroteHumanInput) {
|
|
232
|
-
continue;
|
|
233
|
-
}
|
|
234
|
-
const hi = chunk;
|
|
235
|
-
const token = (0, runtime_1.makeResumeToken)();
|
|
236
|
-
const requestId = (0, runtime_1.makeRequestId)("human");
|
|
237
|
-
pendingRecordToken = token;
|
|
238
|
-
const options = Array.isArray(hi.input?.options)
|
|
239
|
-
? hi.input.options
|
|
240
|
-
: [];
|
|
241
|
-
const kind = hi.input?.kind || (hi.input?.multiple ? "multi-choice" : "choice");
|
|
242
|
-
const isText = kind === "text";
|
|
243
|
-
const record = {
|
|
244
|
-
token,
|
|
245
|
-
requestId,
|
|
246
|
-
sessionId: sessionId,
|
|
247
|
-
runId,
|
|
248
|
-
workflow: currentState.currentWorkflow,
|
|
249
|
-
node: node || "",
|
|
250
|
-
state: {
|
|
251
|
-
...currentState,
|
|
252
|
-
awaitingHumanInput: true,
|
|
253
|
-
},
|
|
254
|
-
schema: isText
|
|
255
|
-
? {
|
|
256
|
-
kind: kind,
|
|
257
|
-
multiple: Boolean(hi.input?.multiple),
|
|
258
|
-
...(hi.input?.question
|
|
259
|
-
? { question: hi.input.question }
|
|
260
|
-
: {}),
|
|
261
|
-
}
|
|
262
|
-
: {
|
|
263
|
-
kind: kind,
|
|
264
|
-
multiple: Boolean(hi.input?.multiple),
|
|
265
|
-
question: String(hi.input?.question || "Please choose an option."),
|
|
266
|
-
},
|
|
267
|
-
options: options.map((o) => ({
|
|
268
|
-
id: String(o.id),
|
|
269
|
-
label: String(o.label),
|
|
270
|
-
description: typeof o.description === "string" ? o.description : undefined,
|
|
271
|
-
value: o.value,
|
|
272
|
-
})),
|
|
273
|
-
createdAt: Date.now(),
|
|
274
|
-
ttlMs: pendingTtlMs,
|
|
275
|
-
};
|
|
276
|
-
if (pendingStore) {
|
|
277
|
-
await pendingStore.save(record);
|
|
278
|
-
}
|
|
279
|
-
out.write({
|
|
280
|
-
type: "interrupt",
|
|
281
|
-
requestId,
|
|
282
|
-
resumeToken: token,
|
|
283
|
-
workflow: record.workflow,
|
|
284
|
-
node: record.node,
|
|
285
|
-
input: {
|
|
286
|
-
kind: record.schema.kind,
|
|
287
|
-
multiple: record.schema.multiple,
|
|
288
|
-
question: record.schema.question,
|
|
289
|
-
options: record.options.map((o) => ({
|
|
290
|
-
id: o.id,
|
|
291
|
-
label: o.label,
|
|
292
|
-
description: o.description,
|
|
293
|
-
})),
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
wroteHumanInput = true;
|
|
297
|
-
continue;
|
|
298
|
-
}
|
|
299
|
-
if (chunk.type === "text-delta") {
|
|
300
|
-
if (typeof chunk.delta === "string" && chunk.delta.length > 60) {
|
|
301
|
-
const text = chunk.delta;
|
|
302
|
-
for (let i = 0; i < text.length; i += 60) {
|
|
303
|
-
out.write({
|
|
304
|
-
type: "text-delta",
|
|
305
|
-
delta: text.slice(i, i + 60),
|
|
306
|
-
node,
|
|
307
|
-
});
|
|
308
|
-
}
|
|
309
|
-
if (node)
|
|
310
|
-
streamedNodes.add(node);
|
|
311
|
-
}
|
|
312
|
-
else {
|
|
313
|
-
out.write(chunk);
|
|
314
|
-
if (node)
|
|
315
|
-
streamedNodes.add(node);
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
else {
|
|
319
|
-
out.write(chunk);
|
|
320
|
-
}
|
|
321
|
-
if (chunk.type === "transition") {
|
|
322
|
-
loopTransitionTo = String(chunk.transitionTo || "");
|
|
323
|
-
loopTransitionPayload = chunk.payload ?? {};
|
|
324
|
-
break;
|
|
325
|
-
}
|
|
226
|
+
out.write(chunk);
|
|
326
227
|
if (chunk.type === "done") {
|
|
327
228
|
workflowFinalState = chunk.data ?? null;
|
|
328
229
|
break;
|
|
@@ -330,10 +231,8 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
330
231
|
}
|
|
331
232
|
if (finished)
|
|
332
233
|
return;
|
|
333
|
-
const transitionTo =
|
|
334
|
-
const transitionPayload =
|
|
335
|
-
? loopTransitionPayload
|
|
336
|
-
: pending.payload;
|
|
234
|
+
const transitionTo = pending.to;
|
|
235
|
+
const transitionPayload = pending.payload;
|
|
337
236
|
pending.to = null;
|
|
338
237
|
pending.payload = {};
|
|
339
238
|
if (transitionTo) {
|
|
@@ -363,9 +262,10 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
363
262
|
}
|
|
364
263
|
catch (err) {
|
|
365
264
|
out.write({
|
|
366
|
-
type: "
|
|
367
|
-
message:
|
|
265
|
+
type: "error",
|
|
266
|
+
message: `Transition failed to '${transitionTo}': ${err instanceof Error ? err.message : String(err)}`,
|
|
368
267
|
});
|
|
268
|
+
out.write({ type: "done" });
|
|
369
269
|
out.end();
|
|
370
270
|
return;
|
|
371
271
|
}
|
|
@@ -410,7 +310,11 @@ async function orchestrateGraphStream({ sessionId, runId, graph, state, config,
|
|
|
410
310
|
}
|
|
411
311
|
})().catch((err) => {
|
|
412
312
|
console.error("[error:orchestrateGraphStream]", err);
|
|
413
|
-
out.write({
|
|
313
|
+
out.write({
|
|
314
|
+
type: "error",
|
|
315
|
+
message: err instanceof Error ? err.message : String(err),
|
|
316
|
+
});
|
|
317
|
+
out.write({ type: "done" });
|
|
414
318
|
out.end();
|
|
415
319
|
});
|
|
416
320
|
return out;
|
|
@@ -2,8 +2,7 @@ import type { StreamChunk } from "@kortyx/stream";
|
|
|
2
2
|
import type { StreamEvent } from "@langchain/core/tracers/log_stream";
|
|
3
3
|
interface TransformOptions {
|
|
4
4
|
debug?: boolean;
|
|
5
|
-
|
|
6
|
-
forwardModelStream?: boolean;
|
|
5
|
+
emitStatus?: boolean;
|
|
7
6
|
}
|
|
8
7
|
export declare function transformGraphStreamForUI(stream: AsyncIterable<StreamEvent>, options?: TransformOptions): AsyncGenerator<StreamChunk>;
|
|
9
8
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transform-graph-stream-for-ui.d.ts","sourceRoot":"","sources":["../../src/stream/transform-graph-stream-for-ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"transform-graph-stream-for-ui.d.ts","sourceRoot":"","sources":["../../src/stream/transform-graph-stream-for-ui.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAEtE,UAAU,gBAAgB;IACxB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAQD,wBAAuB,yBAAyB,CAC9C,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,EAClC,OAAO,GAAE,gBAAqB,GAC7B,cAAc,CAAC,WAAW,CAAC,CA6D7B"}
|
|
@@ -1,32 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.transformGraphStreamForUI = transformGraphStreamForUI;
|
|
4
|
-
const utils_1 = require("@kortyx/utils");
|
|
5
4
|
async function* transformGraphStreamForUI(stream, options = {}) {
|
|
6
|
-
const { debug = false,
|
|
7
|
-
let currentNode = null;
|
|
8
|
-
const streamedTextByNode = new Map();
|
|
5
|
+
const { debug = false, emitStatus = debug } = options;
|
|
9
6
|
const startedNodes = new Set();
|
|
10
7
|
const endedNodes = new Set();
|
|
11
|
-
let sawInterrupt = false;
|
|
12
|
-
function findChoiceSchema(obj) {
|
|
13
|
-
try {
|
|
14
|
-
if (!obj || typeof obj !== "object")
|
|
15
|
-
return null;
|
|
16
|
-
if (typeof obj.kind === "string" &&
|
|
17
|
-
(obj.kind === "choice" || obj.kind === "multi-choice") &&
|
|
18
|
-
Array.isArray(obj.options)) {
|
|
19
|
-
return obj;
|
|
20
|
-
}
|
|
21
|
-
for (const v of Object.values(obj)) {
|
|
22
|
-
const inner = findChoiceSchema(v);
|
|
23
|
-
if (inner)
|
|
24
|
-
return inner;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch { }
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
8
|
for await (const event of stream) {
|
|
31
9
|
const { event: type, name, data } = event ?? {};
|
|
32
10
|
if (debug)
|
|
@@ -34,7 +12,6 @@ async function* transformGraphStreamForUI(stream, options = {}) {
|
|
|
34
12
|
switch (type) {
|
|
35
13
|
case "on_chain_start":
|
|
36
14
|
if (name && !name.startsWith("ChannelWrite")) {
|
|
37
|
-
currentNode = name;
|
|
38
15
|
if (name === "__start__" || name === "__end__")
|
|
39
16
|
break;
|
|
40
17
|
if (startedNodes.has(name))
|
|
@@ -42,67 +19,8 @@ async function* transformGraphStreamForUI(stream, options = {}) {
|
|
|
42
19
|
startedNodes.add(name);
|
|
43
20
|
if (debug)
|
|
44
21
|
console.log(`[debug:start] node=${name}`);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
break;
|
|
48
|
-
case "on_graph_interrupt": {
|
|
49
|
-
sawInterrupt = true;
|
|
50
|
-
if (debug)
|
|
51
|
-
console.log(`[debug:on_graph_interrupt]`, JSON.stringify({ name, data }, null, 2));
|
|
52
|
-
const where = (typeof name === "string" && name) ||
|
|
53
|
-
data?.node ||
|
|
54
|
-
"unknown";
|
|
55
|
-
const schema = findChoiceSchema(data);
|
|
56
|
-
if (schema) {
|
|
57
|
-
const isText = schema.kind === "text";
|
|
58
|
-
const options = Array.isArray(schema.options)
|
|
59
|
-
? schema.options
|
|
60
|
-
.map((o) => ({
|
|
61
|
-
id: String(o.id ?? ""),
|
|
62
|
-
label: String(o.label ?? ""),
|
|
63
|
-
...(o.description
|
|
64
|
-
? { description: String(o.description) }
|
|
65
|
-
: {}),
|
|
66
|
-
}))
|
|
67
|
-
.filter((o) => o.id && o.label)
|
|
68
|
-
: [];
|
|
69
|
-
yield {
|
|
70
|
-
type: "interrupt",
|
|
71
|
-
requestId: "",
|
|
72
|
-
resumeToken: "",
|
|
73
|
-
node: typeof where === "string" ? where : undefined,
|
|
74
|
-
input: {
|
|
75
|
-
kind: schema.kind,
|
|
76
|
-
multiple: Boolean(schema.multiple),
|
|
77
|
-
...(isText
|
|
78
|
-
? { question: schema.question }
|
|
79
|
-
: {
|
|
80
|
-
question: typeof schema.question === "string"
|
|
81
|
-
? schema.question
|
|
82
|
-
: "Please choose",
|
|
83
|
-
}),
|
|
84
|
-
...(options.length > 0 ? { options } : {}),
|
|
85
|
-
},
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
yield { type: "status", message: `⏸️ Interrupted at: ${where}` };
|
|
90
|
-
}
|
|
91
|
-
break;
|
|
92
|
-
}
|
|
93
|
-
case "on_chat_model_stream":
|
|
94
|
-
if (forwardModelStream && data?.chunk?.content) {
|
|
95
|
-
if (currentNode && !streamedTextByNode.get(currentNode)) {
|
|
96
|
-
yield { type: "text-start", node: currentNode };
|
|
97
|
-
streamedTextByNode.set(currentNode, true);
|
|
98
|
-
}
|
|
99
|
-
const delta = (0, utils_1.contentToText)(data.chunk.content);
|
|
100
|
-
if (delta) {
|
|
101
|
-
yield {
|
|
102
|
-
type: "text-delta",
|
|
103
|
-
delta,
|
|
104
|
-
node: currentNode ?? "ai",
|
|
105
|
-
};
|
|
22
|
+
if (emitStatus) {
|
|
23
|
+
yield { type: "status", message: `Processing node: ${name}` };
|
|
106
24
|
}
|
|
107
25
|
}
|
|
108
26
|
break;
|
|
@@ -113,79 +31,27 @@ async function* transformGraphStreamForUI(stream, options = {}) {
|
|
|
113
31
|
console.log(`[debug:on_chain_end:${nodeName}] output=`, JSON.stringify(output, null, 2));
|
|
114
32
|
if (!output || nodeName?.startsWith("ChannelWrite"))
|
|
115
33
|
break;
|
|
116
|
-
if (nodeName && streamedTextByNode.get(nodeName)) {
|
|
117
|
-
yield { type: "text-end", node: nodeName };
|
|
118
|
-
streamedTextByNode.delete(nodeName);
|
|
119
|
-
}
|
|
120
34
|
if (nodeName !== "__start__" && nodeName !== "__end__") {
|
|
121
35
|
if (!endedNodes.has(nodeName)) {
|
|
122
|
-
|
|
36
|
+
if (emitStatus) {
|
|
37
|
+
yield {
|
|
38
|
+
type: "status",
|
|
39
|
+
message: `✅ Completed node: ${nodeName}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
123
42
|
endedNodes.add(nodeName);
|
|
124
43
|
}
|
|
125
44
|
}
|
|
126
|
-
currentNode = null;
|
|
127
45
|
break;
|
|
128
46
|
}
|
|
129
47
|
case "on_graph_end": {
|
|
130
48
|
if (debug)
|
|
131
49
|
console.log(`[debug:on_graph_end]`, JSON.stringify(data, null, 2));
|
|
132
|
-
|
|
133
|
-
const interrupts = out && out.__interrupt__;
|
|
134
|
-
if (interrupts && Array.isArray(interrupts) && interrupts.length > 0) {
|
|
135
|
-
const first = interrupts[0];
|
|
136
|
-
const val = first?.value ?? first;
|
|
137
|
-
const schema = findChoiceSchema(val);
|
|
138
|
-
if (schema && Array.isArray(schema.options)) {
|
|
139
|
-
const isText = schema.kind === "text";
|
|
140
|
-
const options = Array.isArray(schema.options)
|
|
141
|
-
? schema.options
|
|
142
|
-
.map((o) => ({
|
|
143
|
-
id: String(o.id ?? ""),
|
|
144
|
-
label: String(o.label ?? ""),
|
|
145
|
-
...(o.description
|
|
146
|
-
? { description: String(o.description) }
|
|
147
|
-
: {}),
|
|
148
|
-
}))
|
|
149
|
-
.filter((o) => o.id && o.label)
|
|
150
|
-
: [];
|
|
151
|
-
yield {
|
|
152
|
-
type: "interrupt",
|
|
153
|
-
requestId: "",
|
|
154
|
-
resumeToken: "",
|
|
155
|
-
input: {
|
|
156
|
-
kind: schema.kind,
|
|
157
|
-
multiple: Boolean(schema.multiple),
|
|
158
|
-
...(isText
|
|
159
|
-
? { question: schema.question }
|
|
160
|
-
: {
|
|
161
|
-
question: typeof schema.question === "string"
|
|
162
|
-
? schema.question
|
|
163
|
-
: "Please choose",
|
|
164
|
-
}),
|
|
165
|
-
...(options.length > 0 ? { options } : {}),
|
|
166
|
-
},
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
yield { type: "status", message: "⏸️ Interrupt received" };
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (sawInterrupt && debug)
|
|
174
|
-
yield { type: "status", message: "🔚 Graph ended after interrupt" };
|
|
175
|
-
yield { type: "done", data: out };
|
|
50
|
+
yield { type: "done", data: data?.output ?? null };
|
|
176
51
|
break;
|
|
177
52
|
}
|
|
178
53
|
default:
|
|
179
|
-
if (
|
|
180
|
-
sawInterrupt = true;
|
|
181
|
-
if (debug)
|
|
182
|
-
console.log(`[debug:interrupt_like]`, JSON.stringify({ type, name, data }, null, 2));
|
|
183
|
-
yield {
|
|
184
|
-
type: "status",
|
|
185
|
-
message: `⏸️ Interrupt event: ${type} ${name ?? ""}`.trim(),
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
else if (debug) {
|
|
54
|
+
if (debug) {
|
|
189
55
|
console.warn(`[debug:unknown_event]`, type);
|
|
190
56
|
}
|
|
191
57
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kortyx/agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Agent composition utilities for Kortyx.",
|
|
6
6
|
"keywords": [
|
|
@@ -23,6 +23,10 @@
|
|
|
23
23
|
".": {
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"default": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"./browser": {
|
|
28
|
+
"types": "./dist/browser.d.ts",
|
|
29
|
+
"default": "./dist/browser.js"
|
|
26
30
|
}
|
|
27
31
|
},
|
|
28
32
|
"files": [
|
|
@@ -46,7 +50,8 @@
|
|
|
46
50
|
"@kortyx/stream": "workspace:*",
|
|
47
51
|
"@kortyx/utils": "workspace:*",
|
|
48
52
|
"@langchain/core": "^1.0.1",
|
|
49
|
-
"@langchain/langgraph": "^1.0.1"
|
|
53
|
+
"@langchain/langgraph": "^1.0.1",
|
|
54
|
+
"zod": "^3.23.8"
|
|
50
55
|
},
|
|
51
56
|
"devDependencies": {
|
|
52
57
|
"turbo": "^2.5.4",
|