flowent 0.2.0 → 0.2.1

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 (67) hide show
  1. package/backend/pyproject.toml +31 -5
  2. package/backend/src/flowent/agent.py +13 -4
  3. package/backend/src/flowent/compact.py +35 -14
  4. package/backend/src/flowent/llm.py +73 -7
  5. package/backend/src/flowent/main.py +260 -59
  6. package/backend/src/flowent/static/assets/index-CRSV2xu1.css +2 -0
  7. package/backend/src/flowent/static/assets/index-DUYj6rgD.js +82 -0
  8. package/backend/src/flowent/static/index.html +2 -2
  9. package/backend/src/flowent/storage.py +135 -3
  10. package/backend/src/flowent/usage.py +315 -0
  11. package/backend/uv.lock +971 -3
  12. package/dist/frontend/assets/index-CRSV2xu1.css +2 -0
  13. package/dist/frontend/assets/index-DUYj6rgD.js +82 -0
  14. package/dist/frontend/index.html +2 -2
  15. package/package.json +24 -3
  16. package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
  17. package/backend/src/flowent/__pycache__/_version.cpython-313.pyc +0 -0
  18. package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
  19. package/backend/src/flowent/__pycache__/approval.cpython-313.pyc +0 -0
  20. package/backend/src/flowent/__pycache__/channels.cpython-313.pyc +0 -0
  21. package/backend/src/flowent/__pycache__/cli.cpython-313.pyc +0 -0
  22. package/backend/src/flowent/__pycache__/compact.cpython-313.pyc +0 -0
  23. package/backend/src/flowent/__pycache__/context.cpython-313.pyc +0 -0
  24. package/backend/src/flowent/__pycache__/llm.cpython-313.pyc +0 -0
  25. package/backend/src/flowent/__pycache__/logging.cpython-313.pyc +0 -0
  26. package/backend/src/flowent/__pycache__/main.cpython-313.pyc +0 -0
  27. package/backend/src/flowent/__pycache__/mcp.cpython-313.pyc +0 -0
  28. package/backend/src/flowent/__pycache__/mcp_import.cpython-313.pyc +0 -0
  29. package/backend/src/flowent/__pycache__/patch.cpython-313.pyc +0 -0
  30. package/backend/src/flowent/__pycache__/paths.cpython-313.pyc +0 -0
  31. package/backend/src/flowent/__pycache__/permissions.cpython-313.pyc +0 -0
  32. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  33. package/backend/src/flowent/__pycache__/skills.cpython-313.pyc +0 -0
  34. package/backend/src/flowent/__pycache__/storage.cpython-313.pyc +0 -0
  35. package/backend/src/flowent/__pycache__/tools.cpython-313.pyc +0 -0
  36. package/backend/src/flowent/static/assets/index-BlaCigkZ.js +0 -82
  37. package/backend/src/flowent/static/assets/index-CRvbsH4K.css +0 -2
  38. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  39. package/backend/tests/__pycache__/test_agent_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  40. package/backend/tests/__pycache__/test_approval.cpython-313-pytest-9.0.3.pyc +0 -0
  41. package/backend/tests/__pycache__/test_channels.cpython-313-pytest-9.0.3.pyc +0 -0
  42. package/backend/tests/__pycache__/test_health.cpython-313-pytest-9.0.3.pyc +0 -0
  43. package/backend/tests/__pycache__/test_llm_providers.cpython-313-pytest-9.0.3.pyc +0 -0
  44. package/backend/tests/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  45. package/backend/tests/__pycache__/test_mcp.cpython-313-pytest-9.0.3.pyc +0 -0
  46. package/backend/tests/__pycache__/test_patch.cpython-313-pytest-9.0.3.pyc +0 -0
  47. package/backend/tests/__pycache__/test_permissions.cpython-313-pytest-9.0.3.pyc +0 -0
  48. package/backend/tests/__pycache__/test_persistence.cpython-313-pytest-9.0.3.pyc +0 -0
  49. package/backend/tests/__pycache__/test_skills.cpython-313-pytest-9.0.3.pyc +0 -0
  50. package/backend/tests/__pycache__/test_startup_requirements.cpython-313-pytest-9.0.3.pyc +0 -0
  51. package/backend/tests/__pycache__/test_workspace_chat.cpython-313-pytest-9.0.3.pyc +0 -0
  52. package/backend/tests/conftest.py +0 -60
  53. package/backend/tests/test_agent_tools.py +0 -1124
  54. package/backend/tests/test_approval.py +0 -283
  55. package/backend/tests/test_channels.py +0 -360
  56. package/backend/tests/test_health.py +0 -12
  57. package/backend/tests/test_llm_providers.py +0 -548
  58. package/backend/tests/test_logging.py +0 -212
  59. package/backend/tests/test_mcp.py +0 -788
  60. package/backend/tests/test_patch.py +0 -112
  61. package/backend/tests/test_permissions.py +0 -588
  62. package/backend/tests/test_persistence.py +0 -249
  63. package/backend/tests/test_skills.py +0 -462
  64. package/backend/tests/test_startup_requirements.py +0 -144
  65. package/backend/tests/test_workspace_chat.py +0 -2174
  66. package/dist/frontend/assets/index-BlaCigkZ.js +0 -82
  67. package/dist/frontend/assets/index-CRvbsH4K.css +0 -2
