@langgraph-js/pure-graph 1.0.1 → 1.2.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 (89) hide show
  1. package/.prettierrc +11 -0
  2. package/README.md +104 -10
  3. package/bun.lock +209 -0
  4. package/dist/adapter/hono/assistants.js +3 -9
  5. package/dist/adapter/hono/endpoint.js +1 -2
  6. package/dist/adapter/hono/runs.js +6 -40
  7. package/dist/adapter/hono/threads.js +5 -46
  8. package/dist/adapter/nextjs/endpoint.d.ts +1 -0
  9. package/dist/adapter/nextjs/endpoint.js +2 -0
  10. package/dist/adapter/nextjs/index.d.ts +1 -0
  11. package/dist/adapter/nextjs/index.js +2 -0
  12. package/dist/adapter/nextjs/router.d.ts +5 -0
  13. package/dist/adapter/nextjs/router.js +168 -0
  14. package/dist/adapter/{hono → nextjs}/zod.d.ts +5 -5
  15. package/dist/adapter/{hono → nextjs}/zod.js +22 -5
  16. package/dist/adapter/zod.d.ts +577 -0
  17. package/dist/adapter/zod.js +119 -0
  18. package/dist/createEndpoint.d.ts +1 -2
  19. package/dist/createEndpoint.js +5 -5
  20. package/dist/global.d.ts +6 -4
  21. package/dist/global.js +10 -5
  22. package/dist/graph/stream.d.ts +1 -1
  23. package/dist/graph/stream.js +19 -11
  24. package/dist/index.d.ts +1 -0
  25. package/dist/index.js +1 -0
  26. package/dist/queue/event_message.js +1 -1
  27. package/dist/queue/stream_queue.d.ts +5 -3
  28. package/dist/queue/stream_queue.js +4 -2
  29. package/dist/storage/index.d.ts +9 -4
  30. package/dist/storage/index.js +38 -3
  31. package/dist/storage/memory/queue.js +13 -4
  32. package/dist/storage/redis/queue.d.ts +39 -0
  33. package/dist/storage/redis/queue.js +130 -0
  34. package/dist/storage/sqlite/DB.d.ts +3 -0
  35. package/dist/storage/sqlite/DB.js +14 -0
  36. package/dist/storage/sqlite/checkpoint.d.ts +18 -0
  37. package/dist/storage/sqlite/checkpoint.js +374 -0
  38. package/dist/storage/sqlite/threads.d.ts +43 -0
  39. package/dist/storage/sqlite/threads.js +266 -0
  40. package/dist/storage/sqlite/type.d.ts +15 -0
  41. package/dist/storage/sqlite/type.js +1 -0
  42. package/dist/utils/createEntrypointGraph.d.ts +14 -0
  43. package/dist/utils/createEntrypointGraph.js +11 -0
  44. package/dist/utils/getGraph.js +3 -3
  45. package/examples/nextjs/README.md +36 -0
  46. package/examples/nextjs/app/api/langgraph/[...path]/route.ts +10 -0
  47. package/examples/nextjs/app/favicon.ico +0 -0
  48. package/examples/nextjs/app/globals.css +26 -0
  49. package/examples/nextjs/app/layout.tsx +34 -0
  50. package/examples/nextjs/app/page.tsx +211 -0
  51. package/examples/nextjs/next.config.ts +26 -0
  52. package/examples/nextjs/package.json +24 -0
  53. package/examples/nextjs/postcss.config.mjs +5 -0
  54. package/examples/nextjs/tsconfig.json +27 -0
  55. package/package.json +10 -4
  56. package/packages/agent-graph/demo.json +35 -0
  57. package/packages/agent-graph/package.json +18 -0
  58. package/packages/agent-graph/src/index.ts +47 -0
  59. package/packages/agent-graph/src/tools/tavily.ts +9 -0
  60. package/packages/agent-graph/src/tools.ts +38 -0
  61. package/packages/agent-graph/src/types.ts +42 -0
  62. package/pnpm-workspace.yaml +4 -0
  63. package/src/adapter/hono/assistants.ts +16 -33
  64. package/src/adapter/hono/endpoint.ts +1 -2
  65. package/src/adapter/hono/runs.ts +15 -51
  66. package/src/adapter/hono/threads.ts +15 -70
  67. package/src/adapter/nextjs/endpoint.ts +2 -0
  68. package/src/adapter/nextjs/index.ts +2 -0
  69. package/src/adapter/nextjs/router.ts +193 -0
  70. package/src/adapter/{hono → nextjs}/zod.ts +22 -5
  71. package/src/adapter/zod.ts +135 -0
  72. package/src/createEndpoint.ts +12 -5
  73. package/src/e.d.ts +3 -0
  74. package/src/global.ts +11 -6
  75. package/src/graph/stream.ts +20 -10
  76. package/src/index.ts +1 -0
  77. package/src/queue/stream_queue.ts +6 -5
  78. package/src/storage/index.ts +42 -4
  79. package/src/storage/redis/queue.ts +148 -0
  80. package/src/storage/sqlite/DB.ts +16 -0
  81. package/src/storage/sqlite/checkpoint.ts +503 -0
  82. package/src/storage/sqlite/threads.ts +366 -0
  83. package/src/storage/sqlite/type.ts +12 -0
  84. package/src/utils/createEntrypointGraph.ts +20 -0
  85. package/src/utils/getGraph.ts +3 -3
  86. package/test/graph/entrypoint.ts +21 -0
  87. package/test/graph/index.ts +45 -6
  88. package/test/hono.ts +5 -0
  89. package/test/test.ts +0 -10
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "nextjs",
3
+ "version": "0.1.0",
4
+ "private": true,
5
+ "scripts": {
6
+ "dev": "next dev --turbopack",
7
+ "build": "next build --turbopack",
8
+ "start": "next start"
9
+ },
10
+ "dependencies": {
11
+ "@langgraph-js/pure-graph": "workspace:^*",
12
+ "next": "15.5.4",
13
+ "react": "19.1.0",
14
+ "react-dom": "19.1.0"
15
+ },
16
+ "devDependencies": {
17
+ "@tailwindcss/postcss": "^4",
18
+ "@types/node": "^20",
19
+ "@types/react": "^19",
20
+ "@types/react-dom": "^19",
21
+ "tailwindcss": "^4",
22
+ "typescript": "^5"
23
+ }
24
+ }
@@ -0,0 +1,5 @@
1
+ const config = {
2
+ plugins: ["@tailwindcss/postcss"],
3
+ };
4
+
5
+ export default config;
@@ -0,0 +1,27 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2017",
4
+ "lib": ["dom", "dom.iterable", "esnext"],
5
+ "allowJs": true,
6
+ "skipLibCheck": true,
7
+ "strict": true,
8
+ "noEmit": true,
9
+ "esModuleInterop": true,
10
+ "module": "esnext",
11
+ "moduleResolution": "bundler",
12
+ "resolveJsonModule": true,
13
+ "isolatedModules": true,
14
+ "jsx": "preserve",
15
+ "incremental": true,
16
+ "plugins": [
17
+ {
18
+ "name": "next"
19
+ }
20
+ ],
21
+ "paths": {
22
+ "@/*": ["./*"]
23
+ }
24
+ },
25
+ "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
26
+ "exclude": ["node_modules"]
27
+ }
package/package.json CHANGED
@@ -1,31 +1,37 @@
1
1
  {
2
2
  "name": "@langgraph-js/pure-graph",
3
- "version": "1.0.1",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "keywords": [],
7
7
  "author": "",
8
8
  "license": "MIT",
9
9
  "dependencies": {
10
- "@langchain/core": "^0.3.77",
10
+ "@langchain/core": "^0.3.78",
11
11
  "@langchain/langgraph": "^0.4.9",
12
12
  "@langchain/langgraph-checkpoint": "^0.1.1",
13
+ "@langchain/langgraph-checkpoint-sqlite": "^0.2.1",
13
14
  "@langgraph-js/pro": "^1.8.1",
15
+ "better-sqlite3": "^12.4.1",
14
16
  "eventemitter3": "^5.0.1",
15
17
  "zod": "^3"
16
18
  },
17
19
  "optionalDependencies": {
18
20
  "@hono/zod-validator": "^0.7.3",
19
- "hono": "^4.9.9"
21
+ "hono": "^4.9.9",
22
+ "redis": "^5.8.3"
20
23
  },
21
24
  "devDependencies": {
25
+ "@langchain/langgraph-checkpoint-redis": "^0.0.2",
22
26
  "@langchain/langgraph-sdk": "^0.1.7",
27
+ "@langchain/openai": "^0.6.14",
23
28
  "@langgraph-js/sdk": "^2.0.1",
24
29
  "@types/node": "^22.13.5",
25
30
  "typescript": "^5.9.2"
26
31
  },
27
32
  "scripts": {
28
33
  "dev": "bun run test/hono.ts",
29
- "build": "tsc"
34
+ "build": " tsc",
35
+ "prepublish": "pnpm build"
30
36
  }
31
37
  }
