@langgraph-js/pure-graph 1.3.0 → 1.4.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 (71) hide show
  1. package/README.md +22 -14
  2. package/dist/adapter/nextjs/router.js +6 -6
  3. package/dist/global.d.ts +3 -2
  4. package/dist/storage/index.d.ts +4 -3
  5. package/dist/storage/index.js +13 -1
  6. package/dist/storage/pg/checkpoint.d.ts +2 -0
  7. package/dist/storage/pg/checkpoint.js +9 -0
  8. package/dist/storage/pg/threads.d.ts +43 -0
  9. package/dist/storage/pg/threads.js +304 -0
  10. package/dist/tsconfig.tsbuildinfo +1 -0
  11. package/package.json +38 -5
  12. package/.prettierrc +0 -11
  13. package/bun.lock +0 -209
  14. package/dist/adapter/hono/zod.d.ts +0 -203
  15. package/dist/adapter/hono/zod.js +0 -43
  16. package/dist/adapter/nextjs/zod.d.ts +0 -203
  17. package/dist/adapter/nextjs/zod.js +0 -60
  18. package/examples/nextjs/README.md +0 -36
  19. package/examples/nextjs/app/api/langgraph/[...path]/route.ts +0 -10
  20. package/examples/nextjs/app/favicon.ico +0 -0
  21. package/examples/nextjs/app/globals.css +0 -26
  22. package/examples/nextjs/app/layout.tsx +0 -34
  23. package/examples/nextjs/app/page.tsx +0 -211
  24. package/examples/nextjs/next.config.ts +0 -26
  25. package/examples/nextjs/package.json +0 -24
  26. package/examples/nextjs/postcss.config.mjs +0 -5
  27. package/examples/nextjs/tsconfig.json +0 -27
  28. package/packages/agent-graph/demo.json +0 -35
  29. package/packages/agent-graph/package.json +0 -18
  30. package/packages/agent-graph/src/index.ts +0 -47
  31. package/packages/agent-graph/src/tools/tavily.ts +0 -9
  32. package/packages/agent-graph/src/tools.ts +0 -38
  33. package/packages/agent-graph/src/types.ts +0 -42
  34. package/pnpm-workspace.yaml +0 -4
  35. package/src/adapter/hono/assistants.ts +0 -24
  36. package/src/adapter/hono/endpoint.ts +0 -3
  37. package/src/adapter/hono/index.ts +0 -14
  38. package/src/adapter/hono/runs.ts +0 -92
  39. package/src/adapter/hono/threads.ts +0 -37
  40. package/src/adapter/nextjs/endpoint.ts +0 -2
  41. package/src/adapter/nextjs/index.ts +0 -2
  42. package/src/adapter/nextjs/router.ts +0 -206
  43. package/src/adapter/nextjs/zod.ts +0 -66
  44. package/src/adapter/zod.ts +0 -144
  45. package/src/createEndpoint.ts +0 -116
  46. package/src/e.d.ts +0 -3
  47. package/src/global.ts +0 -11
  48. package/src/graph/stream.ts +0 -263
  49. package/src/graph/stringify.ts +0 -219
  50. package/src/index.ts +0 -6
  51. package/src/queue/JsonPlusSerializer.ts +0 -143
  52. package/src/queue/event_message.ts +0 -30
  53. package/src/queue/stream_queue.ts +0 -237
  54. package/src/storage/index.ts +0 -52
  55. package/src/storage/memory/checkpoint.ts +0 -2
  56. package/src/storage/memory/queue.ts +0 -91
  57. package/src/storage/memory/threads.ts +0 -183
  58. package/src/storage/redis/queue.ts +0 -148
  59. package/src/storage/sqlite/DB.ts +0 -16
  60. package/src/storage/sqlite/checkpoint.ts +0 -502
  61. package/src/storage/sqlite/threads.ts +0 -405
  62. package/src/storage/sqlite/type.ts +0 -12
  63. package/src/threads/index.ts +0 -37
  64. package/src/types.ts +0 -118
  65. package/src/utils/createEntrypointGraph.ts +0 -20
  66. package/src/utils/getGraph.ts +0 -44
  67. package/src/utils/getLangGraphCommand.ts +0 -21
  68. package/test/graph/entrypoint.ts +0 -21
  69. package/test/graph/index.ts +0 -60
  70. package/test/hono.ts +0 -15
  71. package/tsconfig.json +0 -20
