@langgraph-js/pure-graph 2.8.1 → 3.0.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.
Files changed (48) hide show
  1. package/dist/adapter/fetch/assistants.d.ts +42 -0
  2. package/dist/adapter/fetch/endpoint.d.ts +25 -0
  3. package/dist/adapter/fetch/index.d.ts +5 -3
  4. package/dist/adapter/fetch/index.js +858 -25
  5. package/dist/adapter/fetch/index.js.map +1 -1
  6. package/dist/adapter/fetch/runs-extended.d.ts +21 -0
  7. package/dist/adapter/fetch/runs-stateless.d.ts +28 -0
  8. package/dist/adapter/fetch/runs.d.ts +0 -4
  9. package/dist/adapter/fetch/threads.d.ts +36 -0
  10. package/dist/adapter/nextjs/index.js +1 -1
  11. package/dist/adapter/zod.d.ts +292 -1
  12. package/dist/agents/ask_subagents.d.ts +32 -0
  13. package/dist/agents/index.d.ts +1 -0
  14. package/dist/createEndpoint-BViLxrhh.js +208 -0
  15. package/dist/createEndpoint-BViLxrhh.js.map +1 -0
  16. package/dist/createEndpoint.d.ts +25 -0
  17. package/dist/index.d.ts +1 -1
  18. package/dist/index.js +75 -17
  19. package/dist/index.js.map +1 -1
  20. package/dist/queue/stream_queue.d.ts +4 -4
  21. package/dist/queue-CtVch_az.js +153 -0
  22. package/dist/queue-CtVch_az.js.map +1 -0
  23. package/dist/remote/index.js +158 -0
  24. package/dist/remote/index.js.map +1 -0
  25. package/dist/remote-threads-CrG03ZS7.js +255 -0
  26. package/dist/remote-threads-CrG03ZS7.js.map +1 -0
  27. package/dist/storage/index.d.ts +1 -1
  28. package/dist/storage/kysely/index.d.ts +1 -0
  29. package/dist/storage/kysely/remote-threads.d.ts +124 -0
  30. package/dist/storage/kysely/threads.d.ts +26 -2
  31. package/dist/storage/kysely/types.d.ts +10 -0
  32. package/dist/storage/memory/queue.d.ts +1 -1
  33. package/dist/storage/memory/threads.d.ts +27 -1
  34. package/dist/storage/redis/queue.d.ts +15 -12
  35. package/dist/storage/remote/fetch.d.ts +20 -0
  36. package/dist/storage/remote/remote-server.d.ts +17 -0
  37. package/dist/storage/remote/server.d.ts +11 -0
  38. package/dist/storage/remote/types.d.ts +121 -0
  39. package/dist/{stream-B7KiKwj1.js → stream-umoA6h4q.js} +513 -77
  40. package/dist/stream-umoA6h4q.js.map +1 -0
  41. package/dist/threads/index.d.ts +25 -1
  42. package/dist/types.d.ts +53 -1
  43. package/package.json +11 -5
  44. package/dist/createEndpoint-BsPsukFX.js +0 -122
  45. package/dist/createEndpoint-BsPsukFX.js.map +0 -1
  46. package/dist/queue-BSCnCent.js +0 -134
  47. package/dist/queue-BSCnCent.js.map +0 -1
  48. package/dist/stream-B7KiKwj1.js.map +0 -1
package/dist/index.js CHANGED
@@ -1,21 +1,10 @@
1
- export { A as AssistantEndpoint, c as createEndpoint } from './createEndpoint-BsPsukFX.js';
2
- export { L as LangGraphGlobal, r as registerGraph } from './stream-B7KiKwj1.js';
3
- import { StateGraph, entrypoint, getPreviousState, getConfig } from '@langchain/langgraph';
1
+ export { A as AssistantEndpoint, c as createEndpoint } from './createEndpoint-BViLxrhh.js';
2
+ export { L as LangGraphGlobal, r as registerGraph } from './stream-umoA6h4q.js';
3
+ import { entrypoint, getPreviousState, getConfig, Command } from '@langchain/langgraph';
4
4
  import { schemaMetaRegistry } from '@langchain/langgraph/zod';
5
5
  import { getDefaultsForSchema } from 'zod-defaults';
6
-
7
- const createEntrypointGraph = ({
8
- stateSchema,
9
- config,
10
- graph,
11
- checkpointer
12
- }) => {
13
- const name = graph.getName();
14
- return new StateGraph(stateSchema, config).addNode(name, (state, config2) => graph.invoke(state, config2)).addEdge("__start__", name).addEdge(name, "__end__").compile({
15
- name,
16
- checkpointer
17
- });
18
- };
6
+ import { tool, HumanMessage } from 'langchain';
7
+ import { z } from 'zod';
19
8
 
