langgraph-cli 0.4.2__tar.gz → 0.4.3__tar.gz

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 (122) hide show
  1. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/PKG-INFO +1 -1
  2. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graph_prerelease_reqs/agent.py +1 -7
  3. langgraph_cli-0.4.3/examples/graph_prerelease_reqs/deps/additional_deps/pyproject.toml +9 -0
  4. langgraph_cli-0.4.3/examples/graph_prerelease_reqs/deps/zuper_deps/pyproject.toml +9 -0
  5. langgraph_cli-0.4.3/examples/graph_prerelease_reqs/langgraph.json +13 -0
  6. langgraph_cli-0.4.3/examples/graph_prerelease_reqs/pyproject.toml +14 -0
  7. langgraph_cli-0.4.3/examples/graph_prerelease_reqs_fail/agent.py +89 -0
  8. langgraph_cli-0.4.3/examples/graph_prerelease_reqs_fail/pyproject.toml +11 -0
  9. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs/agent.py +8 -7
  10. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs/langgraph.json +1 -0
  11. {langgraph_cli-0.4.2/examples/graphs_reqs_b → langgraph_cli-0.4.3/examples/graphs_reqs_a}/graphs_submod/agent.py +9 -5
  12. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/langgraph.json +1 -0
  13. {langgraph_cli-0.4.2/examples/graphs_reqs_a → langgraph_cli-0.4.3/examples/graphs_reqs_b}/graphs_submod/agent.py +9 -4
  14. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/langgraph.json +1 -0
  15. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/langgraph.json +1 -0
  16. langgraph_cli-0.4.3/langgraph_cli/__init__.py +1 -0
  17. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/config.py +40 -6
  18. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/docker.py +3 -1
  19. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/langgraph.json +1 -0
  20. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/schemas/schema.json +18 -0
  21. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/schemas/schema.v0.json +18 -0
  22. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/cli/test_cli.py +2 -2
  23. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/test_config.py +21 -21
  24. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/test_docker.py +22 -0
  25. langgraph_cli-0.4.3/tests/unit_tests/test_util.py +188 -0
  26. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/uv.lock +628 -411
  27. langgraph_cli-0.4.2/examples/graph_prerelease_reqs/requirements.txt +0 -6
  28. langgraph_cli-0.4.2/langgraph_cli/__init__.py +0 -1
  29. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/.gitignore +0 -0
  30. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/LICENSE +0 -0
  31. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/Makefile +0 -0
  32. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/README.md +0 -0
  33. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/.env.example +0 -0
  34. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/.gitignore +0 -0
  35. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/Makefile +0 -0
  36. {langgraph_cli-0.4.2/examples/graph_prerelease_reqs → langgraph_cli-0.4.3/examples/graph_prerelease_reqs_fail}/langgraph.json +0 -0
  37. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs/storm.py +0 -0
  38. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/__init__.py +0 -0
  39. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/graphs_submod/__init__.py +0 -0
  40. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/graphs_submod/subprompt.txt +0 -0
  41. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/hello.py +0 -0
  42. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/prompt.txt +0 -0
  43. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_a/requirements.txt +0 -0
  44. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/graphs_submod/subprompt.txt +0 -0
  45. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/hello.py +0 -0
  46. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/prompt.txt +0 -0
  47. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/requirements.txt +0 -0
  48. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/utils/__init__.py +0 -0
  49. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/graphs_reqs_b/utils/greeter.py +0 -0
  50. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/langgraph.json +0 -0
  51. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/my_app.py +0 -0
  52. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/pipconf.txt +0 -0
  53. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/poetry.lock +0 -0
  54. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/examples/pyproject.toml +0 -0
  55. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/generate_schema.py +0 -0
  56. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/.dockerignore +0 -0
  57. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/.env.example +0 -0
  58. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/.eslintrc.cjs +0 -0
  59. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/.gitignore +0 -0
  60. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/LICENSE +0 -0
  61. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/README.md +0 -0
  62. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/jest.config.js +0 -0
  63. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/package.json +0 -0
  64. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/src/agent/graph.ts +0 -0
  65. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/src/agent/state.ts +0 -0
  66. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/static/studio.png +0 -0
  67. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/tests/agent.test.ts +0 -0
  68. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/tests/graph.int.test.ts +0 -0
  69. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/tsconfig.json +0 -0
  70. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-examples/yarn.lock +0 -0
  71. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/.eslintrc.cjs +0 -0
  72. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/apps/agent/langgraph.json +0 -0
  73. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/apps/agent/package.json +0 -0
  74. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/apps/agent/src/graph.ts +0 -0
  75. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/apps/agent/src/state.ts +0 -0
  76. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/apps/agent/tsconfig.json +0 -0
  77. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/libs/shared/package.json +0 -0
  78. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/libs/shared/src/index.ts +0 -0
  79. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/libs/shared/tsconfig.json +0 -0
  80. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/package.json +0 -0
  81. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/tsconfig.json +0 -0
  82. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/turbo.json +0 -0
  83. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/js-monorepo-example/yarn.lock +0 -0
  84. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/__main__.py +0 -0
  85. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/analytics.py +0 -0
  86. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/cli.py +0 -0
  87. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/constants.py +0 -0
  88. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/exec.py +0 -0
  89. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/progress.py +0 -0
  90. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/py.typed +0 -0
  91. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/templates.py +0 -0
  92. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/util.py +0 -0
  93. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/langgraph_cli/version.py +0 -0
  94. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/pyproject.toml +0 -0
  95. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/.env.example +0 -0
  96. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/pyproject.toml +0 -0
  97. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/src/agent/__init__.py +0 -0
  98. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/src/agent/graph.py +0 -0
  99. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/apps/agent/src/agent/state.py +0 -0
  100. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/libs/common/__init__.py +0 -0
  101. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/libs/common/helpers.py +0 -0
  102. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/libs/shared/pyproject.toml +0 -0
  103. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/libs/shared/src/shared/__init__.py +0 -0
  104. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/libs/shared/src/shared/utils.py +0 -0
  105. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/python-monorepo-example/pyproject.toml +0 -0
  106. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/schemas/version.schema.json +0 -0
  107. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/__init__.py +0 -0
  108. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/integration_tests/__init__.py +0 -0
  109. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/integration_tests/test_cli.py +0 -0
  110. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/__init__.py +0 -0
  111. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/agent.py +0 -0
  112. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/cli/__init__.py +0 -0
  113. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/cli/langgraph.json +0 -0
  114. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/cli/pyproject.toml +0 -0
  115. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/cli/test_templates.py +0 -0
  116. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/conftest.py +0 -0
  117. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/graphs/agent.py +0 -0
  118. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/helpers.py +0 -0
  119. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/multiplatform/js.mts +0 -0
  120. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/multiplatform/python.py +0 -0
  121. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/pipconfig.txt +0 -0
  122. {langgraph_cli-0.4.2 → langgraph_cli-0.4.3}/tests/unit_tests/test_config.json +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: langgraph-cli
