flowai-cli 0.2.0__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 (72) hide show
  1. flowai_cli-0.2.0/.gitignore +11 -0
  2. flowai_cli-0.2.0/LICENSE +21 -0
  3. flowai_cli-0.2.0/PKG-INFO +223 -0
  4. flowai_cli-0.2.0/README.md +171 -0
  5. flowai_cli-0.2.0/examples/01_quickstart.py +36 -0
  6. flowai_cli-0.2.0/examples/02_nvidia_deepseek.py +40 -0
  7. flowai_cli-0.2.0/examples/03_workflow_graph.py +56 -0
  8. flowai_cli-0.2.0/examples/04_fastmcp_agent.py +37 -0
  9. flowai_cli-0.2.0/examples/05_debate_and_swarm.py +68 -0
  10. flowai_cli-0.2.0/flowai/__init__.py +72 -0
  11. flowai_cli-0.2.0/flowai/__main__.py +8 -0
  12. flowai_cli-0.2.0/flowai/agents/__init__.py +21 -0
  13. flowai_cli-0.2.0/flowai/agents/base.py +61 -0
  14. flowai_cli-0.2.0/flowai/agents/patterns/__init__.py +11 -0
  15. flowai_cli-0.2.0/flowai/agents/patterns/debate.py +79 -0
  16. flowai_cli-0.2.0/flowai/agents/patterns/reflection.py +74 -0
  17. flowai_cli-0.2.0/flowai/agents/specialized.py +87 -0
  18. flowai_cli-0.2.0/flowai/agents/standard.py +176 -0
  19. flowai_cli-0.2.0/flowai/cli/__init__.py +5 -0
  20. flowai_cli-0.2.0/flowai/cli/main.py +562 -0
  21. flowai_cli-0.2.0/flowai/cli/ui.py +98 -0
  22. flowai_cli-0.2.0/flowai/config/__init__.py +5 -0
  23. flowai_cli-0.2.0/flowai/config/settings.py +204 -0
  24. flowai_cli-0.2.0/flowai/errors.py +30 -0
  25. flowai_cli-0.2.0/flowai/mcp/__init__.py +5 -0
  26. flowai_cli-0.2.0/flowai/mcp/client.py +77 -0
  27. flowai_cli-0.2.0/flowai/memory/__init__.py +16 -0
  28. flowai_cli-0.2.0/flowai/memory/base.py +45 -0
  29. flowai_cli-0.2.0/flowai/memory/chroma.py +97 -0
  30. flowai_cli-0.2.0/flowai/memory/in_memory.py +65 -0
  31. flowai_cli-0.2.0/flowai/memory/qdrant.py +104 -0
  32. flowai_cli-0.2.0/flowai/observability/__init__.py +15 -0
  33. flowai_cli-0.2.0/flowai/observability/events.py +45 -0
  34. flowai_cli-0.2.0/flowai/observability/opentelemetry.py +56 -0
  35. flowai_cli-0.2.0/flowai/observability/tracer.py +80 -0
  36. flowai_cli-0.2.0/flowai/plugins/__init__.py +5 -0
  37. flowai_cli-0.2.0/flowai/plugins/loader.py +31 -0
  38. flowai_cli-0.2.0/flowai/providers/__init__.py +35 -0
  39. flowai_cli-0.2.0/flowai/providers/anthropic.py +268 -0
  40. flowai_cli-0.2.0/flowai/providers/base.py +180 -0
  41. flowai_cli-0.2.0/flowai/providers/gemini.py +230 -0
  42. flowai_cli-0.2.0/flowai/providers/nvidia.py +57 -0
  43. flowai_cli-0.2.0/flowai/providers/ollama.py +237 -0
  44. flowai_cli-0.2.0/flowai/providers/openai.py +274 -0
  45. flowai_cli-0.2.0/flowai/providers/registry.py +50 -0
  46. flowai_cli-0.2.0/flowai/runtime/__init__.py +5 -0
  47. flowai_cli-0.2.0/flowai/runtime/session.py +76 -0
  48. flowai_cli-0.2.0/flowai/server/__init__.py +5 -0
  49. flowai_cli-0.2.0/flowai/server/app.py +133 -0
  50. flowai_cli-0.2.0/flowai/tools/__init__.py +39 -0
  51. flowai_cli-0.2.0/flowai/tools/base.py +56 -0
  52. flowai_cli-0.2.0/flowai/tools/builtin.py +128 -0
  53. flowai_cli-0.2.0/flowai/tools/decorator.py +103 -0
  54. flowai_cli-0.2.0/flowai/tools/files.py +197 -0
  55. flowai_cli-0.2.0/flowai/tools/registry.py +84 -0
  56. flowai_cli-0.2.0/flowai/tools/web.py +94 -0
  57. flowai_cli-0.2.0/flowai/workflow/__init__.py +15 -0
  58. flowai_cli-0.2.0/flowai/workflow/checkpoint.py +73 -0
  59. flowai_cli-0.2.0/flowai/workflow/engine.py +144 -0
  60. flowai_cli-0.2.0/flowai/workflow/state.py +43 -0
  61. flowai_cli-0.2.0/flowai.yaml +36 -0
  62. flowai_cli-0.2.0/pyproject.toml +87 -0
  63. flowai_cli-0.2.0/tests/test_agents.py +90 -0
  64. flowai_cli-0.2.0/tests/test_builtin_tools.py +124 -0
  65. flowai_cli-0.2.0/tests/test_cli.py +126 -0
  66. flowai_cli-0.2.0/tests/test_memory.py +42 -0
  67. flowai_cli-0.2.0/tests/test_observability.py +38 -0
  68. flowai_cli-0.2.0/tests/test_server.py +38 -0
  69. flowai_cli-0.2.0/tests/test_session.py +29 -0
  70. flowai_cli-0.2.0/tests/test_streaming.py +174 -0
  71. flowai_cli-0.2.0/tests/test_tools.py +55 -0
  72. flowai_cli-0.2.0/tests/test_workflow.py +61 -0