@@ -0,0 +1,35 @@
1
+ {
2
+ "agent_protocol": {
3
+ "id": "novel-writing-assistant",
4
+ "protocolVersion": "1.0.0",
5
+ "name": "小说创作助手",
6
+ "description": "专业的AI小说创作助手,提供情节构思、人物塑造、世界观构建和写作指导的全方位服务",
7
+ "url": "https://api.novelai.net/ai/generate",
8
+ "iconUrl": "https://img.icons8.com/fluency/96/000000/book.png",
9
+ "version": "2.0.1",
10
+ "documentationUrl": "https://docs.novelai.net/",
11
+ "llm": [
12
+ {
13
+ "provider": "openai",
14
+ "model": "gpt-4o-mini"
15
+ },
16
+ {
17
+ "provider": "openai",
18
+ "model": "qwen-plus"
19
+ }
20
+ ],
21
+ "systemPrompt": "你是一位经验丰富的小说家和创意写作导师,精通各种文学体裁和叙事技巧。你善于分析经典作品的结构,帮助创作者构建引人入胜的情节、塑造立体的人物形象,并提供专业的写作建议和灵感启发。",
22
+ "tools": [
23
+ {
24
+ "tool_type": "mcp",
25
+ "url": "https://mcp.exa.ai/mcp?exaApiKey=ce1249b7-6b78-4ec8-8be9-41823b5d2365",
26
+ "headers": {}
27
+ },
28
+ {
29
+ "tool_type": "builtin",
30
+ "name": "tavily_search"
31
+ }
32
+ ],
33
+ "subAgents": []
34
+ }
35
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "packages",
3
+ "version": "1.0.0",
4
+ "description": "",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "keywords": [],
10
+ "author": "",
11
+ "license": "ISC",
12
+ "dependencies": {
13
+ "@langchain/mcp-adapters": "^0.6.0",
14
+ "@langchain/openai": "^0.6.14",
15
+ "@langchain/tavily": "^0.1.5",
16
+ "@langgraph-js/pure-graph": "workspace:^*"
17
+ }
18
+ }
@@ -0,0 +1,47 @@
1
+ import { Annotation, entrypoint } from '@langchain/langgraph';
2
+ import { createState } from '@langgraph-js/pro';
3
+ import { AgentProtocol } from './types';
4
+ import { createReactAgent, createReactAgentAnnotation } from '@langchain/langgraph/prebuilt';
5
+ import { ChatOpenAI } from '@langchain/openai';
6
+ import { BaseChatModel } from '@langchain/core/language_models/chat_models';
7
+ import { createTools } from './tools';
8
+ import { createEntrypointGraph } from '@langgraph-js/pure-graph';
9
+ const AgentProtocolState = createState().build({
10
+ agent_protocol: Annotation<AgentProtocol>(),
11
+ model_name: Annotation<string>(),
12
+ });
13
+
14
+ const AgentGraphState = createState(AgentProtocolState, createReactAgentAnnotation()).build({});
15
+
16
+ export const createLLM = async (protocol: AgentProtocol, model_name?: string): Promise<BaseChatModel> => {
17
+ if (!model_name) {
18
+ model_name = protocol.llm[0].model;
19
+ } else {
20
+ const llm = protocol.llm.find((i) => i.model === model_name);
21
+ if (!llm) {
22
+ throw new Error(`Model ${model_name} not found`);
23
+ }
24
+ model_name = llm.model;
25
+ }
26
+ return new ChatOpenAI({
27
+ model: model_name,
28
+ });
29
+ };
30
+
31
+ export const graph = createEntrypointGraph({
32
+ stateSchema: AgentGraphState,
33
+ graph: entrypoint({ name: 'agent-graph' }, async (state: typeof AgentGraphState.State) => {
34
+ const protocol = state.agent_protocol;
35
+
36
+ const tools = await createTools(protocol);
37
+
38
+ const agent = createReactAgent({
39
+ llm: await createLLM(protocol, state.model_name),
40
+ tools,
41
+ prompt: protocol.systemPrompt,
42
+ stateSchema: AgentGraphState,
43
+ });
44
+ const response = await agent.invoke(state);
45
+ return response;
46
+ }),
47
+ });
@@ -0,0 +1,9 @@
1
+ import { TavilyExtract, TavilySearch } from '@langchain/tavily';
2
+ export const tavily_search = new TavilySearch({
3
+ maxResults: 5,
4
+ apiBaseUrl: process.env.TAVILY_HOST,
5
+ });
6
+
7
+ export const tavily_extract = new TavilyExtract({
8
+ apiBaseUrl: process.env.TAVILY_HOST,
9
+ });
@@ -0,0 +1,38 @@
1
+ import { AgentProtocol } from './types';
2
+ import { StructuredTool } from '@langchain/core/tools';
3
+ import { MultiServerMCPClient } from '@langchain/mcp-adapters';
4
+ import * as tavily from './tools/tavily';
5
+ const prebuiltTools: Record<string, StructuredTool> = {
6
+ ...tavily,
7
+ };
8
+
9
+ export const createPrebuiltTools = async (protocol: AgentProtocol): Promise<StructuredTool[]> => {
10
+ const PrebuiltConfigs = protocol.tools.filter((i) => i.tool_type === 'builtin');
11
+ if (PrebuiltConfigs.length === 0) {
12
+ return [];
13
+ }
14
+ return PrebuiltConfigs.map((i) => prebuiltTools[i.name]);
15
+ };
16
+
17
+ export const createMCPTools = async (protocol: AgentProtocol): Promise<StructuredTool[]> => {
18
+ const MCPConfigs = protocol.tools.filter((i) => i.tool_type === 'mcp');
19
+ if (MCPConfigs.length === 0) {
20
+ return [];
21
+ }
22
+ const client = new MultiServerMCPClient({
23
+ mcpServers: Object.fromEntries(
24
+ MCPConfigs.map((i) => [
25
+ i.name,
26
+ {
27
+ url: i.url,
28
+ headers: i.headers,
29
+ },
30
+ ]),
31
+ ),
32
+ });
33
+ return client.getTools();
34
+ };
35
+
36
+ export const createTools = async (protocol: AgentProtocol): Promise<StructuredTool[]> => {
37
+ return [...(await createMCPTools(protocol)), ...(await createPrebuiltTools(protocol))];
38
+ };
@@ -0,0 +1,42 @@
1
+ export interface AgentTool {
2
+ name: string;
3
+ tool_type: string;
4
+ description?: string;
5
+ }
6
+
7
+ export interface MCPTool extends AgentTool {
8
+ tool_type: 'mcp';
9
+ type: string;
10
+ url: string;
11
+ headers?: Record<string, string>;
12
+ }
13
+ export interface BuiltinTool extends AgentTool {
14
+ tool_type: 'builtin';
15
+ }
16
+
17
+ export interface InnerTool extends AgentTool {
18
+ tool_type: 'inner';
19
+ }
20
+
21
+ export interface SubAgent {
22
+ protocolId: string;
23
+ protocol?: AgentProtocol;
24
+ }
25
+
26
+ export interface AgentProtocol {
27
+ id: string;
28
+ protocolVersion: string;
29
+ name: string;
30
+ description: string;
31
+ url: string;
32
+ iconUrl?: string;
33
+ version: string;
34
+ documentationUrl?: string;
35
+ llm: {
36
+ provider?: string;
37
+ model: string;
38
+ }[];
39
+ systemPrompt: string;
40
+ tools: (BuiltinTool | InnerTool | MCPTool)[];
41
+ subAgents: SubAgent[];
42
+ }
@@ -0,0 +1,4 @@
1
+ packages:
2
+ # 指定根目录直接子目录中的包
3
+ - "packages/*"
4
+ - "examples/*"
@@ -1,41 +1,24 @@
1
1
  import { zValidator } from '@hono/zod-validator';