3
- Version: 0.4.2
3
+ Version: 0.4.3
4
4
  Summary: CLI for interacting with LangGraph API
5
5
  Project-URL: Repository, https://www.github.com/langchain-ai/langgraph
6
6
  License-Expression: MIT
@@ -1,7 +1,6 @@
1
1
  from collections.abc import Sequence
2
2
  from typing import Annotated, Literal, TypedDict
3
3
 
4
- from langchain.chat_models import init_chat_model
5
4
  from langchain_community.tools.tavily_search import TavilySearchResults
6
5
  from langchain_core.messages import BaseMessage
7
6
  from langchain_openai import ChatOpenAI
@@ -10,10 +9,8 @@ from langgraph.prebuilt import ToolNode
10
9
 
11
10
  tools = [TavilySearchResults(max_results=1)]
12
11
 
13
- model_anth = init_chat_model("claude-3-7-sonnet-20250219", model_provider="anthropic")
14
12
  model_oai = ChatOpenAI(temperature=0)
15
13
 
16
- model_anth = model_anth.bind_tools(tools)
17
14
  model_oai = model_oai.bind_tools(tools)
18
15
 
19
16
 
@@ -35,10 +32,7 @@ def should_continue(state):
35
32
 
36
33
  # Define the function that calls the model
37
34
  def call_model(state, config):
38
- if config["configurable"].get("model", "anthropic") == "anthropic":
39
- model = model_anth
40
- else:
41
- model = model_oai
35
+ model = model_oai
42
36
  messages = state["messages"]
43
37
  response = model.invoke(messages)
44
38
  # We return a list, because this will get added to the existing list
