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.
- spec_agents_core-0.5.1/.gitignore +11 -0
- spec_agents_core-0.5.1/CHANGELOG.md +50 -0
- spec_agents_core-0.5.1/LICENSE +21 -0
- spec_agents_core-0.5.1/PKG-INFO +93 -0
- spec_agents_core-0.5.1/README.md +48 -0
- spec_agents_core-0.5.1/pyproject.toml +65 -0
- spec_agents_core-0.5.1/src/agent_fabric/__init__.py +55 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/__init__.py +39 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/base.py +155 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/fabric.py +496 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/kinds.py +641 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/runtime.py +234 -0
- spec_agents_core-0.5.1/src/agent_fabric/agents/spec.py +244 -0
- spec_agents_core-0.5.1/src/agent_fabric/artifacts.py +206 -0
- spec_agents_core-0.5.1/src/agent_fabric/cli/__init__.py +113 -0
- spec_agents_core-0.5.1/src/agent_fabric/cli/__main__.py +5 -0
- spec_agents_core-0.5.1/src/agent_fabric/cli/commands.py +153 -0
- spec_agents_core-0.5.1/src/agent_fabric/cli/live.py +83 -0
- spec_agents_core-0.5.1/src/agent_fabric/cli/render.py +127 -0
- spec_agents_core-0.5.1/src/agent_fabric/compat.py +67 -0
- spec_agents_core-0.5.1/src/agent_fabric/component.py +318 -0
- spec_agents_core-0.5.1/src/agent_fabric/contracts.py +223 -0
- spec_agents_core-0.5.1/src/agent_fabric/errors.py +243 -0
- spec_agents_core-0.5.1/src/agent_fabric/evals.py +185 -0
- spec_agents_core-0.5.1/src/agent_fabric/executor.py +235 -0
- spec_agents_core-0.5.1/src/agent_fabric/integrations/__init__.py +1 -0
- spec_agents_core-0.5.1/src/agent_fabric/integrations/crewai.py +112 -0
- spec_agents_core-0.5.1/src/agent_fabric/integrations/dspy.py +169 -0
- spec_agents_core-0.5.1/src/agent_fabric/lint.py +379 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/__init__.py +25 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/backends.py +152 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/interpreter.py +187 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/planner.py +236 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/prompts.py +118 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/repair.py +79 -0
- spec_agents_core-0.5.1/src/agent_fabric/llm/self_correction.py +188 -0
- spec_agents_core-0.5.1/src/agent_fabric/markdown.py +163 -0
- spec_agents_core-0.5.1/src/agent_fabric/memory/__init__.py +11 -0
- spec_agents_core-0.5.1/src/agent_fabric/memory/base.py +115 -0
- spec_agents_core-0.5.1/src/agent_fabric/memory/langchain_adapter.py +87 -0
- spec_agents_core-0.5.1/src/agent_fabric/pipeline.py +469 -0
- spec_agents_core-0.5.1/src/agent_fabric/prompt.py +270 -0
- spec_agents_core-0.5.1/src/agent_fabric/py.typed +0 -0
- spec_agents_core-0.5.1/src/agent_fabric/registry.py +309 -0
- spec_agents_core-0.5.1/src/agent_fabric/report.py +52 -0
- spec_agents_core-0.5.1/src/agent_fabric/scaffold.py +167 -0
- spec_agents_core-0.5.1/src/agent_fabric/skills_export.py +194 -0
- spec_agents_core-0.5.1/src/agent_fabric/spec.py +330 -0
- spec_agents_core-0.5.1/src/agent_fabric/tabular.py +354 -0
- spec_agents_core-0.5.1/src/agent_fabric/testing.py +18 -0
- spec_agents_core-0.5.1/tests/test_baselines.py +41 -0
- spec_agents_core-0.5.1/tests/test_boundaries.py +118 -0
- spec_agents_core-0.5.1/tests/test_cli.py +118 -0
- spec_agents_core-0.5.1/tests/test_compat.py +92 -0
- spec_agents_core-0.5.1/tests/test_contracts.py +144 -0
- spec_agents_core-0.5.1/tests/test_lint_descriptions.py +69 -0
- spec_agents_core-0.5.1/tests/test_prompt_domain.py +206 -0
- spec_agents_core-0.5.1/tests/test_skills_export.py +97 -0
|
@@ -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
|
+
]
|