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.
Files changed (98) hide show
  1. sirenspec-0.1.0/LICENSE +21 -0
  2. sirenspec-0.1.0/PKG-INFO +515 -0
  3. sirenspec-0.1.0/README.md +454 -0
  4. sirenspec-0.1.0/pyproject.toml +87 -0
  5. sirenspec-0.1.0/setup.cfg +4 -0
  6. sirenspec-0.1.0/src/sirenspec/__init__.py +58 -0
  7. sirenspec-0.1.0/src/sirenspec/cli/__init__.py +36 -0
  8. sirenspec-0.1.0/src/sirenspec/cli/explain.py +352 -0
  9. sirenspec-0.1.0/src/sirenspec/cli/init.py +163 -0
  10. sirenspec-0.1.0/src/sirenspec/cli/render.py +43 -0
  11. sirenspec-0.1.0/src/sirenspec/cli/run.py +495 -0
  12. sirenspec-0.1.0/src/sirenspec/cli/test.py +110 -0
  13. sirenspec-0.1.0/src/sirenspec/cli/validate.py +41 -0
  14. sirenspec-0.1.0/src/sirenspec/core/__init__.py +0 -0
  15. sirenspec-0.1.0/src/sirenspec/core/agent_runner.py +170 -0
  16. sirenspec-0.1.0/src/sirenspec/core/budget.py +158 -0
  17. sirenspec-0.1.0/src/sirenspec/core/context.py +54 -0
  18. sirenspec-0.1.0/src/sirenspec/core/data/__init__.py +0 -0
  19. sirenspec-0.1.0/src/sirenspec/core/data/litellm_pricing_snapshot.json +185 -0
  20. sirenspec-0.1.0/src/sirenspec/core/events.py +65 -0
  21. sirenspec-0.1.0/src/sirenspec/core/executor.py +1424 -0
  22. sirenspec-0.1.0/src/sirenspec/core/factory_runner.py +383 -0
  23. sirenspec-0.1.0/src/sirenspec/core/human_runner.py +129 -0
  24. sirenspec-0.1.0/src/sirenspec/core/interpolation.py +342 -0
  25. sirenspec-0.1.0/src/sirenspec/core/models.py +674 -0
  26. sirenspec-0.1.0/src/sirenspec/core/pricing.py +209 -0
  27. sirenspec-0.1.0/src/sirenspec/core/retry.py +123 -0
  28. sirenspec-0.1.0/src/sirenspec/core/swrm_runner.py +423 -0
  29. sirenspec-0.1.0/src/sirenspec/core/tool_runner.py +87 -0
  30. sirenspec-0.1.0/src/sirenspec/core/usage.py +36 -0
  31. sirenspec-0.1.0/src/sirenspec/core/workflow_registry.py +40 -0
  32. sirenspec-0.1.0/src/sirenspec/core/workflow_runner.py +52 -0
  33. sirenspec-0.1.0/src/sirenspec/exceptions.py +160 -0
  34. sirenspec-0.1.0/src/sirenspec/guardrails/__init__.py +0 -0
  35. sirenspec-0.1.0/src/sirenspec/guardrails/base.py +61 -0
  36. sirenspec-0.1.0/src/sirenspec/guardrails/cost_cap.py +100 -0
  37. sirenspec-0.1.0/src/sirenspec/guardrails/injection.py +50 -0
  38. sirenspec-0.1.0/src/sirenspec/guardrails/length.py +42 -0
  39. sirenspec-0.1.0/src/sirenspec/guardrails/pii.py +198 -0
  40. sirenspec-0.1.0/src/sirenspec/guardrails/registry.py +145 -0
  41. sirenspec-0.1.0/src/sirenspec/guardrails/schema.py +83 -0
  42. sirenspec-0.1.0/src/sirenspec/providers/__init__.py +0 -0
  43. sirenspec-0.1.0/src/sirenspec/providers/anthropic_provider.py +117 -0
  44. sirenspec-0.1.0/src/sirenspec/providers/base.py +55 -0
  45. sirenspec-0.1.0/src/sirenspec/providers/ollama_provider.py +101 -0
  46. sirenspec-0.1.0/src/sirenspec/providers/openai_provider.py +98 -0
  47. sirenspec-0.1.0/src/sirenspec/providers/registry.py +90 -0
  48. sirenspec-0.1.0/src/sirenspec/py.typed +0 -0
  49. sirenspec-0.1.0/src/sirenspec/render/__init__.py +1 -0
  50. sirenspec-0.1.0/src/sirenspec/render/mermaid.py +80 -0
  51. sirenspec-0.1.0/src/sirenspec/templates.py +205 -0
  52. sirenspec-0.1.0/src/sirenspec/testing/__init__.py +1 -0
  53. sirenspec-0.1.0/src/sirenspec/testing/assertions.py +167 -0
  54. sirenspec-0.1.0/src/sirenspec/testing/cassette.py +230 -0
  55. sirenspec-0.1.0/src/sirenspec/testing/models.py +64 -0
  56. sirenspec-0.1.0/src/sirenspec/testing/runner.py +220 -0
  57. sirenspec-0.1.0/src/sirenspec/tools/__init__.py +6 -0
  58. sirenspec-0.1.0/src/sirenspec/tools/http_adapter.py +100 -0
  59. sirenspec-0.1.0/src/sirenspec/tools/python_adapter.py +72 -0
  60. sirenspec-0.1.0/src/sirenspec/yaml/__init__.py +0 -0
  61. sirenspec-0.1.0/src/sirenspec/yaml/parser.py +85 -0
  62. sirenspec-0.1.0/src/sirenspec.egg-info/PKG-INFO +515 -0
  63. sirenspec-0.1.0/src/sirenspec.egg-info/SOURCES.txt +96 -0
  64. sirenspec-0.1.0/src/sirenspec.egg-info/dependency_links.txt +1 -0
  65. sirenspec-0.1.0/src/sirenspec.egg-info/entry_points.txt +2 -0
  66. sirenspec-0.1.0/src/sirenspec.egg-info/requires.txt +15 -0
  67. sirenspec-0.1.0/src/sirenspec.egg-info/top_level.txt +1 -0
  68. sirenspec-0.1.0/tests/test_anthropic_provider.py +114 -0
  69. sirenspec-0.1.0/tests/test_cli.py +154 -0
  70. sirenspec-0.1.0/tests/test_context.py +84 -0
  71. sirenspec-0.1.0/tests/test_cookbook.py +494 -0
  72. sirenspec-0.1.0/tests/test_cost_cap_guardrail.py +672 -0
  73. sirenspec-0.1.0/tests/test_executor.py +332 -0
  74. sirenspec-0.1.0/tests/test_explain.py +398 -0
  75. sirenspec-0.1.0/tests/test_factory_node.py +1156 -0
  76. sirenspec-0.1.0/tests/test_guardrail_registry.py +44 -0
  77. sirenspec-0.1.0/tests/test_human_node.py +374 -0
  78. sirenspec-0.1.0/tests/test_init_command.py +107 -0
  79. sirenspec-0.1.0/tests/test_injection_guardrail.py +58 -0
  80. sirenspec-0.1.0/tests/test_interpolation.py +473 -0
  81. sirenspec-0.1.0/tests/test_length_guardrail.py +61 -0
  82. sirenspec-0.1.0/tests/test_models.py +151 -0
  83. sirenspec-0.1.0/tests/test_openai_provider.py +130 -0
  84. sirenspec-0.1.0/tests/test_pii_guardrail.py +293 -0
  85. sirenspec-0.1.0/tests/test_provider_registry.py +42 -0
  86. sirenspec-0.1.0/tests/test_render.py +215 -0
  87. sirenspec-0.1.0/tests/test_retry.py +436 -0
  88. sirenspec-0.1.0/tests/test_schema_guardrail.py +148 -0
  89. sirenspec-0.1.0/tests/test_sirenspec_test.py +632 -0
  90. sirenspec-0.1.0/tests/test_streaming.py +809 -0
  91. sirenspec-0.1.0/tests/test_swarm_renderer.py +491 -0
  92. sirenspec-0.1.0/tests/test_swrm.py +568 -0
  93. sirenspec-0.1.0/tests/test_token_usage.py +203 -0
  94. sirenspec-0.1.0/tests/test_tool_nodes.py +547 -0
  95. sirenspec-0.1.0/tests/test_trace.py +94 -0
  96. sirenspec-0.1.0/tests/test_workflow_budget.py +354 -0
  97. sirenspec-0.1.0/tests/test_workflow_node.py +340 -0
  98. sirenspec-0.1.0/tests/test_yaml_parser.py +102 -0
@@ -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.
@@ -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
+ [![CI](https://github.com/sirenspec/sirenspec/actions/workflows/ci.yml/badge.svg)](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 |