@@ -0,0 +1,9 @@
1
+ [project]
2
+ name = "graph-prerelease-reqs-additional-deps"
3
+ version = "0.1.0"
4
+ description = "Test for prerelease stuff"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "langgraph==0.6.0"
9
+ ]
@@ -0,0 +1,9 @@
1
+ [project]
2
+ name = "graph-prerelease-reqs-zuper-deps"
3
+ version = "0.1.0"
4
+ description = "Test for prerelease stuff"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "langchain-openai==0.3.0"
9
+ ]
@@ -0,0 +1,13 @@
1
+ {
2
+ "python_version": "3.12",
3
+ "dependencies": [
4
+ ".",
5
+ "./deps/additional_deps",
6
+ "./deps/zuper_deps"
7
+ ],
8
+ "graphs": {
9
+ "agent": "./agent.py:graph"
10
+ },
11
+ "env": "../.env"
12
+ }
13
+
@@ -0,0 +1,14 @@
1
+ [project]
2
+ name = "graph-prerelease-reqs"
3
+ version = "0.1.0"
4
+ description = "Test for prerelease stuff"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "langchain-openai==1.0.0a2",
9
+ "langgraph==1.0.0a2",
10
+ "langchain_community>=0.3.0",
11
+ ]
12
+
13
+ [tool.uv]
14
+ prerelease = "allow"
@@ -0,0 +1,89 @@
1
+ from collections.abc import Sequence
2
+ from typing import Annotated, Literal, TypedDict
3
+
4
+ from langchain_community.tools.tavily_search import TavilySearchResults
5
+ from langchain_core.messages import BaseMessage
6
+ from langchain_openai import ChatOpenAI
7
+ from langgraph.graph import END, StateGraph, add_messages
8
+ from langgraph.prebuilt import ToolNode
9
+
10
+ tools = [TavilySearchResults(max_results=1)]
11
+
12
+ model_oai = ChatOpenAI(temperature=0)
13
+
14
+ model_oai = model_oai.bind_tools(tools)
15
+
16
+
17
+ class AgentState(TypedDict):
18
+ messages: Annotated[Sequence[BaseMessage], add_messages]
19
+
20
+
21
+ # Define the function that determines whether to continue or not
22
+ def should_continue(state):
23
+ messages = state["messages"]
24
+ last_message = messages[-1]
25
+ # If there are no tool calls, then we finish
26
+ if not last_message.tool_calls:
27
+ return "end"
28
+ # Otherwise if there is, we continue
29
+ else:
30
+ return "continue"
31
+
32
+
33
+ # Define the function that calls the model
34
+ def call_model(state, config):
35
+ model = model_oai
36
+ messages = state["messages"]
37
+ response = model.invoke(messages)
38
+ # We return a list, because this will get added to the existing list
39
+ return {"messages": [response]}
40
+
41
+
42
+ # Define the function to execute tools
43
+ tool_node = ToolNode(tools)
44
+
45
+
46
+ class ContextSchema(TypedDict):
47
+ model: Literal["anthropic", "openai"]
48
+
49
+
50
+ # Define a new graph
51
+ workflow = StateGraph(AgentState, context_schema=ContextSchema)
52
+
53
+ # Define the two nodes we will cycle between
54
+ workflow.add_node("agent", call_model)
55
+ workflow.add_node("action", tool_node)
56
+
57
+ # Set the entrypoint as `agent`
58
+ # This means that this node is the first one called
59
+ workflow.set_entry_point("agent")
60
+
61
+ # We now add a conditional edge
62
+ workflow.add_conditional_edges(
63
+ # First, we define the start node. We use `agent`.
64
+ # This means these are the edges taken after the `agent` node is called.
65
+ "agent",
66
+ # Next, we pass in the function that will determine which node is called next.
67
+ should_continue,
68
+ # Finally we pass in a mapping.
69
+ # The keys are strings, and the values are other nodes.
70
+ # END is a special node marking that the graph should finish.
71
+ # What will happen is we will call `should_continue`, and then the output of that
72
+ # will be matched against the keys in this mapping.
73
+ # Based on which one it matches, that node will then be called.
74
+ {
75
+ # If `tools`, then we call the tool node.
76
+ "continue": "action",
77
+ # Otherwise we finish.
78
+ "end": END,
79
+ },
80
+ )
81
+
82
+ # We now add a normal edge from `tools` to `agent`.
83
+ # This means that after `tools` is called, `agent` node is called next.
84
+ workflow.add_edge("action", "agent")
85
+
86
+ # Finally, we compile it!
87
+ # This compiles it into a LangChain Runnable,
88
+ # meaning you can use it as you would any other runnable
89
+ graph = workflow.compile()
@@ -0,0 +1,11 @@
1
+ [project]
2
+ name = "graph-prerelease-reqs"
3
+ version = "0.1.0"
4
+ description = "Test for prerelease stuff"
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ dependencies = [
8
+ "langchain-openai==1.0.0a2",
9
+ "langgraph==1.0.0a2",
10
+ "langchain_community>=0.3.0",
11
+ ]
@@ -7,6 +7,7 @@ from langchain_core.messages import BaseMessage
7
7
  from langchain_openai import ChatOpenAI
