spec-agents-core 0.5.1__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 (58) hide show
  1. spec_agents_core-0.5.1/.gitignore +11 -0
  2. spec_agents_core-0.5.1/CHANGELOG.md +50 -0
  3. spec_agents_core-0.5.1/LICENSE +21 -0
  4. spec_agents_core-0.5.1/PKG-INFO +93 -0
  5. spec_agents_core-0.5.1/README.md +48 -0
  6. spec_agents_core-0.5.1/pyproject.toml +65 -0
  7. spec_agents_core-0.5.1/src/agent_fabric/__init__.py +55 -0
  8. spec_agents_core-0.5.1/src/agent_fabric/agents/__init__.py +39 -0
  9. spec_agents_core-0.5.1/src/agent_fabric/agents/base.py +155 -0
  10. spec_agents_core-0.5.1/src/agent_fabric/agents/fabric.py +496 -0
  11. spec_agents_core-0.5.1/src/agent_fabric/agents/kinds.py +641 -0
  12. spec_agents_core-0.5.1/src/agent_fabric/agents/runtime.py +234 -0
  13. spec_agents_core-0.5.1/src/agent_fabric/agents/spec.py +244 -0
  14. spec_agents_core-0.5.1/src/agent_fabric/artifacts.py +206 -0
  15. spec_agents_core-0.5.1/src/agent_fabric/cli/__init__.py +113 -0
  16. spec_agents_core-0.5.1/src/agent_fabric/cli/__main__.py +5 -0
  17. spec_agents_core-0.5.1/src/agent_fabric/cli/commands.py +153 -0
  18. spec_agents_core-0.5.1/src/agent_fabric/cli/live.py +83 -0
  19. spec_agents_core-0.5.1/src/agent_fabric/cli/render.py +127 -0
  20. spec_agents_core-0.5.1/src/agent_fabric/compat.py +67 -0
  21. spec_agents_core-0.5.1/src/agent_fabric/component.py +318 -0
  22. spec_agents_core-0.5.1/src/agent_fabric/contracts.py +223 -0
  23. spec_agents_core-0.5.1/src/agent_fabric/errors.py +243 -0
  24. spec_agents_core-0.5.1/src/agent_fabric/evals.py +185 -0
  25. spec_agents_core-0.5.1/src/agent_fabric/executor.py +235 -0
  26. spec_agents_core-0.5.1/src/agent_fabric/integrations/__init__.py +1 -0
  27. spec_agents_core-0.5.1/src/agent_fabric/integrations/crewai.py +112 -0
  28. spec_agents_core-0.5.1/src/agent_fabric/integrations/dspy.py +169 -0
  29. spec_agents_core-0.5.1/src/agent_fabric/lint.py +379 -0
  30. spec_agents_core-0.5.1/src/agent_fabric/llm/__init__.py +25 -0
  31. spec_agents_core-0.5.1/src/agent_fabric/llm/backends.py +152 -0
  32. spec_agents_core-0.5.1/src/agent_fabric/llm/interpreter.py +187 -0
  33. spec_agents_core-0.5.1/src/agent_fabric/llm/planner.py +236 -0
  34. spec_agents_core-0.5.1/src/agent_fabric/llm/prompts.py +118 -0
  35. spec_agents_core-0.5.1/src/agent_fabric/llm/repair.py +79 -0
  36. spec_agents_core-0.5.1/src/agent_fabric/llm/self_correction.py +188 -0
  37. spec_agents_core-0.5.1/src/agent_fabric/markdown.py +163 -0
  38. spec_agents_core-0.5.1/src/agent_fabric/memory/__init__.py +11 -0
  39. spec_agents_core-0.5.1/src/agent_fabric/memory/base.py +115 -0
  40. spec_agents_core-0.5.1/src/agent_fabric/memory/langchain_adapter.py +87 -0
  41. spec_agents_core-0.5.1/src/agent_fabric/pipeline.py +469 -0
  42. spec_agents_core-0.5.1/src/agent_fabric/prompt.py +270 -0
  43. spec_agents_core-0.5.1/src/agent_fabric/py.typed +0 -0
  44. spec_agents_core-0.5.1/src/agent_fabric/registry.py +309 -0
  45. spec_agents_core-0.5.1/src/agent_fabric/report.py +52 -0
  46. spec_agents_core-0.5.1/src/agent_fabric/scaffold.py +167 -0
  47. spec_agents_core-0.5.1/src/agent_fabric/skills_export.py +194 -0
  48. spec_agents_core-0.5.1/src/agent_fabric/spec.py +330 -0
  49. spec_agents_core-0.5.1/src/agent_fabric/tabular.py +354 -0
  50. spec_agents_core-0.5.1/src/agent_fabric/testing.py +18 -0
  51. spec_agents_core-0.5.1/tests/test_baselines.py +41 -0
  52. spec_agents_core-0.5.1/tests/test_boundaries.py +118 -0
  53. spec_agents_core-0.5.1/tests/test_cli.py +118 -0
  54. spec_agents_core-0.5.1/tests/test_compat.py +92 -0
  55. spec_agents_core-0.5.1/tests/test_contracts.py +144 -0
  56. spec_agents_core-0.5.1/tests/test_lint_descriptions.py +69 -0
  57. spec_agents_core-0.5.1/tests/test_prompt_domain.py +206 -0
  58. spec_agents_core-0.5.1/tests/test_skills_export.py +97 -0
