@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.
- package/.prettierrc +11 -0
- package/README.md +104 -10
- package/bun.lock +209 -0
- package/dist/adapter/hono/assistants.js +3 -9
- package/dist/adapter/hono/endpoint.js +1 -2
- package/dist/adapter/hono/runs.js +6 -40
- package/dist/adapter/hono/threads.js +5 -46
- package/dist/adapter/nextjs/endpoint.d.ts +1 -0
- package/dist/adapter/nextjs/endpoint.js +2 -0
- package/dist/adapter/nextjs/index.d.ts +1 -0
- package/dist/adapter/nextjs/index.js +2 -0
- package/dist/adapter/nextjs/router.d.ts +5 -0
- package/dist/adapter/nextjs/router.js +168 -0
- package/dist/adapter/{hono → nextjs}/zod.d.ts +5 -5
- package/dist/adapter/{hono → nextjs}/zod.js +22 -5
- package/dist/adapter/zod.d.ts +577 -0
- package/dist/adapter/zod.js +119 -0
- package/dist/createEndpoint.d.ts +1 -2
- package/dist/createEndpoint.js +5 -5
- package/dist/global.d.ts +6 -4
- package/dist/global.js +10 -5
- package/dist/graph/stream.d.ts +1 -1
- package/dist/graph/stream.js +19 -11
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/queue/event_message.js +1 -1
- package/dist/queue/stream_queue.d.ts +5 -3
- package/dist/queue/stream_queue.js +4 -2
- package/dist/storage/index.d.ts +9 -4
- package/dist/storage/index.js +38 -3
- package/dist/storage/memory/queue.js +13 -4
- package/dist/storage/redis/queue.d.ts +39 -0
- package/dist/storage/redis/queue.js +130 -0
- package/dist/storage/sqlite/DB.d.ts +3 -0
- package/dist/storage/sqlite/DB.js +14 -0
- package/dist/storage/sqlite/checkpoint.d.ts +18 -0
- package/dist/storage/sqlite/checkpoint.js +374 -0
- package/dist/storage/sqlite/threads.d.ts +43 -0
- package/dist/storage/sqlite/threads.js +266 -0
- package/dist/storage/sqlite/type.d.ts +15 -0
- package/dist/storage/sqlite/type.js +1 -0
- package/dist/utils/createEntrypointGraph.d.ts +14 -0
- package/dist/utils/createEntrypointGraph.js +11 -0
- package/dist/utils/getGraph.js +3 -3
- package/examples/nextjs/README.md +36 -0
- package/examples/nextjs/app/api/langgraph/[...path]/route.ts +10 -0
- package/examples/nextjs/app/favicon.ico +0 -0
- package/examples/nextjs/app/globals.css +26 -0
- package/examples/nextjs/app/layout.tsx +34 -0
- package/examples/nextjs/app/page.tsx +211 -0
- package/examples/nextjs/next.config.ts +26 -0
- package/examples/nextjs/package.json +24 -0
- package/examples/nextjs/postcss.config.mjs +5 -0
- package/examples/nextjs/tsconfig.json +27 -0
- package/package.json +10 -4
- package/packages/agent-graph/demo.json +35 -0
- package/packages/agent-graph/package.json +18 -0
- package/packages/agent-graph/src/index.ts +47 -0
- package/packages/agent-graph/src/tools/tavily.ts +9 -0
- package/packages/agent-graph/src/tools.ts +38 -0
- package/packages/agent-graph/src/types.ts +42 -0
- package/pnpm-workspace.yaml +4 -0
- package/src/adapter/hono/assistants.ts +16 -33
- package/src/adapter/hono/endpoint.ts +1 -2
- package/src/adapter/hono/runs.ts +15 -51
- package/src/adapter/hono/threads.ts +15 -70
- package/src/adapter/nextjs/endpoint.ts +2 -0
- package/src/adapter/nextjs/index.ts +2 -0
- package/src/adapter/nextjs/router.ts +193 -0
- package/src/adapter/{hono → nextjs}/zod.ts +22 -5
- package/src/adapter/zod.ts +135 -0
- package/src/createEndpoint.ts +12 -5
- package/src/e.d.ts +3 -0
- package/src/global.ts +11 -6
- package/src/graph/stream.ts +20 -10
- package/src/index.ts +1 -0
- package/src/queue/stream_queue.ts +6 -5
- package/src/storage/index.ts +42 -4
- package/src/storage/redis/queue.ts +148 -0
- package/src/storage/sqlite/DB.ts +16 -0
- package/src/storage/sqlite/checkpoint.ts +503 -0
- package/src/storage/sqlite/threads.ts +366 -0
- package/src/storage/sqlite/type.ts +12 -0
- package/src/utils/createEntrypointGraph.ts +20 -0
- package/src/utils/getGraph.ts +3 -3
- package/test/graph/entrypoint.ts +21 -0
- package/test/graph/index.ts +45 -6
- package/test/hono.ts +5 -0
- 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,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
|
|
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.
|
|
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
|
+
}
|
|
@@ -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 {
|
|
4
|
+
import { AssistantsSearchSchema, AssistantGraphQuerySchema } from '../zod';
|
|
6
5
|
const api = new Hono();
|
|
7
6
|
|
|
8
|
-
api.post(
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
'
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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;
|
package/src/adapter/hono/runs.ts
CHANGED
|
@@ -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 {
|
|
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',
|
|
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',
|
|
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
|
|
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',
|
|
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 {
|
|
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
|
-
'
|
|
12
|
-
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
);
|
|
13
|
+
return c.json(thread);
|
|
14
|
+
});
|
|
47
15
|
|
|
48
|
-
api.post(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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',
|
|
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',
|
|
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);
|