8
8
  from langgraph.graph import END, StateGraph, add_messages
9
9
  from langgraph.prebuilt import ToolNode
10
+ from langgraph.runtime import Runtime
10
11
 
11
12
  tools = [TavilySearchResults(max_results=1)]
12
13
 
@@ -17,6 +18,10 @@ model_anth = model_anth.bind_tools(tools)
17
18
  model_oai = model_oai.bind_tools(tools)
18
19
 
19
20
 
21
+ class AgentContext(TypedDict):
22
+ model: Literal["anthropic", "openai"]
23
+
24
+
20
25
  class AgentState(TypedDict):
21
26
  messages: Annotated[Sequence[BaseMessage], add_messages]
22
27
 
@@ -34,8 +39,8 @@ def should_continue(state):
34
39
 
35
40
 
36
41
  # Define the function that calls the model
37
- def call_model(state, config):
38
- if config["configurable"].get("model", "anthropic") == "anthropic":
42
+ def call_model(state, runtime: Runtime[AgentContext]):
43
+ if runtime.context.get("model", "anthropic") == "anthropic":
39
44
  model = model_anth
40
45
  else:
41
46
  model = model_oai
@@ -49,12 +54,8 @@ def call_model(state, config):
49
54
  tool_node = ToolNode(tools)
50
55
 
51
56
 
52
- class ContextSchema(TypedDict):
53
- model: Literal["anthropic", "openai"]
54
-
55
-
56
57
  # Define a new graph
57
- workflow = StateGraph(AgentState, context_schema=ContextSchema)
58
+ workflow = StateGraph(AgentState, context_schema=AgentContext)
58
59
 
59
60
  # Define the two nodes we will cycle between
60
61
  workflow.add_node("agent", call_model)
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://langgra.ph/schema.json",
2
3
  "python_version": "3.12",