2
2
  import { Hono } from 'hono';
3
- import { z } from 'zod';
4
3
  import { client } from './endpoint';
5
- import { MetadataSchema } from './zod';
4
+ import { AssistantsSearchSchema, AssistantGraphQuerySchema } from '../zod';
6
5
  const api = new Hono();
7
6
 
8
- api.post(
9
- '/assistants/search',
10
- zValidator(
11
- 'json',
12
- z.object({
13
- graph_id: z.string().optional(),
14
- metadata: MetadataSchema.optional(),
15
- limit: z.number().int().optional(),
16
- offset: z.number().int().optional(),
17
- }),
18
- ),
19
- async (c) => {
20
- // Search Assistants
21
- const payload = c.req.valid('json');
22
- let total = 0;
23
- const data = await client.assistants.search(payload);
24
- c.res.headers.set('X-Pagination-Total', total.toString());
25
- return c.json(data);
26
- },
27
- );
7
+ api.post('/assistants/search', zValidator('json', AssistantsSearchSchema), async (c) => {
8
+ // Search Assistants
9
+ const payload = c.req.valid('json');
10
+ let total = 0;
11
+ const data = await client.assistants.search(payload);
12
+ c.res.headers.set('X-Pagination-Total', total.toString());
13
+ return c.json(data);
14
+ });
28
15
 