@@ -0,0 +1,11 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dags/
7
+ *.egg-info/
8
+ examples/output/
9
+ build/
10
+ .coverage
11
+ coverage.xml
@@ -0,0 +1,50 @@
1
+ # Changelog
2
+
3
+ ## [0.5.1](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.5.0...agent-fabric-v0.5.1) (2026-10-02)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * document the spec-agents-* distribution names in the package READMEs ([#96](https://github.com/marcionicolau/spec-agents/issues/96)) ([fffad88](https://github.com/marcionicolau/spec-agents/commit/fffad88e5c8405bb01c7d9dddf66b7cf52a13e28)), closes [#76](https://github.com/marcionicolau/spec-agents/issues/76)
9
+
10
+ ## [0.5.0](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.4.0...agent-fabric-v0.5.0) (2026-10-02)
11
+
12
+
13
+ ### Features
14
+
15
+ * **agent-fabric:** core/pack API level contract ([#75](https://github.com/marcionicolau/spec-agents/issues/75)) ([d880a74](https://github.com/marcionicolau/spec-agents/commit/d880a744481b888e1e435a1c0d482e44fa942e03)), closes [#20](https://github.com/marcionicolau/spec-agents/issues/20)
16
+ * **agent-fabric:** define the public API surface with __all__, fix __version__ ([#57](https://github.com/marcionicolau/spec-agents/issues/57)) ([c9ab564](https://github.com/marcionicolau/spec-agents/commit/c9ab56432fb2e95c5f1a1ebd9428a23c42b9d89f)), closes [#56](https://github.com/marcionicolau/spec-agents/issues/56)
17
+
18
+ ## [0.4.0](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.3.0...agent-fabric-v0.4.0) (2026-10-01)
19
+
20
+
21
+ ### Features
22
+
23
+ * **agent-fabric:** export skills as spec-compliant Agent Skills ([#54](https://github.com/marcionicolau/spec-agents/issues/54)) ([bb2b9bb](https://github.com/marcionicolau/spec-agents/commit/bb2b9bbf395bb90107a8bdcb47aad5516d0aadab)), closes [#22](https://github.com/marcionicolau/spec-agents/issues/22)
24
+
25
+ ## [0.3.0](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.2.0...agent-fabric-v0.3.0) (2026-10-01)
26
+
27
+
28
+ ### Features
29
+
30
+ * **agent-fabric:** gate deterministic eval suites on stored baselines ([#52](https://github.com/marcionicolau/spec-agents/issues/52)) ([378b2fd](https://github.com/marcionicolau/spec-agents/commit/378b2fdbed74a0213dc142720ae05c0a17525b6f)), closes [#24](https://github.com/marcionicolau/spec-agents/issues/24)
31
+
32
+ ## [0.2.0](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.1.0...agent-fabric-v0.2.0) (2026-10-01)
33
+
34
+
35
+ ### Features
36
+
37
+ * **agent-fabric:** fail PRs whose SKILL.md contract changes lack a version bump ([#51](https://github.com/marcionicolau/spec-agents/issues/51)) ([ac97619](https://github.com/marcionicolau/spec-agents/commit/ac97619390756378cb1b8cdd9145814a93417ba0))
38
+ * **agent-fabric:** lint skill descriptions for what-and-when style ([#49](https://github.com/marcionicolau/spec-agents/issues/49)) ([321a834](https://github.com/marcionicolau/spec-agents/commit/321a8343fa8f8953a7bea7974841858015e9c890)), closes [#23](https://github.com/marcionicolau/spec-agents/issues/23)
39
+
40
+ ## [0.1.0](https://github.com/marcionicolau/spec-agents/compare/agent-fabric-v0.0.1...agent-fabric-v0.1.0) (2026-10-01)
41
+
42
+
43
+ ### Features
44
+
45
+ * **agent-fabric:** enforce architecture boundaries and type-check the core; fix live view crash ([#38](https://github.com/marcionicolau/spec-agents/issues/38)) ([45b277f](https://github.com/marcionicolau/spec-agents/commit/45b277f586b14bf966d13f3eaacb66df52f5649b))
46
+
47
+
48
+ ### Bug Fixes
49
+
50
+ * **statistics:** warn on perfect collinearity with inf VIF; ci: require lowest-versions job ([#35](https://github.com/marcionicolau/spec-agents/issues/35)) ([e1502a1](https://github.com/marcionicolau/spec-agents/commit/e1502a1a7d0cfb65dd65e6087843ae6bddc4a378))
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcio Nicolau
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,93 @@
1
+ Metadata-Version: 2.5
2
+ Name: spec-agents-core
3
+ Version: 0.5.1
4
+ Summary: Spec-driven pipelines and hierarchical agents (PydanticAI, DSPy, CrewAI, LangChain) over a LiteLLM proxy
5
+ Project-URL: Homepage, https://github.com/marcionicolau/spec-agents
6
+ Project-URL: Repository, https://github.com/marcionicolau/spec-agents
7
+ Project-URL: Issues, https://github.com/marcionicolau/spec-agents/issues
8
+ Project-URL: Changelog, https://github.com/marcionicolau/spec-agents/blob/main/packages/agent-fabric/CHANGELOG.md
9
+ Project-URL: Documentation, https://github.com/marcionicolau/spec-agents/tree/main/docs
10
+ Author: Marcio Nicolau
11
+ License-Expression: MIT
12
+ License-File: LICENSE
13
+ Keywords: agents,llm,pipelines,pydantic,specs
14
+ Classifier: Development Status :: 2 - Pre-Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: License :: OSI Approved :: MIT License
17
+ Classifier: Programming Language :: Python :: 3 :: Only
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: numpy>=1.26
23
+ Requires-Dist: pydantic>=2.7
24
+ Requires-Dist: pyyaml>=6.0.2
25
+ Requires-Dist: rich>=13.7.1
26
+ Provides-Extra: all
27
+ Requires-Dist: crewai>=0.100; extra == 'all'
28
+ Requires-Dist: dspy>=3.0; extra == 'all'
29
+ Requires-Dist: langchain-core>=0.3; extra == 'all'
30
+ Requires-Dist: pandas>=2.1; extra == 'all'
31
+ Requires-Dist: pydantic-ai-slim[openai]>=1.0; extra == 'all'
32
+ Provides-Extra: crewai
33
+ Requires-Dist: crewai>=0.100; extra == 'crewai'
34
+ Provides-Extra: dspy
35
+ Requires-Dist: dspy>=3.0; extra == 'dspy'
36
+ Provides-Extra: langchain
37
+ Requires-Dist: langchain-core>=0.3; extra == 'langchain'
38
+ Provides-Extra: proxy
39
+ Requires-Dist: litellm[proxy]>=1.60; extra == 'proxy'
40
+ Provides-Extra: pydantic-ai
41
+ Requires-Dist: pydantic-ai-slim[openai]>=1.0; extra == 'pydantic-ai'
42
+ Provides-Extra: tabular
43
+ Requires-Dist: pandas>=2.1; extra == 'tabular'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # spec-agents-core (`agent_fabric`)
47
+
48
+ Domain-agnostic core for **spec-driven pipelines and hierarchical agents**. Components, pipelines and agents are declared in Markdown
49
+ with YAML frontmatter (`SKILL.md`, `AGENT.md`, `fabric.md`); the frontmatter is a contract validated by Pydantic and the body is guidance
50
+ injected into prompts on demand. LLMs plan, delegate, repair and interpret — **they never compute**: every result comes from
51
+ deterministic `Component.compute()` code run by the `PipelineExecutor`.
52
+
53
+ > **Status:** pre-release. Until the first PyPI release, install a wheel from the
54
+ > [GitHub Releases](https://github.com/marcionicolau/spec-agents/releases) or use `uv sync --all-packages` in a checkout;
55
+ > the `pip install` lines below are the PyPI names.
56
+
57
+ ## Names
58
+
59
+ | | |
60
+ | --- | --- |
61
+ | PyPI distribution | `spec-agents-core` |
62
+ | Import name | `agent_fabric` |
63
+ | Directory in the monorepo | `packages/agent-fabric` |
64
+ | Release tag / PR scope | `agent-fabric-vX.Y.Z` / `agent-fabric` |
65
+
66
+ The distribution is named `spec-agents-core` because the shorter names are taken on PyPI; the import name and the entry point do not change.
67
+
68
+ ## Install
69
+ ```bash
70
+ pip install spec-agents-core # core: pydantic, numpy, pyyaml, rich (import name: agent_fabric)
71
+ pip install "spec-agents-core[tabular]" # + pandas (dataframe artifact types)
72
+ pip install "spec-agents-core[all]" # + PydanticAI, DSPy, CrewAI, LangChain adapters
73
+ ```
74
+ Domain packs ([statistics](../statistics/README.md), [lakehouse](../lakehouse/README.md), [coworker](../coworker/README.md),
75
+ [text-pack](../text-pack/README.md)) register themselves through the `agent_fabric.domains` entry point.
76
+
77
+ ## Use
78
+ ```bash
79
+ agent-fabric catalog --skills path/to/skills # list components and pipelines
80
+ agent-fabric agents path/to/config # render and validate an agent tree
81
+ agent-fabric lint --agents path/to/config --strict
82
+ agent-fabric run path/to/config "task" --input name=file.txt
83
+ ```
84
+ ```python
85
+ from agent_fabric import build_registry
86
+ from agent_fabric.agents import AgentFabric, AgentsConfig
87
+
88
+ fabric = AgentFabric(build_registry(discover=True), AgentsConfig.load("config"))
89
+ report = fabric.run("question", {"data": df}, session_id="s1")
90
+ ```
91
+
92
+ Optional frameworks are imported lazily; models are referenced by LiteLLM alias only. See the repository
93
+ [docs](../../docs/README.md) for the architecture, the error model and how to add components, pipelines and agents.
@@ -0,0 +1,48 @@
1
+ # spec-agents-core (`agent_fabric`)
2
+
3
+ Domain-agnostic core for **spec-driven pipelines and hierarchical agents**. Components, pipelines and agents are declared in Markdown
4
+ with YAML frontmatter (`SKILL.md`, `AGENT.md`, `fabric.md`); the frontmatter is a contract validated by Pydantic and the body is guidance
5
+ injected into prompts on demand. LLMs plan, delegate, repair and interpret — **they never compute**: every result comes from
6
+ deterministic `Component.compute()` code run by the `PipelineExecutor`.
7
+
8
+ > **Status:** pre-release. Until the first PyPI release, install a wheel from the
9
+ > [GitHub Releases](https://github.com/marcionicolau/spec-agents/releases) or use `uv sync --all-packages` in a checkout;
10
+ > the `pip install` lines below are the PyPI names.
11
+
12
+ ## Names
13
+
14
+ | | |
15
+ | --- | --- |
16
+ | PyPI distribution | `spec-agents-core` |
17
+ | Import name | `agent_fabric` |
18
+ | Directory in the monorepo | `packages/agent-fabric` |
19
+ | Release tag / PR scope | `agent-fabric-vX.Y.Z` / `agent-fabric` |
20
+
21
+ The distribution is named `spec-agents-core` because the shorter names are taken on PyPI; the import name and the entry point do not change.
22
+
23
+ ## Install
24
+ ```bash
25
+ pip install spec-agents-core # core: pydantic, numpy, pyyaml, rich (import name: agent_fabric)
26
+ pip install "spec-agents-core[tabular]" # + pandas (dataframe artifact types)
27
+ pip install "spec-agents-core[all]" # + PydanticAI, DSPy, CrewAI, LangChain adapters
28
+ ```
29
+ Domain packs ([statistics](../statistics/README.md), [lakehouse](../lakehouse/README.md), [coworker](../coworker/README.md),
30
+ [text-pack](../text-pack/README.md)) register themselves through the `agent_fabric.domains` entry point.
31
+
32
+ ## Use
33
+ ```bash
34
+ agent-fabric catalog --skills path/to/skills # list components and pipelines
35
+ agent-fabric agents path/to/config # render and validate an agent tree
36
+ agent-fabric lint --agents path/to/config --strict
37
+ agent-fabric run path/to/config "task" --input name=file.txt
38
+ ```
39
+ ```python
40
+ from agent_fabric import build_registry
41
+ from agent_fabric.agents import AgentFabric, AgentsConfig
42
+
43
+ fabric = AgentFabric(build_registry(discover=True), AgentsConfig.load("config"))
44
+ report = fabric.run("question", {"data": df}, session_id="s1")
45
+ ```
46
+
47
+ Optional frameworks are imported lazily; models are referenced by LiteLLM alias only. See the repository
48
+ [docs](../../docs/README.md) for the architecture, the error model and how to add components, pipelines and agents.
@@ -0,0 +1,65 @@
1
+ [project]
2
+ name = "spec-agents-core"
3
+ dynamic = ["version"]
4
+ description = "Spec-driven pipelines and hierarchical agents (PydanticAI, DSPy, CrewAI, LangChain) over a LiteLLM proxy"
5
+ requires-python = ">=3.12"
6
+ license = "MIT"
7
+ license-files = ["LICENSE"]
8
+ readme = "README.md"
9
+ authors = [{ name = "Marcio Nicolau" }]
10
+ keywords = ["agents", "llm", "pipelines", "specs", "pydantic"]
11
+ classifiers = [
12
+ "Development Status :: 2 - Pre-Alpha",
13
+ "Intended Audience :: Developers",
14
+ "License :: OSI Approved :: MIT License",
15
+ "Programming Language :: Python :: 3 :: Only",
16
+ "Programming Language :: Python :: 3.12",
17
+ "Programming Language :: Python :: 3.13",
18
+ "Typing :: Typed",
19
+ ]
20
+ dependencies = [
21
+ "numpy>=1.26",
22
+ "pydantic>=2.7",
23
+ "pyyaml>=6.0.2",
24
+ "rich>=13.7.1",
25
+ ]
26
+
27
+ [project.scripts]
28
+ agent-fabric = "agent_fabric.cli:main"
29
+
30
+ [project.optional-dependencies]
31
+ all = ["spec-agents-core[tabular,pydantic-ai,dspy,crewai,langchain]"]
32
+ crewai = ["crewai>=0.100"]
33
+ dspy = ["dspy>=3.0"]
34
+ langchain = ["langchain-core>=0.3"]
35
+ proxy = ["litellm[proxy]>=1.60"]
36
+ pydantic-ai = ["pydantic-ai-slim[openai]>=1.0"]
37
+ tabular = ["pandas>=2.1"]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/marcionicolau/spec-agents"
41
+ Repository = "https://github.com/marcionicolau/spec-agents"
42
+ Issues = "https://github.com/marcionicolau/spec-agents/issues"
43
+ Changelog = "https://github.com/marcionicolau/spec-agents/blob/main/packages/agent-fabric/CHANGELOG.md"
44
+ Documentation = "https://github.com/marcionicolau/spec-agents/tree/main/docs"
45
+
46
+ [build-system]
47
+ requires = ["hatchling", "uv-dynamic-versioning>=0.14"]
48
+ build-backend = "hatchling.build"
49
+
50
+ [tool.uv]
51
+ package = true
52
+
53
+ # version = latest "agent-fabric-vX.Y.Z" git tag (other packages' tags are ignored); untagged commits get X.Y.(Z+1).devN+<sha>
54
+ [tool.hatch.version]
55
+ source = "uv-dynamic-versioning"
56
+
57
+ [tool.hatch.build.targets.wheel]
58
+ packages = ["src/agent_fabric"]
59
+
60
+ [tool.uv-dynamic-versioning]
61
+ vcs = "git"
62
+ style = "pep440"
63
+ bump = true
64
+ pattern-prefix = "agent-fabric-"
65
+ fallback-version = "0.0.0"
@@ -0,0 +1,55 @@
1
+ """agent_fabric - spec-driven pipelines and hierarchical agents over a LiteLLM proxy."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Callable, Iterable
6
+ from importlib import metadata as _metadata
7
+
8
+ try:
9
+ __version__ = _metadata.version(
10
+ "spec-agents-core"
11
+ ) # dynamic: derived from the latest agent-fabric-v* git tag at build time
12
+ except _metadata.PackageNotFoundError: # pragma: no cover - source tree without an installed distribution
13
+ __version__ = "0.0.0"
14
+
15
+
16
+ def domain_loader(ref: str) -> Callable:
17
+ """Resolve a domain reference: 'module:register' callable, or an existing directory
18
+ loaded as a code-free spec pack (skills/<name>/SKILL.md, no Python required)."""
19
+ from pathlib import Path
20
+
21
+ p = Path(ref)
22
+ if ":" not in ref and p.is_dir():
23
+ return lambda reg: reg.load_domain(p)
24
+ import importlib
25
+
26
+ mod, _, attr = ref.partition(":")
27
+ return getattr(importlib.import_module(mod), attr or "register")
28
+
29
+
30
+ def build_registry(domains: Iterable[Callable | str] = (), discover: bool = False):
31
+ """Create a Registry and load domain packs (callables ``register(registry)`` or
32
+ references resolved by :func:`domain_loader`)."""
33
+ from .compat import check_pack_api
34
+ from .registry import Registry
35
+
36
+ reg = Registry()
37
+ for d in domains:
38
+ register = d if callable(d) else domain_loader(d)
39
+ check_pack_api(register, d if isinstance(d, str) else getattr(d, "__module__", repr(d)))
40
+ register(reg)
41
+ if discover:
42
+ reg.discover_domains()
43
+ return reg
44
+
45
+
46
+ from .compat import API_LEVEL, API_LEVEL_MIN, requires_api # noqa: E402
47
+
48
+ __all__ = [
49
+ "API_LEVEL",
50
+ "API_LEVEL_MIN",
51
+ "__version__",
52
+ "build_registry",
53
+ "domain_loader",
54
+ "requires_api",
55
+ ]
@@ -0,0 +1,39 @@
1
+ """Hierarchical agents: declared as a tree in YAML, validated as a whole, built by registered builders."""
2
+
3
+ from .base import BaseAgent
4
+ from .fabric import AgentFabric, planner_builder
5
+ from .kinds import (
6
+ Delegation,
7
+ DelegationPlan,
8
+ FunctionAgent,
9
+ LLMWorkerAgent,
10
+ PipelineAgent,
11
+ PlannerAgent,
12
+ PydanticAISupervisor,
13
+ SupervisorAgent,
14
+ )
15
+ from .runtime import AgentResult, AgentRunReport, AgentTask, Budget, BudgetSettings, RunContext, TraceEvent
16
+ from .spec import AgentsConfig, AgentSpec
17
+
18
+ __all__ = [
19
+ "AgentFabric",
20
+ "AgentResult",
21
+ "AgentRunReport",
22
+ "AgentSpec",
23
+ "AgentTask",
24
+ "AgentsConfig",
25
+ "BaseAgent",
26
+ "Budget",
27
+ "BudgetSettings",
28
+ "Delegation",
29
+ "DelegationPlan",
30
+ "FunctionAgent",
31
+ "LLMWorkerAgent",
32
+ "PipelineAgent",
33
+ "PlannerAgent",
34
+ "PydanticAISupervisor",
35
+ "RunContext",
36
+ "SupervisorAgent",
37
+ "TraceEvent",
38
+ "planner_builder",
39
+ ]
@@ -0,0 +1,155 @@
1
+ """Base agent: template method shared by every kind (budget, trace, fallback, memory)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import time
6
+ from abc import ABC, abstractmethod
7
+ from typing import TYPE_CHECKING, Any
8
+
9
+ from ..errors import BudgetExceeded, FabricError
10
+ from ..llm.backends import LLMSettings
11
+ from ..llm.prompts import AGENT_SYSTEM, compact
12
+ from ..memory.base import RunSummary, memory_context, namespaced
13
+ from .runtime import AgentResult, AgentTask, MeteredBackend, RunContext, Status
14
+ from .spec import AgentSpec
15
+
16
+ if TYPE_CHECKING: # pragma: no cover
17
+ from .fabric import AgentFabric
18
+
19
+
20
+ class BaseAgent(ABC):
21
+ accepts_sub_agents: bool = False
22
+
23
+ def __init__(
24
+ self, name: str, spec: AgentSpec, fabric: AgentFabric, children: dict[str, BaseAgent] | None = None
25
+ ) -> None:
26
+ self.name, self.spec, self.fabric = name, spec, fabric
27
+ self.children: dict[str, BaseAgent] = children or {}
28
+ self.fallback_agent: BaseAgent | None = None
29
+
30
+ # ------------------------------------------------------------------ template method
31
+ def run(self, task: AgentTask, ctx: RunContext, parent_path: str = "", depth: int = 0) -> AgentResult:
32
+ """Run the agent on a task: the template method every agent goes through.
33
+
34
+ Records the start and end events, charges the run budget (``max_depth`` and ``max_agent_runs``) and calls the kind-specific ``_run``. A
35
+ `BudgetExceeded` or other `FabricError` becomes a ``failed`` result carrying the located error; when a ``fallback`` backend is configured it is
36
+ tried first and the fallback is noted in ``notes``. Records LLM calls and duration, and, when memory is configured, the instruction, the answer and a
37
+ `RunSummary` under ``<session>/<path>``. Does not raise `FabricError`s: they end up in the result.
38
+ """
39
+ path = f"{parent_path}/{self.name}" if parent_path else self.name
40
+ t0 = time.perf_counter()
41
+ ctx.event(path, "start", task.instruction)
42
+ try:
43
+ ctx.budget.charge_run(path, depth)
44
+ res = self._run(task, ctx, path, depth)
45
+ except BudgetExceeded as exc:
46
+ res = self.result(path, "failed", error=exc.report, summary=exc.message)
47
+ except FabricError as exc:
48
+ ctx.event(path, "error", f"{exc.category.value}: {exc.message}")
49
+ if self.fallback_agent is None:
50
+ res = self.result(path, "failed", error=exc.report, summary=exc.message)
51
+ else:
52
+ ctx.event(path, "fallback", self.fallback_agent.spec.backend)
53
+ try:
54
+ res = self.fallback_agent._run(task, ctx, path, depth)
55
+ res.notes.append(
56
+ f"fell back to backend '{self.fallback_agent.spec.backend}' after "
57
+ f"{exc.category.value} error: {exc.message}"
58
+ )
59
+ except FabricError as exc2:
60
+ res = self.result(
61
+ path,
62
+ "failed",
63
+ error=exc2.report,
64
+ summary=exc2.message,
65
+ notes=[f"primary failed: {exc.message}"],
66
+ )
67
+ res.llm_calls = ctx.llm_calls_by_path.get(path, 0)
68
+ res.duration_s = round(time.perf_counter() - t0, 4)
69
+ ctx.event(path, "end", res.status)
70
+ if ctx.memory is not None:
71
+ ctx.memory.add_message(namespaced(ctx.session_id, path), "user", task.instruction)
72
+ ctx.memory.add_message(namespaced(ctx.session_id, path), "assistant", res.summary or res.status)
73
+ ctx.memory.remember_run(
74
+ namespaced(ctx.session_id, path),
75
+ RunSummary(
76
+ objective=task.instruction, agent=path, status={path: res.status}, headlines=[res.summary[:200]]
77
+ ),
78
+ )
79
+ return res
80
+
81
+ @abstractmethod
82
+ def _run(self, task: AgentTask, ctx: RunContext, path: str, depth: int) -> AgentResult: ...
83
+
84
+ # ------------------------------------------------------------------ helpers
85
+ @property
86
+ def kind(self) -> str:
87
+ """The agent kind (``supervisor``, ``planner``, ``pipeline``, ``llm`` or ``function``)."""
88
+ return self.spec.kind
89
+
90
+ @property
91
+ def settings(self) -> LLMSettings:
92
+ """`LLMSettings` for this agent: the run's settings with the agent's own model, temperature and retries applied."""
93
+ return self.fabric.settings_for(self.spec)
94
+
95
+ @property
96
+ def model(self) -> str:
97
+ """LiteLLM alias this agent uses (its own ``model``, else the default for its kind)."""
98
+ return self.fabric.model_for(self.spec)
99
+
100
+ def llm(self, ctx: RunContext, path: str) -> MeteredBackend:
101
+ """The LLM backend for this agent, metered so every call is charged to the run budget and traced at ``path``."""
102
+ return ctx.metered(self.fabric.llm_backend, path)
103
+
104
+ def result(self, path: str, status: Status, **kw: Any) -> AgentResult:
105
+ """Build an `AgentResult` for this agent at ``path`` with the given status and extra fields."""
106
+ return AgentResult(agent=self.name, path=path, kind=self.kind, status=status, **kw)
107
+
108
+ def system_prompt(self) -> str:
109
+ """Role header (if any) followed by the AGENT.md body - the body is the primary instruction source."""
110
+ s = self.spec
111
+ parts = []
112
+ if s.role or s.goal:
113
+ parts.append(
114
+ AGENT_SYSTEM.format(
115
+ role=s.role or self.name.replace("_", " "), goal=s.goal or s.card, backstory=s.backstory
116
+ ).strip()
117
+ )
118
+ if s.instructions:
119
+ parts.append(s.instructions)
120
+ return "\n\n".join(parts) or f"You are the '{self.name}' agent."
121
+
122
+ def input_keys(self, task: AgentTask, ctx: RunContext) -> list[str]:
123
+ """Blackboard keys this agent reads: the task's own inputs, else the spec's ``inputs``, else every key the run started with."""
124
+ return task.inputs or self.spec.inputs or list(ctx.input_keys)
125
+
126
+ def describe_inputs(self, values: dict[str, Any]) -> str:
127
+ """Describe input values for a prompt: JSON, number and ``any`` values are shown compacted (up to 2500 characters), other types through their artifact profile."""
128
+ types = self.fabric.registry.types
129
+ lines = []
130
+ for key, v in values.items():
131
+ t = types.infer(v)
132
+ if t.name in ("json", "any", "number"):
133
+ lines.append(f"[{key}] {compact(v, max_chars=2500)}")
134
+ else:
135
+ lines.append(f"[{key}] {t.describe(t.profile(v), v)}")
136
+ return "\n".join(lines) or "(none)"
137
+
138
+ def memory_context(self, ctx: RunContext, path: str) -> str:
139
+ """Text of this agent's recent runs in the session, for routers and planners."""
140
+ return memory_context(ctx.memory, namespaced(ctx.session_id, path))
141
+
142
+ def card(self) -> dict[str, Any]:
143
+ """Short description of the agent for parent routers: name, kind, role, what it does and, for supervisors, its sub-agents."""
144
+ return {
145
+ "name": self.name,
146
+ "kind": self.kind,
147
+ "role": self.spec.role,
148
+ "does": self.spec.card,
149
+ **({"sub_agents": sorted(self.children)} if self.children else {}),
150
+ }
151
+
152
+
153
+ __all__ = [
154
+ "BaseAgent",
155
+ ]