langgraph-api 0.2.26__py3-none-any.whl → 0.2.28__py3-none-any.whl

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.

Potentially problematic release.


This version of langgraph-api might be problematic. Click here for more details.

Files changed (42) hide show
  1. langgraph_api/__init__.py +1 -1
  2. langgraph_api/api/assistants.py +4 -4
  3. langgraph_api/api/store.py +10 -6
  4. langgraph_api/asgi_transport.py +171 -0
  5. langgraph_api/asyncio.py +17 -0
  6. langgraph_api/config.py +1 -0
  7. langgraph_api/graph.py +28 -5
  8. langgraph_api/js/remote.py +16 -11
  9. langgraph_api/metadata.py +28 -16
  10. langgraph_api/store.py +127 -0
  11. langgraph_api/stream.py +17 -7
  12. langgraph_api/worker.py +1 -1
  13. {langgraph_api-0.2.26.dist-info → langgraph_api-0.2.28.dist-info}/METADATA +24 -30
  14. {langgraph_api-0.2.26.dist-info → langgraph_api-0.2.28.dist-info}/RECORD +42 -64
  15. {langgraph_api-0.2.26.dist-info → langgraph_api-0.2.28.dist-info}/WHEEL +1 -1
  16. langgraph_api-0.2.28.dist-info/entry_points.txt +2 -0
  17. langgraph_api/js/tests/api.test.mts +0 -2194
  18. langgraph_api/js/tests/auth.test.mts +0 -648
  19. langgraph_api/js/tests/compose-postgres.auth.yml +0 -59
  20. langgraph_api/js/tests/compose-postgres.yml +0 -59
  21. langgraph_api/js/tests/graphs/.gitignore +0 -1
  22. langgraph_api/js/tests/graphs/agent.css +0 -1
  23. langgraph_api/js/tests/graphs/agent.mts +0 -187
  24. langgraph_api/js/tests/graphs/agent.ui.tsx +0 -10
  25. langgraph_api/js/tests/graphs/agent_simple.mts +0 -105
  26. langgraph_api/js/tests/graphs/auth.mts +0 -106
  27. langgraph_api/js/tests/graphs/command.mts +0 -48
  28. langgraph_api/js/tests/graphs/delay.mts +0 -30
  29. langgraph_api/js/tests/graphs/dynamic.mts +0 -24
  30. langgraph_api/js/tests/graphs/error.mts +0 -17
  31. langgraph_api/js/tests/graphs/http.mts +0 -76
  32. langgraph_api/js/tests/graphs/langgraph.json +0 -11
  33. langgraph_api/js/tests/graphs/nested.mts +0 -44
  34. langgraph_api/js/tests/graphs/package.json +0 -13
  35. langgraph_api/js/tests/graphs/weather.mts +0 -57
  36. langgraph_api/js/tests/graphs/yarn.lock +0 -242
  37. langgraph_api/js/tests/utils.mts +0 -17
  38. langgraph_api-0.2.26.dist-info/LICENSE +0 -93
  39. langgraph_api-0.2.26.dist-info/entry_points.txt +0 -3
  40. logging.json +0 -22
  41. openapi.json +0 -4562
  42. /LICENSE → /langgraph_api-0.2.28.dist-info/licenses/LICENSE +0 -0