29
- api.get(
30
- '/assistants/:assistant_id/graph',
31
- zValidator('query', z.object({ xray: z.string().optional() })),
32
- async (c) => {
33
- const xray = c.req.valid('query').xray;
34
- const data = await client.assistants.getGraph(c.req.param('assistant_id'), {
35
- xray: xray !== undefined ? xray === 'true' : undefined,
36
- });
37
- return c.json(data);
38
- },
39
- );
16
+ api.get('/assistants/:assistant_id/graph', zValidator('query', AssistantGraphQuerySchema), async (c) => {
17
+ const xray = c.req.valid('query').xray;
18
+ const data = await client.assistants.getGraph(c.req.param('assistant_id'), {
19
+ xray: xray !== undefined ? xray === 'true' : undefined,
20
+ });
21
+ return c.json(data);
22
+ });
40
23
 
41
24
  export default api;
@@ -1,4 +1,3 @@
1
1
  import { createEndpoint } from '../../createEndpoint.js';
2
- import { MemoryThreadsManager } from '../../storage/memory/threads.js';
3
2
 
4
- export const client = createEndpoint(new MemoryThreadsManager());
3
+ export const client = createEndpoint();
@@ -2,9 +2,14 @@ import { zValidator } from '@hono/zod-validator';
2
2
  import { Hono } from 'hono';