@@ -1,35 +0,0 @@
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
- }
@@ -1,18 +0,0 @@
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
- }
@@ -1,47 +0,0 @@
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
- });
@@ -1,9 +0,0 @@
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
- });
@@ -1,38 +0,0 @@
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
- };
@@ -1,42 +0,0 @@
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
- }
@@ -1,4 +0,0 @@
1
- packages:
2
- # 指定根目录直接子目录中的包
3
- - "packages/*"
4
- - "examples/*"
@@ -1,24 +0,0 @@
1
- import { zValidator } from '@hono/zod-validator';
2
- import { Hono } from 'hono';
3
- import { client } from './endpoint';
4
- import { AssistantsSearchSchema, AssistantGraphQuerySchema } from '../zod';
5
- const api = new Hono();
6
-
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
- });
15
-
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
- });
23
-
24
- export default api;
@@ -1,3 +0,0 @@
1
- import { createEndpoint } from '../../createEndpoint.js';
2
-
3
- export const client = createEndpoint();
@@ -1,14 +0,0 @@
1
- import { Hono } from 'hono';
2
- import Assistants from './assistants';
3
- import Runs from './runs';
4
- import Threads from './threads';
5
- import { cors } from 'hono/cors';
6
- const app = new Hono();
7
-
8
- app.use(cors());
9
-
10
- app.route('/', Assistants);
11
- app.route('/', Runs);
12
- app.route('/', Threads);
13
-
14
- export default app;
@@ -1,92 +0,0 @@
1
- import { zValidator } from '@hono/zod-validator';
2
- import { Hono } from 'hono';
3
-
4
- import { streamSSE } from 'hono/streaming';
5
- import { client } from './endpoint';
6
- import {
7
- ThreadIdParamSchema,
8
- RunIdParamSchema,
9
- RunStreamPayloadSchema,
10
- RunListQuerySchema,
11
- RunCancelQuerySchema,
12
- ThreadStateUpdate,
13
- } from '../zod';
14
- import { serialiseAsDict } from '../../graph/stream';
15
- import { RunnableConfig } from '@langchain/core/runnables';
16
- import z from 'zod';
17
-
18
- const api = new Hono();
19
-
20
- // 最常用的对话接口
21
- api.post(
22
- '/threads/:thread_id/runs/stream',
23
- zValidator('param', ThreadIdParamSchema),
24
- zValidator('json', RunStreamPayloadSchema),
25
- async (c) => {
26
- // Stream Run
27
- const { thread_id } = c.req.valid('param');
28
- const payload = c.req.valid('json');
29
-
30
- // c.header('Content-Location', `/threads/${thread_id}/runs/${run.run_id}`);
31
- return streamSSE(c, async (stream) => {
32
- /** @ts-ignore zod v3 的问题,与 ts 类型不一致 */
33
- for await (const { event, data } of client.runs.stream(thread_id, payload.assistant_id, payload)) {
34
- await stream.writeSSE({ data: serialiseAsDict(data) ?? '', event });
35
- }
36
- });
37
- },
38
- );
39
-
40
- api.get(
41
- '/threads/:thread_id/runs',
42
- zValidator('param', ThreadIdParamSchema),
43
- zValidator('query', RunListQuerySchema),
44
- async (c) => {
45
- const { thread_id } = c.req.valid('param');
46
- const { limit, offset, status } = c.req.valid('query');
47
- const runs = await client.runs.list(thread_id, { limit, offset, status });
48
- return c.json(runs);
49
- },
50
- );
51
-
52
- api.post(
53
- '/threads/:thread_id/runs/:run_id/cancel',
54
- zValidator('param', RunIdParamSchema),
55
- zValidator('query', RunCancelQuerySchema),
56
- async (c) => {
57
- // Cancel Run Http
58
- const { thread_id, run_id } = c.req.valid('param');
59
- const { wait, action } = c.req.valid('query');
60
- const cancel = client.runs.cancel(thread_id, run_id, wait, action);
61
- if (wait) {
62
- await cancel;
63
- }
64
- return c.body(null, wait ? 204 : 202);
65
- },
66
- );
67
-
68
- api.post(
69
- '/threads/:thread_id/state',
70
- zValidator('param', z.object({ thread_id: z.string().uuid() })),
71
- zValidator('json', ThreadStateUpdate),
72
- async (c) => {
73
- // Update Thread State
74
- const { thread_id } = c.req.valid('param');
75
- const payload = c.req.valid('json');
76
- // const config: RunnableConfig = { configurable: { thread_id } };
77
-
78
- // if (payload.checkpoint_id) {
79
- // config.configurable ??= {};
80
- // config.configurable.checkpoint_id = payload.checkpoint_id;
81
- // }
82
- // if (payload.checkpoint) {
83
- // config.configurable ??= {};
84
- // Object.assign(config.configurable, payload.checkpoint);
85
- // }
86
-
87
- const inserted = await client.threads.updateState(thread_id, payload);
88
-
89
- return c.json(inserted);
90
- },
91
- );
92
- export default api;
@@ -1,37 +0,0 @@
1
- import { zValidator } from '@hono/zod-validator';
2
- import { Hono } from 'hono';
3
- import { client } from './endpoint';
4
- import { ThreadIdParamSchema, ThreadCreatePayloadSchema, ThreadSearchPayloadSchema } from '../zod';
5
-
6
- const api = new Hono();
7
-
8
- // Threads Routes
9
- api.post('/threads', zValidator('json', ThreadCreatePayloadSchema), async (c) => {
10
- const payload = c.req.valid('json');
11
- const thread = await client.threads.create(payload);
12
-
13
- return c.json(thread);
14
- });
15
-
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
- });
23
-
24
- api.get('/threads/:thread_id', zValidator('param', ThreadIdParamSchema), async (c) => {
25
- // Get Thread
26
- const { thread_id } = c.req.valid('param');
27
- return c.json(await client.threads.get(thread_id));
28
- });
29
-
30
- api.delete('/threads/:thread_id', zValidator('param', ThreadIdParamSchema), async (c) => {
31
- // Delete Thread
32
- const { thread_id } = c.req.valid('param');
33
- await client.threads.delete(thread_id);
34
- return new Response(null, { status: 204 });
35
- });
36
-
37
- export default api;
@@ -1,2 +0,0 @@
1
- import { createEndpoint } from '../../createEndpoint.js';
2
- export const client = createEndpoint();
@@ -1,2 +0,0 @@
1
- // 统一路由处理器
2
- export { GET, POST, DELETE } from "./router";
@@ -1,206 +0,0 @@
1
- /** @ts-ignore */
2
- import { NextRequest, NextResponse } from 'next/server';
3
- import { client } from './endpoint';
4
- import {
5
- AssistantsSearchSchema,
6
- AssistantGraphQuerySchema,
7
- RunStreamPayloadSchema,
8
- RunListQuerySchema,
9
- RunCancelQuerySchema,
10
- ThreadCreatePayloadSchema,
11
- ThreadSearchPayloadSchema,
12
- ThreadStateUpdate,
13
- } from '../zod';
14
- import { serialiseAsDict } from '../../graph/stream';
15
-
16
- // Next.js App Router 的 SSE 响应实现
17
- async function sseResponse(generator: AsyncGenerator<{ event: string; data: unknown }>): Promise<Response> {
18
- const encoder = new TextEncoder();
19
- const stream = new ReadableStream({
20
- async start(controller) {
21
- try {
22
- for await (const { event, data } of generator) {
23
- const line = `event: ${event}\n` + `data: ${serialiseAsDict(data, 0)}\n\n`;
24
- controller.enqueue(encoder.encode(line));
25
- }
26
- } catch (err) {
27
- // ignore
28
- } finally {
29
- controller.close();
30
- }
31
- },
32
- });
33
- return new Response(stream, {
34
- headers: {
35
- 'Content-Type': 'text/event-stream; charset=utf-8',
36
- 'Cache-Control': 'no-cache, no-transform',
37
- Connection: 'keep-alive',
38
- },
39
- });
40
- }
41
-
42
- // 统一路由处理器
43
- export async function GET(req: NextRequest) {
44
- const url = new URL(req.url);
45
- const pathname = url.pathname;
46
-
47
- // Assistants routes
48
- if (pathname.match(/\/assistants\/[^/]+\/graph$/)) {
49
- const match = pathname.match(/\/assistants\/([^/]+)\/graph$/);
50
- if (match) {
51
- const assistant_id = match[1];
52
- const xrayParam = url.searchParams.get('xray');
53
- const queryParams = { xray: xrayParam };
54
- const { xray } = AssistantGraphQuerySchema.parse(queryParams);
55
- const data = await client.assistants.getGraph(assistant_id, {
56
- xray: xray !== undefined ? xray === 'true' : undefined,
57
- });
58
- return NextResponse.json(data);
59
- }
60
- }
61
-
62
- // Threads routes
63
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}$/)) {
64
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})$/);
65
- if (match) {
66
- const thread_id = match[1];
67
- const data = await client.threads.get(thread_id);
68
- return NextResponse.json(data);
69
- }
70
- }
71
-
72
- // Runs routes
73
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/runs$/)) {
74
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/runs$/);
75
- if (match) {
76
- const thread_id = match[1];
77
- const limit = url.searchParams.get('limit');
78
- const offset = url.searchParams.get('offset');
79
- const status = url.searchParams.get('status');
80
- const queryParams = { limit, offset, status };
81
- const {
82
- limit: parsedLimit,
83
- offset: parsedOffset,
84
- status: parsedStatus,
85
- } = RunListQuerySchema.parse(queryParams);
86
- const runs = await client.runs.list(thread_id, {
87
- limit: parsedLimit,
88
- offset: parsedOffset,
89
- status: parsedStatus,
90
- });
91
- return Response.json(runs);
92
- }
93
- }
94
-
95
- return new NextResponse('Not Found', { status: 404 });
96
- }
97
-
98
- export async function POST(req: NextRequest) {
99
- const url = new URL(req.url);
100
- const pathname = url.pathname;
101
-
102
- // Assistants routes
103
- if (pathname.endsWith('/assistants/search')) {
104
- const body = await req.json();
105
- const payload = AssistantsSearchSchema.parse(body);
106
- const data = await client.assistants.search({
107
- graphId: payload.graph_id,
108
- metadata: payload.metadata as any,
109
- limit: payload.limit,
110
- offset: payload.offset,
111
- } as any);
112
- return NextResponse.json(data, {
113
- headers: { 'X-Pagination-Total': String(data.length) },
114
- });
115
- }
116
-
117
- // Threads routes
118
- if (pathname.endsWith('/threads')) {
119
- const body = await req.json();
120
- const payload = ThreadCreatePayloadSchema.parse(body);
121
- const thread = await client.threads.create({
122
- thread_id: payload.thread_id,
123
- metadata: payload.metadata as any,
124
- if_exists: (payload.if_exists as any) ?? undefined,
125
- });
126
- return NextResponse.json(thread);
127
- }
128
-
129
- if (pathname.endsWith('/threads/search')) {
130
- const body = await req.json();
131
- const payload = ThreadSearchPayloadSchema.parse(body);
132
- const result = await client.threads.search({
133
- metadata: payload.metadata as any,
134
- status: payload.status as any,
135
- limit: payload.limit,
136
- offset: payload.offset,
137
- sortBy: (payload.sort_by as any) ?? undefined,
138
- sortOrder: (payload.sort_order as any) ?? undefined,
139
- });
140
- return NextResponse.json(result, {
141
- headers: { 'X-Pagination-Total': String(result.length) },
142
- });
143
- }
144
-
145
- // Threads state update
146
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/state$/)) {
147
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/state$/);
148
- if (match) {
149
- const thread_id = match[1];
150
- const body = await req.json();
151
- const payload = ThreadStateUpdate.parse(body);
152
- const result = await client.threads.updateState(thread_id, payload);
153
- return NextResponse.json(result);
154
- }
155
- }
156
-
157
- // Runs routes - stream
158
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/runs\/stream$/)) {
159
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/runs\/stream$/);
160
- if (match) {
161
- const thread_id = match[1];
162
- const body = await req.json();
163
- const payload = RunStreamPayloadSchema.parse(body);
164
- const generator = client.runs.stream(thread_id, payload.assistant_id as string, payload as any);
165
- return sseResponse(generator as any);
166
- }
167
- }
168
-
169
- // Runs routes - cancel
170
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}\/runs\/[0-9a-fA-F-]{36}\/cancel$/)) {
171
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})\/runs\/([0-9a-fA-F-]{36})\/cancel$/);
172
- if (match) {
173
- const thread_id = match[1];
174
- const run_id = match[2];
175
- const waitParam = url.searchParams.get('wait');
176
- const actionParam = url.searchParams.get('action');
177
- const queryParams = {
178
- wait: waitParam ? waitParam === 'true' : false,
179
- action: actionParam ?? 'interrupt',
180
- };
181
- const { wait, action } = RunCancelQuerySchema.parse(queryParams);
182
- const promise = client.runs.cancel(thread_id, run_id, wait, action);
183
- if (wait) await promise;
184
- return new Response(null, { status: wait ? 204 : 202 });
185
- }
186
- }
187
-
188
- return new NextResponse('Not Found', { status: 404 });
189
- }
190
-
191
- export async function DELETE(req: NextRequest) {
192
- const url = new URL(req.url);
193
- const pathname = url.pathname;
194
-
195
- // Threads routes
196
- if (pathname.match(/\/threads\/[0-9a-fA-F-]{36}$/)) {
197
- const match = pathname.match(/\/threads\/([0-9a-fA-F-]{36})$/);
198
- if (match) {
199
- const thread_id = match[1];
200
- await client.threads.delete(thread_id);
201
- return new NextResponse(null, { status: 204 });
202
- }
203
- }
204
-
205
- return new NextResponse('Not Found', { status: 404 });
206
- }
@@ -1,66 +0,0 @@
1
- import z from "zod";
2
-
3
- export const AssistantConfigurable = z
4
- .object({
5
- thread_id: z.string().optional(),
6
- thread_ts: z.string().optional(),
7
- })
8
- .catchall(z.unknown());
9
-
10
- export const AssistantConfig = z
11
- .object({
12
- tags: z.array(z.string()).optional(),
13
- recursion_limit: z.number().int().optional(),
14
- configurable: AssistantConfigurable.optional(),
15
- })
16
- .catchall(z.unknown())
17
- .describe("The configuration of an assistant.");
18
-
19
- export const Assistant = z.object({
20
- assistant_id: z.string().uuid(),
21
- graph_id: z.string(),
22
- config: AssistantConfig,
23
- created_at: z.string(),
24
- updated_at: z.string(),
25
- metadata: z.object({}).catchall(z.any()),
26
- });
27
-
28
- export const MetadataSchema = z
29
- .object({
30
- source: z
31
- .union([
32
- z.literal("input"),
33
- z.literal("loop"),
34
- z.literal("update"),
35
- z.string(),
36
- ])
37
- .optional(),
38
- step: z.number().optional(),
39
- writes: z.record(z.unknown()).nullable().optional(),
40
- parents: z.record(z.string()).optional(),
41
- })
42
- .catchall(z.unknown());
43
-
44
- export const SendSchema = z.object({
45
- node: z.string(),
46
- input: z.unknown().nullable(),
47
- });
48
-
49
- export const CommandSchema = z.object({
50
- update: z
51
- .union([
52
- z.record(z.unknown()),
53
- z.array(z.tuple([z.string(), z.unknown()])),
54
- ])
55
- .nullable()
56
- .optional(),
57
- resume: z.unknown().optional(),
58
- goto: z
59
- .union([
60
- SendSchema,
61
- z.array(SendSchema),
62
- z.string(),
63
- z.array(z.string()),
64
- ])
65
- .optional(),
66
- });