flatagents 2.7.0__tar.gz → 4.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 (59) hide show
  1. {flatagents-2.7.0 → flatagents-4.0.0}/AGENTS.md +19 -4
  2. {flatagents-2.7.0 → flatagents-4.0.0}/PKG-INFO +5 -4
  3. {flatagents-2.7.0 → flatagents-4.0.0}/README.md +4 -3
  4. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/__init__.py +34 -1
  5. flatagents-4.0.0/flatagents/adapters/__init__.py +32 -0
  6. flatagents-4.0.0/flatagents/adapters/call_throttle.py +110 -0
  7. flatagents-4.0.0/flatagents/adapters/claude_code.py +931 -0
  8. flatagents-4.0.0/flatagents/adapters/claude_code_sessions.py +295 -0
  9. flatagents-4.0.0/flatagents/adapters/codex_cli.py +993 -0
  10. flatagents-4.0.0/flatagents/adapters/codex_cli_sessions.py +291 -0
  11. flatagents-4.0.0/flatagents/adapters/compat.py +41 -0
  12. flatagents-4.0.0/flatagents/adapters/pi_agent_bridge.py +125 -0
  13. flatagents-4.0.0/flatagents/adapters/pi_agent_runner.mjs +99 -0
  14. flatagents-4.0.0/flatagents/adapters/smolagents.py +122 -0
  15. flatagents-4.0.0/flatagents/assets/flatagent.d.ts +56 -0
  16. flatagents-4.0.0/flatagents/assets/flatagent.schema.json +689 -0
  17. flatagents-4.0.0/flatagents/assets/flatagent.slim.d.ts +15 -0
  18. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/flatagents-runtime.d.ts +1 -1
  19. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/flatagents-runtime.schema.json +1 -1
  20. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/flatagents-runtime.slim.d.ts +1 -1
  21. flatagents-4.0.0/flatagents/assets/flatmachine.d.ts +367 -0
  22. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/flatmachine.schema.json +603 -280
  23. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/flatmachine.slim.d.ts +14 -13
  24. flatagents-4.0.0/flatagents/assets/profile.d.ts +138 -0
  25. flatagents-2.7.0/flatagents/assets/flatagent.schema.json → flatagents-4.0.0/flatagents/assets/profile.schema.json +220 -169
  26. flatagents-4.0.0/flatagents/assets/profile.slim.d.ts +100 -0
  27. flatagents-4.0.0/flatagents/assets/prompt.d.ts +81 -0
  28. flatagents-4.0.0/flatagents/assets/prompt.schema.json +213 -0
  29. flatagents-2.7.0/flatagents/assets/flatagent.slim.d.ts → flatagents-4.0.0/flatagents/assets/prompt.slim.d.ts +8 -36
  30. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/baseagent.py +10 -6
  31. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/flatagent.py +386 -53
  32. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/profiles.py +81 -2
  33. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/validation.py +10 -0
  34. {flatagents-2.7.0 → flatagents-4.0.0}/pyproject.toml +1 -1
  35. flatagents-2.7.0/MACHINES.md +0 -207
  36. flatagents-2.7.0/flatagents/assets/flatagent.d.ts +0 -245
  37. flatagents-2.7.0/flatagents/assets/flatmachine.d.ts +0 -480
  38. flatagents-2.7.0/flatagents/assets/profiles.d.ts +0 -156
  39. flatagents-2.7.0/flatagents/assets/profiles.schema.json +0 -138
  40. flatagents-2.7.0/flatagents/assets/profiles.slim.d.ts +0 -39
  41. {flatagents-2.7.0 → flatagents-4.0.0}/.gitignore +0 -0
  42. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/README.md +0 -0
  43. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/assets/__init__.py +0 -0
  44. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/monitoring.py +0 -0
  45. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/__init__.py +0 -0
  46. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/anthropic.py +0 -0
  47. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/cerebras.py +0 -0
  48. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/github_copilot_auth.py +0 -0
  49. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/github_copilot_client.py +0 -0
  50. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/github_copilot_login.py +0 -0
  51. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/github_copilot_types.py +0 -0
  52. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/openai.py +0 -0
  53. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/openai_codex_auth.py +0 -0
  54. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/openai_codex_client.py +0 -0
  55. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/openai_codex_login.py +0 -0
  56. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/providers/openai_codex_types.py +0 -0
  57. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/tool_loop.py +0 -0
  58. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/tools.py +0 -0
  59. {flatagents-2.7.0 → flatagents-4.0.0}/flatagents/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  # FlatAgents + FlatMachines Reference
