agent-chat-fastapi-langgraph-assistant-ui 0.2.0__tar.gz → 0.3.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.
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/.gitignore +5 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/PKG-INFO +30 -4
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/README.md +29 -3
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/pyproject.toml +11 -4
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/scripts/build_wheel.sh +33 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/__init__.py +51 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/config.py +3 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/agent_factory.py +14 -3
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/calculator.py +4 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/get_graph.py +2 -1
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/agents.md +74 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/configuration.md +60 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/index.md +29 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/providers.md +42 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/quickstart.md +45 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs/threads.md +72 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/docs.py +35 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/registry.py +8 -4
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/server.py +639 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/threads.py +111 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/404/index.html +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/404.html +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/__next.__PAGE__.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/__next._full.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/__next._head.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/__next._index.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/__next._tree.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._full.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._head.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._index.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._not-found.__PAGE__.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._not-found.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/__next._tree.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/index.html +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_not-found/index.txt +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/index.html +1 -1
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/index.txt +1 -1
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/404/index.html +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/404.html +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/__next.__PAGE__.txt +7 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/__next._full.txt +18 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/__next._head.txt +8 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/__next._index.txt +5 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/__next._tree.txt +5 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/1f69191700b503ef.js +28 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/3ace7f114fa1f091.js +2 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/4d2c63e33cdf7066.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/7c80bf5e80113a8b.css +3 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/8c25bd17dcc24038.css +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/a53a0fc1920ff4e8.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/a6dad97d9634a72d.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/a9779bfdd3066160.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/c4faa8443adcf05d.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/c7d807cf58f04d9d.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/d3d30b9a6eebcdc0.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/f258a48c9462f5ff.js +4 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/chunks/turbopack-ff4ab21e688d1749.js +3 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/4fa387ec64143e14-s.3b336396.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/53b9e256198e5412-s.853d50a3.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/5ce348bf30bf5439-s.56c1f21e.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/6306c77e7c8268e4-s.e3369375.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/7178b3e590c64307-s.55554cd0.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/797e433ab948586e-s.p.29207c2f.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/7d817b4c03b0c5f1-s.a40b9a8b.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/8a480f0b521d4e75-s.ea323500.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/bbc41e54d2fcbd21-s.fe42ddf4.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/caa3a2e1cccd8315-s.p.3b6cae6d.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/favicon.0b3bf435.ico +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/media/fef07dbb0973bf53-s.518e079e.woff2 +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/vDJ9TpIrx4WCEQOfdoH8L/_buildManifest.js +11 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/vDJ9TpIrx4WCEQOfdoH8L/_clientMiddlewareManifest.json +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_next/static/vDJ9TpIrx4WCEQOfdoH8L/_ssgManifest.js +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._full.txt +14 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._head.txt +8 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._index.txt +5 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._not-found.__PAGE__.txt +5 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._not-found.txt +4 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/__next._tree.txt +2 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/index.html +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/_not-found/index.txt +14 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next._full.txt +20 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next._head.txt +8 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next._index.txt +5 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next._tree.txt +4 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next.admin.__PAGE__.txt +9 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/__next.admin.txt +4 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/index.html +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/admin/index.txt +20 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/favicon.ico +0 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/index.html +1 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web_full/index.txt +18 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/tests/test_docs.py +25 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/tests/test_full_ui.py +45 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/tests/test_provider_agnostic.py +1 -1
- agent_chat_fastapi_langgraph_assistant_ui-0.3.3/tests/test_threads.py +143 -0
- agent_chat_fastapi_langgraph_assistant_ui-0.2.0/.gitignore +0 -3
- agent_chat_fastapi_langgraph_assistant_ui-0.2.0/scripts/build_wheel.sh +0 -24
- agent_chat_fastapi_langgraph_assistant_ui-0.2.0/src/agent_chat_minimal/__init__.py +0 -24
- agent_chat_fastapi_langgraph_assistant_ui-0.2.0/src/agent_chat_minimal/server.py +0 -336
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/Dockerfile +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/scripts/smoke_test_wheel.sh +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/__init__.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/tools/__init__.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/demo_agent/tools/graph_tool.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0/src/agent_chat_minimal/web/_next/static/HvflKuXozGvVNVw4d_lvG → agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web/_next/static/F2G0VtxugBGp8iZRIDw24}/_buildManifest.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0/src/agent_chat_minimal/web/_next/static/HvflKuXozGvVNVw4d_lvG → agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web/_next/static/F2G0VtxugBGp8iZRIDw24}/_clientMiddlewareManifest.json +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0/src/agent_chat_minimal/web/_next/static/HvflKuXozGvVNVw4d_lvG → agent_chat_fastapi_langgraph_assistant_ui-0.3.3/src/agent_chat_minimal/web/_next/static/F2G0VtxugBGp8iZRIDw24}/_ssgManifest.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/01753452ac5baafa.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/30d8e87dcbdddc4d.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/339892169798c284.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/4a95dc46ade64fde.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/8c25bd17dcc24038.css +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/a09b0e81b13178b3.css +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/a6dad97d9634a72d.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/a6dad97d9634a72d.js.map +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/c1f433e6da65e45d.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/e54de45640ef90a8.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/src/agent_chat_minimal/web/_next/static/chunks/turbopack-6a8c15a03bc4b465.js +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/tests/test_config_state.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/tests/test_injectable_graph.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/tests/test_registry.py +0 -0
- {agent_chat_fastapi_langgraph_assistant_ui-0.2.0 → agent_chat_fastapi_langgraph_assistant_ui-0.3.3}/tests/test_serving.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: agent-chat-fastapi-langgraph-assistant-ui
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Portable FastAPI and LangGraph chat with a bundled static UI
|
|
5
5
|
Requires-Python: >=3.11
|
|
6
6
|
Requires-Dist: assistant-stream-ce>=0.0.2
|
|
@@ -45,9 +45,11 @@ python -m pip install packages/agent-chat-minimal/dist/*.whl
|
|
|
45
45
|
minimal-chat-serve --port 8011
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
-
Open <http://localhost:8011
|
|
49
|
-
|
|
50
|
-
`
|
|
48
|
+
Open <http://localhost:8011/> (single-prompt chat) or
|
|
49
|
+
<http://localhost:8011/full/> (thread sidebar with previous chats).
|
|
50
|
+
Set `OPENAI_API_KEY` to enable `/assistant`; without it, the UIs and
|
|
51
|
+
`/health` still work and `/assistant` returns 503.
|
|
52
|
+
`MINIMAL_WEB_DIR` / `FULL_WEB_DIR` may override the bundled web directories.
|
|
51
53
|
|
|
52
54
|
## Arbitrary agents & providers
|
|
53
55
|
|
|
@@ -70,6 +72,30 @@ app = create_app(graph=make_my_agent("anthropic:claude-sonnet-4-5"))
|
|
|
70
72
|
`state.thread_id` / `runConfig.thread_id` is forwarded as LangGraph
|
|
71
73
|
`configurable.thread_id` for checkpointer-backed graphs.
|
|
72
74
|
|
|
75
|
+
## Documentation (in the wheel)
|
|
76
|
+
|
|
77
|
+
Six guides ship inside the package and are readable at runtime:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from agent_chat_minimal import docs
|
|
81
|
+
docs.list() # ['index', 'quickstart', 'agents', ...]
|
|
82
|
+
docs.show("threads")
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
| Guide | Covers |
|
|
86
|
+
| ----- | ------ |
|
|
87
|
+
| `quickstart` | install → first chat in 2 minutes |
|
|
88
|
+
| `agents` | write + serve + share your own agent |
|
|
89
|
+
| `providers` | OpenAI / Anthropic / Ollama specs & creds |
|
|
90
|
+
| `configuration` | env vars, CLI flags, hooks, 503 semantics |
|
|
91
|
+
| `threads` | multi-thread chats, frontend-full compat |
|
|
92
|
+
|
|
93
|
+
## Threads (frontend-full compatible)
|
|
94
|
+
|
|
95
|
+
The server also speaks the full-stack thread protocol (`/threads`,
|
|
96
|
+
`/threads/{id}/messages`, scoped `POST /assistant` with `thread_id`/`user_id`),
|
|
97
|
+
so `frontend-full` works against either backend. See the `threads` guide.
|
|
98
|
+
|
|
73
99
|
## Configuration
|
|
74
100
|
|
|
75
101
|
```text
|
|
@@ -28,9 +28,11 @@ python -m pip install packages/agent-chat-minimal/dist/*.whl
|
|
|
28
28
|
minimal-chat-serve --port 8011
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
Open <http://localhost:8011
|
|
32
|
-
|
|
33
|
-
`
|
|
31
|
+
Open <http://localhost:8011/> (single-prompt chat) or
|
|
32
|
+
<http://localhost:8011/full/> (thread sidebar with previous chats).
|
|
33
|
+
Set `OPENAI_API_KEY` to enable `/assistant`; without it, the UIs and
|
|
34
|
+
`/health` still work and `/assistant` returns 503.
|
|
35
|
+
`MINIMAL_WEB_DIR` / `FULL_WEB_DIR` may override the bundled web directories.
|
|
34
36
|
|
|
35
37
|
## Arbitrary agents & providers
|
|
36
38
|
|
|
@@ -53,6 +55,30 @@ app = create_app(graph=make_my_agent("anthropic:claude-sonnet-4-5"))
|
|
|
53
55
|
`state.thread_id` / `runConfig.thread_id` is forwarded as LangGraph
|
|
54
56
|
`configurable.thread_id` for checkpointer-backed graphs.
|
|
55
57
|
|
|
58
|
+
## Documentation (in the wheel)
|
|
59
|
+
|
|
60
|
+
Six guides ship inside the package and are readable at runtime:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from agent_chat_minimal import docs
|
|
64
|
+
docs.list() # ['index', 'quickstart', 'agents', ...]
|
|
65
|
+
docs.show("threads")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
| Guide | Covers |
|
|
69
|
+
| ----- | ------ |
|
|
70
|
+
| `quickstart` | install → first chat in 2 minutes |
|
|
71
|
+
| `agents` | write + serve + share your own agent |
|
|
72
|
+
| `providers` | OpenAI / Anthropic / Ollama specs & creds |
|
|
73
|
+
| `configuration` | env vars, CLI flags, hooks, 503 semantics |
|
|
74
|
+
| `threads` | multi-thread chats, frontend-full compat |
|
|
75
|
+
|
|
76
|
+
## Threads (frontend-full compatible)
|
|
77
|
+
|
|
78
|
+
The server also speaks the full-stack thread protocol (`/threads`,
|
|
79
|
+
`/threads/{id}/messages`, scoped `POST /assistant` with `thread_id`/`user_id`),
|
|
80
|
+
so `frontend-full` works against either backend. See the `threads` guide.
|
|
81
|
+
|
|
56
82
|
## Configuration
|
|
57
83
|
|
|
58
84
|
```text
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "agent-chat-fastapi-langgraph-assistant-ui"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
description = "Portable FastAPI and LangGraph chat with a bundled static UI"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.11"
|
|
@@ -33,13 +33,20 @@ minimal-chat-serve = "agent_chat_minimal.server:main"
|
|
|
33
33
|
|
|
34
34
|
[tool.hatch.build.targets.wheel]
|
|
35
35
|
packages = ["src/agent_chat_minimal"]
|
|
36
|
+
# The tracked .gitkeep placeholders would otherwise be collected twice (once
|
|
37
|
+
# via `packages`, once via `force-include`) and fail the build with "A second
|
|
38
|
+
# file is being added to the wheel archive at the same path".
|
|
39
|
+
exclude = ["**/.gitkeep"]
|
|
36
40
|
|
|
37
41
|
[tool.hatch.build.targets.wheel.force-include]
|
|
38
42
|
"src/agent_chat_minimal/web" = "agent_chat_minimal/web"
|
|
43
|
+
"src/agent_chat_minimal/web_full" = "agent_chat_minimal/web_full"
|
|
39
44
|
|
|
40
|
-
# The sdist
|
|
41
|
-
#
|
|
45
|
+
# The sdist file list comes from git, where the staged prebuilt UIs are
|
|
46
|
+
# ignored - so they must be force-included here (staged from
|
|
47
|
+
# application/frontend/{frontend-minimal,frontend-full}/out before building).
|
|
42
48
|
# python -m build builds the wheel from the sdist, so without this the PyPI
|
|
43
|
-
# wheel would ship without the
|
|
49
|
+
# wheel would ship without the UIs.
|
|
44
50
|
[tool.hatch.build.targets.sdist.force-include]
|
|
45
51
|
"src/agent_chat_minimal/web" = "src/agent_chat_minimal/web"
|
|
52
|
+
"src/agent_chat_minimal/web_full" = "src/agent_chat_minimal/web_full"
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
set -euo pipefail
|
|
3
|
+
|
|
4
|
+
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
|
5
|
+
frontend_minimal="$repo_root/application/frontend/frontend-minimal"
|
|
6
|
+
frontend_full="$repo_root/application/frontend/frontend-full"
|
|
7
|
+
package="$repo_root/packages/agent-chat-minimal"
|
|
8
|
+
web="$package/src/agent_chat_minimal/web"
|
|
9
|
+
web_full="$package/src/agent_chat_minimal/web_full"
|
|
10
|
+
|
|
11
|
+
cleanup() {
|
|
12
|
+
rm -rf "$web" "$web_full"
|
|
13
|
+
mkdir -p "$web" "$web_full"
|
|
14
|
+
: > "$web/.gitkeep"
|
|
15
|
+
: > "$web_full/.gitkeep"
|
|
16
|
+
}
|
|
17
|
+
trap cleanup EXIT
|
|
18
|
+
|
|
19
|
+
pnpm --dir "$frontend_minimal" install --frozen-lockfile
|
|
20
|
+
pnpm --dir "$frontend_minimal" build
|
|
21
|
+
rm -rf "$web"
|
|
22
|
+
cp -R "$frontend_minimal/out" "$web"
|
|
23
|
+
|
|
24
|
+
# Full UI (thread sidebar) is namespaced under /full and talks same-origin.
|
|
25
|
+
pnpm --dir "$frontend_full" install --frozen-lockfile
|
|
26
|
+
NEXT_PUBLIC_API_BASE="" FULL_UI_BASE_PATH=/full pnpm --dir "$frontend_full" build
|
|
27
|
+
rm -rf "$web_full"
|
|
28
|
+
cp -R "$frontend_full/out" "$web_full"
|
|
29
|
+
|
|
30
|
+
(
|
|
31
|
+
cd "$package"
|
|
32
|
+
uv build --wheel
|
|
33
|
+
)
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""Portable FastAPI + LangGraph chat with a bundled Assistant UI.
|
|
2
|
+
|
|
3
|
+
Quick links (also shipped as markdown in ``agent_chat_minimal/docs/``):
|
|
4
|
+
|
|
5
|
+
- ``docs.list()`` / ``docs.get(name)`` — guides: quickstart, agents,
|
|
6
|
+
providers, configuration, threads.
|
|
7
|
+
- ``create_app(...)`` — serve one graph, a factory, or an agent registry.
|
|
8
|
+
- ``Settings.from_env()`` — all env vars in one place.
|
|
9
|
+
- ``GET /docs`` on a running server — interactive Swagger UI.
|
|
10
|
+
|
|
11
|
+
Example:
|
|
12
|
+
>>> from agent_chat_minimal import create_app
|
|
13
|
+
>>> app = create_app(agents={"weather": ...}) # doctest: +SKIP
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from . import docs
|
|
17
|
+
from .config import ENV_DOC, Settings
|
|
18
|
+
from .registry import AGENT_REGISTRY, discover_agents
|
|
19
|
+
from .server import (
|
|
20
|
+
DEFAULT_WEB_DIR,
|
|
21
|
+
DEFAULT_WEB_FULL_DIR,
|
|
22
|
+
ChatGraph,
|
|
23
|
+
ScopedChatRequest,
|
|
24
|
+
create_app,
|
|
25
|
+
default_prepare_state,
|
|
26
|
+
main,
|
|
27
|
+
resolve_thread_id,
|
|
28
|
+
)
|
|
29
|
+
from .threads import ThreadManager, ThreadMessageStore, ThreadMetadata
|
|
30
|
+
|
|
31
|
+
__version__ = "0.3.3"
|
|
32
|
+
|
|
33
|
+
__all__ = [
|
|
34
|
+
"__version__",
|
|
35
|
+
"AGENT_REGISTRY",
|
|
36
|
+
"ENV_DOC",
|
|
37
|
+
"ChatGraph",
|
|
38
|
+
"DEFAULT_WEB_DIR",
|
|
39
|
+
"DEFAULT_WEB_FULL_DIR",
|
|
40
|
+
"ScopedChatRequest",
|
|
41
|
+
"Settings",
|
|
42
|
+
"ThreadManager",
|
|
43
|
+
"ThreadMessageStore",
|
|
44
|
+
"ThreadMetadata",
|
|
45
|
+
"create_app",
|
|
46
|
+
"default_prepare_state",
|
|
47
|
+
"discover_agents",
|
|
48
|
+
"docs",
|
|
49
|
+
"main",
|
|
50
|
+
"resolve_thread_id",
|
|
51
|
+
]
|
|
@@ -16,6 +16,7 @@ class Settings:
|
|
|
16
16
|
model: str = "openai:gpt-4o-mini"
|
|
17
17
|
default_agent: str = "weather"
|
|
18
18
|
web_dir: str | None = None
|
|
19
|
+
web_full_dir: str | None = None
|
|
19
20
|
|
|
20
21
|
@classmethod
|
|
21
22
|
def from_env(cls) -> "Settings":
|
|
@@ -30,6 +31,7 @@ class Settings:
|
|
|
30
31
|
model=os.getenv("MODEL", "openai:gpt-4o-mini"),
|
|
31
32
|
default_agent=os.getenv("DEFAULT_AGENT", "weather"),
|
|
32
33
|
web_dir=os.getenv("MINIMAL_WEB_DIR"),
|
|
34
|
+
web_full_dir=os.getenv("FULL_WEB_DIR"),
|
|
33
35
|
)
|
|
34
36
|
|
|
35
37
|
def web_dir_path(self, fallback: Path) -> Path | None:
|
|
@@ -44,6 +46,7 @@ PORT=8011 # uvicorn bind port
|
|
|
44
46
|
MODEL=openai:gpt-4o-mini # provider:model spec (anthropic:.., ollama:..)
|
|
45
47
|
DEFAULT_AGENT=weather # registry id aliased by POST /assistant
|
|
46
48
|
MINIMAL_WEB_DIR= # override bundled web/ (empty = bundled)
|
|
49
|
+
FULL_WEB_DIR= # override bundled web_full/ (empty = bundled)
|
|
47
50
|
OPENAI_API_KEY= # credential for the default openai model
|
|
48
51
|
ANTHROPIC_API_KEY= # credential when MODEL uses anthropic:
|
|
49
52
|
"""
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"""Shared helpers for building provider-agnostic tool agents (#12)."""
|
|
2
2
|
|
|
3
|
-
from typing import Annotated, TypedDict
|
|
3
|
+
from typing import Annotated, Any, TypedDict
|
|
4
4
|
|
|
5
5
|
from langchain_core.language_models.chat_models import BaseChatModel
|
|
6
6
|
from langchain_core.messages import BaseMessage
|
|
@@ -32,8 +32,19 @@ def make_tool_agent(
|
|
|
32
32
|
model: str | BaseChatModel,
|
|
33
33
|
tools: list,
|
|
34
34
|
system_prompt: str | None = None,
|
|
35
|
+
checkpointer: Any | None = None,
|
|
35
36
|
) -> StateGraph:
|
|
36
|
-
"""Build a compiled ``agent <-> tools`` graph for any tool list.
|
|
37
|
+
"""Build a compiled ``agent <-> tools`` graph for any tool list.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
model: ``provider:name`` spec (see :mod:`docs/providers`) or a chat
|
|
41
|
+
model instance.
|
|
42
|
+
tools: LangChain tools bound to the model and served by a ``ToolNode``.
|
|
43
|
+
system_prompt: Optional system message prepended at invoke time.
|
|
44
|
+
checkpointer: Optional LangGraph checkpointer (e.g. ``MemorySaver()``).
|
|
45
|
+
Compiling with one enables per-``thread_id`` persistence: pass
|
|
46
|
+
``config={"configurable": {"thread_id": ...}}`` at invoke time.
|
|
47
|
+
"""
|
|
37
48
|
llm = resolve_llm(model).bind_tools(tools)
|
|
38
49
|
tool_node = ToolNode(tools)
|
|
39
50
|
|
|
@@ -53,4 +64,4 @@ def make_tool_agent(
|
|
|
53
64
|
workflow.set_entry_point("agent")
|
|
54
65
|
workflow.add_conditional_edges("agent", tools_condition)
|
|
55
66
|
workflow.add_edge("tools", "agent")
|
|
56
|
-
return workflow.compile()
|
|
67
|
+
return workflow.compile(checkpointer=checkpointer)
|
|
@@ -44,6 +44,9 @@ CALCULATOR_SYSTEM_PROMPT = (
|
|
|
44
44
|
|
|
45
45
|
def make_calculator_agent(
|
|
46
46
|
model: str | BaseChatModel = "openai:gpt-4o-mini",
|
|
47
|
+
checkpointer=None,
|
|
47
48
|
) -> StateGraph:
|
|
48
49
|
"""Build the calculator agent for any provider model spec/instance."""
|
|
49
|
-
return make_tool_agent(
|
|
50
|
+
return make_tool_agent(
|
|
51
|
+
model, list(CALCULATOR_TOOLS), CALCULATOR_SYSTEM_PROMPT, checkpointer
|
|
52
|
+
)
|
|
@@ -19,6 +19,7 @@ def get_weather(city: str):
|
|
|
19
19
|
|
|
20
20
|
def make_agent_with_weather_tool(
|
|
21
21
|
model: str | BaseChatModel = "openai:gpt-4o-mini",
|
|
22
|
+
checkpointer=None,
|
|
22
23
|
) -> StateGraph:
|
|
23
24
|
"""Build the weather demo agent for any provider model spec/instance.
|
|
24
25
|
|
|
@@ -31,4 +32,4 @@ def make_agent_with_weather_tool(
|
|
|
31
32
|
if model == "gpt-4o-mini": # backward compat: bare legacy default
|
|
32
33
|
model = "openai:gpt-4o-mini"
|
|
33
34
|
tools = [get_weather, render_graph]
|
|
34
|
-
return make_tool_agent(model, tools)
|
|
35
|
+
return make_tool_agent(model, tools, checkpointer=checkpointer)
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# Implementing an agent
|
|
2
|
+
|
|
3
|
+
Any compiled LangGraph graph over `{"messages": [...]}` is servable. The only
|
|
4
|
+
contract (see `ChatGraph` in `server.py`) is:
|
|
5
|
+
|
|
6
|
+
```python
|
|
7
|
+
graph.astream(input, config=..., stream_mode=[...], subgraphs=True)
|
|
8
|
+
# yields (namespace, event_type, chunk) triples
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Minimal custom agent (5 minutes)
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
# my_agent.py
|
|
15
|
+
from langchain_core.tools import tool
|
|
16
|
+
from agent_chat_minimal.demo_agent.agent_factory import make_tool_agent
|
|
17
|
+
|
|
18
|
+
@tool
|
|
19
|
+
def shout(text: str) -> str:
|
|
20
|
+
"""Uppercase the input."""
|
|
21
|
+
return text.upper()
|
|
22
|
+
|
|
23
|
+
def make_shout_agent(model="openai:gpt-4o-mini", checkpointer=None):
|
|
24
|
+
return make_tool_agent(model, [shout], "Reply ONLY with the tool result.")
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Serve it — no server fork needed:
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# serve.py
|
|
31
|
+
from agent_chat_minimal import create_app
|
|
32
|
+
from my_agent import make_shout_agent
|
|
33
|
+
|
|
34
|
+
app = create_app(graph_factory=make_shout_agent)
|
|
35
|
+
# python -m uvicorn serve:app --port 8011
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Prefer an instance? `create_app(graph=make_shout_agent(...))` works too;
|
|
39
|
+
the factory form defers credential errors to startup instead of import.
|
|
40
|
+
|
|
41
|
+
## Multi-agent serving
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
app = create_app(agents={"shout": make_shout_agent})
|
|
45
|
+
# POST /assistant/shout, GET /agents -> ["calculator","shout","weather"]
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`POST /assistant` aliases the `default_agent` (`"weather"` unless overridden).
|
|
49
|
+
|
|
50
|
+
## Reference: calculator agent
|
|
51
|
+
|
|
52
|
+
`demo_agent/calculator.py` (`add`/`subtract`/`multiply`/`divide` +
|
|
53
|
+
`make_calculator_agent`) is the canonical example: tools, system prompt,
|
|
54
|
+
provider-agnostic model arg, optional `checkpointer` passthrough.
|
|
55
|
+
|
|
56
|
+
## Sharing via pip (no fork)
|
|
57
|
+
|
|
58
|
+
Register the `agent_chat.agents` entry-points group:
|
|
59
|
+
|
|
60
|
+
```toml
|
|
61
|
+
[project.entry-points."agent_chat.agents"]
|
|
62
|
+
shout = "my_package.my_agent:make_shout_agent"
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`discover_agents()` picks it up automatically alongside the built-ins.
|
|
66
|
+
|
|
67
|
+
## Checklist
|
|
68
|
+
|
|
69
|
+
- [ ] Factory signature `(model=..., checkpointer=None)` so the server can
|
|
70
|
+
inject the shared checkpointer.
|
|
71
|
+
- [ ] Tools have clear docstrings — the model only sees those.
|
|
72
|
+
- [ ] Offline test with a fake model (see `tests/test_provider_agnostic.py`).
|
|
73
|
+
- [ ] `minimal-chat-serve --agent shout --check` builds without network creds
|
|
74
|
+
only if the model is fake/local; otherwise expect a credential error.
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
Single source of truth: `Settings` in `config.py` (stdlib only, no extra
|
|
4
|
+
dependency). CLI flags override env vars.
|
|
5
|
+
|
|
6
|
+
## Environment
|
|
7
|
+
|
|
8
|
+
```text
|
|
9
|
+
HOST=0.0.0.0 # uvicorn bind host
|
|
10
|
+
PORT=8011 # uvicorn bind port
|
|
11
|
+
MODEL=openai:gpt-4o-mini # provider:model spec (see providers.md)
|
|
12
|
+
DEFAULT_AGENT=weather # registry id aliased by POST /assistant
|
|
13
|
+
MINIMAL_WEB_DIR= # override bundled web/ (empty = bundled)
|
|
14
|
+
OPENAI_API_KEY= # credential for the default openai model
|
|
15
|
+
ANTHROPIC_API_KEY= # credential when MODEL uses anthropic:
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```python
|
|
19
|
+
from agent_chat_minimal import Settings
|
|
20
|
+
Settings.from_env() # Settings(host='0.0.0.0', port=8011, ...)
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## CLI
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
minimal-chat-serve --host 127.0.0.1 --port 8011 \
|
|
27
|
+
--model ollama:llama3.1 --agent calculator
|
|
28
|
+
minimal-chat-serve --agent weather --check # build graph, exit, no server
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
`--check` is the fast CI smoke test: non-zero exit with the real factory
|
|
32
|
+
error when credentials are missing.
|
|
33
|
+
|
|
34
|
+
## Hooks (`create_app(...)`)
|
|
35
|
+
|
|
36
|
+
| Parameter | Purpose |
|
|
37
|
+
| ---------------- | -------------------------------------------------- |
|
|
38
|
+
| `graph=` | Serve one prebuilt graph (`/agents == ["default"]`)|
|
|
39
|
+
| `graph_factory=` | Deferred single-graph build (errors at startup) |
|
|
40
|
+
| `agents=` | Name → factory map (multi-agent mode) |
|
|
41
|
+
| `default_agent=` | Id aliased by `POST /assistant` |
|
|
42
|
+
| `web_dir=` | Override the bundled UI directory |
|
|
43
|
+
| `prepare_state=` | `(state, request) -> message dicts` reducer |
|
|
44
|
+
| `checkpointer=` | Shared checkpointer (`"memory"` default, see below)|
|
|
45
|
+
| `thread_manager=`/`message_store=` | Swap thread storage (tests) |
|
|
46
|
+
|
|
47
|
+
## Checkpointer
|
|
48
|
+
|
|
49
|
+
`"memory"` (default) builds one shared `MemorySaver` and passes it to every
|
|
50
|
+
factory whose signature accepts `checkpointer`. Per-`thread_id` graph state
|
|
51
|
+
then persists across requests (see [threads.md](threads.md)). Pass an explicit
|
|
52
|
+
saver instance for custom backends, or `None` to disable injection.
|
|
53
|
+
|
|
54
|
+
## `/assistant` 503 semantics
|
|
55
|
+
|
|
56
|
+
- Default registry + no `OPENAI_API_KEY` → legacy
|
|
57
|
+
`{"error": "OPENAI_API_KEY not configured", ...}` (backward compatible).
|
|
58
|
+
- Custom graph/factory failure →
|
|
59
|
+
`{"error": "agent_not_ready", "message": ..., "hint": ...}` with the real
|
|
60
|
+
factory exception in `hint`.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# agent-chat-minimal — documentation index
|
|
2
|
+
|
|
3
|
+
Portable FastAPI + LangGraph chat server with a bundled Assistant UI.
|
|
4
|
+
Install from PyPI (Python 3.11+, no Node needed) and serve one command:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
pip install agent-chat-fastapi-langgraph-assistant-ui
|
|
8
|
+
minimal-chat-serve --port 8011
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Guides (shipped inside the wheel under `agent_chat_minimal/docs/`):
|
|
12
|
+
|
|
13
|
+
- [quickstart.md](quickstart.md) — install, serve, first chat (2 minutes).
|
|
14
|
+
- [agents.md](agents.md) — implement and serve your own agent.
|
|
15
|
+
- [providers.md](providers.md) — model specs for OpenAI, Anthropic, Ollama, ….
|
|
16
|
+
- [configuration.md](configuration.md) — env vars, CLI flags, hooks.
|
|
17
|
+
- [threads.md](threads.md) — multi-thread chats, frontend-full compatibility.
|
|
18
|
+
- [index.md](index.md) — this file: architecture overview.
|
|
19
|
+
|
|
20
|
+
Discoverability: every guide is readable at runtime without unpacking the wheel:
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
from agent_chat_minimal import docs
|
|
24
|
+
docs.list() # ['agents', 'configuration', ...]
|
|
25
|
+
print(docs.get("agents"))
|
|
26
|
+
docs.show("threads") # prints to stdout
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
FastAPI also serves interactive Swagger UI at `GET /docs` when the server runs.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Model providers
|
|
2
|
+
|
|
3
|
+
Factories take either a `provider:name` spec (resolved via LangChain's
|
|
4
|
+
`init_chat_model`) or an already-built chat model instance.
|
|
5
|
+
|
|
6
|
+
## Specs
|
|
7
|
+
|
|
8
|
+
| Spec prefix | Example | Credential env | Install extra |
|
|
9
|
+
| ----------- | --------------------------- | ------------------- | -------------------- |
|
|
10
|
+
| `openai:` | `openai:gpt-4o-mini` | `OPENAI_API_KEY` | `langchain-openai` ✓ |
|
|
11
|
+
| `anthropic:`| `anthropic:claude-sonnet-4-5` | `ANTHROPIC_API_KEY` | `langchain-anthropic`|
|
|
12
|
+
| `ollama:` | `ollama:llama3.1` | none (local daemon) | `langchain-ollama` |
|
|
13
|
+
| `google_genai:` | `google_genai:gemini-2.5-flash` | `GOOGLE_API_KEY`| `langchain-google-genai` |
|
|
14
|
+
|
|
15
|
+
✓ = bundled with this wheel. Others need their LangChain partner package;
|
|
16
|
+
the import happens lazily, only when that provider is selected.
|
|
17
|
+
|
|
18
|
+
Bare `gpt-4o-mini` still works (provider inferred as OpenAI) for backward
|
|
19
|
+
compatibility; prefer the explicit `openai:` prefix.
|
|
20
|
+
|
|
21
|
+
## Selecting the model
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
MODEL=anthropic:claude-sonnet-4-5 minimal-chat-serve
|
|
25
|
+
minimal-chat-serve --model ollama:llama3.1 --agent calculator
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Instances and offline tests
|
|
29
|
+
|
|
30
|
+
Pass any `BaseChatModel` (streaming or fake) straight in:
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from langchain_core.language_models.fake_chat_models import GenericFakeChatModel
|
|
34
|
+
|
|
35
|
+
class Bindable(GenericFakeChatModel):
|
|
36
|
+
def bind_tools(self, *a, **k):
|
|
37
|
+
return self # base class raises NotImplementedError
|
|
38
|
+
|
|
39
|
+
graph = make_calculator_agent(Bindable(messages=iter([...])))
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This is how the bundled tests run the full agent loop with no network.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install agent-chat-fastapi-langgraph-assistant-ui
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Or from this repo (builds the UI + wheel; Node/pnpm needed only here):
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
packages/agent-chat-minimal/scripts/build_wheel.sh
|
|
13
|
+
python -m pip install packages/agent-chat-minimal/dist/*.whl
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Serve
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
export OPENAI_API_KEY=sk-...
|
|
20
|
+
minimal-chat-serve --port 8011
|
|
21
|
+
# open http://localhost:8011/
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Without `OPENAI_API_KEY`, the UI and `GET /health` still work; `POST /assistant`
|
|
25
|
+
returns 503 with setup instructions.
|
|
26
|
+
|
|
27
|
+
## First chat
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
curl -s localhost:8011/health
|
|
31
|
+
# {"status":"ok"}
|
|
32
|
+
|
|
33
|
+
curl -s localhost:8011/agents
|
|
34
|
+
# {"agents":["calculator","weather"],"default":"weather"}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
In the UI, try *"What is 12 × 8?"* (calculator) or *"Weather in London?"*.
|
|
38
|
+
For the sidebar with previous chats, open <http://localhost:8011/full/>.
|
|
39
|
+
|
|
40
|
+
## Next steps
|
|
41
|
+
|
|
42
|
+
- Custom agent? → [agents.md](agents.md).
|
|
43
|
+
- Another model provider? → [providers.md](providers.md).
|
|
44
|
+
- Env vars and flags? → [configuration.md](configuration.md).
|
|
45
|
+
- Threaded chats / frontend-full? → [threads.md](threads.md).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Threads (multi-conversation chats)
|
|
2
|
+
|
|
3
|
+
The portable server speaks the same thread protocol as the full backend, so
|
|
4
|
+
`frontend-full` (thread list, history, multiple chats) works against either
|
|
5
|
+
server. Single-prompt clients can ignore this page entirely.
|
|
6
|
+
|
|
7
|
+
## Concepts
|
|
8
|
+
|
|
9
|
+
- **Thread**: a conversation id. Metadata (title, owner, archived) is kept by
|
|
10
|
+
`ThreadManager`; content lives in two places:
|
|
11
|
+
- assistant-ui message objects, stored verbatim per thread (tool UI parts
|
|
12
|
+
rehydrate on reload);
|
|
13
|
+
- LangGraph checkpointer state keyed by `thread_id` (graph-side memory).
|
|
14
|
+
- **Scoped request**: `POST /assistant` accepts `thread_id`/`user_id`
|
|
15
|
+
top-level fields (plus the classic `commands`/`state`). Missing ids are
|
|
16
|
+
auto-generated and their metadata auto-created — the same behavior as the
|
|
17
|
+
full backend.
|
|
18
|
+
|
|
19
|
+
## Endpoints
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
GET /threads[?user_id=&include_archived=]
|
|
23
|
+
POST /threads {localId, user_id?, title?}
|
|
24
|
+
GET /threads/{id} PATCH /threads/{id} {title}
|
|
25
|
+
POST /threads/{id}/archive|unarchive
|
|
26
|
+
DELETE /threads/{id} (also drops stored messages)
|
|
27
|
+
GET /threads/{id}/messages (persisted UI messages, else checkpointer fallback)
|
|
28
|
+
POST /threads/{id}/messages {message} (history.append hook)
|
|
29
|
+
POST /assistant POST /assistant/{agent_id} (scoped shape supported)
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Example flow
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
curl -X POST localhost:8011/threads -H 'Content-Type: application/json' \
|
|
36
|
+
-d '{"localId":"trip","title":"Trip planning"}'
|
|
37
|
+
|
|
38
|
+
curl -X POST localhost:8011/assistant -H 'Content-Type: application/json' \
|
|
39
|
+
-d '{"thread_id":"trip","state":{"thread_id":"trip"},"commands":[]}'
|
|
40
|
+
|
|
41
|
+
curl localhost:8011/threads/trip/messages
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Frontend-full compatibility
|
|
45
|
+
|
|
46
|
+
## Bundled full UI
|
|
47
|
+
|
|
48
|
+
The wheel ships the full frontend (thread sidebar) at `/full/` — no separate
|
|
49
|
+
Next.js server needed. It is built with `NEXT_PUBLIC_API_BASE=""` so it talks
|
|
50
|
+
to the same origin (`/assistant`, `/threads`). The minimal single-prompt chat
|
|
51
|
+
stays at `/`. To serve a custom full build instead:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
FULL_WEB_DIR=/path/to/frontend-full/out minimal-chat-serve
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Pointing an external full frontend at the portable server also works
|
|
58
|
+
(`NEXT_PUBLIC_API_URL` without the trailing `/assistant`); thread list,
|
|
59
|
+
switching, rename, archive, and history rehydration all use the endpoints
|
|
60
|
+
above. Responses stream over the Assistant Stream protocol with
|
|
61
|
+
`messages`/`updates`/`custom` events, including `tool_updates` progress
|
|
62
|
+
entries like the full backend.
|
|
63
|
+
|
|
64
|
+
## Persistence notes
|
|
65
|
+
|
|
66
|
+
- Default storage is in-memory (`MemorySaver` + dicts): restarts lose it —
|
|
67
|
+
identical to the full backend's default. Restart-safe backends plug in via
|
|
68
|
+
`create_app(checkpointer=<saver>)`.
|
|
69
|
+
- History larger than the 500-message store cap (or 200 tool updates) is
|
|
70
|
+
trimmed oldest-first.
|
|
71
|
+
- AI messages with `tool_calls` but no matching `ToolMessage` are dropped
|
|
72
|
+
before invoke (invalid-history guard, same as full backend).
|