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.
Files changed (43) hide show
  1. flatmachines-1.0.0/.gitignore +13 -0
  2. flatmachines-1.0.0/MACHINES.md +141 -0
  3. flatmachines-1.0.0/PKG-INFO +390 -0
  4. flatmachines-1.0.0/README.md +336 -0
  5. flatmachines-1.0.0/flatmachines/__init__.py +136 -0
  6. flatmachines-1.0.0/flatmachines/actions.py +408 -0
  7. flatmachines-1.0.0/flatmachines/adapters/__init__.py +38 -0
  8. flatmachines-1.0.0/flatmachines/adapters/flatagent.py +86 -0
  9. flatmachines-1.0.0/flatmachines/adapters/pi_agent_bridge.py +127 -0
  10. flatmachines-1.0.0/flatmachines/adapters/pi_agent_runner.mjs +99 -0
  11. flatmachines-1.0.0/flatmachines/adapters/smolagents.py +125 -0
  12. flatmachines-1.0.0/flatmachines/agents.py +144 -0
  13. flatmachines-1.0.0/flatmachines/assets/MACHINES.md +141 -0
  14. flatmachines-1.0.0/flatmachines/assets/README.md +11 -0
  15. flatmachines-1.0.0/flatmachines/assets/__init__.py +0 -0
  16. flatmachines-1.0.0/flatmachines/assets/flatagent.d.ts +219 -0
  17. flatmachines-1.0.0/flatmachines/assets/flatagent.schema.json +271 -0
  18. flatmachines-1.0.0/flatmachines/assets/flatagent.slim.d.ts +58 -0
  19. flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.d.ts +523 -0
  20. flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.schema.json +281 -0
  21. flatmachines-1.0.0/flatmachines/assets/flatagents-runtime.slim.d.ts +187 -0
  22. flatmachines-1.0.0/flatmachines/assets/flatmachine.d.ts +403 -0
  23. flatmachines-1.0.0/flatmachines/assets/flatmachine.schema.json +620 -0
  24. flatmachines-1.0.0/flatmachines/assets/flatmachine.slim.d.ts +106 -0
  25. flatmachines-1.0.0/flatmachines/assets/profiles.d.ts +140 -0
  26. flatmachines-1.0.0/flatmachines/assets/profiles.schema.json +93 -0
  27. flatmachines-1.0.0/flatmachines/assets/profiles.slim.d.ts +26 -0
  28. flatmachines-1.0.0/flatmachines/backends.py +222 -0
  29. flatmachines-1.0.0/flatmachines/distributed.py +835 -0
  30. flatmachines-1.0.0/flatmachines/distributed_hooks.py +351 -0
  31. flatmachines-1.0.0/flatmachines/execution.py +638 -0
  32. flatmachines-1.0.0/flatmachines/expressions/__init__.py +60 -0
  33. flatmachines-1.0.0/flatmachines/expressions/cel.py +101 -0
  34. flatmachines-1.0.0/flatmachines/expressions/simple.py +166 -0
  35. flatmachines-1.0.0/flatmachines/flatmachine.py +1263 -0
  36. flatmachines-1.0.0/flatmachines/hooks.py +381 -0
  37. flatmachines-1.0.0/flatmachines/locking.py +69 -0
  38. flatmachines-1.0.0/flatmachines/monitoring.py +505 -0
  39. flatmachines-1.0.0/flatmachines/persistence.py +213 -0
  40. flatmachines-1.0.0/flatmachines/run.py +117 -0
  41. flatmachines-1.0.0/flatmachines/utils.py +166 -0
  42. flatmachines-1.0.0/flatmachines/validation.py +79 -0
  43. flatmachines-1.0.0/pyproject.toml +71 -0
@@ -0,0 +1,13 @@
1
+ .env
2
+ uv.lock
3
+ node_modules
4
+ __pycache__
5
+ dist
6
+ .DS_Store
7
+ .venv
8
+
9
+ .claude
10
+
11
+ local
12
+ data
13
+ .checkpoints
@@ -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 |