2
2
 
3
- > **Target: <1000 tokens.** LLM-optimized. See `flatagent.d.ts`, `flatmachine.d.ts`, `profiles.d.ts` for schemas.
3
+ > **Target: <1000 tokens.** LLM-optimized. See `flatagent.d.ts`, `flatmachine.d.ts`, `profile.d.ts`, `prompt.d.ts` for schemas.
4
4
  >
5
5
  > **Versioning:** All specs and SDKs use lockstep versioning.
6
6
 
@@ -21,8 +21,8 @@
21
21
 
22
22
  ```yaml
23
23
  # profiles.yml — agents reference by name
24
- spec: flatprofiles
25
- spec_version: "2.5.0"
24
+ spec: flatprofile
25
+ spec_version: "4.0.0"
26
26
  data:
27
27
  model_profiles:
28
28
  fast: { provider: cerebras, name: zai-glm-4.6, temperature: 0.6 }
@@ -40,7 +40,7 @@ Resolution: default → profile → overrides → override
40
40
  - Backend selection precedence remains: constructor `backend` → resolved `model.backend` → auto-detect (litellm/aisuite only).
41
41
  - `oauth` settings are read from resolved model config; works identically whether model came from inline agent config or profile.
42
42
  - Auth file precedence:
43
- - Codex: `oauth.auth_file` → legacy `codex_auth_file` → legacy `auth.auth_file` → `FLATAGENTS_CODEX_AUTH_FILE` → `~/.agents/flatmachines/auth.json`
43
+ - Codex: `oauth.auth_file` → legacy `codex_auth_file` → legacy `auth.auth_file` → `FLATAGENTS_CODEX_AUTH_FILE` → `~/.pi/agent/auth.json`
44
44
  - Copilot: `oauth.auth_file` → `copilot_auth_file` → legacy `auth.auth_file` → `FLATAGENTS_COPILOT_AUTH_FILE` → `~/.agents/flatmachines/auth.json`
45
45
  - Token handling: pre-request refresh on expiry; if refresh fails, re-read auth store once for cross-process refresh; fallback refresh+retry on `401/403`.
46
46
  - Retries on `429/500/502/503/504` with exponential backoff (no jitter).
@@ -52,6 +52,21 @@ Resolution: default → profile → overrides → override
52
52
  - Inline flatagent config (`spec: flatagent`)
53
53
  - Typed adapter ref: `{ type: "flatagent" | "smolagents" | "pi-agent", ref?: "...", config?: {...} }`
54
54
 
55
+ ## LLM I/O & Formatting (Hard Rules)
56
+
57
+ - Between LLM stages, default to **plain text/Markdown** handoffs.
58
+ - Avoid JSON/Jinja-shaped model-to-model output unless required by strict schema validation or a boundary contract (API/DB/file format).
59
+ - Why: JSON/Jinja handoffs increase parse fragility and token overhead.
60
+ - Keep `input` / `output_to_context` mappings explicit and shallow.
61
+ - Push heavy transforms to boundary actions only (final save/write steps).
62
+ - Preserve full source text across stages (avoid excerpt-only chains unless explicitly requested).
63
+ - Jinja in config (`input`, `output_to_context`, `transitions`, `foreach`, `wait_for`) must be cross-SDK portable:
64
+ - use property access, comparisons, simple conditionals
65
+ - avoid Python-specific features (`.items()`, `|tojson`, `len()`, `isinstance()`, list comprehensions).
66
+ - **Never truncate** LLM inputs/outputs silently.
67
+ - If size is a problem: ask user, enforce prompt limits, reject+retry, or add a repair/compaction stage.
68
+ - Each transform must have a one-line justification; otherwise remove it.
69
+
55
70
  ## State Fields
56
71
 
57
72
  | Field | Purpose |
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flatagents
3
- Version: 2.7.0
3
+ Version: 4.0.0
4
4
  Summary: A lightweight framework for building LLM-powered agents.
5
5
  Project-URL: Homepage, https://github.com/memgrafter/flatagents
6
6
  Project-URL: Repository, https://github.com/memgrafter/flatagents
@@ -45,7 +45,7 @@ Description-Content-Type: text/markdown
45
45
 
46
46
  Define single-call LLM agents in YAML. Use this package when you want **one structured call** per agent, with optional MCP tools and profile-driven model configs. For orchestration, install `flatmachines` separately.
47
47
 
48
- **For LLM/machine readers:** see [MACHINES.md](https://github.com/memgrafter/flatagents/blob/main/MACHINES.md).
48
+ **For LLM/machine readers:** see [AGENTS.md](./AGENTS.md).
49
49
 
50
50
  ## Install
51
51
 
@@ -100,7 +100,7 @@ If `data.output` is provided, FlatAgents requests JSON mode and parses the respo
100
100
  ## Model Profiles (profiles.yml)
101
101
 
102
102
  ```yaml