@@ -0,0 +1,11 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ venv/
5
+ dist/
6
+ build/
7
+ *.egg-info/
8
+ .pytest_cache/
9
+ .ruff_cache/
10
+ .flowai/
11
+ .env
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ajay Rama Swamy Katragaada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,223 @@
1
+ Metadata-Version: 2.5
2
+ Name: flowai-cli
3
+ Version: 0.2.0
4
+ Summary: FlowAI: an open-source, extensible Python agent harness with a terminal-first CLI.
5
+ Project-URL: Homepage, https://github.com/Ajayramaswamy2005/FlowAI
6
+ Project-URL: Source, https://github.com/Ajayramaswamy2005/FlowAI
7
+ Project-URL: Issues, https://github.com/Ajayramaswamy2005/FlowAI/issues
8
+ Author: Ajay Rama Swamy Katragaada
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent,cli,fastapi,llm,mcp,nvidia,ollama,pydantic,workflow
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: httpx>=0.27.0
23
+ Requires-Dist: pydantic>=2.7.0
24
+ Requires-Dist: pyyaml>=6.0.1
25
+ Provides-Extra: all
26
+ Requires-Dist: chromadb>=0.5.0; extra == 'all'
27
+ Requires-Dist: fastapi>=0.111.0; extra == 'all'
28
+ Requires-Dist: mcp>=1.0.0; extra == 'all'
29
+ Requires-Dist: opentelemetry-api>=1.25.0; extra == 'all'
30
+ Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'all'
31
+ Requires-Dist: qdrant-client>=1.9.0; extra == 'all'
32
+ Requires-Dist: uvicorn[standard]>=0.30.0; extra == 'all'
33
+ Provides-Extra: chroma
34
+ Requires-Dist: chromadb>=0.5.0; extra == 'chroma'
35
+ Provides-Extra: dev
36
+ Requires-Dist: fastapi>=0.111.0; extra == 'dev'
37
+ Requires-Dist: httpx>=0.27.0; extra == 'dev'
38
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
39
+ Requires-Dist: pytest>=8.0; extra == 'dev'
40
+ Requires-Dist: ruff>=0.5; extra == 'dev'
41
+ Provides-Extra: mcp
42
+ Requires-Dist: mcp>=1.0.0; extra == 'mcp'
43
+ Provides-Extra: observability
44
+ Requires-Dist: opentelemetry-api>=1.25.0; extra == 'observability'
45
+ Requires-Dist: opentelemetry-sdk>=1.25.0; extra == 'observability'
46
+ Provides-Extra: qdrant
47
+ Requires-Dist: qdrant-client>=1.9.0; extra == 'qdrant'
48
+ Provides-Extra: server
49
+ Requires-Dist: fastapi>=0.111.0; extra == 'server'
50
+ Requires-Dist: uvicorn[standard]>=0.30.0; extra == 'server'
51
+ Description-Content-Type: text/markdown
52
+
53
+ # FlowAI
54
+
55
+ FlowAI is an AI agent you run in your terminal, in the same spirit as Claude
56
+ Code or OpenCode. Bring your own key from Anthropic, OpenAI, NVIDIA, Google
57
+ Gemini or OpenRouter, or run fully local with Ollama. The agent can read, search
58
+ and edit the files in your project, run shell commands (after asking you), and
59
+ search the web.
60
+
61
+ It is also a Python library: the same agents, tools, workflows and memory the
62
+ CLI uses are yours to build on.
63
+
64
+ ## Install
65
+
66
+ ```bash
67
+ pip install flowai-cli # once it is published to PyPI
68
+ pipx install flowai-cli # same, in its own isolated environment
69
+
70
+ # from a checkout of this repository:
71
+ pip install .
72
+ ```
73
+
74
+ Python 3.10 or newer. The package is `flowai-cli` (the name `flowai` is taken on PyPI);
75
+ the command it installs is `flowai`, and the import is `import flowai`.
76
+
77
+ ## First run
78
+
79
+ ```bash
80
+ flowai
81
+ ```
82
+
83
+ The first time, FlowAI asks for a provider and an API key and saves them to
84
+ `~/.flowai/config.json`. After that, `flowai` opens a session in the current
85
+ directory:
86
+
87
+ ```
88
+ ------------------------------------------------------------
89
+ FlowAI 0.2.0 anthropic / claude-sonnet-5-5
90
+ workspace: /home/you/my-project
91
+ session: ses_3f9a1c2e
92
+ /help for commands, /exit to quit
93
+ ------------------------------------------------------------
94
+
95
+ > why does the test in tests/test_api.py fail?
96
+
97
+ [tool] grep_files(pattern=def test_, path=tests)
98
+ [done] tests/test_api.py:12: def test_create_user(): (+4 more lines)
99
+ [tool] read_file(path=tests/test_api.py)
100
+ ...
101
+ ```
102
+
103
+ Set up non-interactively instead (for scripts or CI):
104
+
105
+ ```bash
106
+ flowai configure --provider anthropic --key "$ANTHROPIC_API_KEY"
107
+ ```
108
+
109
+ Or skip configuration entirely: if `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
110
+ `NVIDIA_API_KEY`, `GEMINI_API_KEY` or `OPENROUTER_API_KEY` is set, FlowAI uses
111
+ it.
112
+
113
+ ## Commands
114
+
115
+ | Command | What it does |
116
+ |---|---|
117
+ | `flowai` | Interactive session in the current directory |
118
+ | `flowai "add type hints to utils.py"` | Run one task and exit |
119
+ | `flowai chat --resume` (or `-c`) | Continue the most recent session |
120
+ | `flowai run -q "..."` | One task, print only the final answer (good for scripts) |
121
+ | `echo "..." \| flowai run` | Read the prompt from stdin |
122
+ | `flowai configure` | Choose provider, model and API key |
123
+ | `flowai init [dir]` | Create a `flowai.yaml` and a starter `main.py` |
124
+ | `flowai inspect` | Show config status, saved sessions, checkpoints |
125
+ | `flowai tools` | List the built-in tools |
126
+ | `flowai serve` | HTTP API with streaming (`pip install 'flowai-cli[server]'`) |
127
+
128
+ Options for `chat` and `run`: `--provider`, `--model`, `-w/--workspace DIR`,
129
+ `--yolo` (do not ask before shell/python tools run), `--no-tools`,
130
+ `--max-iterations N`.
131
+
132
+ Inside a session: `/help`, `/model <name>`, `/provider <name> [model]`,
133
+ `/tools`, `/cost`, `/new`, `/reset`, `/yolo`, `/exit`.
134
+
135
+ ## What the agent can do
136
+
137
+ | Tool | Notes |
138
+ |---|---|
139
+ | `read_file`, `list_dir`, `glob_files`, `grep_files` | Read-only; never asks |
140
+ | `write_file`, `edit_file` | Changes files inside the workspace only |
141
+ | `bash` | Asks first. Runs in the workspace, 120 s timeout |
142
+ | `python_repl` | Asks first. Runs code in a fresh namespace |
143
+ | `search_web`, `fetch_url` | DuckDuckGo search and page fetch |
144
+
145
+ **Safety.** Every file path is resolved against the workspace (the directory
146
+ you started in, or `-w`) and refused if it points outside. Shell, Python and
147
+ MCP tools show you exactly what they will run and wait for `y`, `n` or `a`
148
+ (always, for that tool, this session). With no terminal attached, those tools
149
+ are refused rather than run. `--yolo` or `approval: "auto"` in `flowai.yaml`
150
+ turns the prompt off; use it only in a sandbox.
151
+
152
+ ## Configuration
153
+
154
+ Settings are layered, later wins:
155
+
156
+ 1. `~/.flowai/config.json`, written by `flowai configure`
157
+ 2. `flowai.yaml` (or `.yml`, `.toml`, `.json`) in the current directory or any
158
+ parent, so it works from a subdirectory of your project
159
+ 3. Environment: `FLOWAI_PROVIDER`, `FLOWAI_MODEL`, and the provider key variables
160
+
161
+ See [flowai.yaml](flowai.yaml) for every option, including `mcp_servers` for
162
+ borrowing tools from Model Context Protocol servers (`pip install 'flowai-cli[mcp]'`).
163
+
164
+ ## Using it as a library
165
+
166
+ ```python
167
+ import asyncio
168
+ from flowai import Agent, tool
169
+
170
+ @tool
171
+ def compound_interest(principal: float, rate: float, years: int) -> float:
172
+ """Balance after compounding yearly."""
173
+ return round(principal * (1 + rate) ** years, 2)
174
+
175
+ agent = Agent(
176
+ name="Advisor",
177
+ provider="anthropic", # nvidia, ollama, openai, gemini, openrouter
178
+ model="claude-sonnet-5-5",
179
+ tools=[compound_interest],
180
+ )
181
+
182
+ print(asyncio.run(agent.run("What will $5,000 be after 10 years at 8%?")))
183
+ ```
184
+
185
+ `agent.stream(prompt)` yields tokens as they arrive and runs tool calls along
186
+ the way. Tools you register in your own code run without an approval prompt
187
+ (you wrote them); give a `ToolRegistry` an `approver` callback to change that.
188
+
189
+ Beyond a single agent the library has:
190
+
191
+ - **Specialised agents**: `PlannerAgent`, `CriticAgent`, `ToolAgent`, `SupervisorAgent`
192
+ - **Patterns**: `ReflectionPattern`, `PlanAndExecutePattern`, `DebatePattern`, `Swarm`
193
+ - **Workflows**: a graph engine with conditional edges, loops, parallel
194
+ branches and checkpointing (`Workflow`, `FileCheckpointer`)
195
+ - **Memory**: `InMemory`, `QdrantMemory` (`flowai-cli[qdrant]`), `ChromaMemory` (`flowai-cli[chroma]`)
196
+ - **Observability**: per-span token counts and estimated cost (`agent.tracer`),
197
+ an event bus, and an OpenTelemetry exporter (`flowai-cli[observability]`)
198
+ - **Plugins**: third-party providers via the `flowai.plugins` entry point
199
+
200
+ Runnable examples are in [examples/](examples/).
201
+
202
+ ## Developing FlowAI
203
+
204
+ ```bash
205
+ pip install -e '.[dev]'
206
+ pytest
207
+ ruff check flowai tests
208
+ ```
209
+
210
+ The tests are offline: providers are faked at the HTTP layer, so no key is needed.
211
+
212
+ ## Releasing to PyPI
213
+
214
+ 1. Bump `version` in `pyproject.toml` and `__version__` in `flowai/__init__.py`.
215
+ 2. Push a tag `flowai-vX.Y.Z`. The `flowai-release` workflow builds this
216
+ directory and publishes it with PyPI Trusted Publishing; configure the
217
+ `flowai-cli` project on PyPI to trust this repository and workflow first.
218
+
219
+
220
+
221
+ ## License
222
+
223
+ MIT
@@ -0,0 +1,171 @@
1
+ # FlowAI
2
+
3
+ FlowAI is an AI agent you run in your terminal, in the same spirit as Claude
4
+ Code or OpenCode. Bring your own key from Anthropic, OpenAI, NVIDIA, Google
5
+ Gemini or OpenRouter, or run fully local with Ollama. The agent can read, search
6
+ and edit the files in your project, run shell commands (after asking you), and
7
+ search the web.
8
+
9
+ It is also a Python library: the same agents, tools, workflows and memory the
10
+ CLI uses are yours to build on.
11
+
12
+ ## Install
13
+
14
+ ```bash
15
+ pip install flowai-cli # once it is published to PyPI
16
+ pipx install flowai-cli # same, in its own isolated environment
17
+
18
+ # from a checkout of this repository:
19
+ pip install .
20
+ ```
21
+
22
+ Python 3.10 or newer. The package is `flowai-cli` (the name `flowai` is taken on PyPI);
23
+ the command it installs is `flowai`, and the import is `import flowai`.
24
+
25
+ ## First run
26
+
27
+ ```bash
28
+ flowai
29
+ ```
30
+
31
+ The first time, FlowAI asks for a provider and an API key and saves them to
32
+ `~/.flowai/config.json`. After that, `flowai` opens a session in the current
33
+ directory:
34
+
35
+ ```
36
+ ------------------------------------------------------------
37
+ FlowAI 0.2.0 anthropic / claude-sonnet-5-5
38
+ workspace: /home/you/my-project
39
+ session: ses_3f9a1c2e
40
+ /help for commands, /exit to quit
41
+ ------------------------------------------------------------
42
+
43
+ > why does the test in tests/test_api.py fail?
44
+
45
+ [tool] grep_files(pattern=def test_, path=tests)
46
+ [done] tests/test_api.py:12: def test_create_user(): (+4 more lines)
47
+ [tool] read_file(path=tests/test_api.py)
48
+ ...
49
+ ```
50
+
51
+ Set up non-interactively instead (for scripts or CI):
52
+
53
+ ```bash
54
+ flowai configure --provider anthropic --key "$ANTHROPIC_API_KEY"
55
+ ```
56
+
57
+ Or skip configuration entirely: if `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`,
58
+ `NVIDIA_API_KEY`, `GEMINI_API_KEY` or `OPENROUTER_API_KEY` is set, FlowAI uses
59
+ it.
60
+
61
+ ## Commands
62
+
63
+ | Command | What it does |
64
+ |---|---|
65
+ | `flowai` | Interactive session in the current directory |
66
+ | `flowai "add type hints to utils.py"` | Run one task and exit |
67
+ | `flowai chat --resume` (or `-c`) | Continue the most recent session |
68
+ | `flowai run -q "..."` | One task, print only the final answer (good for scripts) |
69
+ | `echo "..." \| flowai run` | Read the prompt from stdin |
70
+ | `flowai configure` | Choose provider, model and API key |
71
+ | `flowai init [dir]` | Create a `flowai.yaml` and a starter `main.py` |
72
+ | `flowai inspect` | Show config status, saved sessions, checkpoints |
73
+ | `flowai tools` | List the built-in tools |
74
+ | `flowai serve` | HTTP API with streaming (`pip install 'flowai-cli[server]'`) |
75
+
76
+ Options for `chat` and `run`: `--provider`, `--model`, `-w/--workspace DIR`,
77
+ `--yolo` (do not ask before shell/python tools run), `--no-tools`,
78
+ `--max-iterations N`.
79
+
80
+ Inside a session: `/help`, `/model <name>`, `/provider <name> [model]`,
81
+ `/tools`, `/cost`, `/new`, `/reset`, `/yolo`, `/exit`.
82
+
83
+ ## What the agent can do
84
+
85
+ | Tool | Notes |
86
+ |---|---|
87
+ | `read_file`, `list_dir`, `glob_files`, `grep_files` | Read-only; never asks |
88
+ | `write_file`, `edit_file` | Changes files inside the workspace only |
89
+ | `bash` | Asks first. Runs in the workspace, 120 s timeout |
90
+ | `python_repl` | Asks first. Runs code in a fresh namespace |
91
+ | `search_web`, `fetch_url` | DuckDuckGo search and page fetch |
92
+
93
+ **Safety.** Every file path is resolved against the workspace (the directory
94
+ you started in, or `-w`) and refused if it points outside. Shell, Python and
95
+ MCP tools show you exactly what they will run and wait for `y`, `n` or `a`
96
+ (always, for that tool, this session). With no terminal attached, those tools
97
+ are refused rather than run. `--yolo` or `approval: "auto"` in `flowai.yaml`
98
+ turns the prompt off; use it only in a sandbox.
99
+
100
+ ## Configuration
101
+
102
+ Settings are layered, later wins:
103
+
104
+ 1. `~/.flowai/config.json`, written by `flowai configure`
105
+ 2. `flowai.yaml` (or `.yml`, `.toml`, `.json`) in the current directory or any
106
+ parent, so it works from a subdirectory of your project
107
+ 3. Environment: `FLOWAI_PROVIDER`, `FLOWAI_MODEL`, and the provider key variables
108
+
109
+ See [flowai.yaml](flowai.yaml) for every option, including `mcp_servers` for
110
+ borrowing tools from Model Context Protocol servers (`pip install 'flowai-cli[mcp]'`).
111
+
112
+ ## Using it as a library
113
+
114
+ ```python
115
+ import asyncio
116
+ from flowai import Agent, tool
117
+
118
+ @tool
119
+ def compound_interest(principal: float, rate: float, years: int) -> float:
120
+ """Balance after compounding yearly."""
121
+ return round(principal * (1 + rate) ** years, 2)
122
+
123
+ agent = Agent(
124
+ name="Advisor",
125
+ provider="anthropic", # nvidia, ollama, openai, gemini, openrouter
126
+ model="claude-sonnet-5-5",
127
+ tools=[compound_interest],
128
+ )
129
+
130
+ print(asyncio.run(agent.run("What will $5,000 be after 10 years at 8%?")))
131
+ ```
132
+
133
+ `agent.stream(prompt)` yields tokens as they arrive and runs tool calls along
134
+ the way. Tools you register in your own code run without an approval prompt
135
+ (you wrote them); give a `ToolRegistry` an `approver` callback to change that.
136
+
137
+ Beyond a single agent the library has:
138
+
139
+ - **Specialised agents**: `PlannerAgent`, `CriticAgent`, `ToolAgent`, `SupervisorAgent`
140
+ - **Patterns**: `ReflectionPattern`, `PlanAndExecutePattern`, `DebatePattern`, `Swarm`
141
+ - **Workflows**: a graph engine with conditional edges, loops, parallel
142
+ branches and checkpointing (`Workflow`, `FileCheckpointer`)
143
+ - **Memory**: `InMemory`, `QdrantMemory` (`flowai-cli[qdrant]`), `ChromaMemory` (`flowai-cli[chroma]`)
144
+ - **Observability**: per-span token counts and estimated cost (`agent.tracer`),
145
+ an event bus, and an OpenTelemetry exporter (`flowai-cli[observability]`)
146
+ - **Plugins**: third-party providers via the `flowai.plugins` entry point
147
+
148
+ Runnable examples are in [examples/](examples/).
149
+
150
+ ## Developing FlowAI
151
+
152
+ ```bash
153
+ pip install -e '.[dev]'
154
+ pytest
155
+ ruff check flowai tests
156
+ ```
157
+
158
+ The tests are offline: providers are faked at the HTTP layer, so no key is needed.
159
+
160
+ ## Releasing to PyPI
161
+
162
+ 1. Bump `version` in `pyproject.toml` and `__version__` in `flowai/__init__.py`.
163
+ 2. Push a tag `flowai-vX.Y.Z`. The `flowai-release` workflow builds this
164
+ directory and publishes it with PyPI Trusted Publishing; configure the
165
+ `flowai-cli` project on PyPI to trust this repository and workflow first.
166
+
167
+
168
+
169
+ ## License
170
+
171
+ MIT
@@ -0,0 +1,36 @@
1
+ """Example 01: Quickstart with FlowAI."""
2
+
3
+ import asyncio
4
+
5
+ from flowai import Agent, tool
6
+ from flowai.memory import ConversationMemory
7
+
8
+
9
+ @tool
10
+ def calculate_growth(initial: float, rate: float, periods: int) -> float:
11
+ """Calculate compound interest growth."""
12
+ return round(initial * ((1 + rate) ** periods), 2)
13
+
14
+
15
+ async def main():
16
+ # Initialize an agent with in-memory conversation memory
17
+ memory = ConversationMemory()
18
+ agent = Agent(
19
+ name="FinanceAgent",
20
+ provider="openai", # or "nvidia", "ollama", "anthropic", "gemini"
21
+ model="gpt-4o-mini",
22
+ tools=[calculate_growth],
23
+ memory=memory,
24
+ )
25
+
26
+ print("=== FlowAI Quickstart Agent ===")
27
+ response = await agent.run("If I invest $10,000 at 7% for 5 years, what will it be worth?")
28
+ print(f"Agent Reply:\n{response}\n")
29
+
30
+ # Conversation history is preserved
31
+ print("=== Preserved Conversation History ===")
32
+ print(memory.format_history())
33
+
34
+
35
+ if __name__ == "__main__":
36
+ asyncio.run(main())
@@ -0,0 +1,40 @@
1
+ """Example 02: NVIDIA API Catalog with DeepSeek-R1 / DeepSeek-V4."""
2
+
3
+ import asyncio
4
+
5
+ from flowai import Agent, tool
6
+
7
+
8
+ @tool
9
+ def check_server_health(host: str) -> dict:
10
+ """Check system resource status and latency."""
11
+ return {"host": host, "status": "healthy", "cpu_percent": 24.5, "latency_ms": 12.4}
12
+
13
+
14
+ async def main():
15
+ # Make sure NVIDIA_API_KEY is set in your environment
16
+ agent = Agent(
17
+ name="NvidiaDeepSeekAgent",
18
+ provider="nvidia",
19
+ model="deepseek-ai/deepseek-r1",
20
+ system_prompt="You are a DevOps autonomous triage engineer.",
21
+ tools=[check_server_health],
22
+ )
23
+
24
+ print("=== Invoking DeepSeek on NVIDIA API Catalog ===")
25
+ prompt = "Check the health of 'prod-cluster-us-east-1' and summarize your findings."
26
+
27
+ # Non-streaming invocation
28
+ result = await agent.run(prompt)
29
+ print("\n--- Agent Conclusion ---")
30
+ print(result)
31
+
32
+ # Token streaming invocation
33
+ print("\n--- Streaming Response ---")
34
+ async for chunk in agent.stream("Recommend 2 optimization actions."):
35
+ print(chunk.text_delta, end="", flush=True)
36
+ print()
37
+
38
+
39
+ if __name__ == "__main__":
40
+ asyncio.run(main())
@@ -0,0 +1,56 @@
1
+ """Example 03: Multi-agent Workflow DAG with State Passing and Checkpoints."""
2
+
3
+ import asyncio
4
+
5
+ from flowai import Agent, Workflow
6
+ from flowai.workflow.checkpoint import InMemoryCheckpointer
7
+
8
+
9
+ async def main():
10
+ # 1. Instantiate specialized agents
11
+ researcher = Agent(
12
+ name="Researcher",
13
+ model="gpt-4o-mini",
14
+ system_prompt="You are a Technical Researcher. Provide facts, architecture patterns, and benchmarks.",
15
+ )
16
+ coder = Agent(
17
+ name="Coder",
18
+ model="gpt-4o-mini",
19
+ system_prompt="You are a Principal Software Engineer. Write clean, idiomatic Python code based on research.",
20
+ )
21
+ reviewer = Agent(
22
+ name="Reviewer",
23
+ model="gpt-4o-mini",
24
+ system_prompt="You are a Code Reviewer. Inspect code for bugs, edge cases, and performance bottlenecks.",
25
+ )
26
+
27
+ # 2. Construct DAG Workflow with Checkpointing
28
+ checkpointer = InMemoryCheckpointer()
29
+ wf = Workflow(name="CodeGenerationPipeline", checkpointer=checkpointer)
30
+
31
+ wf.add_agent(researcher, name="research_node")
32
+ wf.add_agent(coder, name="coding_node")
33
+ wf.add_agent(reviewer, name="review_node")
34
+
35
+ # Connect nodes in a linear sequential pipeline
36
+ wf.add_edge("research_node", "coding_node")
37
+ wf.add_edge("coding_node", "review_node")
38
+
39
+ # 3. Execute workflow
40
+ task = "Design and implement a thread-safe token bucket rate limiter in Python."
41
+ print(f"Starting Workflow for task: '{task}' ...\n")
42
+ final_state = await wf.run(task, entry_point="research_node")
43
+
44
+ print("=== Final Pipeline State Output ===")
45
+ print(f"Total Steps Executed: {final_state.step}")
46
+ print(f"Researcher Output:\n{final_state.get('research_node_output')[:300]}...\n")
47
+ print(f"Coder Output:\n{final_state.get('coding_node_output')[:300]}...\n")
48
+ print(f"Reviewer Output:\n{final_state.get('review_node_output')}\n")
49
+
50
+ # Verify checkpoints
51
+ checkpoints = await checkpointer.list_checkpoints(final_state.session_id)
52
+ print(f"Checkpoints persisted: {checkpoints}")
53
+
54
+
55
+ if __name__ == "__main__":
56
+ asyncio.run(main())
@@ -0,0 +1,37 @@
1
+ """Example 04: FastMCP / Model Context Protocol Integration."""
2
+
3
+ import asyncio
4
+
5
+ from flowai import Agent
6
+ from flowai.mcp import MCPClient
7
+
8
+
9
+ async def main():
10
+ print("=== FlowAI MCP Integration Example ===")
11
+
12
+ # Initialize client to an MCP server (e.g. SQLite, GitHub, or custom FastMCP server)
13
+ mcp_client = MCPClient(
14
+ command="npx",
15
+ args=["-y", "@modelcontextprotocol/server-everything"],
16
+ )
17
+
18
+ print("Connecting to MCP server and discovering exposed tools...")
19
+ tools = await mcp_client.connect_and_discover_tools()
20
+ print(f"Discovered {len(tools)} MCP tools:")
21
+ for t in tools:
22
+ print(f" - {t.name}: {t.description}")
23
+
24
+ # Plug discovered MCP tools directly into a FlowAI agent
25
+ agent = Agent(
26
+ name="MCPWorker",
27
+ provider="nvidia",
28
+ model="deepseek-ai/deepseek-r1",
29
+ tools=tools,
30
+ )
31
+
32
+ reply = await agent.run("List the tools you have and pick one to demonstrate.")
33
+ print(f"\n{agent.name}: {reply}")
34
+
35
+
36
+ if __name__ == "__main__":
37
+ asyncio.run(main())
@@ -0,0 +1,68 @@
1
+ """Example 05: Multi-agent Debate and Swarm Patterns."""
2
+
3
+ import asyncio
4
+
5
+ from flowai import Agent, DebatePattern, Swarm
6
+ from flowai.providers.base import BaseProvider, ProviderResponse
7
+
8
+
9
+ class ScriptedProvider(BaseProvider):
10
+ """Deterministic provider for simulation."""
11
+
12
+ def __init__(self, script: dict[str, str]):
13
+ super().__init__(model="scripted")
14
+ self.script = script
15
+
16
+ async def generate(self, messages, tools=None, **kwargs):
17
+ last_msg = messages[-1].content
18
+ for k, reply in self.script.items():
19
+ if k in last_msg:
20
+ return ProviderResponse(content=reply)
21
+ return ProviderResponse(content="Default response.")
22
+
23
+ async def stream(self, messages, tools=None, **kwargs):
24
+ yield
25
+
26
+ async def embeddings(self, texts, model=None, **kwargs):
27
+ return []
28
+
29
+
30
+ async def test_debate():
31
+ print("=== Multi-Agent Debate Pattern ===")
32
+ provider_pro = ScriptedProvider({"IN FAVOR": "Remote work increases productivity and mental wellbeing."})
33
+ provider_con = ScriptedProvider({"AGAINST": "In-office work fosters spontaneous collaboration and mentorship."})
34
+ provider_judge = ScriptedProvider({"impartial judge": "Both presented strong points; hybrid mode is optimal."})
35
+
36
+ debater_a = Agent("ProRemote", provider=provider_pro)
37
+ debater_b = Agent("ProOffice", provider=provider_con)
38
+ judge = Agent("Judge", provider=provider_judge)
39
+
40
+ debate = DebatePattern(debater_a, debater_b, judge, rounds=1)
41
+ result = await debate.execute("Should companies mandate 5 days in-office?")
42
+ print("Debate Transcript:")
43
+ for entry in result["transcript"]:
44
+ print(f" - {entry}")
45
+ print(f"\nVerdict:\n{result['verdict']}\n")
46
+
47
+
48
+ async def test_swarm():
49
+ print("=== Multi-Agent Swarm Dynamic Handoff ===")
50
+ triage_script = {
51
+ "Python": "HANDOFF_TO: PythonExpert Please write the Python implementation.",
52
+ "SQL": "HANDOFF_TO: SQLExpert Please optimize the SQL query.",
53
+ }
54
+ triage = Agent("TriageAgent", provider=ScriptedProvider(triage_script))
55
+ py_agent = Agent("PythonExpert", provider=ScriptedProvider({"write": "def solve(): return 42"}))
56
+
57
+ swarm = Swarm(agents=[triage, py_agent], initial_agent=triage)
58
+ result = await swarm.execute("I need a Python function to compute answer to life.")
59
+ print(f"Swarm Result:\n{result}")
60
+
61
+
62
+ async def main():
63
+ await test_debate()
64
+ await test_swarm()
65
+
66
+
67
+ if __name__ == "__main__":
68
+ asyncio.run(main())