3
4
  "dependencies": [
4
5
  "langchain_community",
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Sequence
2
2
  from pathlib import Path
3
- from typing import Annotated, TypedDict
3
+ from typing import Annotated, Literal, TypedDict
4
4
 
5
5
  from langchain_anthropic import ChatAnthropic
6
6
  from langchain_community.tools.tavily_search import TavilySearchResults
@@ -8,6 +8,7 @@ from langchain_core.messages import BaseMessage
8
8
  from langchain_openai import ChatOpenAI
9
9
  from langgraph.graph import END, StateGraph, add_messages
10
10
  from langgraph.prebuilt import ToolNode
11
+ from langgraph.runtime import Runtime
11
12
 
12
13
  tools = [TavilySearchResults(max_results=1)]
13
14
 
@@ -21,6 +22,10 @@ prompt = open(Path(__file__).parent.parent / "prompt.txt").read()
21
22
  subprompt = open(Path(__file__).parent / "subprompt.txt").read()
22
23
 
23
24
 
25
+ class AgentContext(TypedDict):
26
+ model: Literal["anthropic", "openai"]
27
+
28
+
24
29
  class AgentState(TypedDict):
25
30
  messages: Annotated[Sequence[BaseMessage], add_messages]
26
31
 
@@ -38,8 +43,8 @@ def should_continue(state):
38
43
 
39
44
 
40
45
  # Define the function that calls the model
41
- def call_model(state, config):
42
- if config["configurable"].get("model", "anthropic") == "anthropic":
46
+ def call_model(state, runtime: Runtime[AgentContext]):
47
+ if runtime.context.get("model", "anthropic") == "anthropic":
43
48
  model = model_anth
44
49
  else:
45
50
  model = model_oai
@@ -52,9 +57,8 @@ def call_model(state, config):
52
57
  # Define the function to execute tools
53
58
  tool_node = ToolNode(tools)
54
59
 
55
-
56
60
  # Define a new graph
57
- workflow = StateGraph(AgentState)
61
+ workflow = StateGraph(AgentState, context_schema=AgentContext)
58
62
 
59
63
  # Define the two nodes we will cycle between
60
64
  workflow.add_node("agent", call_model)
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://langgra.ph/schema.json",
2
3
  "dependencies": [
3
4
  "."
4
5
  ],
@@ -1,6 +1,6 @@
1
1
  from collections.abc import Sequence
2
2
  from pathlib import Path
3
- from typing import Annotated, TypedDict
3
+ from typing import Annotated, Literal, TypedDict
4
4
 
5
5
  from langchain_anthropic import ChatAnthropic
6
6
  from langchain_community.tools.tavily_search import TavilySearchResults
@@ -8,6 +8,7 @@ from langchain_core.messages import BaseMessage
8
8
  from langchain_openai import ChatOpenAI
9
9
  from langgraph.graph import END, StateGraph, add_messages
10
10
  from langgraph.prebuilt import ToolNode
11
+ from langgraph.runtime import Runtime
11
12
 
12
13
  tools = [TavilySearchResults(max_results=1)]
13
14
 
@@ -21,6 +22,10 @@ prompt = open(Path(__file__).parent.parent / "prompt.txt").read()
21
22
  subprompt = open(Path(__file__).parent / "subprompt.txt").read()
22
23
 
23
24
 
25
+ class AgentContext(TypedDict):
26
+ model: Literal["anthropic", "openai"]
27
+
28
+
24
29
  class AgentState(TypedDict):
25
30
  messages: Annotated[Sequence[BaseMessage], add_messages]
26
31
 
@@ -38,8 +43,8 @@ def should_continue(state):
38
43
 
39
44
 
40
45
  # Define the function that calls the model
41
- def call_model(state, config):
42
- if config["configurable"].get("model", "anthropic") == "anthropic":
46
+ def call_model(state, runtime: Runtime[AgentContext]):
47
+ if runtime.context.get("model", "anthropic") == "anthropic":
43
48
  model = model_anth
44
49
  else:
45
50
  model = model_oai
@@ -54,7 +59,7 @@ tool_node = ToolNode(tools)
54
59
 
55
60
 
56
61
  # Define a new graph
57
- workflow = StateGraph(AgentState)
62
+ workflow = StateGraph(AgentState, context_schema=AgentContext)
58
63
 
59
64
  # Define the two nodes we will cycle between
60
65
  workflow.add_node("agent", call_model)
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://langgra.ph/schema.json",
2
3
  "dependencies": [
3
4
  "."
4
5
  ],
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://langgra.ph/schema.json",
2
3
  "node_version": "20",
3
4
  "graphs": {
4
5
  "agent": "./src/agent/graph.ts:graph"
@@ -0,0 +1 @@
1
+ __version__ = "0.4.3"
@@ -18,6 +18,7 @@ DEFAULT_IMAGE_DISTRO = "debian"
18
18
 
19
19
 
20
20
  Distros = Literal["debian", "wolfi", "bullseye", "bookworm"]
21
+ MiddlewareOrders = Literal["auth_first", "middleware_first"]
21
22
 
22
23
 
23
24
  class TTLConfig(TypedDict, total=False):
@@ -359,6 +360,25 @@ class HttpConfig(TypedDict, total=False):
359
360
  agent's behavior or permissions on a request's headers."""
360
361
  logging_headers: Optional[ConfigurableHeaderConfig]
361
362
  """Optional. Defines which headers are excluded from logging."""
363
+ middleware_order: Optional[MiddlewareOrders]
364
+ """Optional. Defines the order in which to apply server customizations.
365
+
366
+ Choices:
367
+ - "auth_first": Authentication hooks (custom or default) are evaluated
368
+ before custom middleware.
369
+ - "middleware_first": Custom middleware is evaluated
370
+ before authentication hooks (custom or default).
371
+
372
+ Default is `middleware_first`.
373
+ """
374
+ enable_custom_route_auth: bool
375
+ """Optional. If True, authentication is enabled for custom routes,
376
+ not just the routes that are protected by default.
377
+ (Routes protected by default include /assistants, /threads, and /runs).
378
+
379
+ Default is False. This flag only affects authentication behavior
380
+ if `app` is provided and contains custom routes.
381
+ """
362
382
 
363
383
 
364
384
  class Config(TypedDict, total=False):
@@ -1256,16 +1276,22 @@ def python_config_to_docker(
1256
1276
  else:
1257
1277
  pip_installer = "pip"
1258
1278
  if pip_installer == "uv":
1259
- install_cmd = "uv pip install --system --prerelease=allow"
1279
+ install_cmd = "uv pip install --system"
1260
1280
  elif pip_installer == "pip":
1261
1281
  install_cmd = "pip install"
1262
1282
  else:
1263
1283
  raise ValueError(f"Invalid pip_installer: {pip_installer}")
1264
1284
 
1265
1285
  # configure pip
1266
- pip_install = f"PYTHONDONTWRITEBYTECODE=1 {install_cmd} --no-cache-dir -c /api/constraints.txt"
1286
+ local_reqs_pip_install = f"PYTHONDONTWRITEBYTECODE=1 {install_cmd} --no-cache-dir -c /api/constraints.txt"
1287
+ global_reqs_pip_install = f"PYTHONDONTWRITEBYTECODE=1 {install_cmd} --no-cache-dir -c /api/constraints.txt"
1267
1288
  if config.get("pip_config_file"):
1268
- pip_install = f"PIP_CONFIG_FILE=/pipconfig.txt {pip_install}"
1289
+ local_reqs_pip_install = (
1290
+ f"PIP_CONFIG_FILE=/pipconfig.txt {local_reqs_pip_install}"
1291
+ )
1292
+ global_reqs_pip_install = (
1293
+ f"PIP_CONFIG_FILE=/pipconfig.txt {global_reqs_pip_install}"
1294
+ )
1269
1295
  pip_config_file_str = (
1270
1296
  f"ADD {config['pip_config_file']} /pipconfig.txt"
1271
1297
  if config.get("pip_config_file")
@@ -1282,7 +1308,9 @@ def python_config_to_docker(
1282
1308
  # Rewrite HTTP app path, so it points to the correct location in the Docker container
1283
1309
  _update_http_app_path(config_path, config, local_deps)
1284
1310
 
1285
- pip_pkgs_str = f"RUN {pip_install} {' '.join(pypi_deps)}" if pypi_deps else ""
1311
+ pip_pkgs_str = (
1312
+ f"RUN {local_reqs_pip_install} {' '.join(pypi_deps)}" if pypi_deps else ""
1313
+ )
1286
1314
  if local_deps.pip_reqs:
1287
1315
  pip_reqs_str = os.linesep.join(
1288
1316
  (
@@ -1292,7 +1320,7 @@ def python_config_to_docker(
1292
1320
  )
1293
1321
  for reqpath, destpath in local_deps.pip_reqs
1294
1322
  )
1295
- pip_reqs_str += f"{os.linesep}RUN {pip_install} {' '.join('-r ' + r for _, r in local_deps.pip_reqs)}"
1323
+ pip_reqs_str += f"{os.linesep}RUN {local_reqs_pip_install} {' '.join('-r ' + r for _, r in local_deps.pip_reqs)}"
1296
1324
  pip_reqs_str = f"""# -- Installing local requirements --
1297
1325
  {pip_reqs_str}
1298
1326
  # -- End of local requirements install --"""
@@ -1402,7 +1430,13 @@ ADD {relpath} /deps/{name}
1402
1430
  installs,
1403
1431
  "",
1404
1432
  "# -- Installing all local dependencies --",
1405
- f"RUN {pip_install} -e /deps/*",
1433
+ f"""RUN for dep in /deps/*; do \
1434
+ echo "Installing $dep"; \
1435
+ if [ -d "$dep" ]; then \
1436
+ echo "Installing $dep"; \
1437
+ (cd "$dep" && {global_reqs_pip_install} .); \
1438
+ fi; \
1439
+ done""",
1406
1440
  "# -- End of local dependencies install --",
1407
1441
  os.linesep.join(env_vars),
1408
1442
  "",
@@ -40,7 +40,9 @@ def _parse_version(version: str) -> Version:
40
40
  patch = "0"
41
41
  else:
42
42
  major, minor, patch = parts
43
- return Version(int(major.lstrip("v")), int(minor), int(patch.split("-")[0]))
43
+ return Version(
44
+ int(major.lstrip("v")), int(minor), int(patch.split("-")[0].split("+")[0])
45
+ )
44
46
 
45
47
 
46
48
  def check_capabilities(runner) -> DockerCapabilities:
@@ -1,4 +1,5 @@
1
1
  {
2
+ "$schema": "https://langgra.ph/schema.json",
2
3
  "dependencies": [".", "../../libs/shared", "../../libs/common"],
3
4
  "graphs": {
4
5
  "agent": "./src/agent/graph.py:graph"
@@ -577,6 +577,10 @@
577
577
  "type": "boolean",
578
578
  "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n"
579
579
  },
580
+ "enable_custom_route_auth": {
581
+ "type": "boolean",
582
+ "description": "Optional. If True, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n"
583
+ },
580
584
  "logging_headers": {
581
585
  "anyOf": [
582
586
  {
@@ -587,6 +591,20 @@
587
591
  }
588
592
  ],
589
593
  "description": "Optional. Defines which headers are excluded from logging."
594
+ },
595
+ "middleware_order": {
596
+ "anyOf": [
597
+ {
598
+ "enum": [
599
+ "auth_first",
600
+ "middleware_first"
601
+ ]
602
+ },
603
+ {
604
+ "type": "null"
605
+ }
606
+ ],
607
+ "description": "Optional. Defines the order in which to apply server customizations.\n"
590
608
  }
591
609
  },
592
610
  "required": []
@@ -577,6 +577,10 @@
577
577
  "type": "boolean",
578
578
  "description": "Optional. If True, /threads routes are removed.\n\nDefault is False.\n"
579
579
  },
580
+ "enable_custom_route_auth": {
581
+ "type": "boolean",
582
+ "description": "Optional. If True, authentication is enabled for custom routes,\nnot just the routes that are protected by default.\n(Routes protected by default include /assistants, /threads, and /runs).\n\nDefault is False. This flag only affects authentication behavior\nif `app` is provided and contains custom routes.\n"
583
+ },
580
584
  "logging_headers": {
581
585
  "anyOf": [
582
586
  {
@@ -587,6 +591,20 @@
587
591
  }
588
592
  ],
589
593
  "description": "Optional. Defines which headers are excluded from logging."
594
+ },
595
+ "middleware_order": {
596
+ "anyOf": [
597
+ {
598
+ "enum": [
599
+ "auth_first",
600
+ "middleware_first"
601
+ ]
602
+ },
603
+ {
604
+ "type": "null"
605
+ }
606
+ ],
607
+ "description": "Optional. Defines the order in which to apply server customizations.\n"
590
608
  }
591
609
  },
