@memgrafter/flatagents 0.8.1 → 0.9.0
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.
- package/MACHINES.md +103 -0
- package/README.md +257 -155
- package/package.json +5 -2
- package/schemas/flatagent.d.ts +1 -1
- package/schemas/flatagent.slim.d.ts +1 -1
- package/schemas/flatagents-runtime.d.ts +178 -12
- package/schemas/flatagents-runtime.schema.json +40 -2
- package/schemas/flatagents-runtime.slim.d.ts +53 -1
- package/schemas/flatmachine.d.ts +1 -1
- package/schemas/flatmachine.slim.d.ts +1 -1
- package/schemas/profiles.d.ts +1 -1
- package/schemas/profiles.slim.d.ts +1 -1
package/MACHINES.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
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: "0.9.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
|
+
## State Fields
|
|
38
|
+
|
|
39
|
+
| Field | Purpose |
|
|
40
|
+
|-------|---------|
|
|
41
|
+
| `type` | `initial` (entry) / `final` (exit+output) |
|
|
42
|
+
| `agent` | Agent to call |
|
|
43
|
+
| `machine` | Machine(s) — string or `[array]` for parallel |
|
|
44
|
+
| `foreach` | Array expr for dynamic parallelism (`as`: item var, `key`: result key) |
|
|
45
|
+
| `launch` / `launch_input` | Fire-and-forget machine(s) |
|
|
46
|
+
| `input` | Map input to agent/machine |
|
|
47
|
+
| `output_to_context` | Map `output.*` to `context.*` |
|
|
48
|
+
| `execution` | `{ type: retry, backoffs: [2,8,16], jitter: 0.1 }` |
|
|
49
|
+
| `on_error` | State name or `{ default: x, ErrorType: y }` |
|
|
50
|
+
| `transitions` | `[{ condition: "expr", to: state }, { to: default }]` |
|
|
51
|
+
| `mode` | `settled` (all) / `any` (first) for parallel |
|
|
52
|
+
| `timeout` | Seconds (0=forever) |
|
|
53
|
+
|
|
54
|
+
## Patterns
|
|
55
|
+
|
|
56
|
+
**Execution types**: `default` | `retry` (backoffs, jitter) | `parallel` (n_samples) | `mdap_voting` (k_margin, max_candidates)
|
|
57
|
+
|
|
58
|
+
**Transitions**: `condition: "context.score >= 8"` with `to: state`. Last without condition = default.
|
|
59
|
+
|
|
60
|
+
**Loops**: Transition `to: same_state`. Machine has `max_steps` safety.
|
|
61
|
+
|
|
62
|
+
**Errors**: `on_error: state` or per-type. Context gets `last_error`, `last_error_type`.
|
|
63
|
+
|
|
64
|
+
**Parallel machines**:
|
|
65
|
+
```yaml
|
|
66
|
+
machine: [review_a, review_b] # Results keyed by name
|
|
67
|
+
mode: settled # or "any"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Foreach**:
|
|
71
|
+
```yaml
|
|
72
|
+
foreach: "{{ context.items }}"
|
|
73
|
+
as: item
|
|
74
|
+
machine: processor
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Launch** (fire-and-forget):
|
|
78
|
+
```yaml
|
|
79
|
+
launch: background_task
|
|
80
|
+
launch_input: { data: "{{ context.data }}" }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Context Variables
|
|
84
|
+
|
|
85
|
+
`context.*` (all states), `input.*` (initial), `output.*` (in output_to_context), `item`/`as` (foreach)
|
|
86
|
+
|
|
87
|
+
## Hooks
|
|
88
|
+
|
|
89
|
+
`on_machine_start`, `on_machine_end`, `on_state_enter`, `on_state_exit`, `on_transition`, `on_error`, `on_action`
|
|
90
|
+
|
|
91
|
+
```python
|
|
92
|
+
class MyHooks(MachineHooks):
|
|
93
|
+
def on_action(self, action: str, context: dict) -> dict:
|
|
94
|
+
if action == "fetch": context["data"] = api_call()
|
|
95
|
+
return context
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Persistence
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
persistence: { enabled: true, backend: local } # local | memory
|
|
102
|
+
```
|
|
103
|
+
Resume: `machine.execute(resume_from=execution_id)`
|
package/README.md
CHANGED
|
@@ -1,221 +1,323 @@
|
|
|
1
|
-
# FlatAgents
|
|
1
|
+
# FlatAgents
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Define LLM agents in YAML. Run them anywhere.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
**For LLM/machine readers:** see [MACHINES.md](./MACHINES.md) for comprehensive reference.
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
npm install flatagents
|
|
9
|
-
```
|
|
7
|
+
## Why?
|
|
10
8
|
|
|
11
|
-
|
|
9
|
+
- **Composition over inheritance** — compose stateless agents and checkpointable machines
|
|
10
|
+
- **Compact structure** — easy for LLMs to read and generate
|
|
11
|
+
- **Simple hook interfaces** — escape hatches without complexity; webhook ready
|
|
12
|
+
- **Inspectable** — every agent and machine is readable config
|
|
13
|
+
- **Language-agnostic** — reduce code in any particular runtime
|
|
14
|
+
- **Common TypeScript interface** — single schema for agents, single schema for machines
|
|
15
|
+
- **Limitations** — machine topologies can get complex at scale
|
|
12
16
|
|
|
13
|
-
|
|
17
|
+
*Inspired by Kubernetes manifests and character card specifications.*
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
import { FlatAgent } from 'flatagents';
|
|
19
|
+
## Versioning
|
|
17
20
|
|
|
18
|
-
|
|
19
|
-
const result = await agent.call({ query: "Hello World" });
|
|
20
|
-
console.log(result.output);
|
|
21
|
-
```
|
|
21
|
+
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.
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
## Core Concepts
|
|
24
|
+
|
|
25
|
+
Use machines to write flatagents and flatmachines, they are designed for LLMs.
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
| Term | What it is |
|
|
28
|
+
|------|------------|
|
|
29
|
+
| **FlatAgent** | A single LLM call: model + prompts + output schema |
|
|
30
|
+
| **FlatMachine** | A state machine that orchestrates multiple agents, actions, and state machines |
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
persistence: new MemoryBackend()
|
|
32
|
-
});
|
|
32
|
+
Use FlatAgent alone for simple tasks. Use FlatMachine when you need multi-step workflows, branching, or error handling.
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
+
| Example | What it demonstrates |
|
|
37
|
+
|---------|---------------------|
|
|
38
|
+
| [helloworld](./sdk/examples/helloworld/python) | Minimal setup — single agent, single state machine |
|
|
39
|
+
| [writer_critic](./sdk/examples/writer_critic/python) | Multi-agent loop — writer drafts, critic reviews, iterates |
|
|
40
|
+
| [story_writer](./sdk/examples/story_writer/python) | Multi-step creative workflow with chapter generation |
|
|
41
|
+
| [human-in-the-loop](./sdk/examples/human-in-the-loop/python) | Pause execution for human approval via hooks |
|
|
42
|
+
| [error_handling](./sdk/examples/error_handling/python) | Error recovery and retry patterns at state machine level |
|
|
43
|
+
| [dynamic_agent](./sdk/examples/dynamic_agent/python) | On-the-fly agent generation from runtime context |
|
|
44
|
+
| [character_card](./sdk/examples/character_card/python) | Loading agent config from character card format |
|
|
45
|
+
| [mdap](./sdk/examples/mdap/python) | MDAP voting execution — multi-sample consensus |
|
|
46
|
+
| [gepa_self_optimizer](./sdk/examples/gepa_self_optimizer/python) | Self-optimizing prompts via reflection and critique |
|
|
47
|
+
| [research_paper_analysis](./sdk/examples/research_paper_analysis/python) | Document analysis with structured extraction |
|
|
48
|
+
| [multi_paper_synthesizer](./sdk/examples/multi_paper_synthesizer/python) | Cross-document synthesis with dynamic machine launching |
|
|
49
|
+
| [support_triage_json](./sdk/examples/support_triage_json/python) | JSON input/output with classification pipeline |
|
|
50
|
+
| [parallelism](./sdk/examples/parallelism/python) | Parallel machines, dynamic foreach, fire-and-forget launches |
|
|
51
|
+
|
|
52
|
+
## Quick Start
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install flatagents[all]
|
|
36
56
|
```
|
|
37
57
|
|
|
38
|
-
|
|
58
|
+
```python
|
|
59
|
+
from flatagents import FlatAgent
|
|
60
|
+
|
|
61
|
+
agent = FlatAgent(config_file="reviewer.yml")
|
|
62
|
+
result = await agent.call(query="Review this code...")
|
|
63
|
+
print(result.output)
|
|
64
|
+
```
|
|
39
65
|
|
|
40
|
-
|
|
41
|
-
A single LLM call configured in YAML:
|
|
66
|
+
## Example Agent
|
|
42
67
|
|
|
68
|
+
**reviewer.yml**
|
|
43
69
|
```yaml
|
|
44
70
|
spec: flatagent
|
|
45
|
-
spec_version: "
|
|
71
|
+
spec_version: "0.8.2"
|
|
72
|
+
|
|
46
73
|
data:
|
|
47
|
-
name:
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
system:
|
|
52
|
-
|
|
74
|
+
name: code-reviewer
|
|
75
|
+
|
|
76
|
+
model: "smart-expensive" # Reference profile from profiles.yml
|
|
77
|
+
|
|
78
|
+
system: |
|
|
79
|
+
You are a senior code reviewer. Analyze code for bugs,
|
|
80
|
+
style issues, and potential improvements.
|
|
81
|
+
|
|
82
|
+
user: |
|
|
83
|
+
Review this code:
|
|
84
|
+
{{ input.code }}
|
|
85
|
+
|
|
53
86
|
output:
|
|
54
|
-
|
|
87
|
+
issues:
|
|
88
|
+
type: list
|
|
89
|
+
items:
|
|
90
|
+
type: str
|
|
91
|
+
description: "List of issues found"
|
|
92
|
+
rating:
|
|
55
93
|
type: str
|
|
56
|
-
|
|
94
|
+
enum: ["good", "needs_work", "critical"]
|
|
95
|
+
description: "Overall code quality"
|
|
57
96
|
```
|
|
58
97
|
|
|
59
|
-
|
|
60
|
-
A state machine that orchestrates agents:
|
|
98
|
+
**What the fields mean:**
|
|
61
99
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
data
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
result: ""
|
|
69
|
-
states:
|
|
70
|
-
initial:
|
|
71
|
-
type: initial
|
|
72
|
-
agent: agent.yml
|
|
73
|
-
transitions:
|
|
74
|
-
- to: final
|
|
75
|
-
final:
|
|
76
|
-
type: final
|
|
77
|
-
output:
|
|
78
|
-
result: "{{ context.result }}"
|
|
79
|
-
```
|
|
100
|
+
- **spec/spec_version** — Format identifier and version
|
|
101
|
+
- **data.name** — Agent identifier
|
|
102
|
+
- **data.model** — Profile name, inline config, or profile with overrides
|
|
103
|
+
- **data.system** — System prompt (sets behavior)
|
|
104
|
+
- **data.user** — User prompt template (uses Jinja2, `{{ input.* }}` for runtime values)
|
|
105
|
+
- **data.output** — Structured output schema (the runtime extracts these fields)
|
|
80
106
|
|
|
81
|
-
##
|
|
107
|
+
## Model Profiles
|
|
82
108
|
|
|
83
|
-
|
|
109
|
+
Centralize model configurations in `profiles.yml` and reference them by name:
|
|
110
|
+
|
|
111
|
+
**profiles.yml**
|
|
84
112
|
```yaml
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
113
|
+
spec: flatprofiles
|
|
114
|
+
spec_version: "0.8.2"
|
|
115
|
+
|
|
116
|
+
data:
|
|
117
|
+
model_profiles:
|
|
118
|
+
fast-cheap:
|
|
119
|
+
provider: cerebras
|
|
120
|
+
name: zai-glm-4.6
|
|
121
|
+
temperature: 0.6
|
|
122
|
+
max_tokens: 2048
|
|
123
|
+
|
|
124
|
+
smart-expensive:
|
|
125
|
+
provider: anthropic
|
|
126
|
+
name: claude-3-opus-20240229
|
|
127
|
+
temperature: 0.3
|
|
128
|
+
max_tokens: 4096
|
|
129
|
+
|
|
130
|
+
default: fast-cheap # Fallback when agent has no model
|
|
131
|
+
# override: smart-expensive # Uncomment to force all agents
|
|
90
132
|
```
|
|
91
133
|
|
|
92
|
-
|
|
134
|
+
**Agent usage:**
|
|
93
135
|
```yaml
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
136
|
+
# String shorthand — profile lookup
|
|
137
|
+
model: "fast-cheap"
|
|
138
|
+
|
|
139
|
+
# Profile with overrides
|
|
140
|
+
model:
|
|
141
|
+
profile: "fast-cheap"
|
|
142
|
+
temperature: 0.9
|
|
143
|
+
|
|
144
|
+
# Inline config (no profile)
|
|
145
|
+
model:
|
|
146
|
+
provider: openai
|
|
147
|
+
name: gpt-4
|
|
148
|
+
temperature: 0.3
|
|
101
149
|
```
|
|
102
150
|
|
|
103
|
-
|
|
151
|
+
Resolution order (low → high): default profile → named profile → inline overrides → override profile
|
|
152
|
+
|
|
153
|
+
## Output Types
|
|
154
|
+
|
|
104
155
|
```yaml
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
156
|
+
output:
|
|
157
|
+
answer: { type: str }
|
|
158
|
+
count: { type: int }
|
|
159
|
+
score: { type: float }
|
|
160
|
+
valid: { type: bool }
|
|
161
|
+
raw: { type: json }
|
|
162
|
+
items: { type: list, items: { type: str } }
|
|
163
|
+
metadata: { type: object, properties: { key: { type: str } } }
|
|
112
164
|
```
|
|
113
165
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
166
|
+
Use `enum: [...]` to constrain string values.
|
|
167
|
+
|
|
168
|
+
## Multi-Agent Workflows
|
|
169
|
+
|
|
170
|
+
For orchestration, use FlatMachine ([full docs in MACHINES.md](./MACHINES.md)):
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from flatagents import FlatMachine
|
|
174
|
+
|
|
175
|
+
machine = FlatMachine(config_file="workflow.yml")
|
|
176
|
+
result = await machine.execute(input={"query": "..."})
|
|
123
177
|
```
|
|
124
178
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
179
|
+
FlatMachine provides: state transitions, conditional branching, loops, retry with backoff, and error recovery—all in YAML.
|
|
180
|
+
|
|
181
|
+
## Features
|
|
182
|
+
|
|
183
|
+
- Checkpoint and restore
|
|
184
|
+
- Python SDK (TypeScript SDK in progress)
|
|
185
|
+
- [MACHINES.md](./MACHINES.md) — LLM-optimized reference docs
|
|
186
|
+
- Decider agents and machines
|
|
187
|
+
- On-the-fly agent and machine definitions
|
|
188
|
+
- Webhook hooks for remote state machine handling
|
|
189
|
+
- Metrics and logging
|
|
190
|
+
- Error recovery and exception handling at the state machine level
|
|
191
|
+
- Parallel machine execution (`machine: [a, b, c]`)
|
|
192
|
+
- Dynamic parallelism with `foreach`
|
|
193
|
+
- Fire-and-forget launches for background tasks
|
|
194
|
+
|
|
195
|
+
## Planned
|
|
196
|
+
|
|
197
|
+
- Distributed execution — cross-network machine peering, inter-machine strategies
|
|
198
|
+
- SQL persistence backend
|
|
199
|
+
- TypeScript SDK
|
|
200
|
+
- `max_depth` config to limit machine launch nesting
|
|
201
|
+
- Checkpoint pruning to prevent storage explosion
|
|
202
|
+
- `$root/` path prefix — resolve agent/machine refs from workspace root, not config dir
|
|
203
|
+
- Input size validation — warn when prompt exceeds model context window
|
|
204
|
+
- Serialization warnings — flag non-JSON-serializable context values before checkpoint
|
|
205
|
+
|
|
206
|
+
## Specs
|
|
207
|
+
|
|
208
|
+
TypeScript definitions are the source of truth:
|
|
209
|
+
- [`flatagent.d.ts`](./flatagent.d.ts)
|
|
210
|
+
- [`flatmachine.d.ts`](./flatmachine.d.ts)
|
|
211
|
+
- [`profiles.d.ts`](./profiles.d.ts)
|
|
212
|
+
|
|
213
|
+
## Python SDK
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
pip install flatagents[litellm]
|
|
131
217
|
```
|
|
132
218
|
|
|
133
|
-
###
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
219
|
+
### LLM Backends
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
from flatagents import LiteLLMBackend, AISuiteBackend
|
|
223
|
+
|
|
224
|
+
# LiteLLM (default)
|
|
225
|
+
agent = FlatAgent(config_file="agent.yml")
|
|
226
|
+
|
|
227
|
+
# AISuite
|
|
228
|
+
backend = AISuiteBackend(model="openai:gpt-4o")
|
|
229
|
+
agent = FlatAgent(config_file="agent.yml", backend=backend)
|
|
138
230
|
```
|
|
139
231
|
|
|
140
|
-
|
|
232
|
+
### Hooks
|
|
233
|
+
|
|
234
|
+
Extend machine behavior with Python hooks:
|
|
235
|
+
|
|
236
|
+
```python
|
|
237
|
+
from flatagents import FlatMachine, MachineHooks
|
|
141
238
|
|
|
142
|
-
|
|
239
|
+
class CustomHooks(MachineHooks):
|
|
240
|
+
def on_state_enter(self, state: str, context: dict) -> dict:
|
|
241
|
+
context["entered_at"] = time.time()
|
|
242
|
+
return context
|
|
143
243
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return context;
|
|
149
|
-
}
|
|
244
|
+
def on_action(self, action: str, context: dict) -> dict:
|
|
245
|
+
if action == "fetch_data":
|
|
246
|
+
context["data"] = fetch_from_api()
|
|
247
|
+
return context
|
|
150
248
|
|
|
151
|
-
|
|
152
|
-
console.error(`Error in ${state}:`, error);
|
|
153
|
-
return "recovery_state";
|
|
154
|
-
}
|
|
155
|
-
}
|
|
249
|
+
machine = FlatMachine(config_file="machine.yml", hooks=CustomHooks())
|
|
156
250
|
```
|
|
157
251
|
|
|
158
|
-
|
|
252
|
+
**Available hooks**: `on_machine_start`, `on_machine_end`, `on_state_enter`, `on_state_exit`, `on_transition`, `on_error`, `on_action`
|
|
253
|
+
|
|
254
|
+
### Execution Types
|
|
159
255
|
|
|
160
256
|
```yaml
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
command: "npx"
|
|
166
|
-
args: ["@modelcontextprotocol/server-filesystem", "/path/to/files"]
|
|
167
|
-
tool_filter:
|
|
168
|
-
allow: ["filesystem:*"]
|
|
257
|
+
execution:
|
|
258
|
+
type: retry # retry | parallel | mdap_voting
|
|
259
|
+
backoffs: [2, 8, 16, 35] # Seconds between retries
|
|
260
|
+
jitter: 0.1 # ±10% random variation
|
|
169
261
|
```
|
|
170
262
|
|
|
171
|
-
|
|
263
|
+
| Type | Use Case |
|
|
264
|
+
|------|----------|
|
|
265
|
+
| `default` | Single call |
|
|
266
|
+
| `retry` | Rate limit handling with backoff |
|
|
267
|
+
| `parallel` | Multiple samples (`n_samples`) |
|
|
268
|
+
| `mdap_voting` | Consensus voting (`k_margin`, `max_candidates`) |
|
|
172
269
|
|
|
173
|
-
|
|
174
|
-
- **Parallelism**: Machine arrays, foreach loops, and fire-and-forget patterns
|
|
175
|
-
- **Human-in-the-loop**: Custom hooks for interactive approval flows
|
|
176
|
-
- **Peering**: Parent-child machine communication with result backends
|
|
270
|
+
### Schema Validation
|
|
177
271
|
|
|
178
|
-
|
|
272
|
+
```python
|
|
273
|
+
from flatagents import validate_flatagent_config, validate_flatmachine_config
|
|
179
274
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
class FlatAgent {
|
|
183
|
-
constructor(config: AgentConfig | string);
|
|
184
|
-
async call(input: Record<string, any>): Promise<{content: string, output: any}>;
|
|
185
|
-
}
|
|
275
|
+
warnings = validate_flatagent_config(config)
|
|
276
|
+
warnings = validate_flatmachine_config(config)
|
|
186
277
|
```
|
|
187
278
|
|
|
188
|
-
###
|
|
189
|
-
```typescript
|
|
190
|
-
class FlatMachine {
|
|
191
|
-
constructor(options: MachineOptions);
|
|
192
|
-
async execute(input?: Record<string, any>): Promise<any>;
|
|
193
|
-
async resume(executionId: string): Promise<any>;
|
|
194
|
-
}
|
|
195
|
-
```
|
|
279
|
+
### Logging & Metrics
|
|
196
280
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
281
|
+
```python
|
|
282
|
+
from flatagents import setup_logging, get_logger
|
|
283
|
+
|
|
284
|
+
setup_logging(level="INFO") # Respects FLATAGENTS_LOG_LEVEL env var
|
|
285
|
+
logger = get_logger(__name__)
|
|
286
|
+
```
|
|
200
287
|
|
|
201
|
-
|
|
202
|
-
- `MemoryBackend`: In-memory storage
|
|
203
|
-
- `LocalFileBackend`: File-based with atomic writes
|
|
288
|
+
**Env vars**: `FLATAGENTS_LOG_LEVEL` (`DEBUG`/`INFO`/`WARNING`/`ERROR`), `FLATAGENTS_LOG_FORMAT` (`standard`/`json`/`simple`)
|
|
204
289
|
|
|
205
|
-
|
|
290
|
+
For OpenTelemetry metrics:
|
|
206
291
|
|
|
207
292
|
```bash
|
|
208
|
-
|
|
209
|
-
|
|
293
|
+
pip install flatagents[metrics]
|
|
294
|
+
export FLATAGENTS_METRICS_ENABLED=true
|
|
210
295
|
```
|
|
211
296
|
|
|
212
|
-
|
|
297
|
+
Metrics are enabled by default and print to stdout every 5s. Redirect to file or use OTLP for production:
|
|
213
298
|
|
|
214
299
|
```bash
|
|
215
|
-
|
|
216
|
-
|
|
300
|
+
# Metrics print to stdout by default
|
|
301
|
+
python your_script.py
|
|
302
|
+
|
|
303
|
+
# Save to file
|
|
304
|
+
python your_script.py >> metrics.log 2>&1
|
|
305
|
+
|
|
306
|
+
# Disable if needed
|
|
307
|
+
FLATAGENTS_METRICS_ENABLED=false python your_script.py
|
|
308
|
+
|
|
309
|
+
# Send to OTLP collector for production
|
|
310
|
+
OTEL_METRICS_EXPORTER=otlp \
|
|
311
|
+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 \
|
|
312
|
+
python your_script.py
|
|
217
313
|
```
|
|
218
314
|
|
|
219
|
-
|
|
315
|
+
**Env vars for metrics**:
|
|
220
316
|
|
|
221
|
-
|
|
317
|
+
| Variable | Default | Purpose |
|
|
318
|
+
|----------|---------|---------|
|
|
319
|
+
| `FLATAGENTS_METRICS_ENABLED` | `true` | Enable OpenTelemetry metrics |
|
|
320
|
+
| `OTEL_METRICS_EXPORTER` | `console` | `console` (stdout) or `otlp` (production) |
|
|
321
|
+
| `OTEL_EXPORTER_OTLP_ENDPOINT` | — | OTLP collector endpoint |
|
|
322
|
+
| `OTEL_METRIC_EXPORT_INTERVAL` | `5000` / `60000` | Export interval in ms (5s for console, 60s for otlp) |
|
|
323
|
+
| `OTEL_SERVICE_NAME` | `flatagents` | Service name in metrics |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@memgrafter/flatagents",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "TypeScript SDK for FlatAgents - Declarative LLM orchestration with YAML",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -17,7 +17,10 @@
|
|
|
17
17
|
},
|
|
18
18
|
"files": [
|
|
19
19
|
"dist",
|
|
20
|
-
"schemas"
|
|
20
|
+
"schemas",
|
|
21
|
+
"MACHINES.md",
|
|
22
|
+
"AGENTS.md",
|
|
23
|
+
"CLAUDE.md"
|
|
21
24
|
],
|
|
22
25
|
"scripts": {
|
|
23
26
|
"build": "tsup",
|
package/schemas/flatagent.d.ts
CHANGED
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
* - ResultBackend: InMemoryResultBackend (MUST)
|
|
14
14
|
* - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST)
|
|
15
15
|
* - MachineHooks: Base interface (MUST)
|
|
16
|
+
* - RegistrationBackend: SQLiteRegistrationBackend (MUST), MemoryRegistrationBackend (SHOULD)
|
|
17
|
+
* - WorkBackend: SQLiteWorkBackend (MUST), MemoryWorkBackend (SHOULD)
|
|
16
18
|
*
|
|
17
19
|
* OPTIONAL IMPLEMENTATIONS:
|
|
18
20
|
* -------------------------
|
|
@@ -314,6 +316,158 @@ export interface LaunchIntent {
|
|
|
314
316
|
launched: boolean;
|
|
315
317
|
}
|
|
316
318
|
|
|
319
|
+
/**
|
|
320
|
+
* REGISTRATION BACKEND:
|
|
321
|
+
* ---------------------
|
|
322
|
+
* Worker lifecycle management for distributed execution.
|
|
323
|
+
*
|
|
324
|
+
* SDKs MUST provide:
|
|
325
|
+
* - SQLiteRegistrationBackend: For local deployments
|
|
326
|
+
*
|
|
327
|
+
* SDKs SHOULD provide:
|
|
328
|
+
* - MemoryRegistrationBackend: For testing
|
|
329
|
+
*
|
|
330
|
+
* Implementation notes:
|
|
331
|
+
* - Time units: Python reference SDK uses seconds for all interval values
|
|
332
|
+
* - Stale threshold: SDKs SHOULD default to 2× heartbeat_interval if not specified
|
|
333
|
+
*/
|
|
334
|
+
export interface RegistrationBackend {
|
|
335
|
+
/**
|
|
336
|
+
* Register a new worker.
|
|
337
|
+
* Creates a new worker record with status "active".
|
|
338
|
+
*/
|
|
339
|
+
register(worker: WorkerRegistration): Promise<WorkerRecord>;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Update worker's last_heartbeat timestamp.
|
|
343
|
+
* Can optionally update metadata.
|
|
344
|
+
*/
|
|
345
|
+
heartbeat(worker_id: string, metadata?: Record<string, any>): Promise<void>;
|
|
346
|
+
|
|
347
|
+
/**
|
|
348
|
+
* Update worker status.
|
|
349
|
+
* Status values (string, not enum for extensibility):
|
|
350
|
+
* - "active": Worker is running and healthy
|
|
351
|
+
* - "terminating": Worker received shutdown signal
|
|
352
|
+
* - "terminated": Worker exited cleanly
|
|
353
|
+
* - "lost": Worker failed heartbeat, presumed dead
|
|
354
|
+
*/
|
|
355
|
+
updateStatus(worker_id: string, status: string): Promise<void>;
|
|
356
|
+
|
|
357
|
+
/**
|
|
358
|
+
* Get a worker record by ID.
|
|
359
|
+
* @returns The worker record, or null if not found
|
|
360
|
+
*/
|
|
361
|
+
get(worker_id: string): Promise<WorkerRecord | null>;
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* List workers matching filter criteria.
|
|
365
|
+
*/
|
|
366
|
+
list(filter?: WorkerFilter): Promise<WorkerRecord[]>;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export interface WorkerRegistration {
|
|
370
|
+
worker_id: string;
|
|
371
|
+
host?: string;
|
|
372
|
+
pid?: number;
|
|
373
|
+
capabilities?: string[]; // e.g., ["gpu", "paper-analysis"]
|
|
374
|
+
pool_id?: string; // Worker pool grouping
|
|
375
|
+
started_at: string;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
export interface WorkerRecord extends WorkerRegistration {
|
|
379
|
+
status: string; // See status values in RegistrationBackend.updateStatus
|
|
380
|
+
last_heartbeat: string;
|
|
381
|
+
current_task_id?: string;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export interface WorkerFilter {
|
|
385
|
+
status?: string | string[];
|
|
386
|
+
capability?: string;
|
|
387
|
+
pool_id?: string;
|
|
388
|
+
stale_threshold_seconds?: number; // Filter workers with old heartbeats
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* WORK BACKEND:
|
|
393
|
+
* -------------
|
|
394
|
+
* Work distribution via named pools with atomic claim.
|
|
395
|
+
*
|
|
396
|
+
* SDKs MUST provide:
|
|
397
|
+
* - SQLiteWorkBackend: For local deployments
|
|
398
|
+
*
|
|
399
|
+
* SDKs SHOULD provide:
|
|
400
|
+
* - MemoryWorkBackend: For testing
|
|
401
|
+
*
|
|
402
|
+
* Implementation notes:
|
|
403
|
+
* - Atomic claim: SDKs MUST ensure no two workers can claim the same job
|
|
404
|
+
* - Test requirements: Include concurrent claim race condition tests
|
|
405
|
+
*/
|
|
406
|
+
export interface WorkBackend {
|
|
407
|
+
/**
|
|
408
|
+
* Get a named work pool.
|
|
409
|
+
* Creates the pool if it doesn't exist.
|
|
410
|
+
*/
|
|
411
|
+
pool(name: string): WorkPool;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
export interface WorkPool {
|
|
415
|
+
/**
|
|
416
|
+
* Add work item to the pool.
|
|
417
|
+
* @param item - The work data (will be JSON serialized)
|
|
418
|
+
* @param options.max_retries - Max retry attempts before poisoning (default: 3)
|
|
419
|
+
* @returns The item ID
|
|
420
|
+
*/
|
|
421
|
+
push(item: any, options?: { max_retries?: number }): Promise<string>;
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Atomically claim next available item.
|
|
425
|
+
* MUST be atomic - no two workers can claim the same job.
|
|
426
|
+
* @returns The claimed item, or null if pool is empty
|
|
427
|
+
*/
|
|
428
|
+
claim(worker_id: string): Promise<WorkItem | null>;
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Mark item as complete.
|
|
432
|
+
* Sets status to "done" and stores result.
|
|
433
|
+
*/
|
|
434
|
+
complete(item_id: string, result?: any): Promise<void>;
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Mark item as failed.
|
|
438
|
+
* Increments attempts. If attempts >= max_retries, marks as "poisoned".
|
|
439
|
+
* Otherwise returns to "pending" status for retry.
|
|
440
|
+
*/
|
|
441
|
+
fail(item_id: string, error?: string): Promise<void>;
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Get pool depth (unclaimed pending items).
|
|
445
|
+
*/
|
|
446
|
+
size(): Promise<number>;
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Release all jobs claimed by a worker.
|
|
450
|
+
* Used for stale worker cleanup.
|
|
451
|
+
* @returns Number of jobs released
|
|
452
|
+
*/
|
|
453
|
+
releaseByWorker(worker_id: string): Promise<number>;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
export interface WorkItem {
|
|
457
|
+
id: string;
|
|
458
|
+
data: any;
|
|
459
|
+
claimed_by?: string;
|
|
460
|
+
claimed_at?: string;
|
|
461
|
+
attempts: number;
|
|
462
|
+
max_retries: number; // default: 3
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Job status values (string):
|
|
466
|
+
// - "pending": Available for claim
|
|
467
|
+
// - "claimed": Currently being processed
|
|
468
|
+
// - "done": Successfully completed
|
|
469
|
+
// - "poisoned": Failed max_retries times, will not be retried
|
|
470
|
+
|
|
317
471
|
export interface BackendConfig {
|
|
318
472
|
/** Checkpoint storage. Default: memory */
|
|
319
473
|
persistence?: "memory" | "local" | "redis" | "postgres" | "s3";
|
|
@@ -323,24 +477,36 @@ export interface BackendConfig {
|
|
|
323
477
|
|
|
324
478
|
/** Inter-machine results. Default: memory */
|
|
325
479
|
results?: "memory" | "redis";
|
|
480
|
+
|
|
481
|
+
/** Worker registration. Default: memory */
|
|
482
|
+
registration?: "memory" | "sqlite" | "redis";
|
|
483
|
+
|
|
484
|
+
/** Work pool. Default: memory */
|
|
485
|
+
work?: "memory" | "sqlite" | "redis";
|
|
486
|
+
|
|
487
|
+
/** Path for sqlite backends (registration and work share this) */
|
|
488
|
+
sqlite_path?: string;
|
|
326
489
|
}
|
|
327
490
|
|
|
328
|
-
export const SPEC_VERSION = "0.
|
|
491
|
+
export const SPEC_VERSION = "0.9.0";
|
|
329
492
|
|
|
330
493
|
/**
|
|
331
494
|
* Wrapper interface for JSON schema generation.
|
|
332
495
|
* Groups all runtime interfaces that SDKs must implement.
|
|
333
496
|
*/
|
|
334
497
|
export interface SDKRuntimeWrapper {
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
498
|
+
spec: "flatagents-runtime";
|
|
499
|
+
spec_version: typeof SPEC_VERSION;
|
|
500
|
+
execution_lock?: ExecutionLock;
|
|
501
|
+
persistence_backend?: PersistenceBackend;
|
|
502
|
+
result_backend?: ResultBackend;
|
|
503
|
+
execution_config?: ExecutionConfig;
|
|
504
|
+
machine_hooks?: MachineHooks;
|
|
505
|
+
llm_backend?: LLMBackend;
|
|
506
|
+
machine_invoker?: MachineInvoker;
|
|
507
|
+
backend_config?: BackendConfig;
|
|
508
|
+
machine_snapshot?: MachineSnapshot;
|
|
509
|
+
registration_backend?: RegistrationBackend;
|
|
510
|
+
work_backend?: WorkBackend;
|
|
346
511
|
}
|
|
512
|
+
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"spec_version": {
|
|
13
13
|
"type": "string",
|
|
14
|
-
"const": "0.
|
|
14
|
+
"const": "0.9.0"
|
|
15
15
|
},
|
|
16
16
|
"execution_lock": {
|
|
17
17
|
"$ref": "#/definitions/ExecutionLock"
|
|
@@ -39,6 +39,12 @@
|
|
|
39
39
|
},
|
|
40
40
|
"machine_snapshot": {
|
|
41
41
|
"$ref": "#/definitions/MachineSnapshot"
|
|
42
|
+
},
|
|
43
|
+
"registration_backend": {
|
|
44
|
+
"$ref": "#/definitions/RegistrationBackend"
|
|
45
|
+
},
|
|
46
|
+
"work_backend": {
|
|
47
|
+
"$ref": "#/definitions/WorkBackend"
|
|
42
48
|
}
|
|
43
49
|
},
|
|
44
50
|
"required": [
|
|
@@ -51,7 +57,7 @@
|
|
|
51
57
|
"ExecutionLock": {
|
|
52
58
|
"type": "object",
|
|
53
59
|
"additionalProperties": false,
|
|
54
|
-
"description": "FlatAgents Runtime Interface Spec ==================================\n\nThis file defines the runtime interfaces that SDKs MUST implement to be considered compliant. These are NOT configuration schemas (see flatagent.d.ts and flatmachine.d.ts for those).\n\nREQUIRED IMPLEMENTATIONS:\n------------------------- - ExecutionLock: NoOpLock (MUST), LocalFileLock (SHOULD) - PersistenceBackend: MemoryBackend (MUST), LocalFileBackend (SHOULD) - ResultBackend: InMemoryResultBackend (MUST) - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST) - MachineHooks: Base interface (MUST)\n\nOPTIONAL IMPLEMENTATIONS:\n------------------------- - Distributed backends (Redis, Postgres, etc.) - LLMBackend (SDK may use native provider SDKs)\n\nEXECUTION LOCKING:\n------------------ Prevents concurrent execution of the same machine instance.\n\nSDKs MUST provide: - NoOpLock: For when locking is handled externally or disabled\n\nSDKs SHOULD provide: - LocalFileLock: For single-node deployments using fcntl/flock\n\nDistributed deployments should implement Redis/Consul/etcd locks.\n\nPERSISTENCE BACKEND:\n-------------------- Storage backend for machine checkpoints.\n\nSDKs MUST provide: - MemoryBackend: For testing and ephemeral runs\n\nSDKs SHOULD provide: - LocalFileBackend: For durable local storage with atomic writes\n\nRESULT BACKEND:\n--------------- Inter-machine communication via URI-addressed results.\n\nURI format: flatagents://{execution_id}/{path} - path is typically \"result\" or \"checkpoint\"\n\nSDKs MUST provide: - InMemoryResultBackend: For single-process execution\n\nEXECUTION TYPES:\n---------------- Execution strategy for agent calls.\n\nSDKs MUST implement all four types: - default: Single call, no retry - retry: Configurable backoffs with jitter - parallel: Run N samples, return all successes - mdap_voting: Multi-sample with consensus voting\n\nMACHINE HOOKS:\n-------------- Extension points for machine execution. All methods are optional and can be sync or async.\n\nSDKs SHOULD provide: - WebhookHooks: Send events to HTTP endpoint - CompositeHooks: Combine multiple hook implementations\n\nLLM BACKEND (OPTIONAL):\n----------------------- Abstraction over LLM providers.\n\nThis interface is OPTIONAL - SDKs may use provider SDKs directly. Useful for: - Unified retry/monitoring across providers - Provider-agnostic code - Testing with mock backends\n\nMACHINE INVOKER:\n---------------- Interface for invoking peer machines. Used internally by FlatMachine for `machine:` and `launch:` states.\n\nBACKEND CONFIGURATION:\n---------------------- Backend configuration for machine settings.\n\nExample in YAML: settings: backends: persistence: local locking: none results: memory"
|
|
60
|
+
"description": "FlatAgents Runtime Interface Spec ==================================\n\nThis file defines the runtime interfaces that SDKs MUST implement to be considered compliant. These are NOT configuration schemas (see flatagent.d.ts and flatmachine.d.ts for those).\n\nREQUIRED IMPLEMENTATIONS:\n------------------------- - ExecutionLock: NoOpLock (MUST), LocalFileLock (SHOULD) - PersistenceBackend: MemoryBackend (MUST), LocalFileBackend (SHOULD) - ResultBackend: InMemoryResultBackend (MUST) - ExecutionType: Default, Retry, Parallel, MDAPVoting (MUST) - MachineHooks: Base interface (MUST) - RegistrationBackend: SQLiteRegistrationBackend (MUST), MemoryRegistrationBackend (SHOULD) - WorkBackend: SQLiteWorkBackend (MUST), MemoryWorkBackend (SHOULD)\n\nOPTIONAL IMPLEMENTATIONS:\n------------------------- - Distributed backends (Redis, Postgres, etc.) - LLMBackend (SDK may use native provider SDKs)\n\nEXECUTION LOCKING:\n------------------ Prevents concurrent execution of the same machine instance.\n\nSDKs MUST provide: - NoOpLock: For when locking is handled externally or disabled\n\nSDKs SHOULD provide: - LocalFileLock: For single-node deployments using fcntl/flock\n\nDistributed deployments should implement Redis/Consul/etcd locks.\n\nPERSISTENCE BACKEND:\n-------------------- Storage backend for machine checkpoints.\n\nSDKs MUST provide: - MemoryBackend: For testing and ephemeral runs\n\nSDKs SHOULD provide: - LocalFileBackend: For durable local storage with atomic writes\n\nRESULT BACKEND:\n--------------- Inter-machine communication via URI-addressed results.\n\nURI format: flatagents://{execution_id}/{path} - path is typically \"result\" or \"checkpoint\"\n\nSDKs MUST provide: - InMemoryResultBackend: For single-process execution\n\nEXECUTION TYPES:\n---------------- Execution strategy for agent calls.\n\nSDKs MUST implement all four types: - default: Single call, no retry - retry: Configurable backoffs with jitter - parallel: Run N samples, return all successes - mdap_voting: Multi-sample with consensus voting\n\nMACHINE HOOKS:\n-------------- Extension points for machine execution. All methods are optional and can be sync or async.\n\nSDKs SHOULD provide: - WebhookHooks: Send events to HTTP endpoint - CompositeHooks: Combine multiple hook implementations\n\nLLM BACKEND (OPTIONAL):\n----------------------- Abstraction over LLM providers.\n\nThis interface is OPTIONAL - SDKs may use provider SDKs directly. Useful for: - Unified retry/monitoring across providers - Provider-agnostic code - Testing with mock backends\n\nMACHINE INVOKER:\n---------------- Interface for invoking peer machines. Used internally by FlatMachine for `machine:` and `launch:` states.\n\nBACKEND CONFIGURATION:\n---------------------- Backend configuration for machine settings.\n\nExample in YAML: settings: backends: persistence: local locking: none results: memory"
|
|
55
61
|
},
|
|
56
62
|
"PersistenceBackend": {
|
|
57
63
|
"type": "object",
|
|
@@ -154,6 +160,28 @@
|
|
|
154
160
|
"redis"
|
|
155
161
|
],
|
|
156
162
|
"description": "Inter-machine results. Default: memory"
|
|
163
|
+
},
|
|
164
|
+
"registration": {
|
|
165
|
+
"type": "string",
|
|
166
|
+
"enum": [
|
|
167
|
+
"memory",
|
|
168
|
+
"sqlite",
|
|
169
|
+
"redis"
|
|
170
|
+
],
|
|
171
|
+
"description": "Worker registration. Default: memory"
|
|
172
|
+
},
|
|
173
|
+
"work": {
|
|
174
|
+
"type": "string",
|
|
175
|
+
"enum": [
|
|
176
|
+
"memory",
|
|
177
|
+
"sqlite",
|
|
178
|
+
"redis"
|
|
179
|
+
],
|
|
180
|
+
"description": "Work pool. Default: memory"
|
|
181
|
+
},
|
|
182
|
+
"sqlite_path": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"description": "Path for sqlite backends (registration and work share this)"
|
|
157
185
|
}
|
|
158
186
|
},
|
|
159
187
|
"additionalProperties": false
|
|
@@ -238,6 +266,16 @@
|
|
|
238
266
|
"launched"
|
|
239
267
|
],
|
|
240
268
|
"additionalProperties": false
|
|
269
|
+
},
|
|
270
|
+
"RegistrationBackend": {
|
|
271
|
+
"type": "object",
|
|
272
|
+
"additionalProperties": false,
|
|
273
|
+
"description": "REGISTRATION BACKEND:\n--------------------- Worker lifecycle management for distributed execution.\n\nSDKs MUST provide: - SQLiteRegistrationBackend: For local deployments\n\nSDKs SHOULD provide: - MemoryRegistrationBackend: For testing\n\nImplementation notes: - Time units: Python reference SDK uses seconds for all interval values - Stale threshold: SDKs SHOULD default to 2× heartbeat_interval if not specified"
|
|
274
|
+
},
|
|
275
|
+
"WorkBackend": {
|
|
276
|
+
"type": "object",
|
|
277
|
+
"additionalProperties": false,
|
|
278
|
+
"description": "WORK BACKEND:\n------------- Work distribution via named pools with atomic claim.\n\nSDKs MUST provide: - SQLiteWorkBackend: For local deployments\n\nSDKs SHOULD provide: - MemoryWorkBackend: For testing\n\nImplementation notes: - Atomic claim: SDKs MUST ensure no two workers can claim the same job - Test requirements: Include concurrent claim race condition tests"
|
|
241
279
|
}
|
|
242
280
|
}
|
|
243
281
|
}
|
|
@@ -102,12 +102,62 @@ export interface LaunchIntent {
|
|
|
102
102
|
input: Record<string, any>;
|
|
103
103
|
launched: boolean;
|
|
104
104
|
}
|
|
105
|
+
export interface RegistrationBackend {
|
|
106
|
+
register(worker: WorkerRegistration): Promise<WorkerRecord>;
|
|
107
|
+
heartbeat(worker_id: string, metadata?: Record<string, any>): Promise<void>;
|
|
108
|
+
updateStatus(worker_id: string, status: string): Promise<void>;
|
|
109
|
+
get(worker_id: string): Promise<WorkerRecord | null>;
|
|
110
|
+
list(filter?: WorkerFilter): Promise<WorkerRecord[]>;
|
|
111
|
+
}
|
|
112
|
+
export interface WorkerRegistration {
|
|
113
|
+
worker_id: string;
|
|
114
|
+
host?: string;
|
|
115
|
+
pid?: number;
|
|
116
|
+
capabilities?: string[];
|
|
117
|
+
pool_id?: string;
|
|
118
|
+
started_at: string;
|
|
119
|
+
}
|
|
120
|
+
export interface WorkerRecord extends WorkerRegistration {
|
|
121
|
+
status: string;
|
|
122
|
+
last_heartbeat: string;
|
|
123
|
+
current_task_id?: string;
|
|
124
|
+
}
|
|
125
|
+
export interface WorkerFilter {
|
|
126
|
+
status?: string | string[];
|
|
127
|
+
capability?: string;
|
|
128
|
+
pool_id?: string;
|
|
129
|
+
stale_threshold_seconds?: number;
|
|
130
|
+
}
|
|
131
|
+
export interface WorkBackend {
|
|
132
|
+
pool(name: string): WorkPool;
|
|
133
|
+
}
|
|
134
|
+
export interface WorkPool {
|
|
135
|
+
push(item: any, options?: {
|
|
136
|
+
max_retries?: number;
|
|
137
|
+
}): Promise<string>;
|
|
138
|
+
claim(worker_id: string): Promise<WorkItem | null>;
|
|
139
|
+
complete(item_id: string, result?: any): Promise<void>;
|
|
140
|
+
fail(item_id: string, error?: string): Promise<void>;
|
|
141
|
+
size(): Promise<number>;
|
|
142
|
+
releaseByWorker(worker_id: string): Promise<number>;
|
|
143
|
+
}
|
|
144
|
+
export interface WorkItem {
|
|
145
|
+
id: string;
|
|
146
|
+
data: any;
|
|
147
|
+
claimed_by?: string;
|
|
148
|
+
claimed_at?: string;
|
|
149
|
+
attempts: number;
|
|
150
|
+
max_retries: number;
|
|
151
|
+
}
|
|
105
152
|
export interface BackendConfig {
|
|
106
153
|
persistence?: "memory" | "local" | "redis" | "postgres" | "s3";
|
|
107
154
|
locking?: "none" | "local" | "redis" | "consul";
|
|
108
155
|
results?: "memory" | "redis";
|
|
156
|
+
registration?: "memory" | "sqlite" | "redis";
|
|
157
|
+
work?: "memory" | "sqlite" | "redis";
|
|
158
|
+
sqlite_path?: string;
|
|
109
159
|
}
|
|
110
|
-
export const SPEC_VERSION = "0.
|
|
160
|
+
export const SPEC_VERSION = "0.9.0";
|
|
111
161
|
export interface SDKRuntimeWrapper {
|
|
112
162
|
spec: "flatagents-runtime";
|
|
113
163
|
spec_version: typeof SPEC_VERSION;
|
|
@@ -120,4 +170,6 @@ export interface SDKRuntimeWrapper {
|
|
|
120
170
|
machine_invoker?: MachineInvoker;
|
|
121
171
|
backend_config?: BackendConfig;
|
|
122
172
|
machine_snapshot?: MachineSnapshot;
|
|
173
|
+
registration_backend?: RegistrationBackend;
|
|
174
|
+
work_backend?: WorkBackend;
|
|
123
175
|
}
|
package/schemas/flatmachine.d.ts
CHANGED
package/schemas/profiles.d.ts
CHANGED