sirenspec 0.1.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.
- sirenspec-0.1.0/LICENSE +21 -0
- sirenspec-0.1.0/PKG-INFO +515 -0
- sirenspec-0.1.0/README.md +454 -0
- sirenspec-0.1.0/pyproject.toml +87 -0
- sirenspec-0.1.0/setup.cfg +4 -0
- sirenspec-0.1.0/src/sirenspec/__init__.py +58 -0
- sirenspec-0.1.0/src/sirenspec/cli/__init__.py +36 -0
- sirenspec-0.1.0/src/sirenspec/cli/explain.py +352 -0
- sirenspec-0.1.0/src/sirenspec/cli/init.py +163 -0
- sirenspec-0.1.0/src/sirenspec/cli/render.py +43 -0
- sirenspec-0.1.0/src/sirenspec/cli/run.py +495 -0
- sirenspec-0.1.0/src/sirenspec/cli/test.py +110 -0
- sirenspec-0.1.0/src/sirenspec/cli/validate.py +41 -0
- sirenspec-0.1.0/src/sirenspec/core/__init__.py +0 -0
- sirenspec-0.1.0/src/sirenspec/core/agent_runner.py +170 -0
- sirenspec-0.1.0/src/sirenspec/core/budget.py +158 -0
- sirenspec-0.1.0/src/sirenspec/core/context.py +54 -0
- sirenspec-0.1.0/src/sirenspec/core/data/__init__.py +0 -0
- sirenspec-0.1.0/src/sirenspec/core/data/litellm_pricing_snapshot.json +185 -0
- sirenspec-0.1.0/src/sirenspec/core/events.py +65 -0
- sirenspec-0.1.0/src/sirenspec/core/executor.py +1424 -0
- sirenspec-0.1.0/src/sirenspec/core/factory_runner.py +383 -0
- sirenspec-0.1.0/src/sirenspec/core/human_runner.py +129 -0
- sirenspec-0.1.0/src/sirenspec/core/interpolation.py +342 -0
- sirenspec-0.1.0/src/sirenspec/core/models.py +674 -0
- sirenspec-0.1.0/src/sirenspec/core/pricing.py +209 -0
- sirenspec-0.1.0/src/sirenspec/core/retry.py +123 -0
- sirenspec-0.1.0/src/sirenspec/core/swrm_runner.py +423 -0
- sirenspec-0.1.0/src/sirenspec/core/tool_runner.py +87 -0
- sirenspec-0.1.0/src/sirenspec/core/usage.py +36 -0
- sirenspec-0.1.0/src/sirenspec/core/workflow_registry.py +40 -0
- sirenspec-0.1.0/src/sirenspec/core/workflow_runner.py +52 -0
- sirenspec-0.1.0/src/sirenspec/exceptions.py +160 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/__init__.py +0 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/base.py +61 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/cost_cap.py +100 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/injection.py +50 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/length.py +42 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/pii.py +198 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/registry.py +145 -0
- sirenspec-0.1.0/src/sirenspec/guardrails/schema.py +83 -0
- sirenspec-0.1.0/src/sirenspec/providers/__init__.py +0 -0
- sirenspec-0.1.0/src/sirenspec/providers/anthropic_provider.py +117 -0
- sirenspec-0.1.0/src/sirenspec/providers/base.py +55 -0
- sirenspec-0.1.0/src/sirenspec/providers/ollama_provider.py +101 -0
- sirenspec-0.1.0/src/sirenspec/providers/openai_provider.py +98 -0
- sirenspec-0.1.0/src/sirenspec/providers/registry.py +90 -0
- sirenspec-0.1.0/src/sirenspec/py.typed +0 -0
- sirenspec-0.1.0/src/sirenspec/render/__init__.py +1 -0
- sirenspec-0.1.0/src/sirenspec/render/mermaid.py +80 -0
- sirenspec-0.1.0/src/sirenspec/templates.py +205 -0
- sirenspec-0.1.0/src/sirenspec/testing/__init__.py +1 -0
- sirenspec-0.1.0/src/sirenspec/testing/assertions.py +167 -0
- sirenspec-0.1.0/src/sirenspec/testing/cassette.py +230 -0
- sirenspec-0.1.0/src/sirenspec/testing/models.py +64 -0
- sirenspec-0.1.0/src/sirenspec/testing/runner.py +220 -0
- sirenspec-0.1.0/src/sirenspec/tools/__init__.py +6 -0
- sirenspec-0.1.0/src/sirenspec/tools/http_adapter.py +100 -0
- sirenspec-0.1.0/src/sirenspec/tools/python_adapter.py +72 -0
- sirenspec-0.1.0/src/sirenspec/yaml/__init__.py +0 -0
- sirenspec-0.1.0/src/sirenspec/yaml/parser.py +85 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/PKG-INFO +515 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/SOURCES.txt +96 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/dependency_links.txt +1 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/entry_points.txt +2 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/requires.txt +15 -0
- sirenspec-0.1.0/src/sirenspec.egg-info/top_level.txt +1 -0
- sirenspec-0.1.0/tests/test_anthropic_provider.py +114 -0
- sirenspec-0.1.0/tests/test_cli.py +154 -0
- sirenspec-0.1.0/tests/test_context.py +84 -0
- sirenspec-0.1.0/tests/test_cookbook.py +494 -0
- sirenspec-0.1.0/tests/test_cost_cap_guardrail.py +672 -0
- sirenspec-0.1.0/tests/test_executor.py +332 -0
- sirenspec-0.1.0/tests/test_explain.py +398 -0
- sirenspec-0.1.0/tests/test_factory_node.py +1156 -0
- sirenspec-0.1.0/tests/test_guardrail_registry.py +44 -0
- sirenspec-0.1.0/tests/test_human_node.py +374 -0
- sirenspec-0.1.0/tests/test_init_command.py +107 -0
- sirenspec-0.1.0/tests/test_injection_guardrail.py +58 -0
- sirenspec-0.1.0/tests/test_interpolation.py +473 -0
- sirenspec-0.1.0/tests/test_length_guardrail.py +61 -0
- sirenspec-0.1.0/tests/test_models.py +151 -0
- sirenspec-0.1.0/tests/test_openai_provider.py +130 -0
- sirenspec-0.1.0/tests/test_pii_guardrail.py +293 -0
- sirenspec-0.1.0/tests/test_provider_registry.py +42 -0
- sirenspec-0.1.0/tests/test_render.py +215 -0
- sirenspec-0.1.0/tests/test_retry.py +436 -0
- sirenspec-0.1.0/tests/test_schema_guardrail.py +148 -0
- sirenspec-0.1.0/tests/test_sirenspec_test.py +632 -0
- sirenspec-0.1.0/tests/test_streaming.py +809 -0
- sirenspec-0.1.0/tests/test_swarm_renderer.py +491 -0
- sirenspec-0.1.0/tests/test_swrm.py +568 -0
- sirenspec-0.1.0/tests/test_token_usage.py +203 -0
- sirenspec-0.1.0/tests/test_tool_nodes.py +547 -0
- sirenspec-0.1.0/tests/test_trace.py +94 -0
- sirenspec-0.1.0/tests/test_workflow_budget.py +354 -0
- sirenspec-0.1.0/tests/test_workflow_node.py +340 -0
- sirenspec-0.1.0/tests/test_yaml_parser.py +102 -0
sirenspec-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 TJLSmith0831
|
|
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.
|
sirenspec-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,515 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sirenspec
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: YAML-first agent orchestration SDK for multi-agent workflows
|
|
5
|
+
Author-email: TJLSmith0831 <tjlsmith0831@gmail.com>
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 TJLSmith0831
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Website, https://sirenspec.dev
|
|
29
|
+
Project-URL: Documentation, https://docs.sirenspec.dev
|
|
30
|
+
Project-URL: Homepage, https://github.com/sirenspec/sirenspec
|
|
31
|
+
Project-URL: Repository, https://github.com/sirenspec/sirenspec
|
|
32
|
+
Project-URL: Issues, https://github.com/sirenspec/sirenspec/issues
|
|
33
|
+
Keywords: agents,llm,yaml,orchestration,multi-agent,openai,anthropic,ollama
|
|
34
|
+
Classifier: Development Status :: 4 - Beta
|
|
35
|
+
Classifier: Intended Audience :: Developers
|
|
36
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
37
|
+
Classifier: Programming Language :: Python :: 3
|
|
38
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
39
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
40
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
41
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
42
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
43
|
+
Requires-Python: >=3.11
|
|
44
|
+
Description-Content-Type: text/markdown
|
|
45
|
+
License-File: LICENSE
|
|
46
|
+
Requires-Dist: anthropic>=0.101.0
|
|
47
|
+
Requires-Dist: jsonschema>=4.0.0
|
|
48
|
+
Requires-Dist: openai>=2.36.0
|
|
49
|
+
Requires-Dist: pydantic>=2.13.4
|
|
50
|
+
Requires-Dist: rich>=15.0.0
|
|
51
|
+
Requires-Dist: ruamel-yaml>=0.19.1
|
|
52
|
+
Requires-Dist: typer>=0.25.1
|
|
53
|
+
Provides-Extra: dev
|
|
54
|
+
Requires-Dist: hypothesis>=6.152.7; extra == "dev"
|
|
55
|
+
Requires-Dist: pytest>=9.0.3; extra == "dev"
|
|
56
|
+
Requires-Dist: pytest-asyncio>=1.3.0; extra == "dev"
|
|
57
|
+
Requires-Dist: pytest-cov>=6.0.0; extra == "dev"
|
|
58
|
+
Requires-Dist: pytest-mock>=3.14.0; extra == "dev"
|
|
59
|
+
Requires-Dist: ruff>=0.15.12; extra == "dev"
|
|
60
|
+
Dynamic: license-file
|
|
61
|
+
|
|
62
|
+
<div align="center">
|
|
63
|
+
<h1>SirenSpec</h1>
|
|
64
|
+
<img src="docs/logo/crest.svg" alt="Crest, the SirenSpec mascot" width="180"/>
|
|
65
|
+
|
|
66
|
+
[](https://github.com/sirenspec/sirenspec/actions/workflows/ci.yml)
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
YAML-first agent orchestration SDK. Define multi-agent workflows in human-readable YAML and execute them against OpenAI, Anthropic, or Ollama backends.
|
|
70
|
+
|
|
71
|
+
📚 Documentation: [docs.sirenspec.dev](https://docs.sirenspec.dev)
|
|
72
|
+
|
|
73
|
+
## Installation
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
# curl — easiest, auto-detects uv / pipx / pip
|
|
77
|
+
curl -fsSL https://sirenspec.dev/install.sh | sh
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Or install directly with your preferred Python tool:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
uv add sirenspec # uv
|
|
84
|
+
pipx install sirenspec # pipx (isolated global install)
|
|
85
|
+
pip install sirenspec # pip
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Python 3.11 or later is required.
|
|
89
|
+
|
|
90
|
+
## Quick Start
|
|
91
|
+
|
|
92
|
+
```bash
|
|
93
|
+
export OPENAI_API_KEY=sk-...
|
|
94
|
+
export ANTHROPIC_API_KEY=sk-ant-...
|
|
95
|
+
|
|
96
|
+
# Scaffold a workflow interactively
|
|
97
|
+
sirenspec init
|
|
98
|
+
|
|
99
|
+
# Or run a cookbook example
|
|
100
|
+
sirenspec run docs/cookbook/simple-agent/workflow.yaml
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Setup (development)
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
uv sync --extra dev
|
|
107
|
+
source .venv/bin/activate
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
The repository pins Python 3.13 in `.python-version` for development. Users running the published package only need Python 3.11 or later.
|
|
111
|
+
|
|
112
|
+
## CLI
|
|
113
|
+
|
|
114
|
+
SirenSpec ships six commands. See the [CLI Reference](https://docs.sirenspec.dev/cli-reference) for the full surface.
|
|
115
|
+
|
|
116
|
+
| Command | Purpose |
|
|
117
|
+
|---------|---------|
|
|
118
|
+
| `sirenspec init` | Interactive scaffolding for a new `workflow.yaml` and `.env.example`. |
|
|
119
|
+
| `sirenspec run` | Execute a workflow with streaming node output (or `--trace` for JSON). |
|
|
120
|
+
| `sirenspec validate` | Parse and schema-check a workflow without making LLM calls. |
|
|
121
|
+
| `sirenspec explain` | Print a dry-run execution plan (text or JSON) — no LLM calls. |
|
|
122
|
+
| `sirenspec render` | Render a workflow as a Mermaid diagram. |
|
|
123
|
+
| `sirenspec test` | Discover and run YAML test fixtures, with optional cassette replay. |
|
|
124
|
+
|
|
125
|
+
### `sirenspec run`
|
|
126
|
+
|
|
127
|
+
By default, each node renders as a Rich-formatted panel as it completes, followed by a summary line. Use `--trace` (or `--output json`) for a machine-readable JSON trace, and `--no-stream` to suppress live token streaming inside each panel.
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
sirenspec run workflow.yaml
|
|
131
|
+
sirenspec run workflow.yaml --input "What is the speed of light?"
|
|
132
|
+
sirenspec run workflow.yaml --trace # full JSON trace to stdout
|
|
133
|
+
sirenspec run workflow.yaml --trace | jq '.output' # machine-readable output
|
|
134
|
+
sirenspec run workflow.yaml --no-stream # panels without per-token streaming
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Options:
|
|
138
|
+
- `--input / -i` — User message (overrides `input.message` in the YAML)
|
|
139
|
+
- `--trace` — Print full JSON trace to stdout (suppresses node panels)
|
|
140
|
+
- `--output` — Output format; use `json` for a raw JSON trace (equivalent to `--trace`)
|
|
141
|
+
- `--trace-file` — Write the JSON trace to a file alongside the streaming output
|
|
142
|
+
- `--quiet` — Suppress node panels; print only the summary
|
|
143
|
+
- `--no-stream` — Disable per-token streaming inside panels
|
|
144
|
+
|
|
145
|
+
Exit code `0` on success, `1` on failure.
|
|
146
|
+
|
|
147
|
+
### `sirenspec validate`
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
sirenspec validate workflow.yaml
|
|
151
|
+
# ✓ workflow.yaml is valid (2 agents, 2 nodes)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### `sirenspec init`
|
|
155
|
+
|
|
156
|
+
Interactively scaffold a workflow. Picks a template, prompts for a provider, and writes `workflow.yaml` plus `.env.example` ready to run.
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
sirenspec init # current directory
|
|
160
|
+
sirenspec init --output ./my-workflow
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### `sirenspec explain`
|
|
164
|
+
|
|
165
|
+
Print a human-readable execution plan — node order, agents, guardrails, and edges — without making LLM calls. Pass `--format json` for machine-readable output.
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
sirenspec explain workflow.yaml
|
|
169
|
+
sirenspec explain workflow.yaml --format json
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### `sirenspec render`
|
|
173
|
+
|
|
174
|
+
Render a workflow as a Mermaid diagram. Conditional edges are labelled with their `when:` expression.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
sirenspec render workflow.yaml --target mermaid
|
|
178
|
+
sirenspec render workflow.yaml --target mermaid --output diagram.md
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### `sirenspec test`
|
|
182
|
+
|
|
183
|
+
Run YAML test fixtures (`*.test.yaml`). Use `--record` / `--mock` with a cassette file to capture and replay LLM responses deterministically.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
sirenspec test tests/
|
|
187
|
+
sirenspec test tests/ --record --cassette cassettes/responses.yaml
|
|
188
|
+
sirenspec test tests/ --mock --cassette cassettes/responses.yaml
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## YAML Workflow Format
|
|
192
|
+
|
|
193
|
+
```yaml
|
|
194
|
+
version: "0.1"
|
|
195
|
+
env_file: .env # optional: load API keys from a .env file
|
|
196
|
+
|
|
197
|
+
agents:
|
|
198
|
+
assistant:
|
|
199
|
+
model: "openai:gpt-4o-mini" # provider:model URI
|
|
200
|
+
system: "You are a helpful assistant."
|
|
201
|
+
guardrails: ["injection", "length"] # optional agent-level override
|
|
202
|
+
|
|
203
|
+
nodes:
|
|
204
|
+
answer:
|
|
205
|
+
agent: assistant
|
|
206
|
+
writes: output.reply # dot-notation context path
|
|
207
|
+
|
|
208
|
+
edges:
|
|
209
|
+
- from: classify # optional: control flow
|
|
210
|
+
to: reply
|
|
211
|
+
when: working.intent == "refund" # optional: conditional edge
|
|
212
|
+
|
|
213
|
+
input:
|
|
214
|
+
message: "What is AI?" # optional static default input
|
|
215
|
+
|
|
216
|
+
guardrails: # workflow-level guardrails
|
|
217
|
+
- injection
|
|
218
|
+
- length
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### Provider URIs
|
|
222
|
+
|
|
223
|
+
Credentials are read from environment variables. All three built-in providers support token streaming.
|
|
224
|
+
|
|
225
|
+
| Provider | URI format | Environment variable | Streaming |
|
|
226
|
+
|----------|-----------|----------------------|-----------|
|
|
227
|
+
| OpenAI | `openai:gpt-4o-mini` | `OPENAI_API_KEY` | Yes |
|
|
228
|
+
| Anthropic | `anthropic:claude-haiku-4-5-20251001` | `ANTHROPIC_API_KEY` | Yes |
|
|
229
|
+
| Ollama | `ollama:llama3` | _(none required)_ | Yes |
|
|
230
|
+
|
|
231
|
+
### `env_file`
|
|
232
|
+
|
|
233
|
+
Point a workflow at a `.env` file (path relative to the workflow file) to load API keys automatically at run time. Variables already set in the environment take precedence.
|
|
234
|
+
|
|
235
|
+
```yaml
|
|
236
|
+
env_file: .env
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Variables are set in `os.environ` before execution, so provider clients pick them up without any extra configuration.
|
|
240
|
+
|
|
241
|
+
### Context paths
|
|
242
|
+
|
|
243
|
+
Nodes write to dot-notation paths in the workflow context:
|
|
244
|
+
|
|
245
|
+
- `output.reply` — final output (included in the trace `output` field)
|
|
246
|
+
- `working.intent` — intermediate state readable by downstream nodes via `{{ working.intent }}`
|
|
247
|
+
|
|
248
|
+
### Template interpolation
|
|
249
|
+
|
|
250
|
+
Use `{{ expr }}` in system prompts and agent prompts to reference runtime values:
|
|
251
|
+
|
|
252
|
+
```yaml
|
|
253
|
+
{{ inputs.message }} # original user input
|
|
254
|
+
{{ env.GITHUB_TOKEN }} # environment variable
|
|
255
|
+
{{ node_id.output }} # another node's output
|
|
256
|
+
{{ node_id.agents.x.output }} # swrm sub-agent output
|
|
257
|
+
{{ value | default('fallback') }} # optional fallback
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
## Node Types
|
|
261
|
+
|
|
262
|
+
### Agent node
|
|
263
|
+
|
|
264
|
+
Classic single-agent node. Runs one LLM call and writes the output to a context path.
|
|
265
|
+
|
|
266
|
+
Streaming is **on by default** (`streaming: true`). Each agent node streams tokens to stdout when run via `sirenspec run`. Set `streaming: false` on individual nodes to opt out, or use `--no-stream` at the CLI level.
|
|
267
|
+
|
|
268
|
+
Guardrails always apply to the **fully assembled response** after streaming completes — they are not applied per-chunk.
|
|
269
|
+
|
|
270
|
+
```yaml
|
|
271
|
+
nodes:
|
|
272
|
+
classify:
|
|
273
|
+
agent: my_agent
|
|
274
|
+
writes: working.intent
|
|
275
|
+
streaming: true # default — stream tokens to stdout
|
|
276
|
+
retry:
|
|
277
|
+
max_attempts: 3
|
|
278
|
+
backoff: exponential
|
|
279
|
+
on_failure:
|
|
280
|
+
action: fallback
|
|
281
|
+
fallback_node: handle_error
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Swrm node
|
|
285
|
+
|
|
286
|
+
Fan-out to multiple agents running concurrently, then optionally synthesise their outputs.
|
|
287
|
+
|
|
288
|
+
```yaml
|
|
289
|
+
nodes:
|
|
290
|
+
analyze:
|
|
291
|
+
type: swrm
|
|
292
|
+
concurrency: 3
|
|
293
|
+
on_failure: continue # or abort
|
|
294
|
+
agents:
|
|
295
|
+
- id: sentiment
|
|
296
|
+
provider: openai
|
|
297
|
+
model: gpt-4o-mini
|
|
298
|
+
prompt: "Analyze: {{ inputs.message }}"
|
|
299
|
+
- id: risk
|
|
300
|
+
provider: anthropic
|
|
301
|
+
model: claude-haiku-4-5-20251001
|
|
302
|
+
prompt: "List risks in: {{ inputs.message }}"
|
|
303
|
+
synthesis:
|
|
304
|
+
provider: anthropic
|
|
305
|
+
model: claude-haiku-4-5-20251001
|
|
306
|
+
prompt: |
|
|
307
|
+
Sentiment: {{ analyze.agents.sentiment.output }}
|
|
308
|
+
Risk: {{ analyze.agents.risk.output }}
|
|
309
|
+
Produce a recommendation.
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Factory node
|
|
313
|
+
|
|
314
|
+
Dynamically spawns one agent instance per item in a runtime list.
|
|
315
|
+
|
|
316
|
+
```yaml
|
|
317
|
+
nodes:
|
|
318
|
+
execute:
|
|
319
|
+
type: factory
|
|
320
|
+
agent: worker
|
|
321
|
+
for_each: "{{ plan.output }}" # must resolve to a JSON array
|
|
322
|
+
inputs:
|
|
323
|
+
task: "{{ item }}"
|
|
324
|
+
index: "{{ index }}"
|
|
325
|
+
concurrency: 4
|
|
326
|
+
writes: working.results
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### Tool node
|
|
330
|
+
|
|
331
|
+
Calls an HTTP endpoint or Python callable instead of an LLM.
|
|
332
|
+
|
|
333
|
+
```yaml
|
|
334
|
+
nodes:
|
|
335
|
+
fetch:
|
|
336
|
+
type: tool
|
|
337
|
+
tool: http
|
|
338
|
+
config:
|
|
339
|
+
url: "https://api.example.com/data"
|
|
340
|
+
method: GET
|
|
341
|
+
headers:
|
|
342
|
+
Authorization: "Bearer {{ env.API_TOKEN }}"
|
|
343
|
+
timeout: 15
|
|
344
|
+
output_key: data
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
### Workflow node
|
|
348
|
+
|
|
349
|
+
Executes another SirenSpec workflow inline as a single node. The sub-workflow's output is written back into the parent context.
|
|
350
|
+
|
|
351
|
+
```yaml
|
|
352
|
+
nodes:
|
|
353
|
+
summarize:
|
|
354
|
+
type: workflow
|
|
355
|
+
ref: ./workflows/summarize.yaml
|
|
356
|
+
inputs:
|
|
357
|
+
topic: "{{ extract.output }}"
|
|
358
|
+
writes: working.summary
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Human node
|
|
362
|
+
|
|
363
|
+
Pauses execution to collect input from a human operator. Consumes no LLM tokens. Supports a `timeout` with `on_timeout` actions (`abort` / `skip` / `use_default`).
|
|
364
|
+
|
|
365
|
+
```yaml
|
|
366
|
+
nodes:
|
|
367
|
+
approve_draft:
|
|
368
|
+
type: human
|
|
369
|
+
prompt: |
|
|
370
|
+
{{ draft.output }}
|
|
371
|
+
|
|
372
|
+
Approve this draft? (yes/edit/reject)
|
|
373
|
+
writes: working.approval
|
|
374
|
+
timeout: 3600
|
|
375
|
+
on_timeout: use_default
|
|
376
|
+
default_output: "approved"
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
## Guardrails
|
|
380
|
+
|
|
381
|
+
| Name | Behaviour | Config |
|
|
382
|
+
|------|-----------|--------|
|
|
383
|
+
| `injection` | Detects prompt-injection patterns. Applied by default. | None |
|
|
384
|
+
| `length` | Truncates output to 4000 chars. | `max_chars`, `mode` |
|
|
385
|
+
| `pii` | Detects and redacts email, phone, SSN, and credit-card data. | `entities`, `action`, `replacement` |
|
|
386
|
+
| `schema` | Validates output as JSON against a JSON Schema Draft 7 dict. | `schema` (required) |
|
|
387
|
+
| `cost_cap` | Enforces token and/or USD ceilings across the run. | `max_tokens` and/or `max_usd`, `action` |
|
|
388
|
+
|
|
389
|
+
Specify at the workflow level (`guardrails:`) or per-agent. Configurable guardrails use a `{name, config}` form:
|
|
390
|
+
|
|
391
|
+
```yaml
|
|
392
|
+
guardrails:
|
|
393
|
+
- injection
|
|
394
|
+
- name: cost_cap
|
|
395
|
+
config:
|
|
396
|
+
max_usd: 5.0
|
|
397
|
+
action: abort
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
An empty list (`[]`) disables all guardrails. See the [Guardrails docs](https://docs.sirenspec.dev/guardrails) for full configuration details.
|
|
401
|
+
|
|
402
|
+
## Budget controls
|
|
403
|
+
|
|
404
|
+
Cap the entire run's spend with a workflow-level `budget:` block. At least one ceiling must be set.
|
|
405
|
+
|
|
406
|
+
```yaml
|
|
407
|
+
budget:
|
|
408
|
+
max_tokens: 50000
|
|
409
|
+
max_cost_usd: 5.00
|
|
410
|
+
max_duration_s: 300
|
|
411
|
+
on_exceeded: abort # abort | warn | skip_remaining
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Per-call ceilings are available on agent nodes via `max_tokens_per_call`.
|
|
415
|
+
|
|
416
|
+
## Retry & on_failure
|
|
417
|
+
|
|
418
|
+
```yaml
|
|
419
|
+
nodes:
|
|
420
|
+
answer:
|
|
421
|
+
agent: assistant
|
|
422
|
+
writes: output.reply
|
|
423
|
+
retry:
|
|
424
|
+
max_attempts: 3
|
|
425
|
+
backoff: exponential # exponential | linear | constant
|
|
426
|
+
base_delay: 1.0
|
|
427
|
+
on: ["429", "network_error"]
|
|
428
|
+
on_failure:
|
|
429
|
+
action: use_default # abort | fallback | skip | use_default
|
|
430
|
+
default_output: "Sorry, I could not process your request."
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
## SDK Usage
|
|
434
|
+
|
|
435
|
+
Everything is exported at the top level — see the [Python SDK docs](https://docs.sirenspec.dev/sdk) for the full surface.
|
|
436
|
+
|
|
437
|
+
```python
|
|
438
|
+
import asyncio
|
|
439
|
+
from sirenspec import load_workflow, execute
|
|
440
|
+
|
|
441
|
+
workflow = load_workflow("workflow.yaml")
|
|
442
|
+
trace = asyncio.run(execute(workflow, user_input="Hello"))
|
|
443
|
+
print(trace["output"])
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Streaming, budget enforcement, nested workflows, and custom guardrails are all exported alongside `execute`:
|
|
447
|
+
|
|
448
|
+
```python
|
|
449
|
+
from sirenspec import (
|
|
450
|
+
execute_streaming, # async generator of per-node events
|
|
451
|
+
NodeCompleteEvent, SummaryEvent,
|
|
452
|
+
BudgetConfig, BudgetExceededError,
|
|
453
|
+
HumanNode, HumanInputError,
|
|
454
|
+
WorkflowRegistry, # for named sub-workflow refs
|
|
455
|
+
Guardrail, GuardrailViolation,
|
|
456
|
+
LLMProvider, TokenUsage,
|
|
457
|
+
)
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
## Cookbook
|
|
461
|
+
|
|
462
|
+
See [`docs/cookbook/`](docs/cookbook/) for 21 runnable examples:
|
|
463
|
+
|
|
464
|
+
### Basics
|
|
465
|
+
| Example | What it demonstrates |
|
|
466
|
+
|---------|----------------------|
|
|
467
|
+
| [simple-agent](docs/cookbook/simple-agent/) | Single agent, minimal config |
|
|
468
|
+
| [sequential-pipeline](docs/cookbook/sequential-pipeline/) | Two-node chain |
|
|
469
|
+
| [conditional-pipeline](docs/cookbook/conditional-pipeline/) | `when:` edge routing |
|
|
470
|
+
|
|
471
|
+
### Multi-agent patterns
|
|
472
|
+
| Example | What it demonstrates |
|
|
473
|
+
|---------|----------------------|
|
|
474
|
+
| [adversarial-pair](docs/cookbook/adversarial-pair/) | Debate + judge pattern |
|
|
475
|
+
| [blind-code-review](docs/cookbook/blind-code-review/) | Multi-turn code refinement |
|
|
476
|
+
| [graphic-design-firm](docs/cookbook/graphic-design-firm/) | 5-node creative pipeline |
|
|
477
|
+
| [news-desk](docs/cookbook/news-desk/) | Reporter → editor → publisher chain |
|
|
478
|
+
| [content-moderation-pipeline](docs/cookbook/content-moderation-pipeline/) | Multi-stage moderation chain |
|
|
479
|
+
|
|
480
|
+
### Swrm & fan-out
|
|
481
|
+
| Example | What it demonstrates |
|
|
482
|
+
|---------|----------------------|
|
|
483
|
+
| [1000-monkeys](docs/cookbook/1000-monkeys/) | Swrm fan-out + curator synthesis |
|
|
484
|
+
| [market-analysis](docs/cookbook/market-analysis/) | Parallel specialist agents + synthesis |
|
|
485
|
+
| [email-triage](docs/cookbook/email-triage/) | Parallel triage with synthesised verdict |
|
|
486
|
+
|
|
487
|
+
### Factory & iteration
|
|
488
|
+
| Example | What it demonstrates |
|
|
489
|
+
|---------|----------------------|
|
|
490
|
+
| [changelog-annotator](docs/cookbook/changelog-annotator/) | Annotate each commit in a list |
|
|
491
|
+
| [github-issues-triage](docs/cookbook/github-issues-triage/) | Per-issue triage via factory |
|
|
492
|
+
| [grading-factory](docs/cookbook/grading-factory/) | Factory + per-item swrm |
|
|
493
|
+
|
|
494
|
+
### Guardrails & budgets
|
|
495
|
+
| Example | What it demonstrates |
|
|
496
|
+
|---------|----------------------|
|
|
497
|
+
| [structured-bug-reporter](docs/cookbook/structured-bug-reporter/) | JSON Schema guardrail enforcement |
|
|
498
|
+
| [budget-guarded](docs/cookbook/budget-guarded/) | Workflow `budget:` block in action |
|
|
499
|
+
|
|
500
|
+
### Human in the loop
|
|
501
|
+
| Example | What it demonstrates |
|
|
502
|
+
|---------|----------------------|
|
|
503
|
+
| [content-approval](docs/cookbook/content-approval/) | Human approval gate before publish |
|
|
504
|
+
|
|
505
|
+
### Stress tests
|
|
506
|
+
| Example | What it demonstrates |
|
|
507
|
+
|---------|----------------------|
|
|
508
|
+
| [telephone-game](docs/cookbook/telephone-game/) | Semantic drift across 5 hops |
|
|
509
|
+
| [compression-gauntlet](docs/cookbook/compression-gauntlet/) | 4-round summarisation loop |
|
|
510
|
+
|
|
511
|
+
### Tool nodes
|
|
512
|
+
| Example | What it demonstrates |
|
|
513
|
+
|---------|----------------------|
|
|
514
|
+
| [pr-summarizer](docs/cookbook/pr-summarizer/) | HTTP tool node + LLM summariser |
|
|
515
|
+
| [code-health-report](docs/cookbook/code-health-report/) | HTTP tool + multi-stage analysis |
|