swarmkit-runtime 1.0.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.
- swarmkit_runtime-1.0.0/.gitignore +66 -0
- swarmkit_runtime-1.0.0/CLAUDE.md +55 -0
- swarmkit_runtime-1.0.0/PKG-INFO +87 -0
- swarmkit_runtime-1.0.0/README.md +44 -0
- swarmkit_runtime-1.0.0/pyproject.toml +82 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/__init__.py +6 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/_workspace_runtime.py +308 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/archetypes/__init__.py +163 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/audit/__init__.py +13 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/authoring/__init__.py +10 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/authoring/_agent.py +289 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/authoring/_prompts.py +486 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/authoring/_tools.py +160 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/cli/__init__.py +662 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/cli/_knowledge.py +283 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/cli/_render.py +243 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/errors/__init__.py +104 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/gaps/__init__.py +107 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/governance/__init__.py +115 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/governance/_mock.py +98 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/governance/agt_provider.py +194 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/knowledge/__init__.py +1 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/knowledge/__main__.py +5 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/knowledge/_server.py +437 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/langgraph_compiler/__init__.py +16 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/langgraph_compiler/_compiler.py +679 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/langgraph_compiler/_panel.py +131 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/langgraph_compiler/_skill_executor.py +185 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/langgraph_compiler/_state.py +40 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/mcp/__init__.py +8 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/mcp/_client.py +259 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/__init__.py +45 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_anthropic.py +148 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_google.py +187 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_mock.py +71 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_ollama.py +133 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_openai.py +155 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_openai_compat.py +64 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_registry.py +62 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/model_providers/_types.py +76 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/resolver/__init__.py +420 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/resolver/_resolved.py +85 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/resolver/_topology.py +506 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/resolver/_triggers.py +100 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/review/__init__.py +118 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/review/_hitl.py +60 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/server.py +134 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/skills/__init__.py +242 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/skills/_output_validator.py +161 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/topology/__init__.py +9 -0
- swarmkit_runtime-1.0.0/src/swarmkit_runtime/workspace/__init__.py +231 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/composed-skills/skills/judge-correctness.yaml +27 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/composed-skills/skills/judge-style.yaml +27 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/composed-skills/skills/panel.yaml +29 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/composed-skills/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/archetypes/supervisor-root.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/schedules/daily.yaml +10 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/skills/audit-log-write.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/topologies/hello.yaml +10 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/triggers/webhook.yaml +10 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/full/workspace.yaml +8 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/archetypes/github-reader.yaml +26 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/skills/github-issue-read.yaml +18 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/skills/github-pr-read.yaml +18 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/skills/github-repo-read.yaml +18 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/topologies/github-read.yaml +21 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/github-mcp/workspace.yaml +20 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/grouped-skills/skills/capability/github-repo-read.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/grouped-skills/skills/decision/llm-judge.yaml +27 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/grouped-skills/workspace.yaml +8 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/minimal/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/archetypes/code-review-worker.yaml +22 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/archetypes/supervisor-root.yaml +15 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/skills/code-quality-review.yaml +27 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/skills/github-repo-read.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/topologies/review.yaml +30 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/resolved-tree/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/with-archetypes/archetypes/abstract-worker.yaml +18 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/with-archetypes/archetypes/concrete-worker.yaml +13 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/with-archetypes/skills/audit-log-write.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces/with-archetypes/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-ambiguous/archetypes/worker.yaml +15 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-ambiguous/skills/content-review-a.yaml +19 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-ambiguous/skills/content-review-b.yaml +19 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-ambiguous/topologies/bad.yaml +13 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-ambiguous/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-no-match/archetypes/expects-decision.yaml +15 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-no-match/skills/capability-only.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-no-match/topologies/bad.yaml +13 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/abstract-no-match/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/archetype-unknown-skill/archetypes/bad.yaml +13 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/archetype-unknown-skill/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/composed-cycle/skills/a.yaml +20 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/composed-cycle/skills/b.yaml +20 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/composed-cycle/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/composed-unknown/skills/broken.yaml +20 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/composed-unknown/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/deep-nesting/skills/a/b/too-deep.yaml +16 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/deep-nesting/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-agent-id/topologies/bad.yaml +12 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-agent-id/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-archetype-id/archetypes/first.yaml +11 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-archetype-id/archetypes/second.yaml +11 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-archetype-id/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-skill-id/skills/one.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-skill-id/skills/two.yaml +14 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/duplicate-skill-id/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/kind-mismatch/skills/wrong-kind.yaml +11 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/kind-mismatch/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/missing-workspace-yaml/topologies/hello.yaml +11 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/trigger-unknown-target/triggers/orphan.yaml +8 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/trigger-unknown-target/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/unknown-archetype/topologies/bad.yaml +10 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/unknown-archetype/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/yaml-parse-error/topologies/broken.yaml +6 -0
- swarmkit_runtime-1.0.0/tests/fixtures/workspaces-invalid/yaml-parse-error/workspace.yaml +5 -0
- swarmkit_runtime-1.0.0/tests/test_agt_governance.py +231 -0
- swarmkit_runtime-1.0.0/tests/test_cli_stubs.py +32 -0
- swarmkit_runtime-1.0.0/tests/test_code_review_swarm.py +109 -0
- swarmkit_runtime-1.0.0/tests/test_compiler.py +514 -0
- swarmkit_runtime-1.0.0/tests/test_github_mcp_skills.py +84 -0
- swarmkit_runtime-1.0.0/tests/test_governance_provider.py +234 -0
- swarmkit_runtime-1.0.0/tests/test_governance_selection.py +89 -0
- swarmkit_runtime-1.0.0/tests/test_hello_swarm_example.py +52 -0
- swarmkit_runtime-1.0.0/tests/test_knowledge_pack.py +189 -0
- swarmkit_runtime-1.0.0/tests/test_knowledge_server.py +272 -0
- swarmkit_runtime-1.0.0/tests/test_mcp_client.py +193 -0
- swarmkit_runtime-1.0.0/tests/test_model_providers.py +318 -0
- swarmkit_runtime-1.0.0/tests/test_output_validator.py +185 -0
- swarmkit_runtime-1.0.0/tests/test_panel.py +83 -0
- swarmkit_runtime-1.0.0/tests/test_registries.py +140 -0
- swarmkit_runtime-1.0.0/tests/test_resolver.py +153 -0
- swarmkit_runtime-1.0.0/tests/test_review_queue.py +96 -0
- swarmkit_runtime-1.0.0/tests/test_run_cli.py +75 -0
- swarmkit_runtime-1.0.0/tests/test_server.py +117 -0
- swarmkit_runtime-1.0.0/tests/test_skill_authoring_swarm.py +123 -0
- swarmkit_runtime-1.0.0/tests/test_skill_executor.py +114 -0
- swarmkit_runtime-1.0.0/tests/test_skill_gap_log.py +89 -0
- swarmkit_runtime-1.0.0/tests/test_smoke.py +21 -0
- swarmkit_runtime-1.0.0/tests/test_validate_cli.py +204 -0
- swarmkit_runtime-1.0.0/tests/test_validation.py +271 -0
- swarmkit_runtime-1.0.0/tests/test_workspace_discovery.py +189 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
*.so
|
|
6
|
+
.Python
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
env/
|
|
10
|
+
.eggs/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
*.egg
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
.pyre/
|
|
19
|
+
.pytype/
|
|
20
|
+
.coverage
|
|
21
|
+
.coverage.*
|
|
22
|
+
htmlcov/
|
|
23
|
+
coverage.xml
|
|
24
|
+
*.cover
|
|
25
|
+
.hypothesis/
|
|
26
|
+
.tox/
|
|
27
|
+
.nox/
|
|
28
|
+
|
|
29
|
+
# Node / TypeScript
|
|
30
|
+
node_modules/
|
|
31
|
+
.next/
|
|
32
|
+
out/
|
|
33
|
+
.turbo/
|
|
34
|
+
.nx/
|
|
35
|
+
dist/
|
|
36
|
+
*.tsbuildinfo
|
|
37
|
+
.pnpm-store/
|
|
38
|
+
.yarn/
|
|
39
|
+
|
|
40
|
+
# Editors / OS
|
|
41
|
+
.vscode/
|
|
42
|
+
.idea/
|
|
43
|
+
*.swp
|
|
44
|
+
*.swo
|
|
45
|
+
.DS_Store
|
|
46
|
+
Thumbs.db
|
|
47
|
+
*~
|
|
48
|
+
|
|
49
|
+
# Env / secrets
|
|
50
|
+
.env
|
|
51
|
+
.env.local
|
|
52
|
+
.env.*.local
|
|
53
|
+
*.pem
|
|
54
|
+
|
|
55
|
+
# SwarmKit runtime artifacts (per design §9.3)
|
|
56
|
+
.swarmkit/
|
|
57
|
+
*.sqlite
|
|
58
|
+
*.sqlite-journal
|
|
59
|
+
|
|
60
|
+
# Claude Code
|
|
61
|
+
.claude/settings.local.json
|
|
62
|
+
|
|
63
|
+
# Build / logs
|
|
64
|
+
*.log
|
|
65
|
+
.cache/
|
|
66
|
+
_site/
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# CLAUDE.md — packages/runtime
|
|
2
|
+
|
|
3
|
+
## Package identity
|
|
4
|
+
|
|
5
|
+
`swarmkit-runtime` — the Python component of the three-package system. Loads topology files, compiles them into LangGraph graphs, enforces governance through the `GovernanceProvider` abstraction, and exposes the `swarmkit` CLI + FastAPI server.
|
|
6
|
+
|
|
7
|
+
The design doc is the authoritative source for architectural decisions — see `design/SwarmKit-Design-v0.6.md`. §9, §14, §16, §18 are the most relevant sections to this package.
|
|
8
|
+
|
|
9
|
+
## Module map
|
|
10
|
+
|
|
11
|
+
| Module | Responsibility | Design ref |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| `cli/` | Typer-based CLI, authoring entry points | §14.2 |
|
|
14
|
+
| `topology/` | Load, validate, resolve topology YAML/JSON | §10 |
|
|
15
|
+
| `skills/` | Skill registry + category semantics (capability, decision, coordination, persistence) | §6 |
|
|
16
|
+
| `archetypes/` | Archetype registry and instantiation | §13 |
|
|
17
|
+
| `governance/` | `GovernanceProvider` interface + `AGTGovernanceProvider` | §8.5, §16.5 |
|
|
18
|
+
| `langgraph_compiler/` | Topology → `StateGraph` dynamic construction | §14.3 |
|
|
19
|
+
| `mcp/` | MCP client + sandboxed server lifecycle | §18 |
|
|
20
|
+
| `audit/` | Append-only audit log, skill gap log surfacing | §14.5, §16.4 |
|
|
21
|
+
|
|
22
|
+
## Non-negotiable invariants
|
|
23
|
+
|
|
24
|
+
These come from the design's architectural principles and separation-of-powers model. Do not relax without explicit approval.
|
|
25
|
+
|
|
26
|
+
1. **Topology is data.** Never generate or inline topology as Python code inside this package. The runtime reads YAML/JSON and interprets.
|
|
27
|
+
2. **All governance goes through `GovernanceProvider`.** No direct AGT imports outside `governance/`. If code needs policy evaluation, identity, or audit, it goes through the interface.
|
|
28
|
+
3. **Audit is append-only from agent perspective.** No code path should expose `update` or `delete` on audit entries to executive-layer callers.
|
|
29
|
+
4. **Pillar boundaries are enforced at the module level** (design §8.4). Executive code invokes skills via middleware that routes through the policy engine — there is no bypass.
|
|
30
|
+
5. **Skills are the only extension primitive.** When adding a capability, add a skill category or skill definition — do not introduce parallel extension mechanisms.
|
|
31
|
+
6. **Eject must stay intact.** Every feature you add to the runtime needs an ejection story; if it cannot be expressed in generated LangGraph code, reconsider the design.
|
|
32
|
+
|
|
33
|
+
## Style
|
|
34
|
+
|
|
35
|
+
- Python 3.11+, strict typing (`mypy --strict`).
|
|
36
|
+
- Prefer `pydantic` models for all schema-shaped data; use `dataclass` only for internal value objects.
|
|
37
|
+
- Async-first where I/O is involved (`anyio` / `httpx` / `fastapi`).
|
|
38
|
+
- Error taxonomy: custom exceptions live in each module's `_errors.py`; no bare `raise Exception`.
|
|
39
|
+
|
|
40
|
+
## Testing
|
|
41
|
+
|
|
42
|
+
- `pytest` + `pytest-asyncio`. Tests live under `tests/`.
|
|
43
|
+
- Integration tests that touch real MCP servers or AGT gate on env vars; unit tests mock at the `GovernanceProvider` seam.
|
|
44
|
+
- Every reference topology ships a smoke test that loads + compiles it without executing.
|
|
45
|
+
|
|
46
|
+
## Commands
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
uv run pytest packages/runtime/tests # tests
|
|
50
|
+
uv run ruff check packages/runtime # lint
|
|
51
|
+
uv run mypy packages/runtime # typecheck
|
|
52
|
+
uv run swarmkit --help # CLI entry
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or via the root justfile: `just test-py`, `just lint-py`, `just typecheck-py`.
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: swarmkit-runtime
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: SwarmKit runtime: topology interpreter, LangGraph compiler, AGT-backed governance, CLI and HTTP server.
|
|
5
|
+
Author: Srijith Kartha
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: agents,agt,langgraph,mcp,multi-agent,swarm
|
|
8
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
9
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Requires-Dist: agent-os-kernel<4.0,>=3.2.0
|
|
17
|
+
Requires-Dist: agent-sre<4.0,>=3.2.0
|
|
18
|
+
Requires-Dist: agentmesh-platform<4.0,>=3.2.0
|
|
19
|
+
Requires-Dist: anthropic>=0.39
|
|
20
|
+
Requires-Dist: anyio>=4.4
|
|
21
|
+
Requires-Dist: fastapi>=0.115
|
|
22
|
+
Requires-Dist: google-genai>=1.0
|
|
23
|
+
Requires-Dist: httpx>=0.27
|
|
24
|
+
Requires-Dist: langchain-core>=0.3
|
|
25
|
+
Requires-Dist: langgraph>=0.2
|
|
26
|
+
Requires-Dist: mcp>=1.0
|
|
27
|
+
Requires-Dist: openai>=1.50
|
|
28
|
+
Requires-Dist: pydantic>=2.8
|
|
29
|
+
Requires-Dist: pyyaml>=6.0
|
|
30
|
+
Requires-Dist: rich>=13.7
|
|
31
|
+
Requires-Dist: sqlalchemy>=2.0
|
|
32
|
+
Requires-Dist: swarmkit-schema
|
|
33
|
+
Requires-Dist: typer>=0.12
|
|
34
|
+
Requires-Dist: uvicorn[standard]>=0.30
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
37
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
38
|
+
Requires-Dist: pytest-cov>=5.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
40
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
41
|
+
Requires-Dist: types-pyyaml; extra == 'dev'
|
|
42
|
+
Description-Content-Type: text/markdown
|
|
43
|
+
|
|
44
|
+
# swarmkit-runtime
|
|
45
|
+
|
|
46
|
+
Python runtime for SwarmKit. Interprets topology files, compiles them into LangGraph `StateGraph`s, enforces governance via the `GovernanceProvider` abstraction (AGT-backed in v1.0), and exposes the `swarmkit` CLI plus a persistent HTTP server.
|
|
47
|
+
|
|
48
|
+
## Layout
|
|
49
|
+
|
|
50
|
+
```
|
|
51
|
+
src/swarmkit_runtime/
|
|
52
|
+
├── cli/ # Typer-based CLI: init, author, run, serve, eject
|
|
53
|
+
├── topology/ # Topology loader, validator, resolver (archetype + skill refs)
|
|
54
|
+
├── skills/ # Skill registry, category-specific semantics, composition
|
|
55
|
+
├── archetypes/ # Archetype registry and instantiation
|
|
56
|
+
├── governance/ # GovernanceProvider interface + AGTGovernanceProvider impl
|
|
57
|
+
├── langgraph_compiler/ # Topology → StateGraph compilation (design §14.3)
|
|
58
|
+
├── mcp/ # MCP client, server lifecycle, sandbox supervision
|
|
59
|
+
└── audit/ # Append-only audit log adapters, skill gap log surfacing
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Design references
|
|
63
|
+
|
|
64
|
+
- §7 Architectural Principles — `topology as data`, `eject, never lock-in`
|
|
65
|
+
- §8 Separation of Powers — `governance/` module is the SwarmKit side; AGT is the implementation
|
|
66
|
+
- §9 System Architecture — this package is component #1 of 3
|
|
67
|
+
- §14 Runtime Architecture — three execution modes (one-shot, persistent, scheduled)
|
|
68
|
+
|
|
69
|
+
## Entry points (design §14.2)
|
|
70
|
+
|
|
71
|
+
| Command | What it does |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| `swarmkit init` | Launch Workspace Authoring Swarm in terminal chat mode |
|
|
74
|
+
| `swarmkit author topology [name]` | Launch Topology Authoring variant |
|
|
75
|
+
| `swarmkit author skill [name]` | Launch Skill Authoring Swarm |
|
|
76
|
+
| `swarmkit author archetype [name]` | Launch Archetype Authoring variant |
|
|
77
|
+
| `swarmkit run topology.yaml` | One-shot execution |
|
|
78
|
+
| `swarmkit serve workspace/` | Persistent / scheduled mode |
|
|
79
|
+
| `swarmkit eject topology.yaml` | Export LangGraph code |
|
|
80
|
+
|
|
81
|
+
## Development
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
uv sync --package swarmkit-runtime
|
|
85
|
+
uv run pytest packages/runtime/tests
|
|
86
|
+
uv run swarmkit --help
|
|
87
|
+
```
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# swarmkit-runtime
|
|
2
|
+
|
|
3
|
+
Python runtime for SwarmKit. Interprets topology files, compiles them into LangGraph `StateGraph`s, enforces governance via the `GovernanceProvider` abstraction (AGT-backed in v1.0), and exposes the `swarmkit` CLI plus a persistent HTTP server.
|
|
4
|
+
|
|
5
|
+
## Layout
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/swarmkit_runtime/
|
|
9
|
+
├── cli/ # Typer-based CLI: init, author, run, serve, eject
|
|
10
|
+
├── topology/ # Topology loader, validator, resolver (archetype + skill refs)
|
|
11
|
+
├── skills/ # Skill registry, category-specific semantics, composition
|
|
12
|
+
├── archetypes/ # Archetype registry and instantiation
|
|
13
|
+
├── governance/ # GovernanceProvider interface + AGTGovernanceProvider impl
|
|
14
|
+
├── langgraph_compiler/ # Topology → StateGraph compilation (design §14.3)
|
|
15
|
+
├── mcp/ # MCP client, server lifecycle, sandbox supervision
|
|
16
|
+
└── audit/ # Append-only audit log adapters, skill gap log surfacing
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Design references
|
|
20
|
+
|
|
21
|
+
- §7 Architectural Principles — `topology as data`, `eject, never lock-in`
|
|
22
|
+
- §8 Separation of Powers — `governance/` module is the SwarmKit side; AGT is the implementation
|
|
23
|
+
- §9 System Architecture — this package is component #1 of 3
|
|
24
|
+
- §14 Runtime Architecture — three execution modes (one-shot, persistent, scheduled)
|
|
25
|
+
|
|
26
|
+
## Entry points (design §14.2)
|
|
27
|
+
|
|
28
|
+
| Command | What it does |
|
|
29
|
+
| --- | --- |
|
|
30
|
+
| `swarmkit init` | Launch Workspace Authoring Swarm in terminal chat mode |
|
|
31
|
+
| `swarmkit author topology [name]` | Launch Topology Authoring variant |
|
|
32
|
+
| `swarmkit author skill [name]` | Launch Skill Authoring Swarm |
|
|
33
|
+
| `swarmkit author archetype [name]` | Launch Archetype Authoring variant |
|
|
34
|
+
| `swarmkit run topology.yaml` | One-shot execution |
|
|
35
|
+
| `swarmkit serve workspace/` | Persistent / scheduled mode |
|
|
36
|
+
| `swarmkit eject topology.yaml` | Export LangGraph code |
|
|
37
|
+
|
|
38
|
+
## Development
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
uv sync --package swarmkit-runtime
|
|
42
|
+
uv run pytest packages/runtime/tests
|
|
43
|
+
uv run swarmkit --help
|
|
44
|
+
```
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "swarmkit-runtime"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "SwarmKit runtime: topology interpreter, LangGraph compiler, AGT-backed governance, CLI and HTTP server."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Srijith Kartha" }]
|
|
9
|
+
keywords = ["agents", "multi-agent", "swarm", "langgraph", "mcp", "agt"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 2 - Pre-Alpha",
|
|
12
|
+
"License :: OSI Approved :: MIT License",
|
|
13
|
+
"Programming Language :: Python :: 3",
|
|
14
|
+
"Programming Language :: Python :: 3.11",
|
|
15
|
+
"Programming Language :: Python :: 3.12",
|
|
16
|
+
"Programming Language :: Python :: 3.13",
|
|
17
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
# Dependencies below are intentionally un-pinned placeholders. Lock concrete
|
|
21
|
+
# versions once Phase 1 implementation begins — see design §20.1.
|
|
22
|
+
dependencies = [
|
|
23
|
+
# Core
|
|
24
|
+
"pydantic>=2.8",
|
|
25
|
+
"pyyaml>=6.0",
|
|
26
|
+
"typer>=0.12", # CLI — `swarmkit` entrypoint
|
|
27
|
+
"rich>=13.7", # terminal rendering for authoring chat
|
|
28
|
+
"httpx>=0.27",
|
|
29
|
+
"anyio>=4.4",
|
|
30
|
+
|
|
31
|
+
# Execution engine (design §7, §14)
|
|
32
|
+
"langgraph>=0.2",
|
|
33
|
+
"langchain-core>=0.3",
|
|
34
|
+
|
|
35
|
+
# Governance — Microsoft AGT (design §8, §16).
|
|
36
|
+
# Pinned to 3.x; AGT is iterating fast (public preview, v1→v3 in 7 weeks).
|
|
37
|
+
# The GovernanceProvider ABC (§8.5) isolates the runtime from AGT API churn.
|
|
38
|
+
"agent-os-kernel>=3.2.0,<4.0",
|
|
39
|
+
"agentmesh-platform>=3.2.0,<4.0",
|
|
40
|
+
"agent-sre>=3.2.0,<4.0",
|
|
41
|
+
|
|
42
|
+
# MCP (design §18)
|
|
43
|
+
"mcp>=1.0",
|
|
44
|
+
|
|
45
|
+
# LLM SDKs — one per ModelProvider built-in (design/details/model-provider-abstraction.md).
|
|
46
|
+
# Only model_providers/ imports these; everything else goes through ModelProvider ABC.
|
|
47
|
+
"anthropic>=0.39",
|
|
48
|
+
"google-genai>=1.0",
|
|
49
|
+
"openai>=1.50",
|
|
50
|
+
# Ollama uses httpx only (already in core deps) — no dedicated SDK.
|
|
51
|
+
|
|
52
|
+
# HTTP server for persistent mode (design §14.1)
|
|
53
|
+
"fastapi>=0.115",
|
|
54
|
+
"uvicorn[standard]>=0.30",
|
|
55
|
+
|
|
56
|
+
# Storage / checkpointing (design §14.5)
|
|
57
|
+
"sqlalchemy>=2.0",
|
|
58
|
+
# "psycopg[binary]>=3.2", # optional Postgres backend
|
|
59
|
+
|
|
60
|
+
# Schema package (workspace sibling)
|
|
61
|
+
"swarmkit-schema",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[project.optional-dependencies]
|
|
65
|
+
dev = [
|
|
66
|
+
"pytest>=8.0",
|
|
67
|
+
"pytest-asyncio>=0.23",
|
|
68
|
+
"pytest-cov>=5.0",
|
|
69
|
+
"mypy>=1.11",
|
|
70
|
+
"ruff>=0.6",
|
|
71
|
+
"types-pyyaml",
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
[project.scripts]
|
|
75
|
+
swarmkit = "swarmkit_runtime.cli:app"
|
|
76
|
+
|
|
77
|
+
[build-system]
|
|
78
|
+
requires = ["hatchling"]
|
|
79
|
+
build-backend = "hatchling.build"
|
|
80
|
+
|
|
81
|
+
[tool.hatch.build.targets.wheel]
|
|
82
|
+
packages = ["src/swarmkit_runtime"]
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
"""WorkspaceRuntime — the backend that CLI, HTTP server, and web UI call into.
|
|
2
|
+
|
|
3
|
+
Owns the full execution lifecycle: resolve workspace → build providers →
|
|
4
|
+
build governance → wire MCP → compile topology → invoke graph → close.
|
|
5
|
+
The CLI is a thin interface over this; ``swarmkit serve`` (M9) and the
|
|
6
|
+
v1.1 web UI will be additional interfaces over the same class.
|
|
7
|
+
|
|
8
|
+
See ``design/details/workspace-runtime.md`` (to be written) and the
|
|
9
|
+
architectural decision in ``memory/feedback_cli_architecture.md``.
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from __future__ import annotations
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
from dataclasses import dataclass, field
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
from langgraph.graph.state import CompiledStateGraph
|
|
21
|
+
|
|
22
|
+
from swarmkit_runtime.governance import GovernanceProvider
|
|
23
|
+
from swarmkit_runtime.governance._mock import MockGovernanceProvider
|
|
24
|
+
from swarmkit_runtime.langgraph_compiler import compile_topology
|
|
25
|
+
from swarmkit_runtime.mcp import MCPClientManager, MCPServerConfig, parse_mcp_servers
|
|
26
|
+
from swarmkit_runtime.model_providers import (
|
|
27
|
+
AnthropicModelProvider,
|
|
28
|
+
GoogleModelProvider,
|
|
29
|
+
GroqModelProvider,
|
|
30
|
+
MockModelProvider,
|
|
31
|
+
OllamaModelProvider,
|
|
32
|
+
OpenAIModelProvider,
|
|
33
|
+
OpenRouterModelProvider,
|
|
34
|
+
ProviderRegistry,
|
|
35
|
+
TogetherModelProvider,
|
|
36
|
+
)
|
|
37
|
+
from swarmkit_runtime.model_providers._registry import ModelProviderProtocol
|
|
38
|
+
from swarmkit_runtime.resolver import ResolvedWorkspace, resolve_workspace
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class RunResult:
|
|
43
|
+
"""Output of a topology execution."""
|
|
44
|
+
|
|
45
|
+
output: str
|
|
46
|
+
agent_results: dict[str, str] = field(default_factory=dict)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MissingMCPServerError(Exception):
|
|
50
|
+
"""A skill targets an MCP server that the workspace doesn't declare."""
|
|
51
|
+
|
|
52
|
+
def __init__(self, missing: list[tuple[str, str]]) -> None:
|
|
53
|
+
self.missing = missing
|
|
54
|
+
lines = [
|
|
55
|
+
f"skill '{sid}' targets MCP server '{srv}' but the workspace declares no such server"
|
|
56
|
+
for sid, srv in missing
|
|
57
|
+
]
|
|
58
|
+
super().__init__("\n".join(lines))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class WorkspaceRuntime:
|
|
62
|
+
"""The backend that both CLI and HTTP server call into.
|
|
63
|
+
|
|
64
|
+
Holds a resolved workspace plus all the wired runtime components
|
|
65
|
+
(model providers, governance, MCP manager). Constructed via the
|
|
66
|
+
``from_workspace_path`` classmethod.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
def __init__(
|
|
70
|
+
self,
|
|
71
|
+
*,
|
|
72
|
+
workspace: ResolvedWorkspace,
|
|
73
|
+
workspace_root: Path,
|
|
74
|
+
provider_registry: ProviderRegistry,
|
|
75
|
+
governance: GovernanceProvider,
|
|
76
|
+
mcp_manager: MCPClientManager | None,
|
|
77
|
+
) -> None:
|
|
78
|
+
self._workspace = workspace
|
|
79
|
+
self._workspace_root = workspace_root
|
|
80
|
+
self._provider_registry = provider_registry
|
|
81
|
+
self._governance = governance
|
|
82
|
+
self._mcp_manager = mcp_manager
|
|
83
|
+
|
|
84
|
+
@classmethod
|
|
85
|
+
def from_workspace_path(cls, path: Path) -> WorkspaceRuntime:
|
|
86
|
+
"""Build a fully-wired runtime from a workspace directory.
|
|
87
|
+
|
|
88
|
+
Resolves the workspace, registers model providers, selects the
|
|
89
|
+
governance provider, parses MCP server config, and validates
|
|
90
|
+
that every mcp_tool skill targets a configured server.
|
|
91
|
+
|
|
92
|
+
Raises ``ResolutionErrors`` if the workspace is invalid, or
|
|
93
|
+
``MissingMCPServerError`` if skills reference unconfigured
|
|
94
|
+
MCP servers.
|
|
95
|
+
"""
|
|
96
|
+
ws_root = path.resolve()
|
|
97
|
+
workspace = resolve_workspace(ws_root)
|
|
98
|
+
|
|
99
|
+
registry = ProviderRegistry()
|
|
100
|
+
register_available_providers(registry)
|
|
101
|
+
|
|
102
|
+
governance = build_governance(workspace, ws_root)
|
|
103
|
+
|
|
104
|
+
mcp_configs = parse_mcp_servers(getattr(workspace.raw, "mcp_servers", None))
|
|
105
|
+
mcp_manager = MCPClientManager(mcp_configs, workspace_root=ws_root) if mcp_configs else None
|
|
106
|
+
|
|
107
|
+
missing = find_missing_mcp_servers(workspace, mcp_configs)
|
|
108
|
+
if missing:
|
|
109
|
+
raise MissingMCPServerError(missing)
|
|
110
|
+
|
|
111
|
+
return cls(
|
|
112
|
+
workspace=workspace,
|
|
113
|
+
workspace_root=ws_root,
|
|
114
|
+
provider_registry=registry,
|
|
115
|
+
governance=governance,
|
|
116
|
+
mcp_manager=mcp_manager,
|
|
117
|
+
)
|
|
118
|
+
|
|
119
|
+
def compile(self, topology_name: str) -> CompiledStateGraph[Any]:
|
|
120
|
+
"""Compile a named topology into a LangGraph graph.
|
|
121
|
+
|
|
122
|
+
Raises ``KeyError`` if the topology doesn't exist.
|
|
123
|
+
"""
|
|
124
|
+
if topology_name not in self._workspace.topologies:
|
|
125
|
+
available = sorted(self._workspace.topologies.keys())
|
|
126
|
+
raise KeyError(
|
|
127
|
+
f"Topology '{topology_name}' not found. "
|
|
128
|
+
f"Available: {', '.join(available) or '(none)'}."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
topology = self._workspace.topologies[topology_name]
|
|
132
|
+
return compile_topology(
|
|
133
|
+
topology,
|
|
134
|
+
provider_registry=self._provider_registry,
|
|
135
|
+
governance=self._governance,
|
|
136
|
+
mcp_manager=self._mcp_manager,
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
async def run(
|
|
140
|
+
self,
|
|
141
|
+
topology_name: str,
|
|
142
|
+
user_input: str,
|
|
143
|
+
*,
|
|
144
|
+
max_steps: int = 10,
|
|
145
|
+
) -> RunResult:
|
|
146
|
+
"""Execute a topology end-to-end and return the result.
|
|
147
|
+
|
|
148
|
+
Handles MCP session lifecycle (start_all / close_all) within
|
|
149
|
+
the same async task so the SDK's anyio task groups unwind cleanly.
|
|
150
|
+
"""
|
|
151
|
+
graph = self.compile(topology_name)
|
|
152
|
+
|
|
153
|
+
if self._mcp_manager is not None:
|
|
154
|
+
await self._mcp_manager.start_all()
|
|
155
|
+
try:
|
|
156
|
+
result = await graph.ainvoke(
|
|
157
|
+
{
|
|
158
|
+
"input": user_input,
|
|
159
|
+
"messages": [],
|
|
160
|
+
"agent_results": {},
|
|
161
|
+
"current_agent": "",
|
|
162
|
+
"output": "",
|
|
163
|
+
},
|
|
164
|
+
config={"recursion_limit": max_steps},
|
|
165
|
+
)
|
|
166
|
+
finally:
|
|
167
|
+
if self._mcp_manager is not None:
|
|
168
|
+
await self._mcp_manager.close_all()
|
|
169
|
+
|
|
170
|
+
return RunResult(
|
|
171
|
+
output=result.get("output", ""),
|
|
172
|
+
agent_results={
|
|
173
|
+
k: str(v) for k, v in result.get("agent_results", {}).items() if isinstance(v, str)
|
|
174
|
+
},
|
|
175
|
+
)
|
|
176
|
+
|
|
177
|
+
async def close(self) -> None:
|
|
178
|
+
"""Release all held resources."""
|
|
179
|
+
if self._mcp_manager is not None:
|
|
180
|
+
await self._mcp_manager.close_all()
|
|
181
|
+
|
|
182
|
+
@property
|
|
183
|
+
def workspace(self) -> ResolvedWorkspace:
|
|
184
|
+
return self._workspace
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def workspace_root(self) -> Path:
|
|
188
|
+
return self._workspace_root
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def governance(self) -> GovernanceProvider:
|
|
192
|
+
return self._governance
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def mcp_manager(self) -> MCPClientManager | None:
|
|
196
|
+
return self._mcp_manager
|
|
197
|
+
|
|
198
|
+
@property
|
|
199
|
+
def provider_registry(self) -> ProviderRegistry:
|
|
200
|
+
return self._provider_registry
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
# ---- helpers (public — used by CLI and tests) ----------------------------
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def register_available_providers(registry: ProviderRegistry) -> None:
|
|
207
|
+
"""Register all model providers whose credentials are in the environment."""
|
|
208
|
+
registry.register(MockModelProvider())
|
|
209
|
+
|
|
210
|
+
if os.environ.get("ANTHROPIC_API_KEY"):
|
|
211
|
+
registry.register(AnthropicModelProvider())
|
|
212
|
+
if os.environ.get("GOOGLE_API_KEY"):
|
|
213
|
+
registry.register(GoogleModelProvider())
|
|
214
|
+
if os.environ.get("OPENAI_API_KEY"):
|
|
215
|
+
registry.register(OpenAIModelProvider())
|
|
216
|
+
if os.environ.get("OPENROUTER_API_KEY"):
|
|
217
|
+
registry.register(OpenRouterModelProvider())
|
|
218
|
+
if os.environ.get("GROQ_API_KEY"):
|
|
219
|
+
registry.register(GroqModelProvider())
|
|
220
|
+
if os.environ.get("TOGETHER_API_KEY"):
|
|
221
|
+
registry.register(TogetherModelProvider())
|
|
222
|
+
|
|
223
|
+
registry.register(OllamaModelProvider())
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def build_governance(workspace: ResolvedWorkspace, ws_root: Path) -> GovernanceProvider:
|
|
227
|
+
"""Select the GovernanceProvider based on workspace.yaml's governance block."""
|
|
228
|
+
gov = getattr(workspace.raw, "governance", None)
|
|
229
|
+
if gov is None:
|
|
230
|
+
return MockGovernanceProvider(allow_all=True)
|
|
231
|
+
|
|
232
|
+
provider_value = gov.provider.value if hasattr(gov.provider, "value") else str(gov.provider)
|
|
233
|
+
|
|
234
|
+
if provider_value == "agt":
|
|
235
|
+
from swarmkit_runtime.governance.agt_provider import AGTGovernanceProvider # noqa: PLC0415
|
|
236
|
+
|
|
237
|
+
config = gov.config or {}
|
|
238
|
+
policies_dir = ws_root / config.get("policies_dir", "policies")
|
|
239
|
+
audit_db = ws_root / ".swarmkit" / "audit.db"
|
|
240
|
+
audit_db.parent.mkdir(parents=True, exist_ok=True)
|
|
241
|
+
return AGTGovernanceProvider.from_config(
|
|
242
|
+
policy_dir=policies_dir,
|
|
243
|
+
audit_db=audit_db,
|
|
244
|
+
)
|
|
245
|
+
|
|
246
|
+
if provider_value == "custom":
|
|
247
|
+
print(
|
|
248
|
+
"warning: governance.provider=custom is not yet supported; "
|
|
249
|
+
"falling back to mock. See design §8.5 for the plugin path.",
|
|
250
|
+
file=sys.stderr,
|
|
251
|
+
)
|
|
252
|
+
|
|
253
|
+
return MockGovernanceProvider(allow_all=True)
|
|
254
|
+
|
|
255
|
+
|
|
256
|
+
def resolve_authoring_provider(
|
|
257
|
+
registry: ProviderRegistry | None = None,
|
|
258
|
+
) -> tuple[ModelProviderProtocol, str]:
|
|
259
|
+
"""Resolve which model provider + model name to use for authoring.
|
|
260
|
+
|
|
261
|
+
Checks SWARMKIT_AUTHOR_MODEL (format: provider/model), then falls
|
|
262
|
+
back to SWARMKIT_PROVIDER + SWARMKIT_MODEL, then first available
|
|
263
|
+
real provider.
|
|
264
|
+
"""
|
|
265
|
+
author_model = os.environ.get("SWARMKIT_AUTHOR_MODEL", "")
|
|
266
|
+
if "/" in author_model:
|
|
267
|
+
provider_id, model_name = author_model.split("/", 1)
|
|
268
|
+
else:
|
|
269
|
+
provider_id = os.environ.get("SWARMKIT_PROVIDER", "")
|
|
270
|
+
model_name = os.environ.get("SWARMKIT_MODEL", "")
|
|
271
|
+
|
|
272
|
+
if registry is None:
|
|
273
|
+
registry = ProviderRegistry()
|
|
274
|
+
register_available_providers(registry)
|
|
275
|
+
|
|
276
|
+
if provider_id:
|
|
277
|
+
provider = registry.get(provider_id)
|
|
278
|
+
if provider is not None:
|
|
279
|
+
return provider, model_name or "claude-sonnet-4-6"
|
|
280
|
+
|
|
281
|
+
for pid in registry.provider_ids:
|
|
282
|
+
if pid == "mock":
|
|
283
|
+
continue
|
|
284
|
+
provider = registry.get(pid)
|
|
285
|
+
if provider is not None:
|
|
286
|
+
return provider, model_name or "claude-sonnet-4-6"
|
|
287
|
+
|
|
288
|
+
raise RuntimeError(
|
|
289
|
+
"No model provider available. Set SWARMKIT_PROVIDER "
|
|
290
|
+
"and the corresponding API key (e.g. GROQ_API_KEY)."
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
def find_missing_mcp_servers(
|
|
295
|
+
workspace: ResolvedWorkspace,
|
|
296
|
+
mcp_configs: dict[str, MCPServerConfig],
|
|
297
|
+
) -> list[tuple[str, str]]:
|
|
298
|
+
"""Return ``(skill_id, server_id)`` pairs whose mcp_tool target is unconfigured."""
|
|
299
|
+
missing: list[tuple[str, str]] = []
|
|
300
|
+
for skill_id, skill in workspace.skills.items():
|
|
301
|
+
impl = skill.raw.implementation
|
|
302
|
+
impl_type = impl.get("type") if isinstance(impl, dict) else getattr(impl, "type", None)
|
|
303
|
+
if impl_type != "mcp_tool":
|
|
304
|
+
continue
|
|
305
|
+
server_id = impl.get("server") if isinstance(impl, dict) else getattr(impl, "server", "")
|
|
306
|
+
if server_id and server_id not in mcp_configs:
|
|
307
|
+
missing.append((skill_id, server_id))
|
|
308
|
+
return missing
|