103
- spec: flatprofiles
103
+ spec: flatprofile
104
104
  spec_version: "0.10.0"
105
105
 
106
106
  data:
@@ -217,4 +217,5 @@ from flatagents import FlatMachine
217
217
 
218
218
  Source of truth:
219
219
  - [`flatagent.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/flatagent.d.ts)
220
- - [`profiles.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/profiles.d.ts)
220
+ - [`prompt.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/prompt.d.ts)
221
+ - [`profile.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/profile.d.ts)
@@ -2,7 +2,7 @@
2
2
 
3
3
  Define single-call LLM agents in YAML. Use this package when you want **one structured call** per agent, with optional MCP tools and profile-driven model configs. For orchestration, install `flatmachines` separately.
4
4
 
5
- **For LLM/machine readers:** see [MACHINES.md](https://github.com/memgrafter/flatagents/blob/main/MACHINES.md).
5
+ **For LLM/machine readers:** see [AGENTS.md](./AGENTS.md).
6
6
 
7
7
  ## Install
8
8
 
@@ -57,7 +57,7 @@ If `data.output` is provided, FlatAgents requests JSON mode and parses the respo
57
57
  ## Model Profiles (profiles.yml)
58
58
 
59
59
  ```yaml
60
- spec: flatprofiles
60
+ spec: flatprofile
61
61
  spec_version: "0.10.0"
62
62
 
63
63
  data:
@@ -174,4 +174,5 @@ from flatagents import FlatMachine
174
174
 
175
175
  Source of truth:
176
176
  - [`flatagent.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/flatagent.d.ts)