592
610
  "required": []
@@ -15,7 +15,7 @@ from langgraph_cli.docker import DEFAULT_POSTGRES_URI, DockerCapabilities, Versi
15
15
  from langgraph_cli.util import clean_empty_lines
16
16
 
17
17
  FORMATTED_CLEANUP_LINES = _get_pip_cleanup_lines(
18
- install_cmd="uv pip install --system --prerelease=allow",
18
+ install_cmd="uv pip install --system",
19
19
  to_uninstall=("pip", "setuptools", "wheel"),
20
20
  pip_installer="uv",
21
21
  )
@@ -149,7 +149,7 @@ services:
149
149
  COPY --from=cli_1 . /deps/cli_1
150
150
  # -- End of local package ../../.. --
151
151
  # -- Installing all local dependencies --
152
- RUN PYTHONDONTWRITEBYTECODE=1 uv pip install --system --prerelease=allow --no-cache-dir -c /api/constraints.txt -e /deps/*
152
+ RUN for dep in /deps/*; do echo "Installing $dep"; if [ -d "$dep" ]; then echo "Installing $dep"; (cd "$dep" && PYTHONDONTWRITEBYTECODE=1 uv pip install --system --no-cache-dir -c /api/constraints.txt .); fi; done
153
153
  # -- End of local dependencies install --
154
154
  ENV LANGSERVE_GRAPHS='{{"agent": "agent.py:graph"}}'
155
155
  {textwrap.indent(textwrap.dedent(FORMATTED_CLEANUP_LINES), " ")}