3
3
 
4
4
  import { streamSSE } from 'hono/streaming';
5
- import { z } from 'zod';
6
5
  import { client } from './endpoint';
7
- import { AssistantConfig, CommandSchema, MetadataSchema } from './zod';
6
+ import {
7
+ ThreadIdParamSchema,
8
+ RunIdParamSchema,
9
+ RunStreamPayloadSchema,
10
+ RunListQuerySchema,
11
+ RunCancelQuerySchema,
12
+ } from '../zod';
8
13
  import { serialiseAsDict } from '../../graph/stream';
9
14
 
10
15
  const api = new Hono();
@@ -12,36 +17,8 @@ const api = new Hono();
12
17
  // 最常用的对话接口
13
18
  api.post(
14
19
  '/threads/:thread_id/runs/stream',
15
- zValidator('param', z.object({ thread_id: z.string().uuid() })),
16
- zValidator(
17
- 'json',
18
- z
19
- .object({
20
- assistant_id: z.union([z.string().uuid(), z.string()]),
21
- checkpoint_id: z.string().optional(),
22
- // checkpoint: CheckpointSchema.optional(),
23
- input: z.any().optional(),
24
- command: CommandSchema.optional(),
25
- metadata: MetadataSchema.optional(),
26
- config: AssistantConfig.optional(),
27
- webhook: z.string().optional(),
28
- interrupt_before: z.union([z.literal('*'), z.array(z.string())]).optional(),
29
- interrupt_after: z.union([z.literal('*'), z.array(z.string())]).optional(),
30
- on_disconnect: z.enum(['cancel', 'continue']).optional().default('continue'),
31
- multitask_strategy: z.enum(['reject', 'rollback', 'interrupt', 'enqueue']).optional(),
32
- stream_mode: z
33
- .array(z.enum(['values', 'messages', 'messages-tuple', 'updates', 'events', 'debug', 'custom']))
34
- .optional(),
35
- stream_subgraphs: z.boolean().optional(),
36
- stream_resumable: z.boolean().optional(),
37
- after_seconds: z.number().optional(),
38
- if_not_exists: z.enum(['create', 'reject']).optional(),
39
- on_completion: z.enum(['complete', 'continue']).optional(),
40
- feedback_keys: z.array(z.string()).optional(),
41
- langsmith_tracer: z.unknown().optional(),
42
- })
43
- .describe('Payload for creating a stateful run.'),
44
- ),
20
+ zValidator('param', ThreadIdParamSchema),
21
+ zValidator('json', RunStreamPayloadSchema),
45
22
  async (c) => {
46
23
  // Stream Run
47
24
  const { thread_id } = c.req.valid('param');
@@ -51,7 +28,7 @@ api.post(
51
28
  return streamSSE(c, async (stream) => {
52
29
  /** @ts-ignore zod v3 的问题,与 ts 类型不一致 */
53
30
  for await (const { event, data } of client.runs.stream(thread_id, payload.assistant_id, payload)) {
54
- await stream.writeSSE({ data: serialiseAsDict(data), event });
31
+ await stream.writeSSE({ data: serialiseAsDict(data) ?? '', event });
55
32
  }
56
33
  });
57
34
  },
@@ -59,33 +36,20 @@ api.post(
59
36
 
60
37
  api.get(
61
38
  '/threads/:thread_id/runs',
62
- zValidator('param', z.object({ thread_id: z.string().uuid() })),
63
- zValidator(
64
- 'query',
65
- z.object({
66
- limit: z.string().optional(),
67
- offset: z.string().optional(),
68
- status: z.enum(['pending', 'running', 'error', 'success', 'timeout', 'interrupted']).optional(),
69
- }),
70
- ),
39
+ zValidator('param', ThreadIdParamSchema),
40
+ zValidator('query', RunListQuerySchema),
71
41
  async (c) => {
72
42
  const { thread_id } = c.req.valid('param');
73
43
  const { limit, offset, status } = c.req.valid('query');
74
- const runs = await client.runs.list(thread_id, { limit: Number(limit), offset: Number(offset), status });
44
+ const runs = await client.runs.list(thread_id, { limit, offset, status });
75
45
  return c.json(runs);
76
46
  },
77
47
  );
78
48
 
79
49
  api.post(
80
50
  '/threads/:thread_id/runs/:run_id/cancel',
81
- zValidator('param', z.object({ thread_id: z.string().uuid(), run_id: z.string().uuid() })),
82
- zValidator(
83
- 'query',
84
- z.object({
85
- wait: z.coerce.boolean().optional().default(false),
86
- action: z.enum(['interrupt', 'rollback']).optional().default('interrupt'),
87
- }),
88
- ),
51
+ zValidator('param', RunIdParamSchema),
52
+ zValidator('query', RunCancelQuerySchema),
89
53
  async (c) => {
90
54
  // Cancel Run Http
91
55
  const { thread_id, run_id } = c.req.valid('param');
@@ -1,88 +1,33 @@
1
1
  import { zValidator } from '@hono/zod-validator';
2
2
  import { Hono } from 'hono';
3
- import { z } from 'zod';
4
3
  import { client } from './endpoint';
5
- import { CommandSchema, MetadataSchema } from './zod';
4
+ import { ThreadIdParamSchema, ThreadCreatePayloadSchema, ThreadSearchPayloadSchema } from '../zod';
6
5
 
7
6
  const api = new Hono();
8
7
 
9
8
  // Threads Routes
10
- api.post(
11
- '/threads',
12
- zValidator(
13
- 'json',
14
- z
15
- .object({
16
- // supersteps: z
17
- // .array(
18
- // z.object({
19
- // updates: z.array(
20
- // z.object({
21
- // values: z.unknown(),
22
- // command: CommandSchema.optional(),
23
- // as_node: z.string(),
24
- // }),
25
- // ),
26
- // }),
27
- // )
28
- // .describe('The supersteps to apply to the thread.')
29
- // .optional(),
30
- thread_id: z
31
- .string()
32
- .uuid()
33
- .describe('The ID of the thread. If not provided, an ID is generated.')
34
- .optional(),
35
- metadata: MetadataSchema.optional(),
36
- if_exists: z.union([z.literal('raise'), z.literal('do_nothing')]).optional(),
37
- })
38
- .describe('Payload for creating a thread.'),
39
- ),
40
- async (c) => {
41
- const payload = c.req.valid('json');
42
- const thread = await client.threads.create(payload);
9
+ api.post('/threads', zValidator('json', ThreadCreatePayloadSchema), async (c) => {
10
+ const payload = c.req.valid('json');
11
+ const thread = await client.threads.create(payload);
43
12
 
44
- return c.json(thread);
45
- },
46
- );
13
+ return c.json(thread);
14
+ });
47
15
 
48
- api.post(
49
- '/threads/search',
50
- zValidator(
51
- 'json',
52
- z
53
- .object({
54
- metadata: z.record(z.unknown()).describe('Metadata to search for.').optional(),
55
- status: z
56
- .enum(['idle', 'busy', 'interrupted', 'error'])
57
- .describe('Filter by thread status.')
58
- .optional(),
59
- values: z.record(z.unknown()).describe('Filter by thread values.').optional(),
60
- limit: z.number().int().gte(1).lte(1000).describe('Maximum number to return.').optional(),
61
- offset: z.number().int().gte(0).describe('Offset to start from.').optional(),
62
- sort_by: z
63
- .enum(['thread_id', 'status', 'created_at', 'updated_at'])
64
- .describe('Sort by field.')
65
- .optional(),
66
- sort_order: z.enum(['asc', 'desc']).describe('Sort order.').optional(),
67
- })
68
- .describe('Payload for listing threads.'),
69
- ),
70
- async (c) => {
71
- // Search Threads
72
- const payload = c.req.valid('json');
73
- const result = await client.threads.search(payload as any);
74
- c.res.headers.set('X-Pagination-Total', result.length.toString());
75
- return c.json(result);
76
- },
77
- );
16
+ api.post('/threads/search', zValidator('json', ThreadSearchPayloadSchema), async (c) => {
17
+ // Search Threads
18
+ const payload = c.req.valid('json');
19
+ const result = await client.threads.search(payload as any);
20
+ c.res.headers.set('X-Pagination-Total', result.length.toString());
21
+ return c.json(result);
22
+ });
78
23
 
79
- api.get('/threads/:thread_id', zValidator('param', z.object({ thread_id: z.string().uuid() })), async (c) => {
24
+ api.get('/threads/:thread_id', zValidator('param', ThreadIdParamSchema), async (c) => {
80
25
  // Get Thread
81
26
  const { thread_id } = c.req.valid('param');
82
27
  return c.json(await client.threads.get(thread_id));
83
28
  });
84
29
 
85
- api.delete('/threads/:thread_id', zValidator('param', z.object({ thread_id: z.string().uuid() })), async (c) => {
30
+ api.delete('/threads/:thread_id', zValidator('param', ThreadIdParamSchema), async (c) => {
86
31
  // Delete Thread
87
32
  const { thread_id } = c.req.valid('param');
88
33
  await client.threads.delete(thread_id);
@@ -0,0 +1,2 @@
1
+ import { createEndpoint } from '../../createEndpoint.js';
2
+ export const client = createEndpoint();
@@ -0,0 +1,2 @@
1
+ // 统一路由处理器
2
+ export { GET, POST, DELETE } from "./router";