feat: natural-language orchestration, DeepSeek provider, coordinator hardening#22
feat: natural-language orchestration, DeepSeek provider, coordinator hardening#22ysfscream wants to merge 3 commits into
Conversation
…hardening Runtime API: - natural-language planner via the `skitter` agent: plan a new composed app from the live discovery registry, or route a request to an existing app so the normal coordinator session path handles execution - DeepSeek LLM provider (config, setup wizard, llm client, env/docs) - graph generation now requires every selected agent to be used Coordinator robustness: - guard the main MQTT message loop so one bad request can no longer tear down the coordinator - track agent online/offline status from discovery (a2a-status) and keep offline agents out of LLM planning - cap per-task event result/error payloads to bound MQTT packet size Shared helpers + tests: - llm.strip_code_fence and discovery.extract_app_tasks remove duplicated fence-stripping / app-extension parsing - tighten _resolve_app_ref to avoid resolving the wrong app - unit + e2e coverage for the above
There was a problem hiding this comment.
Pull request overview
This PR extends Skitter’s coordinator/runtime backend to support natural-language orchestration (planning new workflows from discovered agents or routing to an existing workflow), adds a DeepSeek LLM provider option, and hardens coordinator behavior around discovery liveness and runtime/event publishing.
Changes:
- Add a natural-language planner to the
skitterruntime API that can create new apps or route requests to run an existing app. - Add DeepSeek as an LLM provider (config, setup defaults, LLM client behavior, and docs/env examples).
- Improve coordinator robustness (per-message guard in the MQTT loop, discovery online/offline tracking, and bounded event payload sizes), plus expanded unit/E2E test coverage.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_setup.py | Adds coverage for DeepSeek default model selection in setup. |
| tests/unit/test_runtime_api.py | Adds/extends tests for natural-language planning, app routing, discovery status handling, and task metadata normalization. |
| tests/unit/test_llm.py | Adds test coverage for DeepSeek base URL + chat API path. |
| tests/unit/test_graph.py | Adds tests for required-agent enforcement and retry behavior in graph generation. |
| tests/unit/test_discovery.py | Adds tests for task-agent card detection helper. |
| tests/unit/test_coordinator.py | Updates prompt ordering expectations and adds offline-agent filtering test for registry listing. |
| tests/test_e2e.py | Updates E2E mocking to match new graph generator signature. |
| skitter/setup.py | Adds DeepSeek as a selectable provider and default model mapping. |
| skitter/runtime_api.py | Implements natural-language planning/routing, adds new result types, and enriches app card task metadata. |
| skitter/llm.py | Adds DeepSeek base URL behavior and shared code-fence stripping helper. |
| skitter/graph_gen.py | Adds required-agent validation support and reuses shared code-fence stripping. |
| skitter/discovery.py | Adds helpers to normalize app tasks/needs and detect task-agent cards. |
| skitter/coordinator/service.py | Adds runtime routing for “run app”, improves event payloads, liveness-aware discovery updates, and guards the MQTT loop. |
| skitter/coordinator/reply_handler.py | Publishes richer/truncated task/session event payloads on completion/failure paths. |
| skitter/coordinator/registry.py | Tracks agent online/offline status and filters offline agents from selection lists. |
| skitter/config.py | Documents DeepSeek as a supported llm.api option. |
| docs/usage.md | Updates usage docs for DeepSeek provider and environment variables. |
| docs/architecture.md | Documents natural-language runtime behavior and updated coordinator capabilities. |
| CONTRIBUTING.md | Updates contributor-facing env var docs for DeepSeek support. |
| .gitignore | Adds frontend-related ignore patterns (node_modules/build artifacts). |
| .env.example | Updates example env to include DeepSeek option and model. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| log = logging.getLogger("skitter.llm") | ||
|
|
||
| DEEPSEEK_BASE_URL = "https://api.deepseek.com" |
There was a problem hiding this comment.
I don't think it is necessary to add special treatment for deepseek. Have you tried to use openai-completions and override base_url?
There was a problem hiding this comment.
You're right — removed the dedicated deepseek provider. DeepSeek is OpenAI-compatible, so it now works via api: openai-completions + base_url: https://api.deepseek.com, documented in docs/usage.md. Pushed in 49d9668.
🤖 Addressed by Claude Code
…lidation - remove the DeepSeek LLM provider special-casing (base_url default, routing, setup choice, tests). DeepSeek is OpenAI-compatible, so it works via `openai-completions` + base_url, now documented as such (review feedback) - runtime planner: stop echoing the raw exception in the user-facing message (it is already logged) - validate_graph: reject a non-list `needs` with a clear error instead of iterating it character by character; add a regression test
generate_graph no longer forces every provided agent into the graph: validate_graph loses the required_agent_ids check and the parameter, and the prompt now asks the model to use only the agents relevant to the instructions. This removes a brittle failure mode where the NL planner (which defaults to all available agents) could be forced to build a graph around agents unrelated to the request, failing generation outright. Also drop a stale apps/* pattern from .gitignore (frontend lives in web/, which has its own .gitignore; the top-level node_modules/ catch-all stays).
|
A couple of intentional design notes for reviewers (things deliberately kept as-is):
🤖 Note added by Claude Code |
|
@ysfscream thanks, the coordinator hardening and shared-helper cleanup are good and I'd like to keep those. My one concern is the NL planner running an LLM call inside the coordinator. The coordinator is a singleton handling every app request and agent reply on one serial MQTT loop, so a multi-second planner call there head-of-line-blocks every in-flight workflow. It has to stay lean and LLM-free. Same feature, different home: make the planner its own A2A agent. It subscribes to its own request topic, reads discovery for the live agent/app list (agent status and task-agent filtering go with it), runs the LLM, then either replies, sends Separately, worth thinking about: if an app becomes its own planner and executor (its own templates plus memory, generating and running its graph), you stop needing a coordinator at all. Suggested split: the hardening part (merge as-is), and the planner reworked as its own agent. |
|
Thanks Ivan, this makes sense to me. I agree the coordinator should stay lean and LLM-free. The planner-as-agent direction fits Skitter much better than putting natural-language orchestration inside the coordinator loop. I'll rethink the design and implementation around that split: keep the coordinator hardening/shared cleanup separate, and move the NL planner into its own A2A agent. |
Summary
Backend changes that power the new dashboard's runtime view. Self-contained on the Python side (no frontend in this PR).
Runtime API
skitteragent: plan a new composed app from the live discovery registry, or route a request to an existing app so the normal coordinator session path executes it.deepseek-chat).Coordinator hardening
a2a-status) and keep offline agents out of LLM planning (the registry's offline filter was previously inert).result/errorpayloads to bound MQTT packet size.Cleanup + tests
llm.strip_code_fenceanddiscovery.extract_app_tasksremove duplicated fence-stripping / app-extension parsing._resolve_app_refso a short reference can't resolve to the wrong app.Verification
uv run pytest tests/unit tests/test_e2e.py→ 293 passed (EMQX via docker compose).uvx ruff format/uvx ruff checkclean.