177
- - [`profiles.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/profiles.d.ts)
177
+ - [`prompt.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/prompt.d.ts)
178
+ - [`profile.d.ts`](https://github.com/memgrafter/flatagents/blob/main/sdk/python/flatagents/flatagents/assets/profile.d.ts)
@@ -1,4 +1,4 @@
1
- __version__ = "2.7.0"
1
+ __version__ = "4.0.0"
2
2
 
3
3
  from .baseagent import (
4
4
  # Base agent (abstract, for multi-step agents)
@@ -35,6 +35,8 @@ from .flatagent import FlatAgent
35
35
  from .profiles import (
36
36
  ProfileManager,
37
37
  resolve_model_config,
38
+ load_profile_from_file,
39
+ resolve_profile_config,
38
40
  )
39
41
  from .validation import (
40
42
  validate_flatagent_config,
@@ -63,6 +65,21 @@ from .tool_loop import (
63
65
  StopReason,
64
66
  SteeringProvider,
65
67
  )
68
+ from .adapters import (
69
+ ClaudeCodeExecutor,
70
+ create_claude_code_executor,
71
+ CodexCliExecutor,
72
+ CodexAppServerTransport,
73
+ create_codex_cli_executor,
74
+ SmolagentsExecutor,
75
+ create_smolagents_executor,
76
+ PiAgentBridgeExecutor,
77
+ create_pi_agent_bridge_executor,
78
+ ClaudeCodeSessionHoldback,
79
+ ClaudeCodeForkResult,
80
+ CodexSessionHoldback,
81
+ CodexForkResult,
82
+ )
66
83
  # Provider-specific utilities
67
84
  from .providers import (
68
85
  CerebrasRateLimits,
@@ -159,6 +176,22 @@ __all__ = [
159
176
  # Model Profiles
160
177
  "ProfileManager",
161
178
  "resolve_model_config",
179
+ "load_profile_from_file",
180
+ "resolve_profile_config",
181
+ # Runtime adapters
182
+ "ClaudeCodeExecutor",
183
+ "create_claude_code_executor",
184
+ "CodexCliExecutor",
185
+ "CodexAppServerTransport",
186
+ "create_codex_cli_executor",
187
+ "SmolagentsExecutor",
188
+ "create_smolagents_executor",
189
+ "PiAgentBridgeExecutor",
190
+ "create_pi_agent_bridge_executor",
191
+ "ClaudeCodeSessionHoldback",
192
+ "ClaudeCodeForkResult",
193
+ "CodexSessionHoldback",
194
+ "CodexForkResult",
162
195
  # Tool Use
163
196
  "ToolResult",
164
197
  "ToolProvider",
@@ -0,0 +1,32 @@
1
+ """Single-agent runtime adapters for FlatAgents."""
2
+
3
+ from .claude_code import ClaudeCodeExecutor, create_claude_code_executor
4
+ from .codex_cli import CodexCliExecutor, CodexAppServerTransport, create_codex_cli_executor
5
+ from .pi_agent_bridge import PiAgentBridgeExecutor, create_pi_agent_bridge_executor
6
+ from .claude_code_sessions import SessionHoldback as ClaudeCodeSessionHoldback, ForkResult as ClaudeCodeForkResult
7
+ from .codex_cli_sessions import CodexSessionHoldback, ForkResult as CodexForkResult
8
+
9
+ __all__ = [
10
+ "ClaudeCodeExecutor",
11
+ "create_claude_code_executor",
12
+ "CodexCliExecutor",
13
+ "CodexAppServerTransport",
14
+ "create_codex_cli_executor",
15
+ "PiAgentBridgeExecutor",
16
+ "create_pi_agent_bridge_executor",
17
+ "ClaudeCodeSessionHoldback",
18
+ "ClaudeCodeForkResult",
19
+ "CodexSessionHoldback",
20
+ "CodexForkResult",
21
+ ]
22
+
23
+ try:
24
+ from .smolagents import SmolagentsExecutor, create_smolagents_executor
25
+
26
+ __all__.extend([
27
+ "SmolagentsExecutor",
28
+ "create_smolagents_executor",
29
+ ])
30
+ except ImportError: # pragma: no cover - optional dependency
31
+ SmolagentsExecutor = None # type: ignore[assignment]
32
+ create_smolagents_executor = None # type: ignore[assignment]
@@ -0,0 +1,110 @@
1
+ """Async call throttle — serialized gate with jitter.
2
+
3
+ Enforces a minimum delay between calls. An asyncio.Lock serialises the
4
+ "when to launch" decision so concurrent callers are staggered, but the
5
+ actual work (subprocess, network call, …) runs concurrently once past
6
+ the gate.
7
+
8
+ throttle = CallThrottle(delay=3.0, jitter=4.0)
9
+
10
+ # 3 concurrent tasks:
11
+ # t≈0s task-1 passes gate immediately (first call)
12
+ # t≈0s task-2 acquires lock, sleeps ~7s, passes gate
13
+ # t≈7s task-3 acquires lock, sleeps ~5s, passes gate
14
+ # all 3 subprocesses now running concurrently
15
+
16
+ Delay formula per call::
17
+
18
+ wait = max(0, (last_call + delay + uniform(0, 2*jitter)) - now)
19
+
20
+ With ``delay=3, jitter=4`` the gap between consecutive calls is
21
+ uniformly distributed over **[3, 11] seconds**, with millisecond
22
+ granularity from float arithmetic.
23
+ """
24
+
25
+ from __future__ import annotations
26
+
27
+ import asyncio
28
+ import logging
29
+ import random
30
+ import time
31
+
32
+ logger = logging.getLogger(__name__)
33
+
34
+
35
+ class CallThrottle:
36
+ """Async rate limiter: base delay + uniform jitter between calls.
37
+
38
+ Args:
39
+ delay: Minimum base seconds between calls.
40
+ jitter: Half-width of the jitter window. Actual jitter added is
41
+ ``uniform(0, 2 * jitter)`` so the total gap is in
42
+ ``[delay, delay + 2*jitter]``. Set to 0 for fixed delay.
43
+ """
44
+
45
+ def __init__(self, delay: float = 0.0, jitter: float = 0.0) -> None:
46
+ self._delay = max(0.0, delay)
47
+ self._jitter = max(0.0, jitter)
48
+ self._lock = asyncio.Lock()
49
+ self._last_call: float = 0.0 # monotonic timestamp
50
+
51
+ @property
52
+ def enabled(self) -> bool:
53
+ return self._delay > 0 or self._jitter > 0
54
+
55
+ async def wait(self) -> float:
56
+ """Block until the next call is allowed.
57
+
58
+ Returns the number of seconds actually waited (0.0 on first call
59
+ or when the throttle is disabled).
60
+ """
61
+ if not self.enabled:
62
+ return 0.0
63
+
64
+ async with self._lock:
65
+ now = time.monotonic()
66
+
67
+ if self._last_call == 0.0:
68
+ # First call — no wait
69
+ self._last_call = now
70
+ return 0.0
71
+
72
+ # Compute jitter with ms granularity
73
+ jitter_ms = random.randint(0, int(2 * self._jitter * 1000))
74
+ jitter_s = jitter_ms / 1000.0
75
+
76
+ target = self._last_call + self._delay + jitter_s
77
+ wait_s = max(0.0, target - now)
78
+
79
+ if wait_s > 0:
80
+ logger.debug(
81
+ "CallThrottle: sleeping %.3fs (delay=%.1f jitter=%.3f)",
82
+ wait_s, self._delay, jitter_s,
83
+ )
84
+ await asyncio.sleep(wait_s)
85
+
86
+ self._last_call = time.monotonic()
87
+ return wait_s
88
+
89
+ def reset(self) -> None:
90
+ """Reset the throttle so the next call passes immediately."""
91
+ self._last_call = 0.0
92
+
93
+
94
+ # ---------------------------------------------------------------------------
95
+ # Factory from config dict
96
+ # ---------------------------------------------------------------------------
97
+
98
+ def throttle_from_config(config: dict) -> CallThrottle:
99
+ """Create a CallThrottle from an adapter config dict.
100
+
101
+ Recognised keys::
102
+
103
+ rate_limit_delay: 3.0 # base seconds (default 0 = disabled)
104
+ rate_limit_jitter: 4.0 # ±seconds (default 0)
105
+
106
+ Returns a disabled throttle when neither key is set.
107
+ """
108
+ delay = float(config.get("rate_limit_delay", 0))
109
+ jitter = float(config.get("rate_limit_jitter", 0))
110
+ return CallThrottle(delay=delay, jitter=jitter)