20
9
  const composeWithState = (oldState, newState, stateSchema) => {
21
10
  const channels = schemaMetaRegistry.getChannelsForSchema(stateSchema);
@@ -68,5 +57,74 @@ const createStateEntrypoint = (options, mainLogic) => {
68
57
  return res;
69
58
  };
70
59
 
71
- export { createEntrypointGraph, createStateEntrypoint };
60
+ const SubAgentStateSchema = z.object({
61
+ task_store: z.record(z.string(), z.any()).default({})
62
+ });
63
+ const schema = z.object({
64
+ task_id: z.string().optional().describe("The task id to ask the subagent, if not provided, will use the tool call id"),
65
+ subagent_id: z.string(),
66
+ task_description: z.string().describe("Describe the user state and what you want the subagent to do."),
67
+ data_transfer: z.any().optional().describe("Data to transfer to the subagent.")
68
+ });
69
+ const ask_subagents = (agentCreator, options) => tool(
70
+ async (args, config) => {
71
+ const state = config.state;
72
+ const taskId = args.task_id || config.toolCall.id;
73
+ let sub_state = {
74
+ messages: []
75
+ };
76
+ if (taskId && state?.["task_store"]?.[taskId]) {
77
+ sub_state = state?.["task_store"][taskId];
78
+ } else {
79
+ sub_state = JSON.parse(JSON.stringify(state));
80
+ sub_state.messages = [];
81
+ sub_state.task_store = {};
82
+ }
83
+ const agent = await agentCreator(taskId, args, state);
84
+ sub_state.messages.push(new HumanMessage({ content: args.task_description }));
85
+ if (args.data_transfer) {
86
+ sub_state.messages.push(
87
+ new HumanMessage({
88
+ content: `Here is the data to help you complete the task: ${JSON.stringify(
89
+ args.data_transfer,
90
+ null,
91
+ 2
92
+ )}`
93
+ })
94
+ );
95
+ }
96
+ const new_state = await agent.invoke(sub_state);
97
+ const last_message = new_state["messages"].at(-1);
98
+ const update = {
99
+ task_store: {
100
+ ...state?.["task_store"] || {},
101
+ [taskId]: new_state
102
+ },
103
+ messages: [
104
+ {
105
+ role: "tool",
106
+ content: `task_id: ${taskId}
107
+ ---
108
+ ` + (last_message?.text || ""),
109
+ tool_call_id: config.toolCall.id
110
+ }
111
+ ]
112
+ };
113
+ options?.pass_through_keys?.forEach((key) => {
114
+ if (key in new_state) {
115
+ update[key] = new_state[key];
116
+ }
117
+ });
118
+ return new Command({
119
+ update
120
+ });
121
+ },
122
+ {
123
+ name: options?.name || "ask_subagents",
124
+ description: options?.description || "ask subagents to help you",
125
+ schema
126
+ }
127
+ );
128
+
129
+ export { SubAgentStateSchema, ask_subagents, createStateEntrypoint };
72
130
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/utils/createEntrypointGraph.ts","../src/utils/createStateEntrypoint.ts"],"sourcesContent":["import { InteropZodObject } from '@langchain/core/utils/types';\nimport { BaseCheckpointSaver, CompiledStateGraph, Pregel, StateDefinition, StateGraph } from '@langchain/langgraph';\nexport const createEntrypointGraph = <S extends InteropZodObject, C extends InteropZodObject>({\n stateSchema,\n config,\n graph,\n checkpointer,\n}: {\n stateSchema: S;\n config?: C;\n graph: Pregel<any, any>;\n checkpointer?: BaseCheckpointSaver;\n}): CompiledStateGraph<\n {},\n {},\n string,\n StateDefinition,\n StateDefinition,\n StateDefinition,\n {\n [x: string]: any;\n },\n unknown,\n unknown\n> => {\n const name = graph.getName();\n /** @ts-ignore */\n return new StateGraph(stateSchema, config)\n .addNode(name, (state, config) => graph.invoke(state, config))\n .addEdge('__start__', name)\n .addEdge(name, '__end__')\n .compile({\n name,\n checkpointer,\n });\n};\n","import {\n CompiledGraph,\n entrypoint,\n EntrypointOptions,\n getConfig,\n getPreviousState,\n LangGraphRunnableConfig,\n} from '@langchain/langgraph';\nimport { schemaMetaRegistry } from '@langchain/langgraph/zod';\nimport z from 'zod';\nimport { getDefaultsForSchema } from 'zod-defaults';\nconst composeWithState = <T>(oldState: T, newState: T, stateSchema: any) => {\n const channels = schemaMetaRegistry.getChannelsForSchema(stateSchema);\n\n const previewState = stateSchema.parse(oldState || getDefaultsForSchema(stateSchema));\n // 使用 channels 的 reducer 来合并 state\n const mergedState = { ...previewState };\n for (const [channelName, _] of Object.entries(channels)) {\n const currentValue = (previewState as any)[channelName];\n const newValue = (newState as any)[channelName];\n\n // 只有当 update 中包含该 channel 的值时才处理\n if (newValue !== undefined) {\n let reducer;\n // 尝试从 schema 中查找 reducer\n // 需要解包 ZodDefault, ZodOptional 等包装器\n let currentSchema = stateSchema.shape[channelName];\n while (currentSchema) {\n const meta = schemaMetaRegistry.get(currentSchema);\n if (meta?.reducer?.fn) {\n reducer = meta.reducer.fn;\n break;\n }\n if (currentSchema._def?.innerType) {\n currentSchema = currentSchema._def.innerType;\n } else if (currentSchema._def?.schema) {\n currentSchema = currentSchema._def.schema;\n } else {\n break;\n }\n }\n\n if (reducer && typeof reducer === 'function') {\n // 使用 reducer 函数合并值\n (mergedState as any)[channelName] = reducer(currentValue, newValue);\n } else {\n // 如果没有 reducer,直接使用新值覆盖\n (mergedState as any)[channelName] = newValue;\n }\n }\n }\n\n return mergedState;\n};\nexport const createStateEntrypoint = <ZType extends z.ZodType>(\n options: EntrypointOptions & { stateSchema: ZType },\n mainLogic: (state: z.infer<ZType>, config: LangGraphRunnableConfig) => Promise<any>,\n): CompiledGraph<any, any, any, any, any, any, any, any, any> => {\n const res = entrypoint(options, async (state, ...args) => {\n state = composeWithState(getPreviousState<ZType>(), state, options.stateSchema);\n // 更新 state 并保证 state 被推送\n getConfig()?.configurable?.__pregel_stream?.push([[], 'values', state]);\n const newState = await mainLogic(state as z.infer<ZType>, ...args);\n return entrypoint.final({\n value: newState,\n save: newState,\n });\n });\n // entrypoint 的 state 更新逻辑不一样\n const updateState = res.updateState;\n res.updateState = async function (config: any, state: any, ...args) {\n state = composeWithState((await res.getState(config)).values, state, options.stateSchema);\n return updateState.bind(this)(config, state, ...args);\n };\n return res as any;\n};\n"],"names":["config"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/utils/createStateEntrypoint.ts","../src/agents/ask_subagents.ts"],"sourcesContent":["import {\n CompiledGraph,\n entrypoint,\n EntrypointOptions,\n getConfig,\n getPreviousState,\n LangGraphRunnableConfig,\n} from '@langchain/langgraph';\nimport { schemaMetaRegistry } from '@langchain/langgraph/zod';\nimport z from 'zod';\nimport { getDefaultsForSchema } from 'zod-defaults';\nconst composeWithState = <T>(oldState: T, newState: T, stateSchema: any) => {\n const channels = schemaMetaRegistry.getChannelsForSchema(stateSchema);\n\n const previewState = stateSchema.parse(oldState || getDefaultsForSchema(stateSchema));\n // 使用 channels 的 reducer 来合并 state\n const mergedState = { ...previewState };\n for (const [channelName, _] of Object.entries(channels)) {\n const currentValue = (previewState as any)[channelName];\n const newValue = (newState as any)[channelName];\n\n // 只有当 update 中包含该 channel 的值时才处理\n if (newValue !== undefined) {\n let reducer;\n // 尝试从 schema 中查找 reducer\n // 需要解包 ZodDefault, ZodOptional 等包装器\n let currentSchema = stateSchema.shape[channelName];\n while (currentSchema) {\n const meta = schemaMetaRegistry.get(currentSchema);\n if (meta?.reducer?.fn) {\n reducer = meta.reducer.fn;\n break;\n }\n if (currentSchema._def?.innerType) {\n currentSchema = currentSchema._def.innerType;\n } else if (currentSchema._def?.schema) {\n currentSchema = currentSchema._def.schema;\n } else {\n break;\n }\n }\n\n if (reducer && typeof reducer === 'function') {\n // 使用 reducer 函数合并值\n (mergedState as any)[channelName] = reducer(currentValue, newValue);\n } else {\n // 如果没有 reducer,直接使用新值覆盖\n (mergedState as any)[channelName] = newValue;\n }\n }\n }\n\n return mergedState;\n};\nexport const createStateEntrypoint = <ZType extends z.ZodType>(\n options: EntrypointOptions & { stateSchema: ZType },\n mainLogic: (state: z.infer<ZType>, config: LangGraphRunnableConfig) => Promise<any>,\n): CompiledGraph<any, any, any, any, any, any, any, any, any> => {\n const res = entrypoint(options, async (state, ...args) => {\n state = composeWithState(getPreviousState<ZType>(), state, options.stateSchema);\n // 更新 state 并保证 state 被推送\n getConfig()?.configurable?.__pregel_stream?.push([[], 'values', state]);\n const newState = await mainLogic(state as z.infer<ZType>, ...args);\n return entrypoint.final({\n value: newState,\n save: newState,\n });\n });\n // entrypoint 的 state 更新逻辑不一样\n const updateState = res.updateState;\n res.updateState = async function (config: any, state: any, ...args) {\n state = composeWithState((await res.getState(config)).values, state, options.stateSchema);\n return updateState.bind(this)(config, state, ...args);\n };\n return res as any;\n};\n","import { Command } from '@langchain/langgraph';\nimport { HumanMessage, tool } from 'langchain';\nimport { z } from 'zod';\nimport { Message } from '@langchain/core/messages';\nimport { type ToolRuntime } from '@langchain/core/tools';\n\nexport const SubAgentStateSchema = z.object({\n task_store: z.record(z.string(), z.any()).default({}),\n});\n\nconst schema = z.object({\n task_id: z\n .string()\n .optional()\n .describe('The task id to ask the subagent, if not provided, will use the tool call id'),\n subagent_id: z.string(),\n task_description: z.string().describe('Describe the user state and what you want the subagent to do.'),\n data_transfer: z.any().optional().describe('Data to transfer to the subagent.'),\n});\n\nexport const ask_subagents = (\n agentCreator: (task_id: string, args: z.infer<typeof schema>, parent_state: any) => Promise<any>,\n options?: {\n name?: string;\n description?: string;\n pass_through_keys?: string[];\n },\n) =>\n tool(\n async (args, config: ToolRuntime<typeof SubAgentStateSchema, any>) => {\n const state = config.state;\n const taskId: string = args.task_id || config.toolCall!.id!;\n let sub_state = {\n messages: [] as Message[],\n };\n if (taskId && (state as any)?.['task_store']?.[taskId]) {\n sub_state = (state as any)?.['task_store'][taskId];\n } else {\n // 全复制状态\n sub_state = JSON.parse(JSON.stringify(state));\n sub_state.messages = [];\n /** @ts-ignore 不继承 task_store 中的信息 */\n sub_state.task_store = {};\n }\n\n const agent = await agentCreator(taskId, args, state);\n sub_state.messages.push(new HumanMessage({ content: args.task_description }));\n if (args.data_transfer) {\n sub_state.messages.push(\n new HumanMessage({\n content: `Here is the data to help you complete the task: ${JSON.stringify(\n args.data_transfer,\n null,\n 2,\n )}`,\n }),\n );\n }\n const new_state = await agent.invoke(sub_state);\n const last_message = new_state['messages'].at(-1);\n\n const update: any = {\n task_store: {\n ...(state?.['task_store'] || {}),\n [taskId]: new_state,\n },\n messages: [\n {\n role: 'tool',\n content: `task_id: ${taskId}\\n---\\n` + (last_message?.text || ''),\n tool_call_id: config.toolCall!.id!,\n },\n ],\n };\n\n options?.pass_through_keys?.forEach((key) => {\n if (key in new_state) {\n update[key] = new_state[key];\n }\n });\n\n return new Command({\n update,\n });\n },\n {\n name: options?.name || 'ask_subagents',\n description: options?.description || 'ask subagents to help you',\n schema,\n },\n );\n"],"names":[],"mappings":"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"}
@@ -59,7 +59,7 @@ export interface BaseStreamQueueInterface {
59
59
  /** 获取所有数据 / Get all data */
60
60
  getAll(): Promise<EventMessage[]>;
61
61
  /** 清空队列 / Clear queue */
62
- clear(): void;
62
+ clear(): void | Promise<void>;
63
63
  /**
64
64
  * 监听数据变化
65
65
  * Listen for data changes
@@ -70,7 +70,7 @@ export interface BaseStreamQueueInterface {
70
70
  /** 取消信号控制器 / Cancel signal controller */
71
71
  cancelSignal: AbortController;
72
72
  /** 取消操作 / Cancel operation */
73
- cancel(): void;
73
+ cancel(): Promise<void>;
74
74
  /** 复制队列数据 / Copy queue data */
75
75
  copyToQueue(toId: string, ttl?: number): Promise<BaseStreamQueueInterface>;
76
76
  }
@@ -119,7 +119,7 @@ export declare class StreamQueueManager<Q extends BaseStreamQueueInterface> {
119
119
  * Cancel queue with specified id
120
120
  * @param id 队列 ID / Queue ID
121
121
  */
122
- cancelQueue(id: string): void;
122
+ cancelQueue(id: string): Promise<void>;
123
123
  /**
124
124
  * 向指定 id 的队列推送数据
125
125
  * Push data to queue with specified id
@@ -139,7 +139,7 @@ export declare class StreamQueueManager<Q extends BaseStreamQueueInterface> {
139
139
  * Clear queue with specified id
140
140
  * @param id 队列 ID / Queue ID
141
141
  */
142
- clearQueue(id: string): void;
142
+ clearQueue(id: string): Promise<void>;
143
143
  /**
144
144
  * 删除指定 id 的队列
145
145
  * Remove queue with specified id
@@ -0,0 +1,153 @@
1
+ import { B as BaseStreamQueue, C as CancelEventMessage } from './stream-umoA6h4q.js';
2
+ import { createClient } from 'redis';
3
+
4
+ class RedisStreamQueue extends BaseStreamQueue {
5
+ // 轮询间隔(毫秒)
6
+ constructor(id, compressMessages = true, ttl = 300) {
7
+ super(id, true, ttl);
8
+ this.id = id;
9
+ this.compressMessages = compressMessages;
10
+ this.ttl = ttl;
11
+ this.streamKey = `stream:${this.id}`;
12
+ this.listKey = `queue:${this.id}`;
13
+ this.redis = createClient({
14
+ url: process.env.REDIS_URL
15
+ });
16
+ this.cancelSignal = new AbortController();
17
+ if (!this.redis.isOpen) {
18
+ this.redis.connect();
19
+ }
20
+ this.isConnected = true;
21
+ }
22
+ redis;
23
+ streamKey;
24
+ listKey;
25
+ isConnected = false;
26
+ cancelSignal;
27
+ lastStreamId = "0";
28
+ // 最后读取的 Stream ID
29
+ pollInterval = 100;
30
+ /**
31
+ * 推送消息到 Redis Stream 和 List
32
+ * - Stream: 用于实时推送(集群友好)
33
+ * - List: 用于 getAll() 批量获取历史数据
34
+ */
35
+ async push(item) {
36
+ const encodedData = await this.encodeData(item);
37
+ const dataString = Buffer.from(encodedData).toString("base64");
38
+ const serializedData = Buffer.from(encodedData);
39
+ await this.redis.xAdd(this.streamKey, "*", { data: dataString });
40
+ await this.redis.expire(this.streamKey, this.ttl);
41
+ await this.redis.rPush(this.listKey, serializedData);
42
+ await this.redis.expire(this.listKey, this.ttl);
43
+ this.emit("dataChange", dataString);
44
+ }
45
+ /**
46
+ * 异步生成器:使用 Redis Streams XREAD 轮询消费队列数据
47
+ */
48
+ async *onDataReceive() {
49
+ let isStreamEnded = false;
50
+ if (this.cancelSignal.signal.aborted) {
51
+ return;
52
+ }
53
+ const abortHandler = () => {
54
+ isStreamEnded = true;
55
+ };
56
+ this.cancelSignal.signal.addEventListener("abort", abortHandler);
57
+ try {
58
+ while (!isStreamEnded && !this.cancelSignal.signal.aborted) {
59
+ const streams = await this.redis.xRead([{ key: this.streamKey, id: this.lastStreamId }], {
60
+ BLOCK: this.pollInterval,
61
+ COUNT: 10
62
+ });
63
+ if (streams && streams.length > 0) {
64
+ for (const stream of streams) {
65
+ for (const message of stream.messages) {
66
+ this.lastStreamId = message.id;
67
+ const dataString = message.message.data;
68
+ const data = Buffer.from(dataString, "base64");
69
+ const item = await this.decodeData(data);
70
+ if (item.event === "__stream_end__" || item.event === "__stream_error__" || item.event === "__stream_cancel__") {
71
+ await new Promise((resolve) => setTimeout(resolve, 300));
72
+ isStreamEnded = true;
73
+ if (item.event === "__stream_cancel__") {
74
+ await this.cancel();
75
+ }
76
+ }
77
+ yield item;
78
+ if (isStreamEnded) {
79
+ break;
80
+ }
81
+ }
82
+ if (isStreamEnded) {
83
+ break;
84
+ }
85
+ }
86
+ }
87
+ if (!isStreamEnded && !this.cancelSignal.signal.aborted) {
88
+ await new Promise((resolve) => setTimeout(resolve, this.pollInterval));
89
+ }
90
+ }
91
+ } finally {
92
+ this.cancelSignal.signal.removeEventListener("abort", abortHandler);
93
+ }
94
+ }
95
+ /**
96
+ * 获取队列中的所有数据(从 List 获取历史数据)
97
+ */
98
+ async getAll() {
99
+ const data = await this.redis.lRange(this.listKey, 0, -1);
100
+ if (!data || data.length === 0) {
101
+ return [];
102
+ }
103
+ if (this.compressMessages) {
104
+ return await Promise.all(
105
+ data.map((item) => {
106
+ const buffer = typeof item === "string" ? Buffer.from(item, "binary") : item;
107
+ return this.decodeData(buffer);
108
+ })
109
+ );
110
+ } else {
111
+ return data.map((item) => JSON.parse(item));
112
+ }
113
+ }
114
+ /**
115
+ * 清空队列
116
+ */
117
+ clear() {
118
+ if (this.isConnected) {
119
+ this.redis.del(this.streamKey);
120
+ this.redis.del(this.listKey);
121
+ }
122
+ }
123
+ /**
124
+ * 取消操作
125
+ */
126
+ async cancel() {
127
+ this.cancelSignal.abort("user cancel this run");
128
+ await this.push(new CancelEventMessage());
129
+ }
130
+ /**
131
+ * 复制队列到另一个队列
132
+ */
133
+ async copyToQueue(toId, ttl) {
134
+ const queue = new RedisStreamQueue(toId, this.compressMessages, ttl ?? this.ttl);
135
+ await this.redis.copy(this.listKey, queue.listKey);
136
+ await this.redis.expire(queue.listKey, ttl ?? this.ttl);
137
+ const allStreamData = await this.redis.xRange(this.streamKey, "-", "+");
138
+ if (allStreamData && allStreamData.length > 0) {
139
+ for (const message of allStreamData) {
140
+ const fields = {};
141
+ for (const [key, value] of Object.entries(message.message)) {
142
+ fields[key] = String(value);
143
+ }
144
+ await this.redis.xAdd(queue.streamKey, "*", fields);
145
+ }
146
+ await this.redis.expire(queue.streamKey, ttl ?? this.ttl);
147
+ }
148
+ return queue;
149
+ }
150
+ }
151
+
152
+ export { RedisStreamQueue };
153
+ //# sourceMappingURL=queue-CtVch_az.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue-CtVch_az.js","sources":["../src/storage/redis/queue.ts"],"sourcesContent":["import { CancelEventMessage, EventMessage } from '../../queue/event_message.js';\nimport { BaseStreamQueue } from '../../queue/stream_queue.js';\nimport { BaseStreamQueueInterface } from '../../queue/stream_queue.js';\nimport { createClient, RedisClientType } from 'redis';\n\n/**\n * Redis Stream 实现的消息队列,用于存储消息\n * 使用 Redis Streams 替代 pub/sub,支持集群模式\n */\nexport class RedisStreamQueue extends BaseStreamQueue implements BaseStreamQueueInterface {\n private redis: RedisClientType;\n private streamKey: string;\n private listKey: string;\n private isConnected = false;\n public cancelSignal: AbortController;\n private lastStreamId: string = '0'; // 最后读取的 Stream ID\n private pollInterval: number = 100; // 轮询间隔(毫秒)\n\n constructor(readonly id: string, readonly compressMessages: boolean = true, readonly ttl: number = 300) {\n super(id, true, ttl);\n this.streamKey = `stream:${this.id}`;\n this.listKey = `queue:${this.id}`;\n this.redis = createClient({\n url: process.env.REDIS_URL,\n });\n this.cancelSignal = new AbortController();\n\n // 连接 Redis 客户端(检查是否已经连接)\n if (!this.redis.isOpen) {\n this.redis.connect();\n }\n this.isConnected = true;\n }\n\n /**\n * 推送消息到 Redis Stream 和 List\n * - Stream: 用于实时推送(集群友好)\n * - List: 用于 getAll() 批量获取历史数据\n */\n async push(item: EventMessage): Promise<void> {\n const encodedData = await this.encodeData(item);\n // 将 Uint8Array 转换为 base64 字符串,以便存储到 Redis Stream\n const dataString = Buffer.from(encodedData).toString('base64');\n const serializedData = Buffer.from(encodedData);\n\n // 推送到 Stream(实时推送)\n // 注意:xAdd 的第三个参数必须是简单的键值对对象,值必须是字符串\n await this.redis.xAdd(this.streamKey, '*', { data: dataString });\n\n // 设置 Stream TTL\n await this.redis.expire(this.streamKey, this.ttl);\n\n // 同时推送到 List(用于 getAll)\n await this.redis.rPush(this.listKey, serializedData);\n await this.redis.expire(this.listKey, this.ttl);\n\n this.emit('dataChange', dataString);\n }\n\n /**\n * 异步生成器:使用 Redis Streams XREAD 轮询消费队列数据\n */\n async *onDataReceive(): AsyncGenerator<EventMessage, void, unknown> {\n let isStreamEnded = false;\n\n // 检查是否已取消\n if (this.cancelSignal.signal.aborted) {\n return;\n }\n\n // 监听取消信号\n const abortHandler = () => {\n isStreamEnded = true;\n };\n this.cancelSignal.signal.addEventListener('abort', abortHandler);\n\n try {\n while (!isStreamEnded && !this.cancelSignal.signal.aborted) {\n // 从 Stream 读取新消息(XREAD 阻塞读取)\n const streams = await this.redis.xRead([{ key: this.streamKey, id: this.lastStreamId }], {\n BLOCK: this.pollInterval,\n COUNT: 10,\n });\n\n if (streams && streams.length > 0) {\n for (const stream of streams) {\n for (const message of stream.messages) {\n // 更新最后读取的 ID\n this.lastStreamId = message.id;\n\n // 解析消息:从 base64 字符串转换回 Uint8Array\n const dataString = message.message.data as string;\n const data = Buffer.from(dataString, 'base64');\n const item = (await this.decodeData(data)) as EventMessage;\n\n // 检查是否为流结束或错误信号\n if (\n item.event === '__stream_end__' ||\n item.event === '__stream_error__' ||\n item.event === '__stream_cancel__'\n ) {\n // 延迟 300ms 后结束,确保消息被消费\n await new Promise((resolve) => setTimeout(resolve, 300));\n isStreamEnded = true;\n\n if (item.event === '__stream_cancel__') {\n await this.cancel();\n }\n }\n\n yield item;\n\n if (isStreamEnded) {\n break;\n }\n }\n if (isStreamEnded) {\n break;\n }\n }\n }\n\n // 轮询间隔\n if (!isStreamEnded && !this.cancelSignal.signal.aborted) {\n await new Promise((resolve) => setTimeout(resolve, this.pollInterval));\n }\n }\n } finally {\n this.cancelSignal.signal.removeEventListener('abort', abortHandler);\n }\n }\n\n /**\n * 获取队列中的所有数据(从 List 获取历史数据)\n */\n async getAll(): Promise<EventMessage[]> {\n const data = await this.redis.lRange(this.listKey, 0, -1);\n\n if (!data || data.length === 0) {\n return [];\n }\n\n if (this.compressMessages) {\n return (await Promise.all(\n data.map((item: Buffer | string) => {\n // 处理 Buffer 或字符串类型\n const buffer = typeof item === 'string' ? Buffer.from(item, 'binary') : item;\n return this.decodeData(buffer);\n }),\n )) as EventMessage[];\n } else {\n return data.map((item: string) => JSON.parse(item) as EventMessage);\n }\n }\n\n /**\n * 清空队列\n */\n clear(): void {\n if (this.isConnected) {\n // 同时清空 Stream 和 List\n this.redis.del(this.streamKey);\n this.redis.del(this.listKey);\n }\n }\n\n /**\n * 取消操作\n */\n async cancel(): Promise<void> {\n // First abort to stop any waiting generators\n this.cancelSignal.abort('user cancel this run');\n // Then push the cancel message to signal other consumers\n await this.push(new CancelEventMessage());\n }\n\n /**\n * 复制队列到另一个队列\n */\n async copyToQueue(toId: string, ttl?: number): Promise<RedisStreamQueue> {\n const queue = new RedisStreamQueue(toId, this.compressMessages, ttl ?? this.ttl);\n\n // 复制 List\n await this.redis.copy(this.listKey, queue.listKey);\n await this.redis.expire(queue.listKey, ttl ?? this.ttl);\n\n // 复制 Stream(需要遍历并重新添加)\n const allStreamData = await this.redis.xRange(this.streamKey, '-', '+');\n if (allStreamData && allStreamData.length > 0) {\n for (const message of allStreamData) {\n // 确保所有值都是字符串,Redis Streams 只支持 string 值\n const fields: Record<string, string> = {};\n for (const [key, value] of Object.entries(message.message)) {\n fields[key] = String(value);\n }\n await this.redis.xAdd(queue.streamKey, '*', fields);\n }\n await this.redis.expire(queue.streamKey, ttl ?? this.ttl);\n }\n\n return queue;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ import { Hono } from 'hono';
2
+ import { PostgresAdapter } from '../pg-adapter-BFtir1GE.js';
3
+ import { K as KyselyThreadsManager } from '../stream-umoA6h4q.js';
4
+ import { Pool } from 'pg';
5
+
6
+ class RemoteServer {
7
+ constructor(threadsManager) {
8
+ this.threadsManager = threadsManager;
9
+ }
10
+ /**
11
+ * 创建 Hono 路由
12
+ */
13
+ getRouter() {
14
+ const app = new Hono();
15
+ app.post("/setup", async (c) => {
16
+ await this.threadsManager.setup();
17
+ const response = {
18
+ success: true,
19
+ data: { message: "Database initialized successfully" }
20
+ };
21
+ return c.json(response, 200);
22
+ });
23
+ app.post("/threads", async (c) => {
24
+ const body = await c.req.json();
25
+ const thread = await this.threadsManager.create(body);
26
+ const response = {
27
+ success: true,
28
+ data: thread
29
+ };
30
+ return c.json(response, 201);
31
+ });
32
+ app.get("/threads", async (c) => {
33
+ const query = {
34
+ ids: c.req.query("ids") ? JSON.parse(c.req.query("ids")) : void 0,
35
+ metadata: c.req.query("metadata") ? JSON.parse(c.req.query("metadata")) : void 0,
36
+ limit: c.req.query("limit") ? parseInt(c.req.query("limit")) : void 0,
37
+ offset: c.req.query("offset") ? parseInt(c.req.query("offset")) : void 0,
38
+ status: c.req.query("status"),
39
+ sortBy: c.req.query("sortBy"),
40
+ sortOrder: c.req.query("sortOrder"),
41
+ values: c.req.query("values") ? JSON.parse(c.req.query("values")) : void 0,
42
+ select: c.req.query("select") ? JSON.parse(c.req.query("select")) : void 0,
43
+ withoutDetails: c.req.query("withoutDetails") === "true"
44
+ };
45
+ const threads = await this.threadsManager.search(query);
46
+ const response = {
47
+ success: true,
48
+ data: threads
49
+ };
50
+ return c.json(response, 200);
51
+ });
52
+ app.get("/threads/:threadId", async (c) => {
53
+ const threadId = c.req.param("threadId");
54
+ const thread = await this.threadsManager.get(threadId);
55
+ const response = {
56
+ success: true,
57
+ data: thread
58
+ };
59
+ return c.json(response, 200);
60
+ });
61
+ app.put("/threads/:threadId", async (c) => {
62
+ const threadId = c.req.param("threadId");
63
+ const body = await c.req.json();
64
+ await this.threadsManager.set(threadId, body);
65
+ const response = {
66
+ success: true
67
+ };
68
+ return c.json(response, 200);
69
+ });
70
+ app.delete("/threads/:threadId", async (c) => {
71
+ const threadId = c.req.param("threadId");
72
+ await this.threadsManager.delete(threadId);
73
+ const response = {
74
+ success: true
75
+ };
76
+ return c.json(response, 200);
77
+ });
78
+ app.post("/threads/:threadId/state", async (c) => {
79
+ const threadId = c.req.param("threadId");
80
+ const body = await c.req.json();
81
+ const result = await this.threadsManager.updateState(threadId, body);
82
+ const response = {
83
+ success: true,
84
+ data: result
85
+ };
86
+ return c.json(response, 200);
87
+ });
88
+ app.post("/threads/:threadId/runs", async (c) => {
89
+ const threadId = c.req.param("threadId");
90
+ const assistantId = c.req.query("assistantId");
91
+ const body = await c.req.json();
92
+ const run = await this.threadsManager.createRun(threadId, assistantId, body);
93
+ const response = {
94
+ success: true,
95
+ data: run
96
+ };
97
+ return c.json(response, 201);
98
+ });
99
+ app.get("/threads/:threadId/runs", async (c) => {
100
+ const threadId = c.req.param("threadId");
101
+ const query = {
102
+ limit: c.req.query("limit") ? parseInt(c.req.query("limit")) : void 0,
103
+ offset: c.req.query("offset") ? parseInt(c.req.query("offset")) : void 0,
104
+ status: c.req.query("status")
105
+ };
106
+ const runs = await this.threadsManager.listRuns(threadId, query);
107
+ const response = {
108
+ success: true,
109
+ data: runs
110
+ };
111
+ return c.json(response, 200);
112
+ });
113
+ app.put("/runs/:runId", async (c) => {
114
+ const runId = c.req.param("runId");
115
+ const body = await c.req.json();
116
+ await this.threadsManager.updateRun(runId, body);
117
+ const response = {
118
+ success: true
119
+ };
120
+ return c.json(response, 200);
121
+ });
122
+ return app;
123
+ }
124
+ }
125
+
126
+ const app = new Hono();
127
+ const databaseUrl = process.env.DATABASE_URL;
128
+ if (!databaseUrl) {
129
+ console.error("DATABASE_URL environment variable is required");
130
+ console.error("Example: DATABASE_URL=postgresql://user:password@localhost:5432/dbname");
131
+ process.exit(1);
132
+ }
133
+ console.log("Starting Remote PostgreSQL Server...");
134
+ const pool = new Pool({
135
+ connectionString: databaseUrl
136
+ });
137
+ const pgAdapter = new PostgresAdapter(pool);
138
+ const threadsManager = new KyselyThreadsManager(pgAdapter);
139
+ await threadsManager.setup();
140
+ const remoteServer = new RemoteServer(threadsManager);
141
+ app.route("/api/remote", remoteServer.getRouter());
142
+ app.get("/health", (c) => {
143
+ return c.json({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() });
144
+ });
145
+ const port = parseInt(process.env.PORT || "3001");
146
+ console.log(`Remote PostgreSQL Server is running on port ${port}`);
147
+ console.log(`API Base URL: http://localhost:${port}/api/remote`);
148
+ console.log(`Health Check: http://localhost:${port}/health`);
149
+ console.log("");
150
+ console.log("Client Configuration:");
151
+ console.log(` DATABASE_URL=http://localhost:${port}/api/remote`);
152
+ const server = {
153
+ fetch: app.fetch,
154
+ port
155
+ };
156
+
157
+ export { server as default };
158
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../../src/storage/remote/remote-server.ts","../../src/storage/remote/server.ts"],"sourcesContent":["/**\n * Remote PostgreSQL Server\n * 提供 HTTP API 端点,代理 PostgreSQL 操作\n */\n\nimport { Hono } from 'hono';\nimport { BaseThreadsManager } from '../../threads';\nimport {\n RemoteResponse,\n RemoteApiError,\n RemoteErrorCode,\n SetupResponse,\n CreateThreadRequest,\n SearchThreadsRequest,\n UpdateThreadRequest,\n UpdateStateRequest,\n UpdateStateResponse,\n CreateRunRequest,\n ListRunsRequest,\n UpdateRunRequest,\n} from './types';\n\n/**\n * Remote Server 类\n */\nexport class RemoteServer {\n constructor(private threadsManager: BaseThreadsManager) {}\n\n /**\n * 创建 Hono 路由\n */\n getRouter(): Hono {\n const app = new Hono();\n\n // Setup API\n app.post('/setup', async (c) => {\n await this.threadsManager.setup();\n const response: RemoteResponse<SetupResponse> = {\n success: true,\n data: { message: 'Database initialized successfully' },\n };\n return c.json(response, 200);\n });\n\n // Thread: Create\n app.post('/threads', async (c) => {\n const body: CreateThreadRequest = await c.req.json();\n const thread = await this.threadsManager.create(body);\n const response: RemoteResponse = {\n success: true,\n data: thread,\n };\n return c.json(response, 201);\n });\n\n // Thread: Search\n app.get('/threads', async (c) => {\n const query: SearchThreadsRequest = {\n ids: c.req.query('ids') ? JSON.parse(c.req.query('ids')!) : undefined,\n metadata: c.req.query('metadata') ? JSON.parse(c.req.query('metadata')!) : undefined,\n limit: c.req.query('limit') ? parseInt(c.req.query('limit')!) : undefined,\n offset: c.req.query('offset') ? parseInt(c.req.query('offset')!) : undefined,\n status: c.req.query('status') as any,\n sortBy: c.req.query('sortBy') as any,\n sortOrder: c.req.query('sortOrder') as any,\n values: c.req.query('values') ? JSON.parse(c.req.query('values')!) : undefined,\n select: c.req.query('select') ? JSON.parse(c.req.query('select')!) : undefined,\n withoutDetails: c.req.query('withoutDetails') === 'true',\n };\n const threads = await this.threadsManager.search(query);\n const response: RemoteResponse = {\n success: true,\n data: threads,\n };\n return c.json(response, 200);\n });\n\n // Thread: Get\n app.get('/threads/:threadId', async (c) => {\n const threadId = c.req.param('threadId')!;\n const thread = await this.threadsManager.get(threadId);\n const response: RemoteResponse = {\n success: true,\n data: thread,\n };\n return c.json(response, 200);\n });\n\n // Thread: Update\n app.put('/threads/:threadId', async (c) => {\n const threadId = c.req.param('threadId')!;\n const body: UpdateThreadRequest = await c.req.json();\n await this.threadsManager.set(threadId, body);\n const response: RemoteResponse = {\n success: true,\n };\n return c.json(response, 200);\n });\n\n // Thread: Delete\n app.delete('/threads/:threadId', async (c) => {\n const threadId = c.req.param('threadId')!;\n await this.threadsManager.delete(threadId);\n const response: RemoteResponse = {\n success: true,\n };\n return c.json(response, 200);\n });\n\n // Thread: Update State\n app.post('/threads/:threadId/state', async (c) => {\n const threadId = c.req.param('threadId')!;\n const body: UpdateStateRequest = await c.req.json();\n const result = await this.threadsManager.updateState(threadId, body);\n const response: RemoteResponse<UpdateStateResponse> = {\n success: true,\n data: result as any,\n };\n return c.json(response, 200);\n });\n\n // Run: Create\n app.post('/threads/:threadId/runs', async (c) => {\n const threadId = c.req.param('threadId')!;\n const assistantId = c.req.query('assistantId')!;\n const body: CreateRunRequest = await c.req.json();\n const run = await this.threadsManager.createRun(threadId, assistantId, body);\n const response: RemoteResponse = {\n success: true,\n data: run,\n };\n return c.json(response, 201);\n });\n\n // Run: List\n app.get('/threads/:threadId/runs', async (c) => {\n const threadId = c.req.param('threadId')!;\n const query: ListRunsRequest = {\n limit: c.req.query('limit') ? parseInt(c.req.query('limit')!) : undefined,\n offset: c.req.query('offset') ? parseInt(c.req.query('offset')!) : undefined,\n status: c.req.query('status') as any,\n };\n const runs = await this.threadsManager.listRuns(threadId, query);\n const response: RemoteResponse = {\n success: true,\n data: runs,\n };\n return c.json(response, 200);\n });\n\n // Run: Update\n app.put('/runs/:runId', async (c) => {\n const runId = c.req.param('runId')!;\n const body: UpdateRunRequest = await c.req.json();\n await this.threadsManager.updateRun(runId, body);\n const response: RemoteResponse = {\n success: true,\n };\n return c.json(response, 200);\n });\n\n return app;\n }\n}\n","/**\n * Remote PostgreSQL Server 启动示例\n *\n * 这个文件展示如何启动一个远程 PG 服务器\n * 运行: bun run src/storage/remote/server.ts\n */\n\nimport { Hono } from 'hono';\nimport { RemoteServer } from './remote-server';\nimport { PostgresAdapter } from '../kysely/pg-adapter';\nimport { KyselyThreadsManager } from '../kysely/threads';\nimport { Pool } from 'pg';\n\nconst app = new Hono();\n// 从环境变量获取数据库连接字符串\nconst databaseUrl = process.env.DATABASE_URL;\n\nif (!databaseUrl) {\n console.error('DATABASE_URL environment variable is required');\n console.error('Example: DATABASE_URL=postgresql://user:password@localhost:5432/dbname');\n process.exit(1);\n}\n\nconsole.log('Starting Remote PostgreSQL Server...');\n\n// 创建 PG 连接池\nconst pool = new Pool({\n connectionString: databaseUrl,\n});\n\n// 创建适配器\nconst pgAdapter = new PostgresAdapter(pool);\n\n// 创建 ThreadsManager\nconst threadsManager = new KyselyThreadsManager(pgAdapter);\n\nawait threadsManager.setup();\n// 创建远程服务器\nconst remoteServer = new RemoteServer(threadsManager);\n\n// 注册路由\napp.route('/api/remote', remoteServer.getRouter());\n\n// 添加健康检查端点\napp.get('/health', (c) => {\n return c.json({ status: 'ok', timestamp: new Date().toISOString() });\n});\n\n// 获取配置的端口\nconst port = parseInt(process.env.PORT || '3001');\n\nconsole.log(`Remote PostgreSQL Server is running on port ${port}`);\nconsole.log(`API Base URL: http://localhost:${port}/api/remote`);\nconsole.log(`Health Check: http://localhost:${port}/health`);\nconsole.log('');\nconsole.log('Client Configuration:');\nconsole.log(` DATABASE_URL=http://localhost:${port}/api/remote`);\n// 启动服务器\nexport default {\n fetch: app.fetch,\n port,\n};\n"],"names":[],"mappings":";;;;;AAyBO,MAAM,YAAA,CAAa;AAAA,EACtB,YAAoB,cAAA,EAAoC;AAApC,IAAA,IAAA,CAAA,cAAA,GAAA,cAAA;AAAA,EAAqC;AAAA;AAAA;AAAA;AAAA,EAKzD,SAAA,GAAkB;AACd,IAAA,MAAM,GAAA,GAAM,IAAI,IAAA,EAAK;AAGrB,IAAA,GAAA,CAAI,IAAA,CAAK,QAAA,EAAU,OAAO,CAAA,KAAM;AAC5B,MAAA,MAAM,IAAA,CAAK,eAAe,KAAA,EAAM;AAChC,MAAA,MAAM,QAAA,GAA0C;AAAA,QAC5C,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM,EAAE,OAAA,EAAS,mCAAA;AAAoC,OACzD;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,IAAA,CAAK,UAAA,EAAY,OAAO,CAAA,KAAM;AAC9B,MAAA,MAAM,IAAA,GAA4B,MAAM,CAAA,CAAE,GAAA,CAAI,IAAA,EAAK;AACnD,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,OAAO,IAAI,CAAA;AACpD,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,GAAA,CAAI,UAAA,EAAY,OAAO,CAAA,KAAM;AAC7B,MAAA,MAAM,KAAA,GAA8B;AAAA,QAChC,GAAA,EAAK,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,KAAK,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,KAAK,CAAE,CAAA,GAAI,MAAA;AAAA,QAC5D,QAAA,EAAU,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAE,CAAA,GAAI,MAAA;AAAA,QAC3E,KAAA,EAAO,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,OAAO,CAAE,CAAA,GAAI,MAAA;AAAA,QAChE,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAE,CAAA,GAAI,MAAA;AAAA,QACnE,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA;AAAA,QAC5B,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA;AAAA,QAC5B,SAAA,EAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,WAAW,CAAA;AAAA,QAClC,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAE,CAAA,GAAI,MAAA;AAAA,QACrE,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAE,CAAA,GAAI,MAAA;AAAA,QACrE,cAAA,EAAgB,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,gBAAgB,CAAA,KAAM;AAAA,OACtD;AACA,MAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,cAAA,CAAe,OAAO,KAAK,CAAA;AACtD,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,GAAA,CAAI,oBAAA,EAAsB,OAAO,CAAA,KAAM;AACvC,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,cAAA,CAAe,IAAI,QAAQ,CAAA;AACrD,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,GAAA,CAAI,oBAAA,EAAsB,OAAO,CAAA,KAAM;AACvC,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,IAAA,GAA4B,MAAM,CAAA,CAAE,GAAA,CAAI,IAAA,EAAK;AACnD,MAAA,MAAM,IAAA,CAAK,cAAA,CAAe,GAAA,CAAI,QAAA,EAAU,IAAI,CAAA;AAC5C,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS;AAAA,OACb;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,MAAA,CAAO,oBAAA,EAAsB,OAAO,CAAA,KAAM;AAC1C,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,IAAA,CAAK,cAAA,CAAe,MAAA,CAAO,QAAQ,CAAA;AACzC,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS;AAAA,OACb;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,IAAA,CAAK,0BAAA,EAA4B,OAAO,CAAA,KAAM;AAC9C,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,IAAA,GAA2B,MAAM,CAAA,CAAE,GAAA,CAAI,IAAA,EAAK;AAClD,MAAA,MAAM,SAAS,MAAM,IAAA,CAAK,cAAA,CAAe,WAAA,CAAY,UAAU,IAAI,CAAA;AACnE,MAAA,MAAM,QAAA,GAAgD;AAAA,QAClD,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,IAAA,CAAK,yBAAA,EAA2B,OAAO,CAAA,KAAM;AAC7C,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,WAAA,GAAc,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,aAAa,CAAA;AAC7C,MAAA,MAAM,IAAA,GAAyB,MAAM,CAAA,CAAE,GAAA,CAAI,IAAA,EAAK;AAChD,MAAA,MAAM,MAAM,MAAM,IAAA,CAAK,eAAe,SAAA,CAAU,QAAA,EAAU,aAAa,IAAI,CAAA;AAC3E,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,GAAA,CAAI,yBAAA,EAA2B,OAAO,CAAA,KAAM;AAC5C,MAAA,MAAM,QAAA,GAAW,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,UAAU,CAAA;AACvC,MAAA,MAAM,KAAA,GAAyB;AAAA,QAC3B,KAAA,EAAO,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,OAAO,CAAE,CAAA,GAAI,MAAA;AAAA,QAChE,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,GAAI,QAAA,CAAS,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAE,CAAA,GAAI,MAAA;AAAA,QACnE,MAAA,EAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,QAAQ;AAAA,OAChC;AACA,MAAA,MAAM,OAAO,MAAM,IAAA,CAAK,cAAA,CAAe,QAAA,CAAS,UAAU,KAAK,CAAA;AAC/D,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS,IAAA;AAAA,QACT,IAAA,EAAM;AAAA,OACV;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAGD,IAAA,GAAA,CAAI,GAAA,CAAI,cAAA,EAAgB,OAAO,CAAA,KAAM;AACjC,MAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,GAAA,CAAI,KAAA,CAAM,OAAO,CAAA;AACjC,MAAA,MAAM,IAAA,GAAyB,MAAM,CAAA,CAAE,GAAA,CAAI,IAAA,EAAK;AAChD,MAAA,MAAM,IAAA,CAAK,cAAA,CAAe,SAAA,CAAU,KAAA,EAAO,IAAI,CAAA;AAC/C,MAAA,MAAM,QAAA,GAA2B;AAAA,QAC7B,OAAA,EAAS;AAAA,OACb;AACA,MAAA,OAAO,CAAA,CAAE,IAAA,CAAK,QAAA,EAAU,GAAG,CAAA;AAAA,IAC/B,CAAC,CAAA;AAED,IAAA,OAAO,GAAA;AAAA,EACX;AACJ;;ACtJA,MAAM,GAAA,GAAM,IAAI,IAAA,EAAK;AAErB,MAAM,WAAA,GAAc,QAAQ,GAAA,CAAI,YAAA;AAEhC,IAAI,CAAC,WAAA,EAAa;AACd,EAAA,OAAA,CAAQ,MAAM,+CAA+C,CAAA;AAC7D,EAAA,OAAA,CAAQ,MAAM,wEAAwE,CAAA;AACtF,EAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAClB;AAEA,OAAA,CAAQ,IAAI,sCAAsC,CAAA;AAGlD,MAAM,IAAA,GAAO,IAAI,IAAA,CAAK;AAAA,EAClB,gBAAA,EAAkB;AACtB,CAAC,CAAA;AAGD,MAAM,SAAA,GAAY,IAAI,eAAA,CAAgB,IAAI,CAAA;AAG1C,MAAM,cAAA,GAAiB,IAAI,oBAAA,CAAqB,SAAS,CAAA;AAEzD,MAAM,eAAe,KAAA,EAAM;AAE3B,MAAM,YAAA,GAAe,IAAI,YAAA,CAAa,cAAc,CAAA;AAGpD,GAAA,CAAI,KAAA,CAAM,aAAA,EAAe,YAAA,CAAa,SAAA,EAAW,CAAA;AAGjD,GAAA,CAAI,GAAA,CAAI,SAAA,EAAW,CAAC,CAAA,KAAM;AACtB,EAAA,OAAO,CAAA,CAAE,IAAA,CAAK,EAAE,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAA,iBAAW,IAAI,IAAA,EAAK,EAAE,WAAA,EAAY,EAAG,CAAA;AACvE,CAAC,CAAA;AAGD,MAAM,IAAA,GAAO,QAAA,CAAS,OAAA,CAAQ,GAAA,CAAI,QAAQ,MAAM,CAAA;AAEhD,OAAA,CAAQ,GAAA,CAAI,CAAA,4CAAA,EAA+C,IAAI,CAAA,CAAE,CAAA;AACjE,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,IAAI,CAAA,WAAA,CAAa,CAAA;AAC/D,OAAA,CAAQ,GAAA,CAAI,CAAA,+BAAA,EAAkC,IAAI,CAAA,OAAA,CAAS,CAAA;AAC3D,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,OAAA,CAAQ,IAAI,uBAAuB,CAAA;AACnC,OAAA,CAAQ,GAAA,CAAI,CAAA,gCAAA,EAAmC,IAAI,CAAA,WAAA,CAAa,CAAA;AAEhE,eAAe;AAAA,EACX,OAAO,GAAA,CAAI,KAAA;AAAA,EACX;AACJ,CAAA;;;;"}