@@ -1,249 +0,0 @@
1
- from fastapi.testclient import TestClient
2
-
3
- from flowent.main import create_app
4
-
5
-
6
- def test_app_state_persists_providers_across_app_instances(
7
- tmp_path, monkeypatch
8
- ) -> None:
9
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
10
- client = TestClient(create_app(serve_frontend=False))
11
-
12
- response = client.post(
13
- "/api/providers",
14
- json={
15
- "api_key": "sk-local",
16
- "base_url": "https://api.example.test/v1",
17
- "id": "provider-openai",
18
- "models": ["gpt-5.1", "gpt-5.1-mini"],
19
- "name": "OpenAI",
20
- "type": "openai",
21
- },
22
- )
23
-
24
- assert response.status_code == 200
25
-
26
- restarted_client = TestClient(create_app(serve_frontend=False))
27
- state_response = restarted_client.get("/api/state")
28
-
29
- assert state_response.status_code == 200
30
- assert state_response.json()["providers"] == [
31
- {
32
- "api_key": "sk-local",
33
- "base_url": "https://api.example.test/v1",
34
- "id": "provider-openai",
35
- "models": ["gpt-5.1", "gpt-5.1-mini"],
36
- "name": "OpenAI",
37
- "type": "openai",
38
- }
39
- ]
40
-
41
-
42
- def test_app_state_persists_telegram_bot_across_app_instances(
43
- tmp_path, monkeypatch
44
- ) -> None:
45
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
46
- client = TestClient(create_app(serve_frontend=False))
47
-
48
- response = client.put(
49
- "/api/telegram-bot",
50
- json={
51
- "bot_token": "telegram-secret",
52
- "enabled": False,
53
- "sessions": [],
54
- },
55
- )
56
-
57
- assert response.status_code == 200
58
-
59
- restarted_client = TestClient(create_app(serve_frontend=False))
60
- state_response = restarted_client.get("/api/state")
61
-
62
- assert state_response.status_code == 200
63
- assert state_response.json()["telegram_bot"] == {
64
- "bot_token": "telegram-secret",
65
- "enabled": False,
66
- "error": "",
67
- "sessions": [],
68
- "status": "disabled",
69
- }
70
-
71
-
72
- def test_app_state_persists_settings_and_workspace_messages(
73
- tmp_path, monkeypatch
74
- ) -> None:
75
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
76
- client = TestClient(create_app(serve_frontend=False))
77
- client.post(
78
- "/api/providers",
79
- json={
80
- "api_key": "",
81
- "base_url": "",
82
- "id": "provider-anthropic",
83
- "models": ["claude-sonnet-4-5"],
84
- "name": "Anthropic",
85
- "type": "anthropic",
86
- },
87
- )
88
-
89
- settings_response = client.put(
90
- "/api/settings",
91
- json={
92
- "agent_prompt": "Respond with careful implementation plans.",
93
- "reasoning_effort": "xhigh",
94
- "selected_model": "claude-sonnet-4-5",
95
- "selected_provider_id": "provider-anthropic",
96
- },
97
- )
98
- messages_response = client.put(
99
- "/api/workspace/messages",
100
- json={
101
- "messages": [
102
- {
103
- "author": "assistant",
104
- "content": "Draft a launch checklist",
105
- "id": "message-1",
106
- "thinking": "Read the request.",
107
- "tools": [
108
- {
109
- "id": "tool-1",
110
- "name": "read_file",
111
- "status": "success",
112
- "title": "Read notes.txt",
113
- }
114
- ],
115
- }
116
- ]
117
- },
118
- )
119
-
120
- assert settings_response.status_code == 200
121
- assert messages_response.status_code == 200
122
-
123
- restarted_client = TestClient(create_app(serve_frontend=False))
124
- state = restarted_client.get("/api/state").json()
125
-
126
- assert state["settings"] == {
127
- "agent_prompt": "Respond with careful implementation plans.",
128
- "reasoning_effort": "xhigh",
129
- "selected_model": "claude-sonnet-4-5",
130
- "selected_provider_id": "provider-anthropic",
131
- }
132
- assert state["messages"] == [
133
- {
134
- "author": "assistant",
135
- "content": "Draft a launch checklist",
136
- "id": "message-1",
137
- "thinking": "Read the request.",
138
- "tools": [
139
- {
140
- "arguments": None,
141
- "content": None,
142
- "data": None,
143
- "id": "tool-1",
144
- "name": "read_file",
145
- "status": "success",
146
- "title": "Read notes.txt",
147
- }
148
- ],
149
- }
150
- ]
151
-
152
-
153
- def test_app_state_persists_workspace_error_blocks_across_app_instances(
154
- tmp_path, monkeypatch
155
- ) -> None:
156
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
157
- client = TestClient(create_app(serve_frontend=False))
158
-
159
- messages_response = client.put(
160
- "/api/workspace/messages",
161
- json={
162
- "messages": [
163
- {
164
- "author": "assistant",
165
- "content": "",
166
- "groups": [
167
- {
168
- "id": "message-1-errors",
169
- "items": [
170
- {
171
- "detail": "HTML response returned.",
172
- "id": "message-1-error-1",
173
- "message": "Check the model connection settings and try again.",
174
- "title": "Request failed",
175
- "type": "error",
176
- }
177
- ],
178
- }
179
- ],
180
- "id": "message-1",
181
- "status": "failed",
182
- }
183
- ]
184
- },
185
- )
186
-
187
- assert messages_response.status_code == 200
188
-
189
- restarted_client = TestClient(create_app(serve_frontend=False))
190
- state = restarted_client.get("/api/state").json()
191
-
192
- assert state["messages"] == [
193
- {
194
- "author": "assistant",
195
- "content": "",
196
- "groups": [
197
- {
198
- "id": "message-1-errors",
199
- "items": [
200
- {
201
- "detail": "HTML response returned.",
202
- "id": "message-1-error-1",
203
- "message": "Check the model connection settings and try again.",
204
- "title": "Request failed",
205
- "type": "error",
206
- }
207
- ],
208
- }
209
- ],
210
- "id": "message-1",
211
- "status": "failed",
212
- "tools": [],
213
- }
214
- ]
215
-
216
-
217
- def test_data_directory_uses_flowent_data_dir(tmp_path, monkeypatch) -> None:
218
- data_dir = tmp_path / "custom-flowent"
219
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(data_dir))
220
-
221
- client = TestClient(create_app(serve_frontend=False))
222
- response = client.get("/api/state")
223
-
224
- assert response.status_code == 200
225
- assert (data_dir / "flowent.db").is_file()
226
-
227
-
228
- def test_app_state_defaults_reasoning_effort_for_existing_settings(
229
- tmp_path, monkeypatch
230
- ) -> None:
231
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
232
- client = TestClient(create_app(serve_frontend=False))
233
-
234
- response = client.get("/api/state")
235
-
236
- assert response.status_code == 200
237
- assert response.json()["settings"]["reasoning_effort"] == "default"
238
-
239
-
240
- def test_app_state_defaults_agent_prompt_for_existing_settings(
241
- tmp_path, monkeypatch
242
- ) -> None:
243
- monkeypatch.setenv("FLOWENT_DATA_DIR", str(tmp_path))
244
- client = TestClient(create_app(serve_frontend=False))
245
-
246
- response = client.get("/api/state")
247
-
248
- assert response.status_code == 200
249
- assert response.json()["settings"].get("agent_prompt", "") == ""