flatmachines 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flatmachines-1.0.0/.gitignore +13 -0
- flatmachines-1.0.0/MACHINES.md +141 -0
- flatmachines-1.0.0/PKG-INFO +390 -0
- flatmachines-1.0.0/README.md +336 -0
- flatmachines-1.0.0/flatmachines/__init__.py +136 -0
- flatmachines-1.0.0/flatmachines/actions.py +408 -0
- flatmachines-1.0.0/flatmachines/adapters/__init__.py +38 -0
- flatmachines-1.0.0/flatmachines/adapters/flatagent.py +86 -0
- flatmachines-1.0.0/flatmachines/adapters/pi_agent_bridge.py +127 -0
- flatmachines-1.0.0/flatmachines/adapters/pi_agent_runner.mjs +99 -0
- flatmachines-1.0.0/flatmachines/adapters/smolagents.py +125 -0
- flatmachines-1.0.0/flatmachines/agents.py +144 -0
- flatmachines-1.0.0/flatmachines/assets/MACHINES.md +141 -0
- flatmachines-1.0.0/flatmachines/assets/README.md +11 -0
- flatmachines-1.0.0/flatmachines/assets/__init__.py +0 -0
- flatmachines-1.0.0/flatmachines/assets/flatagent.d.ts +219 -0
- flatmachines-1.0.0/flatmachines/assets/flatagent.schema.json +271 -0
- flatmachines-1.0.0/flatmachines/assets/flatagent.slim.d.ts +58 -0
- flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.d.ts +523 -0
- flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.schema.json +281 -0
- flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.slim.d.ts +187 -0
- flatmachines-1.0.0/flatmachines/assets/flatmachine.d.ts +403 -0
- flatmachines-1.0.0/flatmachines/assets/flatmachine.schema.json +620 -0
- flatmachines-1.0.0/flatmachines/assets/flatmachine.slim.d.ts +106 -0
- flatmachines-1.0.0/flatmachines/assets/profiles.d.ts +140 -0
- flatmachines-1.0.0/flatmachines/assets/profiles.schema.json +93 -0
- flatmachines-1.0.0/flatmachines/assets/profiles.slim.d.ts +26 -0
- flatmachines-1.0.0/flatmachines/backends.py +222 -0
- flatmachines-1.0.0/flatmachines/distributed.py +835 -0
- flatmachines-1.0.0/flatmachines/distributed_hooks.py +351 -0
- flatmachines-1.0.0/flatmachines/execution.py +638 -0
- flatmachines-1.0.0/flatmachines/expressions/__init__.py +60 -0
- flatmachines-1.0.0/flatmachines/expressions/cel.py +101 -0
- flatmachines-1.0.0/flatmachines/expressions/simple.py +166 -0
- flatmachines-1.0.0/flatmachines/flatmachine.py +1263 -0
- flatmachines-1.0.0/flatmachines/hooks.py +381 -0
- flatmachines-1.0.0/flatmachines/locking.py +69 -0
- flatmachines-1.0.0/flatmachines/monitoring.py +505 -0
- flatmachines-1.0.0/flatmachines/persistence.py +213 -0
- flatmachines-1.0.0/flatmachines/run.py +117 -0
- flatmachines-1.0.0/flatmachines/utils.py +166 -0
- flatmachines-1.0.0/flatmachines/validation.py +79 -0
- flatmachines-1.0.0/pyproject.toml +71 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# FlatAgents + FlatMachines Reference
|
|
2
|
+
|
|
3
|
+
> **Target: <1000 tokens.** LLM-optimized. See `flatagent.d.ts`, `flatmachine.d.ts`, `profiles.d.ts` for schemas.
|
|
4
|
+
>
|
|
5
|
+
> **Versioning:** All specs and SDKs use lockstep versioning.
|
|
6
|
+
|
|
7
|
+
## Concepts
|
|
8
|
+
|
|
9
|
+
**FlatAgent**: Single LLM call. Model + prompts + output schema. No orchestration.
|
|
10
|
+
**FlatMachine**: State machine orchestrating agents. States, transitions, conditions, loops, error handling.
|
|
11
|
+
|
|
12
|
+
| Need | Use |
|
|
13
|
+
|------|-----|
|
|
14
|
+
| Single LLM call | FlatAgent |
|
|
15
|
+
| Multi-step/branching/retry/errors | FlatMachine |
|
|
16
|
+
| Parallel execution | `machine: [a, b, c]` |
|
|
17
|
+
| Dynamic parallelism | `foreach` |
|
|
18
|
+
| Background tasks | `launch` |
|
|
19
|
+
|
|
20
|
+
## Model Profiles
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
# profiles.yml — agents reference by name
|
|
24
|
+
spec: flatprofiles
|
|
25
|
+
spec_version: "1.0.0"
|
|
26
|
+
data:
|
|
27
|
+
model_profiles:
|
|
28
|
+
fast: { provider: cerebras, name: zai-glm-4.6, temperature: 0.6 }
|
|
29
|
+
smart: { provider: anthropic, name: claude-3-opus-20240229 }
|
|
30
|
+
default: fast # Fallback
|
|
31
|
+
# override: smart # Force all
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Agent model field: `"fast"` | `{ profile: "fast", temperature: 0.9 }` | `{ provider: x, name: y }`
|
|
35
|
+
Resolution: default → profile → overrides → override
|
|
36
|
+
|
|
37
|
+
## Agent References
|
|
38
|
+
|
|
39
|
+
`data.agents` values may be:
|
|
40
|
+
- String path to a flatagent config
|
|
41
|
+
- Inline flatagent config (`spec: flatagent`)
|
|
42
|
+
- Typed adapter ref: `{ type: "flatagent" | "smolagents" | "pi-agent", ref?: "...", config?: {...} }`
|
|
43
|
+
|
|
44
|
+
## State Fields
|
|
45
|
+
|
|
46
|
+
| Field | Purpose |
|
|
47
|
+
|-------|---------|
|
|
48
|
+
| `type` | `initial` (entry) / `final` (exit+output) |
|
|
49
|
+
| `agent` | Agent to call |
|
|
50
|
+
| `machine` | Machine(s) — string or `[array]` for parallel |
|
|
51
|
+
| `foreach` | Array expr for dynamic parallelism (`as`: item var, `key`: result key) |
|
|
52
|
+
| `launch` / `launch_input` | Fire-and-forget machine(s) |
|
|
53
|
+
| `input` | Map input to agent/machine |
|
|
54
|
+
| `output_to_context` | Map `output.*` to `context.*` |
|
|
55
|
+
| `execution` | `{ type: retry, backoffs: [2,8,16], jitter: 0.1 }` |
|
|
56
|
+
| `on_error` | State name or `{ default: x, ErrorType: y }` |
|
|
57
|
+
| `transitions` | `[{ condition: "expr", to: state }, { to: default }]` |
|
|
58
|
+
| `mode` | `settled` (all) / `any` (first) for parallel |
|
|
59
|
+
| `timeout` | Seconds (0=forever) |
|
|
60
|
+
|
|
61
|
+
## Patterns
|
|
62
|
+
|
|
63
|
+
**Execution types**: `default` | `retry` (backoffs, jitter) | `parallel` (n_samples) | `mdap_voting` (k_margin, max_candidates)
|
|
64
|
+
|
|
65
|
+
**Transitions**: `condition: "context.score >= 8"` with `to: state`. Last without condition = default.
|
|
66
|
+
|
|
67
|
+
**Loops**: Transition `to: same_state`. Machine has `max_steps` safety.
|
|
68
|
+
|
|
69
|
+
**Errors**: `on_error: state` or per-type. Context gets `last_error`, `last_error_type`.
|
|
70
|
+
|
|
71
|
+
**Parallel machines**:
|
|
72
|
+
```yaml
|
|
73
|
+
machine: [review_a, review_b] # Results keyed by name
|
|
74
|
+
mode: settled # or "any"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Foreach**:
|
|
78
|
+
```yaml
|
|
79
|
+
foreach: "{{ context.items }}"
|
|
80
|
+
as: item
|
|
81
|
+
machine: processor
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Launch** (fire-and-forget):
|
|
85
|
+
```yaml
|
|
86
|
+
launch: background_task
|
|
87
|
+
launch_input: { data: "{{ context.data }}" }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Distributed Worker Pattern
|
|
91
|
+
|
|
92
|
+
Use hook actions (e.g., `DistributedWorkerHooks`) with a `RegistrationBackend` + `WorkBackend` to build worker pools.
|
|
93
|
+
|
|
94
|
+
**Core machines**
|
|
95
|
+
- **Checker**: `get_pool_state` → `calculate_spawn` → `spawn_workers`
|
|
96
|
+
- **Worker**: `register_worker` → `claim_job` → process → `complete_job`/`fail_job` → `deregister_worker`
|
|
97
|
+
- **Reaper**: `list_stale_workers` → `reap_stale_workers`
|
|
98
|
+
|
|
99
|
+
`spawn_workers` expects `worker_config_path` in context (or override hooks to resolve it). Custom queues can compose the base hooks and add actions.
|
|
100
|
+
|
|
101
|
+
```yaml
|
|
102
|
+
context:
|
|
103
|
+
worker_config_path: "./job_worker.yml"
|
|
104
|
+
states:
|
|
105
|
+
check_state: { action: get_pool_state }
|
|
106
|
+
calculate_spawn: { action: calculate_spawn }
|
|
107
|
+
spawn_workers: { action: spawn_workers }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
See `sdk/examples/distributed_worker/` for a full example.
|
|
111
|
+
|
|
112
|
+
## Context Variables
|
|
113
|
+
|
|
114
|
+
`context.*` (all states), `input.*` (initial), `output.*` (in output_to_context), `item`/`as` (foreach)
|
|
115
|
+
|
|
116
|
+
## Hooks
|
|
117
|
+
|
|
118
|
+
`on_machine_start`, `on_machine_end`, `on_state_enter`, `on_state_exit`, `on_transition`, `on_error`, `on_action`
|
|
119
|
+
|
|
120
|
+
```python
|
|
121
|
+
class MyHooks(MachineHooks):
|
|
122
|
+
def on_action(self, action: str, context: dict) -> dict:
|
|
123
|
+
if action == "fetch": context["data"] = api_call()
|
|
124
|
+
return context
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Persistence
|
|
128
|
+
|
|
129
|
+
```yaml
|
|
130
|
+
persistence: { enabled: true, backend: local } # local | memory
|
|
131
|
+
```
|
|
132
|
+
Resume: `machine.execute(resume_from=execution_id)`
|
|
133
|
+
|
|
134
|
+
## SDKs
|
|
135
|
+
|
|
136
|
+
### Python SDKs
|
|
137
|
+
- **flatagents** (agents): `pip install flatagents[litellm]`
|
|
138
|
+
- **flatmachines** (orchestration): `pip install flatmachines[flatagents]`
|
|
139
|
+
|
|
140
|
+
### JavaScript SDK
|
|
141
|
+
A single JS SDK lives under [`sdk/js`](./sdk/js). It follows the same specs but is not yet split into separate FlatAgents/FlatMachines packages.
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: flatmachines
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: State machine orchestration for agent workflows.
|
|
5
|
+
Project-URL: Homepage, https://github.com/memgrafter/flatagents
|
|
6
|
+
Project-URL: Repository, https://github.com/memgrafter/flatagents
|
|
7
|
+
Project-URL: Issues, https://github.com/memgrafter/flatagents/issues
|
|
8
|
+
Author-email: memgrafter@gmail.com
|
|
9
|
+
License-Expression: Apache-2.0
|
|
10
|
+
Keywords: agents,llm,orchestration,state-machine,workflow
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: aiofiles
|
|
22
|
+
Requires-Dist: httpx
|
|
23
|
+
Requires-Dist: jinja2
|
|
24
|
+
Requires-Dist: pyyaml
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: cel-python; extra == 'all'
|
|
27
|
+
Requires-Dist: flatagents>=0.10.0; extra == 'all'
|
|
28
|
+
Requires-Dist: jsonschema>=4.0; extra == 'all'
|
|
29
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'all'
|
|
30
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'all'
|
|
31
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'all'
|
|
32
|
+
Requires-Dist: smolagents; extra == 'all'
|
|
33
|
+
Provides-Extra: cel
|
|
34
|
+
Requires-Dist: cel-python; extra == 'cel'
|
|
35
|
+
Provides-Extra: flatagents
|
|
36
|
+
Requires-Dist: flatagents>=0.10.0; extra == 'flatagents'
|
|
37
|
+
Provides-Extra: local
|
|
38
|
+
Requires-Dist: cel-python; extra == 'local'
|
|
39
|
+
Requires-Dist: flatagents>=0.10.0; extra == 'local'
|
|
40
|
+
Requires-Dist: jsonschema>=4.0; extra == 'local'
|
|
41
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'local'
|
|
42
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'local'
|
|
43
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'local'
|
|
44
|
+
Requires-Dist: smolagents; extra == 'local'
|
|
45
|
+
Provides-Extra: metrics
|
|
46
|
+
Requires-Dist: opentelemetry-api>=1.20.0; extra == 'metrics'
|
|
47
|
+
Requires-Dist: opentelemetry-exporter-otlp>=1.20.0; extra == 'metrics'
|
|
48
|
+
Requires-Dist: opentelemetry-sdk>=1.20.0; extra == 'metrics'
|
|
49
|
+
Provides-Extra: smolagents
|
|
50
|
+
Requires-Dist: smolagents; extra == 'smolagents'
|
|
51
|
+
Provides-Extra: validation
|
|
52
|
+
Requires-Dist: jsonschema>=4.0; extra == 'validation'
|
|
53
|
+
Description-Content-Type: text/markdown
|
|
54
|
+
|
|
55
|
+
# FlatAgents
|
|
56
|
+
|
|
57
|
+
Define LLM agents in YAML. Run them anywhere.
|
|
58
|
+
|
|
59
|
+
**For LLM/machine readers:** see [MACHINES.md](./MACHINES.md) for comprehensive reference.
|
|
60
|
+
|
|
61
|
+
## Why?
|
|
62
|
+
|
|
63
|
+
- **Composition over inheritance** — compose stateless agents and checkpointable machines
|
|
64
|
+
- **Compact structure** — easy for LLMs to read and generate
|
|
65
|
+
- **Simple hook interfaces** — escape hatches without complexity; webhook ready
|
|
66
|
+
- **Inspectable** — every agent and machine is readable config
|
|
67
|
+
- **Language-agnostic** — reduce code in any particular runtime
|
|
68
|
+
- **Common TypeScript interface** — single schema for agents, single schema for machines
|
|
69
|
+
- **Limitations** — machine topologies can get complex at scale
|
|
70
|
+
|
|
71
|
+
*Inspired by Kubernetes manifests and character card specifications.*
|
|
72
|
+
|
|
73
|
+
## Versioning
|
|
74
|
+
|
|
75
|
+
All specs (`flatagent.d.ts`, `flatmachine.d.ts`, `profiles.d.ts`) and SDKs (Python, JS) use **lockstep versioning**. A single version number applies across the entire repository.
|
|
76
|
+
|
|
77
|
+
## Core Concepts
|
|
78
|
+
|
|
79
|
+
Use machines to write flatagents and flatmachines, they are designed for LLMs.
|
|
80
|
+
|
|
81
|
+
| Term | What it is |
|
|
82
|
+
|------|------------|
|
|
83
|
+
| **FlatAgent** | A single LLM call: model + prompts + output schema |
|
|
84
|
+
| **FlatMachine** | A state machine that orchestrates multiple agents, actions, and state machines |
|
|
85
|
+
|
|
86
|
+
Use FlatAgent alone for simple tasks. Use FlatMachine when you need multi-step workflows, branching, or error handling.
|
|
87
|
+
|
|
88
|
+
## Examples
|
|
89
|
+
|
|
90
|
+
| Example | What it demonstrates |
|
|
91
|
+
|---------|---------------------|
|
|
92
|
+
| [helloworld](./sdk/examples/helloworld/python) | Minimal setup — single agent, single state machine |
|
|
93
|
+
| [writer_critic](./sdk/examples/writer_critic/python) | Multi-agent loop — writer drafts, critic reviews, iterates |
|
|
94
|
+
| [story_writer](./sdk/examples/story_writer/python) | Multi-step creative workflow with chapter generation |
|
|
95
|
+
| [human-in-the-loop](./sdk/examples/human-in-the-loop/python) | Pause execution for human approval via hooks |
|
|
96
|
+
| [error_handling](./sdk/examples/error_handling/python) | Error recovery and retry patterns at state machine level |
|
|
97
|
+
| [dynamic_agent](./sdk/examples/dynamic_agent/python) | On-the-fly agent generation from runtime context |
|
|
98
|
+
| [character_card](./sdk/examples/character_card/python) | Loading agent config from character card format |
|
|
99
|
+
| [mdap](./sdk/examples/mdap/python) | MDAP voting execution — multi-sample consensus |
|
|
100
|
+
| [gepa_self_optimizer](./sdk/examples/gepa_self_optimizer/python) | Self-optimizing prompts via reflection and critique |
|
|
101
|
+
| [research_paper_analysis](./sdk/examples/research_paper_analysis/python) | Document analysis with structured extraction |
|
|
102
|
+
| [multi_paper_synthesizer](./sdk/examples/multi_paper_synthesizer/python) | Cross-document synthesis with dynamic machine launching |
|
|
103
|
+
| [support_triage_json](./sdk/examples/support_triage_json/python) | JSON input/output with classification pipeline |
|
|
104
|
+
| [distributed_worker](./sdk/examples/distributed_worker/python) | Worker pool with registration + work backends, scaling, stale worker reaping |
|
|
105
|
+
| [parallelism](./sdk/examples/parallelism/python) | Parallel machines, dynamic foreach, fire-and-forget launches |
|
|
106
|
+
|
|
107
|
+
## Quick Start
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
pip install flatagents[all]
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
from flatagents import FlatAgent
|
|
115
|
+
|
|
116
|
+
agent = FlatAgent(config_file="reviewer.yml")
|
|
117
|
+
result = await agent.call(query="Review this code...")
|
|
118
|
+
print(result.output)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Example Agent
|
|
122
|
+
|
|
123
|
+
**reviewer.yml**
|
|
124
|
+
```yaml
|
|
125
|
+
spec: flatagent
|
|
126
|
+
spec_version: "1.0.0"
|
|
127
|
+
|
|
128
|
+
data:
|
|
129
|
+
name: code-reviewer
|
|
130
|
+
|
|
131
|
+
model: "smart-expensive" # Reference profile from profiles.yml
|
|
132
|
+
|
|
133
|
+
system: |
|
|
134
|
+
You are a senior code reviewer. Analyze code for bugs,
|
|
135
|
+
style issues, and potential improvements.
|
|
136
|
+
|
|
137
|
+
user: |
|
|
138
|
+
Review this code:
|
|
139
|
+
{{ input.code }}
|
|
140
|
+
|
|
141
|
+
output:
|
|
142
|
+
issues:
|
|
143
|
+
type: list
|
|
144
|
+
items:
|
|
145
|
+
type: str
|
|
146
|
+
description: "List of issues found"
|
|
147
|
+
rating:
|
|
148
|
+
type: str
|
|
149
|
+
enum: ["good", "needs_work", "critical"]
|
|
150
|
+
description: "Overall code quality"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**What the fields mean:**
|
|
154
|
+
|
|
155
|
+
- **spec/spec_version** — Format identifier and version
|
|
156
|
+
- **data.name** — Agent identifier
|
|
157
|
+
- **data.model** — Profile name, inline config, or profile with overrides
|
|
158
|
+
- **data.system** — System prompt (sets behavior)
|
|
159
|
+
- **data.user** — User prompt template (uses Jinja2, `{{ input.* }}` for runtime values)
|
|
160
|
+
- **data.output** — Structured output schema (the runtime extracts these fields)
|
|
161
|
+
|
|
162
|
+
## Model Profiles
|
|
163
|
+
|
|
164
|
+
Centralize model configurations in `profiles.yml` and reference them by name:
|
|
165
|
+
|
|
166
|
+
**profiles.yml**
|
|
167
|
+
```yaml
|
|
168
|
+
spec: flatprofiles
|
|
169
|
+
spec_version: "1.0.0"
|
|
170
|
+
|
|
171
|
+
data:
|
|
172
|
+
model_profiles:
|
|
173
|
+
fast-cheap:
|
|
174
|
+
provider: cerebras
|
|
175
|
+
name: zai-glm-4.6
|
|
176
|
+
temperature: 0.6
|
|
177
|
+
max_tokens: 2048
|
|
178
|
+
|
|
179
|
+
smart-expensive:
|
|
180
|
+
provider: anthropic
|
|
181
|
+
name: claude-3-opus-20240229
|
|
182
|
+
temperature: 0.3
|
|
183
|
+
max_tokens: 4096
|
|
184
|
+
|
|
185
|
+
default: fast-cheap # Fallback when agent has no model
|
|
186
|
+
# override: smart-expensive # Uncomment to force all agents
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Agent usage:**
|
|
190
|
+
```yaml
|
|
191
|
+
# String shorthand — profile lookup
|
|
192
|
+
model: "fast-cheap"
|
|
193
|
+
|
|
194
|
+
# Profile with overrides
|
|
195
|
+
model:
|
|
196
|
+
profile: "fast-cheap"
|
|
197
|
+
temperature: 0.9
|
|
198
|
+
|
|
199
|
+
# Inline config (no profile)
|
|
200
|
+
model:
|
|
201
|
+
provider: openai
|
|
202
|
+
name: gpt-4
|
|
203
|
+
temperature: 0.3
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
Resolution order (low → high): default profile → named profile → inline overrides → override profile
|
|
207
|
+
|
|
208
|
+
## Output Types
|
|
209
|
+
|
|
210
|
+
```yaml
|
|
211
|
+
output:
|
|
212
|
+
answer: { type: str }
|
|
213
|
+
count: { type: int }
|
|
214
|
+
score: { type: float }
|
|
215
|
+
valid: { type: bool }
|
|
216
|
+
raw: { type: json }
|
|
217
|
+
items: { type: list, items: { type: str } }
|
|
218
|
+
metadata: { type: object, properties: { key: { type: str } } }
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Use `enum: [...]` to constrain string values.
|
|
222
|
+
|
|
223
|
+
## Multi-Agent Workflows
|
|
224
|
+
|
|
225
|
+
For orchestration, use FlatMachine ([full docs in MACHINES.md](./MACHINES.md)):
|
|
226
|
+
|
|
227
|
+
```python
|
|
228
|
+
from flatagents import FlatMachine
|
|
229
|
+
|
|
230
|
+
machine = FlatMachine(config_file="workflow.yml")
|
|
231
|
+
result = await machine.execute(input={"query": "..."})
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
FlatMachine provides: state transitions, conditional branching, loops, retry with backoff, and error recovery—all in YAML.
|
|
235
|
+
|
|
236
|
+
## Distributed Worker Pattern
|
|
237
|
+
|
|
238
|
+
FlatAgents includes `DistributedWorkerHooks` plus `RegistrationBackend`/`WorkBackend` implementations (SQLite in the reference SDK) to build worker pools.
|
|
239
|
+
|
|
240
|
+
Typical topology:
|
|
241
|
+
- **Checker**: `get_pool_state` → `calculate_spawn` → `spawn_workers` (requires `worker_config_path` in context or override in hooks)
|
|
242
|
+
- **Worker**: `register_worker` → `claim_job` → process → `complete_job`/`fail_job` → `deregister_worker`
|
|
243
|
+
- **Reaper**: `list_stale_workers` → `reap_stale_workers`
|
|
244
|
+
|
|
245
|
+
See [distributed_worker](./sdk/examples/distributed_worker/python) for a runnable demo.
|
|
246
|
+
|
|
247
|
+
## Features
|
|
248
|
+
|
|
249
|
+
- Checkpoint and restore
|
|
250
|
+
- Python SDK (TypeScript SDK in progress)
|
|
251
|
+
- [MACHINES.md](./MACHINES.md) — LLM-optimized reference docs
|
|
252
|
+
- Decider agents and machines
|
|
253
|
+
- On-the-fly agent and machine definitions
|
|
254
|
+
- Webhook hooks for remote state machine handling
|
|
255
|
+
- Metrics and logging
|
|
256
|
+
- Error recovery and exception handling at the state machine level
|
|
257
|
+
- Parallel machine execution (`machine: [a, b, c]`)
|
|
258
|
+
- Dynamic parallelism with `foreach`
|
|
259
|
+
- Fire-and-forget launches for background tasks
|
|
260
|
+
- Distributed worker orchestration (registration/work backends, scaling hooks, stale worker reaping)
|
|
261
|
+
|
|
262
|
+
## Planned
|
|
263
|
+
|
|
264
|
+
- Distributed execution backends (Redis/Postgres) + cross-network peering strategies
|
|
265
|
+
- SQL persistence backend
|
|
266
|
+
- TypeScript SDK
|
|
267
|
+
- `max_depth` config to limit machine launch nesting
|
|
268
|
+
- Checkpoint pruning to prevent storage explosion
|
|
269
|
+
- `$root/` path prefix — resolve agent/machine refs from workspace root, not config dir
|
|
270
|
+
- Input size validation — warn when prompt exceeds model context window
|
|
271
|
+
- Serialization warnings — flag non-JSON-serializable context values before checkpoint
|
|
272
|
+
|
|
273
|
+
## Specs
|
|
274
|
+
|
|
275
|
+
TypeScript definitions are the source of truth:
|
|
276
|
+
- [`flatagent.d.ts`](./flatagent.d.ts)
|
|
277
|
+
- [`flatmachine.d.ts`](./flatmachine.d.ts)
|
|
278
|
+
- [`profiles.d.ts`](./profiles.d.ts)
|
|
279
|
+
|
|
280
|
+
## Python SDK
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
pip install flatagents[litellm]
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
### LLM Backends
|
|
287
|
+
|
|
288
|
+
```python
|
|
289
|
+
from flatagents import LiteLLMBackend, AISuiteBackend
|
|
290
|
+
|
|
291
|
+
# LiteLLM (default)
|
|
292
|
+
agent = FlatAgent(config_file="agent.yml")
|
|
293
|
+
|
|
294
|
+
# AISuite
|
|
295
|
+
backend = AISuiteBackend(model="openai:gpt-4o")
|
|
296
|
+
agent = FlatAgent(config_file="agent.yml", backend=backend)
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
### Hooks
|
|
300
|
+
|
|
301
|
+
Extend machine behavior with Python hooks:
|
|
302
|
+
|
|
303
|
+
```python
|
|
304
|
+
from flatagents import FlatMachine, MachineHooks
|
|
305
|
+
|
|
306
|
+
class CustomHooks(MachineHooks):
|
|
307
|
+
def on_state_enter(self, state: str, context: dict) -> dict:
|
|
308
|
+
context["entered_at"] = time.time()
|
|
309
|
+
return context
|
|
310
|
+
|
|
311
|
+
def on_action(self, action: str, context: dict) -> dict:
|
|
312
|
+
if action == "fetch_data":
|
|
313
|
+
context["data"] = fetch_from_api()
|
|
314
|
+
return context
|
|
315
|
+
|
|
316
|
+
machine = FlatMachine(config_file="machine.yml", hooks=CustomHooks())
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Available hooks**: `on_machine_start`, `on_machine_end`, `on_state_enter`, `on_state_exit`, `on_transition`, `on_error`, `on_action`
|
|
320
|
+
|
|
321
|
+
### Execution Types
|
|
322
|
+
|
|
323
|
+
```yaml
|
|
324
|
+
execution:
|
|
325
|
+
type: retry # retry | parallel | mdap_voting
|
|
326
|
+
backoffs: [2, 8, 16, 35] # Seconds between retries
|
|
327
|
+
jitter: 0.1 # ±10% random variation
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
| Type | Use Case |
|
|
331
|
+
|------|----------|
|
|
332
|
+
| `default` | Single call |
|
|
333
|
+
| `retry` | Rate limit handling with backoff |
|
|
334
|
+
| `parallel` | Multiple samples (`n_samples`) |
|
|
335
|
+
| `mdap_voting` | Consensus voting (`k_margin`, `max_candidates`) |
|
|
336
|
+
|
|
337
|
+
### Schema Validation
|
|
338
|
+
|
|
339
|
+
```python
|
|
340
|
+
from flatagents import validate_flatagent_config, validate_flatmachine_config
|
|
341
|
+
|
|
342
|
+
warnings = validate_flatagent_config(config)
|
|
343
|
+
warnings = validate_flatmachine_config(config)
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### Logging & Metrics
|
|
347
|
+
|
|
348
|
+
```python
|
|
349
|
+
from flatagents import setup_logging, get_logger
|
|
350
|
+
|
|
351
|
+
setup_logging(level="INFO") # Respects FLATAGENTS_LOG_LEVEL env var
|
|
352
|
+
logger = get_logger(__name__)
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
**Env vars**: `FLATAGENTS_LOG_LEVEL` (`DEBUG`/`INFO`/`WARNING`/`ERROR`), `FLATAGENTS_LOG_FORMAT` (`standard`/`json`/`simple`)
|
|
356
|
+
|
|
357
|
+
For OpenTelemetry metrics:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
pip install flatagents[metrics]
|
|
361
|
+
export FLATAGENTS_METRICS_ENABLED=true
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
Metrics are enabled by default and print to stdout every 5s. Redirect to file or use OTLP for production:
|
|
365
|
+
|
|
366
|
+
```bash
|
|
367
|
+
# Metrics print to stdout by default
|
|
368
|
+
python your_script.py
|
|
369
|
+
|
|
370
|
+
# Save to file
|
|
371
|
+
python your_script.py >> metrics.log 2>&1
|
|
372
|
+
|
|
373
|
+
# Disable if needed
|
|
374
|
+
FLATAGENTS_METRICS_ENABLED=false python your_script.py
|
|
375
|
+
|
|
376
|
+
# Send to OTLP collector for production
|
|
377
|
+
OTEL_METRICS_EXPORTER=otlp \
|
|
378
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
|
|
379
|
+
python your_script.py
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
**Env vars for metrics**:
|
|
383
|
+
|
|
384
|
+
| Variable | Default | Purpose |
|
|
385
|
+
|----------|---------|---------|
|
|
386
|
+
| `FLATAGENTS_METRICS_ENABLED` | `true` | Enable OpenTelemetry metrics |
|
|
387
|
+
| `OTEL_METRICS_EXPORTER` | `console` | `console` (stdout) or `otlp` (production) |
|
|
388
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint |
|
|
389
|
+
| `OTEL_METRIC_EXPORT_INTERVAL` | `5000` / `60000` | Export interval in ms (5s for console, 60s for otlp) |
|
|
390
|
+
| `OTEL_SERVICE_NAME` | `flatagents` | Service name in metrics |
|