@@ -1,59 +0,0 @@
1
- services:
2
- langgraph-postgres:
3
- image: postgres:16.3
4
- ports:
5
- - "5433:5432"
6
- environment:
7
- POSTGRES_DB: postgres
8
- POSTGRES_USER: postgres
9
- POSTGRES_PASSWORD: postgres
10
- healthcheck:
11
- test: pg_isready -U postgres
12
- start_period: 10s
13
- timeout: 1s
14
- retries: 5
15
- interval: 60s
16
- start_interval: 1s
17
- langgraph-redis:
18
- image: redis:6
19
- restart: on-failure
20
- ports:
21
- - "6381:6379"
22
- healthcheck:
23
- test: redis-cli ping
24
- start_period: 10s
25
- timeout: 1s
26
- retries: 5
27
- interval: 60s
28
- start_interval: 1s
29
- api:
30
- build:
31
- context: graphs
32
- dockerfile_inline: |
33
- FROM langchain/langgraphjs-api:${NODE_VERSION:-20}
34
- ADD . /deps/graphs
35
- WORKDIR /deps/graphs
36
- RUN yarn install --frozen-lockfile
37
- ENV LANGSERVE_GRAPHS='{"agent":"./agent.mts:graph", "nested": "./nested.mts:graph", "weather": "./weather.mts:graph", "error": "./error.mts:graph", "delay": "./delay.mts:graph", "dynamic": "./dynamic.mts:graph", "command": "./command.mts:graph", "agent_simple": "./agent_simple.mts:graph"}'
38
- ENV LANGGRAPH_CONFIG='{"agent": {"configurable": {"model_name": "openai"}}}'
39
- ENV LANGGRAPH_HTTP='{"app": "./http.mts:app"}'
40
- ENV LANGGRAPH_UI='{"agent": "./agent.ui.tsx"}'
41
- RUN tsx /api/langgraph_api/js/build.mts
42
- depends_on:
43
- langgraph-postgres:
44
- condition: service_healthy
45
- langgraph-redis:
46
- condition: service_healthy
47
- ports:
48
- - "9123:8000"
49
- healthcheck:
50
- test: python /api/healthcheck.py
51
- interval: 60s
52
- start_interval: 1s
53
- start_period: 10s
54
- environment:
55
- REDIS_URI: redis://langgraph-redis:6379
56
- DATABASE_URI: postgres://postgres:postgres@langgraph-postgres:5432/postgres?sslmode=disable
57
- N_JOBS_PER_WORKER: "5"
58
- LANGGRAPH_CLOUD_LICENSE_KEY: ${LANGGRAPH_CLOUD_LICENSE_KEY}
59
- FF_JS_ZEROMQ_ENABLED: ${FF_JS_ZEROMQ_ENABLED}
@@ -1 +0,0 @@
1
- node_modules
@@ -1 +0,0 @@
1
- @import "tailwindcss";
@@ -1,187 +0,0 @@
1
- import { BaseMessage, ToolMessage } from "@langchain/core/messages";
2
- import {
3
- Annotation,
4
- StateGraph,
5
- START,
6
- END,
7
- messagesStateReducer,
8
- SharedValue,
9
- interrupt,
10
- type LangGraphRunnableConfig,
11
- } from "@langchain/langgraph";
12
- import { FakeListChatModel } from "@langchain/core/utils/testing";
13
- import { ChatGenerationChunk } from "@langchain/core/outputs";
14
- import { v4 as uuidv4 } from "uuid";
15
- import { CallbackManagerForLLMRun } from "@langchain/core/callbacks/manager";
16
- const GraphAnnotationOutput = Annotation.Root({
17
- messages: Annotation<BaseMessage[]>({
18
- reducer: messagesStateReducer,
19
- default: () => [],
20
- }),
21
- sharedStateValue: Annotation<string | null>(),
22
- interrupt: Annotation<boolean>(),
23
- keyOne: Annotation<string | null>(),
24
- keyTwo: Annotation<string | null>(),
25
- sleep: Annotation<number | null>(),
26
- });
27
-
28
- const GraphAnnotationInput = Annotation.Root({
29
- ...GraphAnnotationOutput.spec,
30
- sharedState: SharedValue.on("user_id"),
31
- sharedStateFromStoreConfig: Annotation<Record<string, any> | null>,
32
- });
33
-
34
- class StableFakeListChatModel extends FakeListChatModel {
35
- streamMessageId: string = uuidv4();
36
-
37
- async *_streamResponseChunks(
38
- _messages: BaseMessage[],
39
- options: this["ParsedCallOptions"],
40
- runManager?: CallbackManagerForLLMRun,
41
- ): AsyncGenerator<ChatGenerationChunk> {
42
- const response = this._currentResponse();
43
- this._incrementResponse();
44
- this.streamMessageId = uuidv4();
45
-
46
- if (this.emitCustomEvent) {
47
- await runManager?.handleCustomEvent("some_test_event", {
48
- someval: true,
49
- });
50
- }
51
-
52
- for await (const text of response) {
53
- await this._sleepIfRequested();
54
- if (options?.thrownErrorString) {
55
- throw new Error(options.thrownErrorString);
56
- }
57
- const chunk = this._createResponseChunk(text);
58
-
59
- // ensure stable ID
60
- chunk.message.id = this.streamMessageId;
61
- chunk.message.lc_kwargs.id = this.streamMessageId;
62
-
63
- yield chunk;
64
-
65
- void runManager?.handleLLMNewToken(
66
- text,
67
- undefined,
68
- undefined,
69
- undefined,
70
- undefined,
71
- { chunk },
72
- );
73
- }
74
- }
75
- }
76
-
77
- // For shared state
78
- const namespace = ["sharedState", "data"];
79
- const key = "user_id";
80
-
81
- const modelMap: Record<string, FakeListChatModel> = {};
82
- const getModel = (threadId: string) => {
83
- modelMap[threadId] ??= new StableFakeListChatModel({
84
- responses: ["begin", "end"],
85
- });
86
- return modelMap[threadId];
87
- };
88
-
89
- const agentNode = async (
90
- state: typeof GraphAnnotationInput.State,
91
- config: LangGraphRunnableConfig,
92
- ) => {
93
- if (state.interrupt) interrupt("i want to interrupt");
94
-
95
- if (state.sleep != null && state.messages.at(-1)?.getType() === "human") {
96
- const sleep = state.sleep;
97
- await new Promise((resolve) => setTimeout(resolve, sleep * 1000));
98
- }
99
-
100
- const model = getModel(config.configurable?.thread_id ?? "$");
101
- const response = await model.invoke(state.messages);
102
- const sharedStateValue = state.sharedState?.data?.user_id ?? null;
103
-
104
- // Define in the first node
105
- // Then retrieve in the second node
106
- const store = config.store;
107
- // Only set if it's not already set
108
- if (store && !state.sharedStateFromStoreConfig) {
109
- const value = { id: config?.configurable?.user_id };
110
- await store.put(namespace, key, value);
111
- }
112
-
113
- return {
114
- interrupt: false,
115
- messages: [response],
116
- sharedState: { data: { user_id: config?.configurable?.user_id } },
117
- sharedStateValue,
118
- };
119
- };
120
-
121
- const toolNode = async (
122
- state: typeof GraphAnnotationInput.State,
123
- config: LangGraphRunnableConfig,
124
- ) => {
125
- const store = config.store;
126
- let sharedStateFromStoreConfig: Record<string, any> | null = null;
127
- if (store) {
128
- const result = await store.get(namespace, key);
129
- sharedStateFromStoreConfig = result?.value ?? null;
130
- }
131
-
132
- const lastMessage = state.messages.at(-1);
133
- if (!lastMessage) return { messages: [], sharedStateFromStoreConfig };
134
- return {
135
- messages: [
136
- new ToolMessage({
137
- content: `tool_call__${lastMessage.content as string}`,
138
- tool_call_id: "tool_call_id",
139
- }),
140
- ],
141
- sharedStateFromStoreConfig,
142
- };
143
- };
144
-
145
- const checkSharedStateNode = async (
146
- _: typeof GraphAnnotationInput.State,
147
- config: LangGraphRunnableConfig,
148
- ): Promise<Partial<typeof GraphAnnotationInput.State>> => {
149
- const store = config.store;
150
- const namespace = ["inputtedState", "data"];
151
- const key = "my_key";
152
- if (store) {
153
- const result = await store.get(namespace, key);
154
- if (!result || !result.value.isTrue) {
155
- throw new Error("Value is not true");
156
- }
157
- }
158
-
159
- return {};
160
- };
161
-
162
- const agentCondEdge = (state: typeof GraphAnnotationInput.State) => {
163
- if ((state.messages[0].content as string) === "should_end") return END;
164
- if ((state.messages[0].content as string) === "___check_state_value")
165
- return "checkSharedState";
166
-
167
- const lastMessage = state.messages.at(-1);
168
- if (lastMessage?.content === "end") return END;
169
- return "tool";
170
- };
171
-
172
- const workflow = new StateGraph(
173
- {
174
- input: GraphAnnotationInput,
175
- output: GraphAnnotationOutput,
176
- },
177
- Annotation.Root({ model_name: Annotation<string> }),
178
- )
179
- .addNode("agent", agentNode)
180
- .addNode("tool", toolNode)
181
- .addNode("checkSharedState", checkSharedStateNode)
182
- .addEdge(START, "agent")
183
- .addConditionalEdges("agent", agentCondEdge)
184
- .addEdge("tool", "agent")
185
- .addEdge("checkSharedState", END);
186
-
187
- export const graph = (async () => workflow.compile())();
@@ -1,10 +0,0 @@
1
- import "./agent.css";
2
- import React from "react";
3
-
4
- export function StockPrice() {
5
- return <div>Stock Price</div>;
6
- }
7
-
8
- export default {
9
- "stock-price": StockPrice,
10
- } as const;
@@ -1,105 +0,0 @@
1
- import {
2
- StateGraph,
3
- END,
4
- Send,
5
- MessagesAnnotation,
6
- Annotation,
7
- START,
8
- LangGraphRunnableConfig,
9
- } from "@langchain/langgraph";
10
- import { AIMessage, BaseMessage, ToolMessage } from "@langchain/core/messages";
11
- import { FakeListChatModel } from "@langchain/core/utils/testing";
12
-
13
- const getStableModel = (() => {
14
- const cached: Record<string, FakeListChatModel> = {};
15
- return (threadId: string) => {
16
- cached[threadId] ??= new FakeListChatModel({
17
- responses: ["begin", "end\u2028"],
18
- });
19
- return cached[threadId];
20
- };
21
- })();
22
-
23
- const AgentState = Annotation.Root({
24
- key_one: Annotation<string>(),
25
- key_two: Annotation<string>(),
26
- sleep: Annotation<number>(),
27
- messages: MessagesAnnotation.spec.messages,
28
- prompts: MessagesAnnotation.spec.messages,
29
- });
30
-
31
- async function callModel(
32
- state: typeof AgentState.State,
33
- config: LangGraphRunnableConfig,
34
- ): Promise<typeof AgentState.Update> {
35
- let userId: string | undefined;
36
-
37
- if (config.configurable?.langgraph_auth_user != null) {
38
- const user = config.configurable?.langgraph_auth_user as
39
- | { identity: string }
40
- | undefined;
41
-
42
- userId = user?.identity;
43
- }
44
-
45
- if (config.configurable?.["x-configurable-header"] != null) {
46
- return {
47
- messages: [`end: ${config.configurable?.["x-configurable-header"]}`],
48
- };
49
- }
50
-
51
- if (config.configurable?.["map-reduce"] != null) {
52
- return { messages: ["map-reduce"] };
53
- }
54
-
55
- const model = getStableModel(config.configurable?.thread_id ?? "$");
56
- const existing = await config.store?.get([userId ?? "ALL"], "key_one");
57
- if (!existing) {
58
- const text = state.messages.at(-1)?.content;
59
- await config.store?.put([userId ?? "ALL"], "key_one", { text });
60
- }
61
-
62
- const response = await model.invoke(state.messages);
63
- return { messages: [response] };
64
- }
65
-
66
- async function callTool(
67
- message: BaseMessage,
68
- ): Promise<typeof AgentState.Update> {
69
- const response = new ToolMessage(
70
- `tool_call__${message.content}`,
71
- "tool_call_id",
72
- );
73
- return { messages: [response] };
74
- }
75
-
76
- function shouldContinue(
77
- state: typeof AgentState.State,
78
- ): typeof END | Send | Send[] {
79
- const lastMessage = state.messages.at(-1);
80
- if ((lastMessage?.content as string).startsWith("end")) return END;
81
- if ((lastMessage?.content as string).includes("map-reduce")) {
82
- return [
83
- new Send("map-reduce", { messages: [new AIMessage("first")] }),
84
- new Send("map-reduce", { messages: [new AIMessage("second")] }),
85
- new Send("map-reduce", { messages: [new AIMessage("third")] }),
86
- ];
87
- }
88
- return new Send("tool", lastMessage);
89
- }
90
-
91
- function callMapReduce(state: {
92
- messages: BaseMessage[];
93
- }): typeof AgentState.Update {
94
- return { prompts: state.messages.slice(-1) };
95
- }
96
-
97
- const workflow = new StateGraph(AgentState)
98
- .addNode("agent", callModel)
99
- .addNode("tool", callTool)
100
- .addNode("map-reduce", callMapReduce)
101
- .addEdge(START, "agent")
102
- .addConditionalEdges("agent", shouldContinue)
103
- .addEdge("tool", "agent");
104
-
105
- export const graph = workflow.compile();
@@ -1,106 +0,0 @@
1
- import { Auth, HTTPException } from "@langchain/langgraph-sdk/auth";
2
- import { JWTPayload, jwtVerify } from "jose";
3
-
4
- const SECRET_KEY = new TextEncoder().encode(
5
- "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7",
6
- );
7
- const ALGORITHM = "HS256";
8
-
9
- const USERS_DB: Record<
10
- string,
11
- {
12
- username: string;
13
- identity: string;
14
- full_name: string;
15
- email: string;
16
- permissions: string[];
17
- hashed_password: string;
18
- disabled: boolean;
19
- }
20
- > = {
21
- johndoe: {
22
- username: "johndoe",
23
- identity: "johndoe",
24
- full_name: "John Doe",
25
- email: "johndoe@example.com",
26
- permissions: ["read", "write", "assistants:write", "me"],
27
- hashed_password:
28
- "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW",
29
- disabled: false,
30
- },
31
- alice: {
32
- username: "alice",
33
- identity: "alice",
34
- full_name: "Alice Chains",
35
- email: "alicechains@example.com",
36
- permissions: ["read", "write", "assistants:write", "me"],
37
- hashed_password:
38
- "$2b$12$gSvqqUPvlXP2tfVFaWK1Be7DlH.PKZbv5H8KnzzVgXXbVxpva.pFm",
39
- disabled: true,
40
- },
41
- };
42
- export const auth = new Auth()
43
- .authenticate(async (request) => {
44
- const authorization = request.headers.get("Authorization");
45
-
46
- const exc = new HTTPException(401, {
47
- message: "Could not validate credentials",
48
- headers: { "WWW-Authenticate": "Bearer" },
49
- });
50
-
51
- if (!authorization?.toLocaleLowerCase().startsWith("bearer ")) {
52
- throw exc;
53
- }
54
-
55
- let payload: JWTPayload | undefined;
56
- try {
57
- const token = authorization.split(" ")[1];
58
- const result = await jwtVerify(token, SECRET_KEY, {
59
- algorithms: [ALGORITHM],
60
- });
61
- payload = result.payload;
62
- } catch (error) {
63
- throw new HTTPException(401, {
64
- message: "Failed to verify JWT token",
65
- cause: error,
66
- });
67
- }
68
-
69
- const scopes = (payload["scopes"] ?? []) as string[];
70
- const username = payload["sub"] as string | undefined;
71
- const user = username ? USERS_DB[username] : null;
72
- if (!user) throw exc;
73
-
74
- let permissions = user.permissions ?? [];
75
- permissions = scopes.filter((scope) => permissions.includes(scope));
76
-
77
- return { ...user, permissions };
78
- })
79
- .on("*", ({ permissions }) => {
80
- if (!permissions?.length) {
81
- throw new HTTPException(403, { message: "Not authorized" });
82
- }
83
- })
84
- .on("assistants:create", ({ value, user, permissions }) => {
85
- if (!permissions?.includes("assistants:write")) {
86
- throw new HTTPException(403, { message: "Not authorized" });
87
- }
88
-
89
- value.metadata ??= {};
90
- value.metadata["owner"] = user.identity;
91
- })
92
- .on("assistants:search", (params) => ({ owner: params.user.identity }))
93
- .on(["threads", "assistants"], ({ action, value, user }) => {
94
- const filters = { owner: user.identity };
95
- if (action === "create" || action === "update" || action === "create_run") {
96
- value.metadata ??= {};
97
- value.metadata["owner"] = user.identity;
98
- }
99
- return filters;
100
- })
101
- .on("store", ({ value, user }) => {
102
- const identity = user.identity;
103
- if (!identity || !value.namespace?.includes(identity)) {
104
- throw new HTTPException(403, { message: "Not authorized" });
105
- }
106
- });
@@ -1,48 +0,0 @@
1
- import {
2
- Annotation,
3
- Command,
4
- END,
5
- interrupt,
6
- Send,
7
- START,
8
- StateGraph,
9
- } from "@langchain/langgraph";
10
-
11
- const StateSchema = Annotation.Root({
12
- messages: Annotation<string[]>({
13
- reducer: (a: string[], b: string | string[]) => [
14
- ...a,
15
- ...(Array.isArray(b) ? b : [b]),
16
- ],
17
- default: () => [],
18
- }),
19
- });
20
-
21
- export const graph = new StateGraph(StateSchema)
22
- .addNode("router", () => new Command({ goto: END }), {
23
- ends: ["before_interrupt", "map", END],
24
- })
25
- .addNode("before_interrupt", () => ({ messages: ["before_interrupt"] }))
26
- .addNode("interrupt", () => {
27
- const resolved = interrupt("interrupt");
28
- return { messages: [`interrupt: ${resolved}`] };
29
- })
30
- .addNode(
31
- "map",
32
- () =>
33
- new Command({
34
- update: { messages: ["map"] },
35
- goto: [
36
- new Send("task", { value: 1 }),
37
- new Send("task", { value: 2 }),
38
- new Send("task", { value: 3 }),
39
- ],
40
- }),
41
- { ends: ["task"] },
42
- )
43
- .addNode("task", (arg: { value: number }) => ({
44
- messages: [`task: ${arg.value}`],
45
- }))
46
- .addEdge(START, "router")
47
- .addEdge("before_interrupt", "interrupt")
48
- .compile();
@@ -1,30 +0,0 @@
1
- import {
2
- MessagesAnnotation,
3
- StateGraph,
4
- END,
5
- START,
6
- Annotation,
7
- } from "@langchain/langgraph";
8
-
9
- const StateSchema = Annotation.Root({
10
- ...MessagesAnnotation.spec,
11
- delay: Annotation<number>(),
12
- });
13
-
14
- const longRunning = async (
15
- state: typeof StateSchema.State,
16
- ): Promise<typeof StateSchema.Update> => {
17
- if (state.delay === -1) {
18
- while (true) {
19
- // hang the event loop
20
- }
21
- }
22
- await new Promise((resolve) => setTimeout(resolve, state.delay));
23
- return { messages: [`finished after ${state.delay}ms`] };
24
- };
25
-
26
- export const graph = new StateGraph(StateSchema)
27
- .addNode("long_running", longRunning)
28
- .addEdge(START, "long_running")
29
- .addEdge("long_running", END)
30
- .compile();
@@ -1,24 +0,0 @@
1
- import { StateGraph, Annotation } from "@langchain/langgraph";
2
-
3
- export const graph = async (config: {
4
- configurable?: { nodeName: string };
5
- }) => {
6
- const node = config.configurable?.nodeName ?? "default";
7
-
8
- const state = Annotation.Root({
9
- node: Annotation<string>,
10
- messages: Annotation<string[]>({
11
- default: () => [],
12
- reducer: (a: string[], b: string[] | string) => {
13
- if (Array.isArray(b)) return [...a, ...b];
14
- return [...a, b];
15
- },
16
- }),
17
- });
18
-
19
- return new StateGraph(state)
20
- .addNode(node, () => ({ node, messages: [node] }))
21
- .addEdge("__start__", node)
22
- .addEdge(node, "__end__")
23
- .compile();
24
- };
@@ -1,17 +0,0 @@
1
- import { StateGraph, START } from "@langchain/langgraph";
2
- import { MessagesAnnotation } from "@langchain/langgraph";
3
-
4
- class CustomError extends Error {
5
- constructor(message: string) {
6
- super(message);
7
- this.name = "CustomError";
8
- }
9
- }
10
-
11
- export const graph = new StateGraph(MessagesAnnotation)
12
- .addNode("error_node", async () => {
13
- await new Promise((resolve) => setTimeout(resolve, 1000));
14
- throw new CustomError("Boo!");
15
- })
16
- .addEdge(START, "error_node")
17
- .compile();
@@ -1,76 +0,0 @@
1
- import { Hono } from "hono";
2
- import { HTTPException } from "hono/http-exception";
3
- import { streamText } from "hono/streaming";
4
- import { Client } from "@langchain/langgraph-sdk";
5
-
6
- let WEBHOOK_PAYLOAD: Record<string, unknown>;
7
-
8
- export const app = new Hono<{
9
- Variables: {
10
- body: string | ArrayBuffer | ReadableStream | null;
11
- };
12
- }>()
13
- .use(async (c, next) => {
14
- if (c.req.query("interrupt") != null) {
15
- return c.json({ status: "interrupted" });
16
- }
17
-
18
- await next();
19
- c.header("x-js-middleware", "true");
20
- })
21
- .use(async (c, next) => {
22
- const runsQuery = new RegExp(
23
- "^(/runs(/stream|/wait)?$|/runs/batch$|/threads/[^/]+/runs(/stream|/wait)?)$",
24
- );
25
-
26
- if (c.req.method === "POST" && c.req.path.match(runsQuery)) {
27
- const value = c.req.header("x-configurable-header");
28
-
29
- if (value != null) {
30
- const body = await c.req.json();
31
-
32
- body["config"] ??= {};
33
- body["config"]["configurable"] ??= {};
34
- body["config"]["configurable"]["x-configurable-header"] ??= value;
35
- }
36
- }
37
-
38
- await next();
39
- })
40
- .get("/custom/client", async (c) => {
41
- const result = await new Client().runs.wait(null, "agent_simple", {
42
- input: { messages: [{ role: "human", content: "input" }] },
43
- });
44
-
45
- return c.json({ result });
46
- })
47
- .get("/custom/my-route", (c) =>
48
- c.json(
49
- { foo: "bar" },
50
- {
51
- headers: {
52
- "x-custom-output": c.req.header("x-custom-input") as string,
53
- },
54
- },
55
- ),
56
- )
57
- .get("/runs/afakeroute", (c) => c.json({ foo: "afakeroute" }))
58
- .get("/custom/error", () => {
59
- throw new HTTPException(400, { message: "Bad request" });
60
- })
61
- .get("/custom/streaming", (c) =>
62
- streamText(c, async (stream) => {
63
- for (let i = 0; i < 4; i++) {
64
- await stream.writeln(`Count: ${i}`);
65
- await new Promise((resolve) => setTimeout(resolve, 10));
66
- }
67
-
68
- await stream.close();
69
- }),
70
- )
71
- .post("/custom/webhook", async (c) => {
72
- WEBHOOK_PAYLOAD = await c.req.json();
73
- return c.json({ status: "success" });
74
- })
75
- .get("/custom/webhook-payload", (c) => c.json(WEBHOOK_PAYLOAD))
76
- .notFound((c) => c.json({ status: "not-found" }));
@@ -1,11 +0,0 @@
1
- {
2
- "node_version": "20",
3
- "graphs": {
4
- "agent": "./agent.mts:graph",
5
- "subgraph": "./subgraph.mts:graph",
6
- "nested": "./nested.mts:graph",
7
- "dynamic": "./dynamic.mts:graph",
8
- "delay": "./delay.mts:graph",
9
- "command": "./command.mts:graph"
10
- }
11
- }