10xscale-agentflow-cli 0.2.4__tar.gz → 0.2.6__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.
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/PKG-INFO +1 -1
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/SOURCES.txt +1 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/PKG-INFO +1 -1
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/services/graph_service.py +15 -6
- 10xscale_agentflow_cli-0.2.6/plan.md +190 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/pyproject.toml +1 -1
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/dependency_links.txt +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/entry_points.txt +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/not-zip-safe +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/requires.txt +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/10xscale_agentflow_cli.egg-info/top_level.txt +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/MANIFEST.in +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/README.md +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/Task.md +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow.json +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/api.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/build.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/init.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/version.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/constants.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/config.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/output.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/validation.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/exceptions.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/logger.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/main.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/templates/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/templates/defaults.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/auth/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/auth/auth_backend.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/auth/base_auth.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/auth/jwt_auth.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/graph_config.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/sentry_config.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/settings.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/setup_logs.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/setup_middleware.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/config/worker_middleware.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/exceptions/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/exceptions/general_exception.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/exceptions/handle_errors.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/exceptions/resources_exceptions.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/exceptions/user_exception.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/loader.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/main.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/router.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/schemas/checkpointer_schemas.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/checkpointer/services/checkpointer_service.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/router.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/schemas/graph_schemas.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/graph/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/ping/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/ping/router.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/setup_router.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/router.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/schemas/store_schemas.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/services/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/routers/store/services/store_service.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/tasks/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/tasks/user_tasks.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/callable_helper.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/parse_output.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/response_helper.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/schemas/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/schemas/output_schemas.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/schemas/user_schemas.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/snowflake_id_generator.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/swagger_helper.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/utils/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/worker.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/graph/__init__.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/graph/react.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/graph/thread_name_generator.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/scripts/generate_docs.py +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/setup.cfg +0 -0
- {10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/tests/test_utils_parse_and_callable.py +0 -0
|
@@ -217,10 +217,14 @@ class GraphService:
|
|
|
217
217
|
input_data, config, meta = await self._prepare_input(graph_input)
|
|
218
218
|
# add user inside config
|
|
219
219
|
config["user"] = user
|
|
220
|
-
config["user_id"] = user.get("
|
|
220
|
+
config["user_id"] = user.get("user_id", "anonymous")
|
|
221
221
|
|
|
222
|
-
#
|
|
223
|
-
|
|
222
|
+
# Try to save thread info in the db even for existing threads
|
|
223
|
+
# this will help in updating last accessed time
|
|
224
|
+
# and get is thread newly created or not, this way it's consistent
|
|
225
|
+
is_new_thread = await self._save_thread(config, config["thread_id"])
|
|
226
|
+
if is_new_thread and type(is_new_thread) is bool:
|
|
227
|
+
meta["is_new_thread"] = True
|
|
224
228
|
|
|
225
229
|
# Execute the graph
|
|
226
230
|
result = await self._graph.ainvoke(
|
|
@@ -282,9 +286,14 @@ class GraphService:
|
|
|
282
286
|
input_data, config, meta = await self._prepare_input(graph_input)
|
|
283
287
|
# add user inside config
|
|
284
288
|
config["user"] = user
|
|
285
|
-
config["user_id"] = user.get("
|
|
289
|
+
config["user_id"] = user.get("user_id", "anonymous")
|
|
286
290
|
|
|
287
|
-
|
|
291
|
+
# Try to save thread info in the db even for existing threads
|
|
292
|
+
# this will help in updating last accessed time
|
|
293
|
+
# and get is thread newly created or not, this way it's consistent
|
|
294
|
+
is_new_thread = await self._save_thread(config, config["thread_id"])
|
|
295
|
+
if is_new_thread and type(is_new_thread) is bool:
|
|
296
|
+
meta["is_new_thread"] = True
|
|
288
297
|
|
|
289
298
|
messages_str = []
|
|
290
299
|
|
|
@@ -400,7 +409,7 @@ class GraphService:
|
|
|
400
409
|
logger.debug(f"User info: {user}")
|
|
401
410
|
|
|
402
411
|
fix_config = {"thread_id": thread_id, "user": user}
|
|
403
|
-
fix_config["user_id"] = user.get("
|
|
412
|
+
fix_config["user_id"] = user.get("user_id", "anonymous")
|
|
404
413
|
if config:
|
|
405
414
|
fix_config.update(config)
|
|
406
415
|
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
# Dev Playground Plan for Agentflow CLI
|
|
2
|
+
|
|
3
|
+
## Summary ✅
|
|
4
|
+
Add a CLI feature (e.g., `agentflow api --open` or `agentflow dev`) that:
|
|
5
|
+
- Starts the development FastAPI server (uvicorn) on the selected host/port.
|
|
6
|
+
- Serves a simple interactive `playground` UI and any related static assets at `/playground`.
|
|
7
|
+
- Automatically opens a single browser window/tab to the `playground` URL when the server is ready.
|
|
8
|
+
|
|
9
|
+
This improves the developer DX by surfacing an interactive dev playground on `dev` runs in a single, consistent UX.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Goals & Requirements 🎯
|
|
14
|
+
- Add a CLI flag to launch the playground automatically (default: opt-in: `--open` or `dev` default true).
|
|
15
|
+
- Serve a lightweight, local playground UI that calls the API endpoints.
|
|
16
|
+
- Ensure the browser opens only once when running the CLI (avoid multiple windows/tabs even while using `--reload`).
|
|
17
|
+
- Avoid opening browser in headless CI or tests.
|
|
18
|
+
- Keep default behavior unchanged (no production browser opens).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Implementation Options (Pros & Cons) 🔧
|
|
23
|
+
Option A — Minimal (Recommended):
|
|
24
|
+
- Add `--open` flag to the existing `api` CLI command (or create an alias `dev`).
|
|
25
|
+
- Add a small static HTML/JS playground at `src/app/static/playground/index.html`.
|
|
26
|
+
- Add a FastAPI route `/playground` to serve the playground or configure `StaticFiles` middleware.
|
|
27
|
+
- Launch uvicorn programmatically via `uvicorn.Server` or start it in a background thread, and once the server responds to `/ping`, open `webbrowser.open(url)`. This avoids opening before the server is ready.
|
|
28
|
+
|
|
29
|
+
Pros: Direct, minimal, leverages existing FastAPI app and uvicorn.
|
|
30
|
+
Cons: Must ensure it doesn't open on reloader spawn; simple logic required to open only once.
|
|
31
|
+
|
|
32
|
+
Option B — Use Swagger / ReDoc (Quick & Safe):
|
|
33
|
+
- Reuse existing `docs_url` or `redoc_url` (e.g., open `/docs`).
|
|
34
|
+
|
|
35
|
+
Pros: No new routes or frontend required.
|
|
36
|
+
Cons: Not a custom playground UI.
|
|
37
|
+
|
|
38
|
+
Option C — Use a local `PyWebView` (Desktop app) or native webview.
|
|
39
|
+
- Spawn a desktop window embedding the playground. More complex and cross-platform issues.
|
|
40
|
+
|
|
41
|
+
Pros: Single top-level window without the browser.
|
|
42
|
+
Cons: Extra dependencies; not necessary for a simple developer experience.
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Technical Considerations and Constraints ⚠️
|
|
47
|
+
- Uvicorn reload behavior: when `--reload` is enabled it spawns a new server process on code changes. Opening the browser should happen only once, not on each worker spawn. Avoid re-opening by either:
|
|
48
|
+
- Opening the browser from the CLI thread after the server responds (preferred). Or,
|
|
49
|
+
- Use environment checks to ensure only the main process opens the browser.
|
|
50
|
+
|
|
51
|
+
- Polling for readiness: Use the `/ping` endpoint to perform a health check until the server responds (timeout e.g., 5s) then open the browser.
|
|
52
|
+
|
|
53
|
+
- Headless / CI environments: Skip opening the browser if `CI` or `GITHUB_ACTIONS` or `CI` env var is set, or if `DISPLAY` is not present (Linux headless) — allow opt-in overriding.
|
|
54
|
+
|
|
55
|
+
- Cross platform `webbrowser` support: the Python `webbrowser` module is cross-platform — use `webbrowser.open(url, new=0)`.
|
|
56
|
+
|
|
57
|
+
- Avoid opening multiple tabs/windows: Use the browser API `open(..., new=0)` to reuse an existing browser window where possible, and only call once.
|
|
58
|
+
|
|
59
|
+
- Security: Keep the playground local, do not expose sensitive resources; add guard to serve playground if `settings.MODE == "DEVELOPMENT"` or explicit config.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## CLI UX Design ✨
|
|
64
|
+
- Preferred command: `agentflow dev` (alias to `agentflow api --open`)
|
|
65
|
+
- Example usage:
|
|
66
|
+
- `agentflow dev` — start dev server + open playground (default)
|
|
67
|
+
- `agentflow api --open` — start server + open playground
|
|
68
|
+
- `agentflow api` — start server without browser (existing behavior)
|
|
69
|
+
- `agentflow dev --no-open` — start server without browser
|
|
70
|
+
|
|
71
|
+
Flags:
|
|
72
|
+
- `--open / --no-open` or `--playground / --no-playground`.
|
|
73
|
+
- `--host`, `--port`, `--reload` retain compatibility.
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Proposed Implementation Steps (High-level) 🛠️
|
|
78
|
+
1. Add CLI option and command alias
|
|
79
|
+
- Add a new CLI `dev` command in `agentflow_cli/cli/commands/` as a thin wrapper around the existing `api` command or add `--open` flag to `APICommand.execute`.
|
|
80
|
+
- Example: `agentflow_cli/cli/commands/api.py`: add `open_playground: bool = False` to signature.
|
|
81
|
+
|
|
82
|
+
2. Playground route & static assets
|
|
83
|
+
- Add a new router `playground.router` in `src/app/routers` exposing `/playground`.
|
|
84
|
+
- Add a `static` directory (e.g. `agentflow_cli/src/app/static/playground/`) with `index.html` and optionally `app.js` and CSS.
|
|
85
|
+
- Use `FastAPI`'s `StaticFiles` or `HTMLResponse`/`Jinja2Templates` to serve.
|
|
86
|
+
- Register the router conditionally when `settings.MODE == 'DEVELOPMENT'` or `settings.PLAYGROUND_ENABLED`.
|
|
87
|
+
|
|
88
|
+
3. Browser opening logic
|
|
89
|
+
- Update `APICommand` to accept `open_playground`.
|
|
90
|
+
- Option A (recommended): Launch the server programmatically: `uvicorn.Server(config)` in a thread, poll `http://host:port/ping` for readiness, then open the browser.
|
|
91
|
+
- Option B: If staying with `uvicorn.run()` (blocking), we can start a small thread to poll and open the browser.
|
|
92
|
+
|
|
93
|
+
Example pseudo-code sketch:
|
|
94
|
+
```python
|
|
95
|
+
# inside APICommand.execute
|
|
96
|
+
if open_playground and not is_ci():
|
|
97
|
+
url = f"http://{host}:{port}/playground"
|
|
98
|
+
t = threading.Thread(target=_wait_and_open, args=(url, host, port), daemon=True)
|
|
99
|
+
t.start()
|
|
100
|
+
|
|
101
|
+
uvicorn.run(...)
|
|
102
|
+
|
|
103
|
+
# helper
|
|
104
|
+
def _wait_and_open(url, host, port):
|
|
105
|
+
for _ in range(50):
|
|
106
|
+
try:
|
|
107
|
+
r = requests.get(f"http://{host}:{port}/ping", timeout=0.5)
|
|
108
|
+
if r.ok:
|
|
109
|
+
webbrowser.open(url, new=0)
|
|
110
|
+
return
|
|
111
|
+
except Exception:
|
|
112
|
+
time.sleep(0.1)
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
4. Unit tests
|
|
117
|
+
- Mock `webbrowser.open` and `requests` to assert the open call when `--open` is used.
|
|
118
|
+
- Mock `uvicorn.run` to avoid actually starting the server during unit tests.
|
|
119
|
+
|
|
120
|
+
5. Integration tests (optional)
|
|
121
|
+
- Spin up app via `TestClient` or start a backward uvicorn instance, call `/playground` to ensure route returns `200`.
|
|
122
|
+
|
|
123
|
+
6. Documentation
|
|
124
|
+
- Update `README.md` and `docs` describing `dev` command and how to use it.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## How to implement single-browser-session behavior (single tab) 🚪
|
|
129
|
+
- Use the `webbrowser`'s `new=0` value to attempt to reuse a window/tab.
|
|
130
|
+
- Add a small CLI-local sentinel — write the url or timestamp into a tempfile (e.g., `/tmp/agentflow_playground_{port}.txt`) and only open the browser if that sentinel is missing or stale (e.g., older than 15 seconds). This avoids re-opening on reload events.
|
|
131
|
+
- The sentinel approach isn't bulletproof but simplifies logic and avoids frequent reopens.
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Edge Cases & Tests 🧪
|
|
136
|
+
- CI environments: Should not open the browser. Detect CI by `CI` env var or skip/guard.
|
|
137
|
+
- Headless Linux: If `DISPLAY` is absent and not WSL, skip opening.
|
|
138
|
+
- `--reload` (dev reload): Avoid re-opening on each reload by keeping a sentinel or ensuring the open call fires only once.
|
|
139
|
+
- Port in use: If port in use, error should be returned gracefully.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## Acceptance Criteria ✅
|
|
144
|
+
- [ ] A `dev` command or `--open-playground` flag is present and documented.
|
|
145
|
+
- [ ] Launcher opens browser to `/playground` only once at initial start.
|
|
146
|
+
- [ ] Playground UI is served at `/playground` and works as expected (basic testing endpoints).
|
|
147
|
+
- [ ] CLI unit tests verify the browser open behavior (using mocking); integration tests verify route serves content.
|
|
148
|
+
|
|
149
|
+
---
|
|
150
|
+
|
|
151
|
+
## Optional Future Enhancements 💡
|
|
152
|
+
- Toggle auto-open link per environment variable or per `setup.cfg`/`settings` for developer preference.
|
|
153
|
+
- Build a more robust playground UI with OAuth injection or virtual keys (with caution).
|
|
154
|
+
- Option to open a standalone desktop playground (PyWebView) for native UX.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## Resources & Links (Research) 📚
|
|
159
|
+
- Python webbrowser: https://docs.python.org/3/library/webbrowser.html
|
|
160
|
+
- Uvicorn reload and process/child detection: https://www.uvicorn.org/
|
|
161
|
+
- Starting uvicorn programmatically: https://www.uvicorn.org/deployment/#programmatically
|
|
162
|
+
- FastAPI static files & HTML responses: https://fastapi.tiangolo.com/tutorial/static-files/
|
|
163
|
+
- Example implementations that open a browser on startup: many projects use `webbrowser.open` plus a health check.
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## Next Steps (Implementation action list) 📝
|
|
169
|
+
- [ ] Add `open_playground` flag to `APICommand` (or add `dev` command).
|
|
170
|
+
- [ ] Add `playground` route & static files.
|
|
171
|
+
- [ ] Add readiness poll + `webbrowser.open` into CLI logic.
|
|
172
|
+
- [ ] Add unit tests for CLI open behavior and route tests for `/playground`.
|
|
173
|
+
- [ ] Document usage and examples in `README.md`.
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
Appendix: Example CLI usage
|
|
179
|
+
```bash
|
|
180
|
+
# Start the server and open playground (default on dev)
|
|
181
|
+
agentflow dev
|
|
182
|
+
|
|
183
|
+
# Start API server without opening browser
|
|
184
|
+
agentflow api --no-open
|
|
185
|
+
|
|
186
|
+
# Start API server and explicitly open
|
|
187
|
+
agentflow api --open
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If you want, I can follow up by implementing a minimal PR that adds `--open` and a tiny `playground` route (HTML + small JS) and tests. Let me know which option you prefer (A: `dev` alias default true, B: `--open` opt-in for `api`), and I will start implementing it.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/api.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/build.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/init.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/commands/version.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/constants.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/config.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/output.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/core/validation.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/cli/exceptions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/__init__.py
RENAMED
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/core/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/loader.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/agentflow_cli/src/app/worker.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/graph/thread_name_generator.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{10xscale_agentflow_cli-0.2.4 → 10xscale_agentflow_cli-0.2.6}/tests/test_utils_parse_and_callable.py
RENAMED
|
File without changes
|