evolvingmachines-evolve 0.0.55.dev1355__py3-none-any.whl
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.
- bridge/__init__.py +5 -0
- bridge/dist/bridge.bundle.cjs +1275 -0
- evolve/__init__.py +819 -0
- evolve/_http.py +71 -0
- evolve/agent.py +896 -0
- evolve/bridge.py +509 -0
- evolve/browser_credentials.py +265 -0
- evolve/browser_profiles.py +95 -0
- evolve/config.py +600 -0
- evolve/hosted.py +8958 -0
- evolve/integrations.py +173 -0
- evolve/managed_secrets.py +175 -0
- evolve/pipeline/__init__.py +59 -0
- evolve/pipeline/pipeline.py +512 -0
- evolve/pipeline/types.py +286 -0
- evolve/prompts/__init__.py +132 -0
- evolve/prompts/agent_md/judge.md +30 -0
- evolve/prompts/agent_md/reduce.md +7 -0
- evolve/prompts/agent_md/verify.md +33 -0
- evolve/prompts/user/judge.md +1 -0
- evolve/prompts/user/retry_feedback.md +9 -0
- evolve/prompts/user/verify.md +1 -0
- evolve/py.typed +0 -0
- evolve/results.py +315 -0
- evolve/retry.py +133 -0
- evolve/schema.py +107 -0
- evolve/sessions_client.py +167 -0
- evolve/storage_client.py +178 -0
- evolve/swarm/__init__.py +75 -0
- evolve/swarm/results.py +140 -0
- evolve/swarm/swarm.py +2116 -0
- evolve/swarm/types.py +241 -0
- evolve/utils.py +227 -0
- evolvingmachines_evolve-0.0.55.dev1355.dist-info/METADATA +52 -0
- evolvingmachines_evolve-0.0.55.dev1355.dist-info/RECORD +38 -0
- evolvingmachines_evolve-0.0.55.dev1355.dist-info/WHEEL +5 -0
- evolvingmachines_evolve-0.0.55.dev1355.dist-info/licenses/LICENSE +201 -0
- evolvingmachines_evolve-0.0.55.dev1355.dist-info/top_level.txt +2 -0
evolve/swarm/types.py
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Type definitions for Swarm abstractions."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import (
|
|
5
|
+
Any,
|
|
6
|
+
Callable,
|
|
7
|
+
Dict,
|
|
8
|
+
List,
|
|
9
|
+
Literal,
|
|
10
|
+
Optional,
|
|
11
|
+
Type,
|
|
12
|
+
TypeVar,
|
|
13
|
+
Union,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from ..config import SandboxProvider, AgentConfig, WorkspaceMode, IntegrationsSetup
|
|
17
|
+
from ..retry import RetryConfig
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# =============================================================================
|
|
21
|
+
# TYPE VARIABLES
|
|
22
|
+
# =============================================================================
|
|
23
|
+
|
|
24
|
+
T = TypeVar('T')
|
|
25
|
+
|
|
26
|
+
# =============================================================================
|
|
27
|
+
# FILE MAP
|
|
28
|
+
# =============================================================================
|
|
29
|
+
|
|
30
|
+
FileMap = Dict[str, Union[str, bytes]]
|
|
31
|
+
|
|
32
|
+
# =============================================================================
|
|
33
|
+
# CONFIGURATION
|
|
34
|
+
# =============================================================================
|
|
35
|
+
|
|
36
|
+
@dataclass
|
|
37
|
+
class SwarmConfig:
|
|
38
|
+
"""Configuration for Swarm instance.
|
|
39
|
+
|
|
40
|
+
All fields are optional - TS SDK resolves defaults from environment:
|
|
41
|
+
- agent defaults to EVOLVE_API_KEY env var with 'claude' type
|
|
42
|
+
- sandbox auto-resolves: E2B_API_KEY → E2B direct, DAYTONA_API_KEY → Daytona, MODAL_TOKEN_* → Modal, EVOLVE_API_KEY → E2B gateway (fallback)
|
|
43
|
+
"""
|
|
44
|
+
agent: Optional[AgentConfig] = None
|
|
45
|
+
sandbox: Optional[SandboxProvider] = None
|
|
46
|
+
tag: str = "swarm"
|
|
47
|
+
concurrency: int = 4
|
|
48
|
+
timeout_ms: int = 3_600_000 # 1 hour
|
|
49
|
+
workspace_mode: WorkspaceMode = "knowledge"
|
|
50
|
+
retry: Optional[RetryConfig] = None
|
|
51
|
+
"""Default retry configuration for all operations (per-operation config takes precedence)."""
|
|
52
|
+
mcp_servers: Optional[Dict[str, Any]] = None
|
|
53
|
+
"""Default MCP servers for all operations (per-operation config takes precedence)."""
|
|
54
|
+
skills: Optional[List[str]] = None
|
|
55
|
+
"""Default skills for all operations (per-operation config takes precedence)."""
|
|
56
|
+
integrations: Optional[IntegrationsSetup] = None
|
|
57
|
+
"""Default Integrations configuration for all operations (per-operation config takes precedence)."""
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Callback types for BestOf
|
|
61
|
+
OnCandidateCompleteCallback = Callable[[int, int, Literal["success", "error"]], None]
|
|
62
|
+
"""(item_index, candidate_index, status)"""
|
|
63
|
+
|
|
64
|
+
OnJudgeCompleteCallback = Callable[[int, int, str], None]
|
|
65
|
+
"""(item_index, winner_index, reasoning)"""
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class BestOfConfig:
|
|
70
|
+
"""Configuration for bestOf operation."""
|
|
71
|
+
judge_criteria: str
|
|
72
|
+
n: Optional[int] = None
|
|
73
|
+
task_agents: Optional[List[AgentConfig]] = None
|
|
74
|
+
judge_agent: Optional[AgentConfig] = None
|
|
75
|
+
mcp_servers: Optional[Dict[str, Any]] = None
|
|
76
|
+
"""MCP servers for candidates (defaults to operation mcp_servers)."""
|
|
77
|
+
judge_mcp_servers: Optional[Dict[str, Any]] = None
|
|
78
|
+
"""MCP servers for judge (defaults to mcp_servers)."""
|
|
79
|
+
skills: Optional[List[str]] = None
|
|
80
|
+
"""Skills for candidates (defaults to operation skills)."""
|
|
81
|
+
judge_skills: Optional[List[str]] = None
|
|
82
|
+
"""Skills for judge (defaults to skills)."""
|
|
83
|
+
integrations: Optional[IntegrationsSetup] = None
|
|
84
|
+
"""Integrations config for candidates (defaults to operation integrations)."""
|
|
85
|
+
judge_integrations: Optional[IntegrationsSetup] = None
|
|
86
|
+
"""Integrations config for judge (defaults to integrations)."""
|
|
87
|
+
on_candidate_complete: Optional[OnCandidateCompleteCallback] = None
|
|
88
|
+
"""Callback when a candidate completes."""
|
|
89
|
+
on_judge_complete: Optional[OnJudgeCompleteCallback] = None
|
|
90
|
+
"""Callback when judge completes."""
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# Callback types for Verify
|
|
94
|
+
OnWorkerCompleteCallback = Callable[[int, int, Literal["success", "error"]], None]
|
|
95
|
+
"""(item_index, attempt, status)"""
|
|
96
|
+
|
|
97
|
+
OnVerifierCompleteCallback = Callable[[int, int, bool, Optional[str]], None]
|
|
98
|
+
"""(item_index, attempt, passed, feedback)"""
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@dataclass
|
|
102
|
+
class VerifyConfig:
|
|
103
|
+
"""Configuration for verify operation.
|
|
104
|
+
|
|
105
|
+
Verify provides LLM-as-judge quality verification with retry loop.
|
|
106
|
+
If verification fails, the worker is re-run with feedback from the verifier.
|
|
107
|
+
"""
|
|
108
|
+
criteria: str
|
|
109
|
+
"""Verification criteria - what the output must satisfy."""
|
|
110
|
+
max_attempts: int = 3
|
|
111
|
+
"""Maximum attempts with feedback (default: 3). Includes initial attempt."""
|
|
112
|
+
verifier_agent: Optional[AgentConfig] = None
|
|
113
|
+
"""Optional: override agent for verifier."""
|
|
114
|
+
verifier_mcp_servers: Optional[Dict[str, Any]] = None
|
|
115
|
+
"""MCP servers for verifier (defaults to operation mcp_servers)."""
|
|
116
|
+
verifier_skills: Optional[List[str]] = None
|
|
117
|
+
"""Skills for verifier (defaults to operation skills)."""
|
|
118
|
+
verifier_integrations: Optional[IntegrationsSetup] = None
|
|
119
|
+
"""Integrations config for verifier (defaults to operation integrations)."""
|
|
120
|
+
on_worker_complete: Optional[OnWorkerCompleteCallback] = None
|
|
121
|
+
"""Callback invoked after each worker completion (before verification)."""
|
|
122
|
+
on_verifier_complete: Optional[OnVerifierCompleteCallback] = None
|
|
123
|
+
"""Callback invoked after each verifier completion."""
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
# =============================================================================
|
|
127
|
+
# METADATA
|
|
128
|
+
# =============================================================================
|
|
129
|
+
|
|
130
|
+
OperationType = Literal["map", "filter", "reduce", "bestof-cand", "bestof-judge", "verify"]
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@dataclass
|
|
134
|
+
class BaseMeta:
|
|
135
|
+
"""Base metadata for all operations."""
|
|
136
|
+
operation_id: str
|
|
137
|
+
"""Unique identifier for this operation."""
|
|
138
|
+
operation: OperationType
|
|
139
|
+
tag: str
|
|
140
|
+
sandbox_id: str
|
|
141
|
+
# Optional observability fields
|
|
142
|
+
swarm_name: Optional[str] = None
|
|
143
|
+
"""Swarm name (from Swarm.config.tag) - identifies the swarm instance."""
|
|
144
|
+
operation_name: Optional[str] = None
|
|
145
|
+
"""Operation name (from params.name) - user-defined label for this operation."""
|
|
146
|
+
error_retry: Optional[int] = None
|
|
147
|
+
"""Error retry number (1, 2, 3...) - only present when retrying after error."""
|
|
148
|
+
verify_retry: Optional[int] = None
|
|
149
|
+
"""Verify retry number (1, 2, 3...) - only present when retrying after verify failure."""
|
|
150
|
+
candidate_index: Optional[int] = None
|
|
151
|
+
"""Candidate index (0, 1, 2...) - only present for bestOf candidates."""
|
|
152
|
+
pipeline_run_id: Optional[str] = None
|
|
153
|
+
"""Pipeline run identifier - only present when run via Pipeline."""
|
|
154
|
+
pipeline_step_index: Optional[int] = None
|
|
155
|
+
"""Pipeline step index - only present when run via Pipeline."""
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
@dataclass
|
|
159
|
+
class IndexedMeta(BaseMeta):
|
|
160
|
+
"""Metadata for indexed operations (map, filter, bestof-cand)."""
|
|
161
|
+
item_index: int = 0
|
|
162
|
+
"""Item index in the batch (0, 1, 2...)."""
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
@dataclass
|
|
166
|
+
class ReduceMeta(BaseMeta):
|
|
167
|
+
"""Metadata for reduce operation."""
|
|
168
|
+
input_count: int = 0
|
|
169
|
+
input_indices: Optional[List[int]] = None
|
|
170
|
+
|
|
171
|
+
def __post_init__(self):
|
|
172
|
+
if self.input_indices is None:
|
|
173
|
+
self.input_indices = []
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@dataclass
|
|
177
|
+
class JudgeMeta(BaseMeta):
|
|
178
|
+
"""Metadata for bestOf judge."""
|
|
179
|
+
candidate_count: int = 0
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@dataclass
|
|
183
|
+
class VerifyMeta(BaseMeta):
|
|
184
|
+
"""Metadata for verify operation."""
|
|
185
|
+
attempts: int = 0
|
|
186
|
+
"""Total verification attempts made."""
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
# =============================================================================
|
|
190
|
+
# PIPELINE CONTEXT (internal - passed from Pipeline to Swarm)
|
|
191
|
+
# =============================================================================
|
|
192
|
+
|
|
193
|
+
@dataclass
|
|
194
|
+
class PipelineContext:
|
|
195
|
+
"""Internal context passed from Pipeline to Swarm for observability."""
|
|
196
|
+
pipeline_run_id: str
|
|
197
|
+
pipeline_step_index: int
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
# =============================================================================
|
|
201
|
+
# PROMPT TYPES
|
|
202
|
+
# =============================================================================
|
|
203
|
+
|
|
204
|
+
PromptFn = Callable[[FileMap, int], str]
|
|
205
|
+
Prompt = Union[str, PromptFn]
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
# =============================================================================
|
|
209
|
+
# ITEM INPUT (for chaining)
|
|
210
|
+
# =============================================================================
|
|
211
|
+
|
|
212
|
+
# Forward reference - actual SwarmResult defined in results.py
|
|
213
|
+
# ItemInput can be a FileMap or a SwarmResult from a previous operation
|
|
214
|
+
ItemInput = Union[FileMap, Any] # Any here will be SwarmResult at runtime
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
# =============================================================================
|
|
218
|
+
# SCHEMA TYPE
|
|
219
|
+
# =============================================================================
|
|
220
|
+
|
|
221
|
+
# Schema can be a Pydantic model, dataclass, or JSON Schema dict
|
|
222
|
+
SchemaType = Union[Type[Any], Dict[str, Any]]
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
# =============================================================================
|
|
226
|
+
# JUDGE DECISION
|
|
227
|
+
# =============================================================================
|
|
228
|
+
|
|
229
|
+
@dataclass
|
|
230
|
+
class JudgeDecision:
|
|
231
|
+
"""Fixed schema for bestOf judge output."""
|
|
232
|
+
winner: int
|
|
233
|
+
reasoning: str
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
@dataclass
|
|
237
|
+
class VerifyDecision:
|
|
238
|
+
"""Fixed schema for verify output."""
|
|
239
|
+
passed: bool
|
|
240
|
+
reasoning: str
|
|
241
|
+
feedback: Optional[str] = None
|
evolve/utils.py
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"""Shared utilities for Evolve SDK."""
|
|
2
|
+
|
|
3
|
+
import base64
|
|
4
|
+
import os
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any, Dict, Optional, Union
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _filter_none(d: Dict[str, Any]) -> Dict[str, Any]:
|
|
10
|
+
"""Filter out None values from a dict. Used for building RPC params."""
|
|
11
|
+
return {k: v for k, v in d.items() if v is not None}
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _decode_files_from_transport(
|
|
15
|
+
encoded: Dict[str, Any],
|
|
16
|
+
) -> Dict[str, Union[str, bytes]]:
|
|
17
|
+
"""Decode base64/text encoded files from JSON-RPC bridge transport.
|
|
18
|
+
|
|
19
|
+
Counterpart to :func:`_encode_files_for_transport`.
|
|
20
|
+
"""
|
|
21
|
+
decoded: Dict[str, Union[str, bytes]] = {}
|
|
22
|
+
for name, file_data in encoded.items():
|
|
23
|
+
content = file_data.get('content', '')
|
|
24
|
+
encoding = file_data.get('encoding', 'text')
|
|
25
|
+
if encoding == 'base64':
|
|
26
|
+
decoded[name] = base64.b64decode(content)
|
|
27
|
+
else:
|
|
28
|
+
decoded[name] = content
|
|
29
|
+
return decoded
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def _parse_checkpoint(data: Optional[Dict[str, Any]]) -> Optional['CheckpointInfo']:
|
|
33
|
+
"""Parse checkpoint dict from bridge response into CheckpointInfo.
|
|
34
|
+
|
|
35
|
+
Returns None when *data* is falsy (e.g. ``None`` or ``{}``).
|
|
36
|
+
Use :func:`_require_checkpoint` in APIs that must return a value.
|
|
37
|
+
"""
|
|
38
|
+
if not data:
|
|
39
|
+
return None
|
|
40
|
+
# Import here to avoid circular import (utils ← results ← utils).
|
|
41
|
+
# Python caches after first load so subsequent calls are a cheap lookup.
|
|
42
|
+
from .results import CheckpointInfo # noqa: E402
|
|
43
|
+
return CheckpointInfo(
|
|
44
|
+
id=data['id'],
|
|
45
|
+
hash=data['hash'],
|
|
46
|
+
tag=data['tag'],
|
|
47
|
+
timestamp=data['timestamp'],
|
|
48
|
+
size_bytes=data.get('size_bytes'),
|
|
49
|
+
agent_type=data.get('agent_type'),
|
|
50
|
+
model=data.get('model'),
|
|
51
|
+
workspace_mode=data.get('workspace_mode'),
|
|
52
|
+
parent_id=data.get('parent_id'),
|
|
53
|
+
comment=data.get('comment'),
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _require_checkpoint(data: Optional[Dict[str, Any]]) -> 'CheckpointInfo':
|
|
58
|
+
"""Like :func:`_parse_checkpoint` but raises on falsy *data*.
|
|
59
|
+
|
|
60
|
+
Use in APIs typed ``-> CheckpointInfo`` where a missing/corrupt
|
|
61
|
+
checkpoint is an error, not a valid state.
|
|
62
|
+
"""
|
|
63
|
+
result = _parse_checkpoint(data)
|
|
64
|
+
if result is None:
|
|
65
|
+
raise ValueError(f"Expected checkpoint data, got: {data!r}")
|
|
66
|
+
return result
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _parse_session_info(data: Optional[Dict[str, Any]]) -> Optional['SessionInfo']:
|
|
70
|
+
"""Parse session dict from bridge response into SessionInfo."""
|
|
71
|
+
if not data:
|
|
72
|
+
return None
|
|
73
|
+
from .results import SessionInfo, _usage_reading_from_data # noqa: E402
|
|
74
|
+
return SessionInfo(
|
|
75
|
+
id=data['id'],
|
|
76
|
+
tag=data['tag'],
|
|
77
|
+
agent=data['agent'],
|
|
78
|
+
model=data.get('model'),
|
|
79
|
+
provider=data['provider'],
|
|
80
|
+
sandbox_id=data.get('sandbox_id'),
|
|
81
|
+
state=data['state'],
|
|
82
|
+
runtime_status=data.get('runtime_status', 'unknown'),
|
|
83
|
+
cost=data.get('cost'),
|
|
84
|
+
created_at=data['created_at'],
|
|
85
|
+
ended_at=data.get('ended_at'),
|
|
86
|
+
step_count=data.get('step_count', 0),
|
|
87
|
+
tool_stats=data.get('tool_stats'),
|
|
88
|
+
# The one-home usage reading, by the one shared parsing rule — a
|
|
89
|
+
# malformed or absent object reads None ("the meter never answered").
|
|
90
|
+
usage=_usage_reading_from_data(data.get('usage')),
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _require_session_info(data: Optional[Dict[str, Any]]) -> 'SessionInfo':
|
|
95
|
+
"""Like :func:`_parse_session_info` but raises on falsy *data*."""
|
|
96
|
+
result = _parse_session_info(data)
|
|
97
|
+
if result is None:
|
|
98
|
+
raise ValueError(f"Expected session data, got: {data!r}")
|
|
99
|
+
return result
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _parse_browser_replay(data: Optional[Dict[str, Any]]) -> Optional['BrowserReplay']:
|
|
103
|
+
"""Parse browser replay dict from bridge response into BrowserReplay."""
|
|
104
|
+
if not data:
|
|
105
|
+
return None
|
|
106
|
+
from .results import BrowserReplay # noqa: E402
|
|
107
|
+
return BrowserReplay(
|
|
108
|
+
session_id=data['session_id'],
|
|
109
|
+
status=data['status'],
|
|
110
|
+
replay_url=data['replay_url'],
|
|
111
|
+
download_url=data['download_url'],
|
|
112
|
+
suggested_start_seconds=data.get('suggested_start_seconds'),
|
|
113
|
+
size_bytes=data.get('size_bytes'),
|
|
114
|
+
ready_at=data.get('ready_at'),
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def _require_browser_replay(data: Optional[Dict[str, Any]]) -> 'BrowserReplay':
|
|
119
|
+
"""Like :func:`_parse_browser_replay` but raises on falsy *data*."""
|
|
120
|
+
result = _parse_browser_replay(data)
|
|
121
|
+
if result is None:
|
|
122
|
+
raise ValueError(f"Expected browser replay data, got: {data!r}")
|
|
123
|
+
return result
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _require_session_transcript(data: Optional[Dict[str, Any]]) -> 'SessionTranscript':
|
|
127
|
+
"""Parse a ``sessions_transcript`` bridge response into SessionTranscript.
|
|
128
|
+
|
|
129
|
+
The bridge (adapter.ts sessionsTranscript) serves the TypeScript SDK's
|
|
130
|
+
already-checked read: the session in snake_case, the events and the
|
|
131
|
+
gateway's usage lines verbatim. A response without its session is refused.
|
|
132
|
+
"""
|
|
133
|
+
if not data:
|
|
134
|
+
raise ValueError(f"Expected session transcript data, got: {data!r}")
|
|
135
|
+
from .results import SessionTranscript # noqa: E402
|
|
136
|
+
events = list(data.get('events') or [])
|
|
137
|
+
total = data.get('total')
|
|
138
|
+
stored_at = data.get('stored_at')
|
|
139
|
+
return SessionTranscript(
|
|
140
|
+
session=_require_session_info(data.get('session')),
|
|
141
|
+
events=events,
|
|
142
|
+
total=total if isinstance(total, int) else len(events),
|
|
143
|
+
gateway_calls=list(data.get('gateway_calls') or []),
|
|
144
|
+
# Absent (a file-served transcript, an older server) stays None — never
|
|
145
|
+
# an empty list, which the contract reserves for an empty row-served page.
|
|
146
|
+
stored_at=list(stored_at) if isinstance(stored_at, list) else None,
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _encode_files_for_transport(
|
|
151
|
+
files: Dict[str, Union[str, bytes]]
|
|
152
|
+
) -> Dict[str, Dict[str, str]]:
|
|
153
|
+
"""Encode files dict for JSON-RPC transport.
|
|
154
|
+
|
|
155
|
+
Handles both text (str) and binary (bytes) content with appropriate encoding.
|
|
156
|
+
Uses 'content' field consistently for both input and output files.
|
|
157
|
+
"""
|
|
158
|
+
result = {}
|
|
159
|
+
for name, file_content in files.items():
|
|
160
|
+
if isinstance(file_content, bytes):
|
|
161
|
+
result[name] = {
|
|
162
|
+
'content': base64.b64encode(file_content).decode('utf-8'),
|
|
163
|
+
'encoding': 'base64'
|
|
164
|
+
}
|
|
165
|
+
else:
|
|
166
|
+
result[name] = {'content': file_content, 'encoding': 'text'}
|
|
167
|
+
return result
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def read_local_dir(local_path: str, recursive: bool = False) -> Dict[str, bytes]:
|
|
171
|
+
"""Read files from a local directory into a dict for upload.
|
|
172
|
+
|
|
173
|
+
Args:
|
|
174
|
+
local_path: Path to local directory
|
|
175
|
+
recursive: Include subdirectories (default: False)
|
|
176
|
+
|
|
177
|
+
Returns:
|
|
178
|
+
Dict mapping relative paths to file content as bytes
|
|
179
|
+
"""
|
|
180
|
+
result: Dict[str, bytes] = {}
|
|
181
|
+
root = Path(local_path)
|
|
182
|
+
|
|
183
|
+
paths = root.rglob('*') if recursive else root.iterdir()
|
|
184
|
+
|
|
185
|
+
for p in paths:
|
|
186
|
+
if p.is_file():
|
|
187
|
+
result[str(p.relative_to(root))] = p.read_bytes()
|
|
188
|
+
|
|
189
|
+
return result
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def save_local_dir(local_path: str, files: Dict[str, Union[str, bytes]]) -> None:
|
|
193
|
+
"""Save files dict to a local directory, creating nested directories as needed.
|
|
194
|
+
|
|
195
|
+
Args:
|
|
196
|
+
local_path: Base directory to save files to
|
|
197
|
+
files: Dict mapping relative paths to content (from get_output_files().files or other source)
|
|
198
|
+
|
|
199
|
+
Example:
|
|
200
|
+
>>> output = await agent.get_output_files(recursive=True)
|
|
201
|
+
>>> save_local_dir('./output', output.files)
|
|
202
|
+
# Creates: ./output/file.txt, ./output/subdir/nested.txt, etc.
|
|
203
|
+
|
|
204
|
+
Raises:
|
|
205
|
+
ValueError: If an entry's path escapes the target directory. The names
|
|
206
|
+
come from sandbox output, so a hostile ``../`` or absolute entry
|
|
207
|
+
must not write outside the directory the caller chose.
|
|
208
|
+
"""
|
|
209
|
+
base = os.path.abspath(local_path)
|
|
210
|
+
prefix = base if base.endswith(os.sep) else base + os.sep
|
|
211
|
+
for name, content in files.items():
|
|
212
|
+
file_path = os.path.abspath(os.path.join(base, name))
|
|
213
|
+
if not file_path.startswith(prefix):
|
|
214
|
+
raise ValueError(f'unsafe file path escapes target directory: {name!r}')
|
|
215
|
+
parent = os.path.dirname(file_path)
|
|
216
|
+
|
|
217
|
+
# Create parent directories if needed
|
|
218
|
+
if parent:
|
|
219
|
+
os.makedirs(parent, exist_ok=True)
|
|
220
|
+
|
|
221
|
+
# Write content
|
|
222
|
+
if isinstance(content, bytes):
|
|
223
|
+
with open(file_path, 'wb') as f:
|
|
224
|
+
f.write(content)
|
|
225
|
+
else:
|
|
226
|
+
with open(file_path, 'w', encoding='utf-8') as f:
|
|
227
|
+
f.write(content)
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: evolvingmachines-evolve
|
|
3
|
+
Version: 0.0.55.dev1355
|
|
4
|
+
Summary: Pythonic SDK for multi-agent orchestration in E2B sandboxes
|
|
5
|
+
Author-email: "Swarmlink, Inc." <brandomagnani@evolvingmachines.ai>
|
|
6
|
+
License: Apache-2.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/evolving-machines-lab/evolve
|
|
8
|
+
Project-URL: Repository, https://github.com/evolving-machines-lab/evolve
|
|
9
|
+
Keywords: ai,agents,sandbox,e2b,orchestration,codex,claude,gemini,evolve
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
23
|
+
Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
|
|
24
|
+
Requires-Dist: python-dotenv>=1.0.0; extra == "dev"
|
|
25
|
+
Requires-Dist: pydantic>=2.0.0; extra == "dev"
|
|
26
|
+
Dynamic: license-file
|
|
27
|
+
|
|
28
|
+
<br><br>
|
|
29
|
+
|
|
30
|
+
<p align="center">
|
|
31
|
+
<img src="https://raw.githubusercontent.com/evolving-machines-lab/evolve/main/logo/evolving-machines-ink.png" alt="Evolving Machines" width="380">
|
|
32
|
+
</p>
|
|
33
|
+
|
|
34
|
+
<br><br>
|
|
35
|
+
|
|
36
|
+
# Evolving Machines — Evolve SDK (Python)
|
|
37
|
+
|
|
38
|
+
Evolve SDK lets you run and orchestrate terminal-based AI agents in secure sandboxes with built-in observability.
|
|
39
|
+
|
|
40
|
+
Check out the [official documentation](https://github.com/evolving-machines-lab/evolve/tree/main/docs) and [cookbooks](https://github.com/evolving-machines-lab/evolve/tree/main/cookbooks).
|
|
41
|
+
|
|
42
|
+
## Reporting Bugs
|
|
43
|
+
|
|
44
|
+
We welcome your feedback. File a [GitHub issue](https://github.com/evolving-machines-lab/evolve/issues) to report bugs or request features.
|
|
45
|
+
|
|
46
|
+
## Connect on Discord
|
|
47
|
+
|
|
48
|
+
Join the [Evolve SDK Developers Discord](https://discord.gg/Q36D8dGyNF) to connect with other developers using Evolve SDK. Get help, share feedback, and discuss your projects with the community.
|
|
49
|
+
|
|
50
|
+
## License
|
|
51
|
+
|
|
52
|
+
See [LICENSE](https://github.com/evolving-machines-lab/evolve/blob/main/LICENSE) for details.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
bridge/__init__.py,sha256=hBfIKEwXusD5YNNkBb27SwzMCCapucjAjgwbltpXYrQ,161
|
|
2
|
+
bridge/dist/bridge.bundle.cjs,sha256=MDD1D1T5JmOyUUIIxZgOELvp5JnR4SnQ4UEKDhJJt84,3528785
|
|
3
|
+
evolve/__init__.py,sha256=26nH0hGuoGLRFGCunbzF69cPkqTtWxLve4eK31HwI_E,21231
|
|
4
|
+
evolve/_http.py,sha256=NQJpAdS0f76n7uP6mNPsaMH7NcPszcHQazQNYJUJ9k8,2752
|
|
5
|
+
evolve/agent.py,sha256=cjAoz3Yvo7AWJ_MjM6yOLb-NdS0cFymLMDOI6VP3bZM,37638
|
|
6
|
+
evolve/bridge.py,sha256=NQ9VOOvVKms_DX-y1-LVi4g2HHNtwE32qRjwcPW9TfQ,18778
|
|
7
|
+
evolve/browser_credentials.py,sha256=sC8vTKBgic48PZ0mW_VHs07xmDGHNh8FXOTBrGe_Vw8,9452
|
|
8
|
+
evolve/browser_profiles.py,sha256=0pwsav3Tltyf2Sv5ghI1FxBl7SUKK_mbnRgUbxF6em0,2747
|
|
9
|
+
evolve/config.py,sha256=bYWkgbq4_C0bYVmn6HLuHQdgVLel7K4WQ_yRhQ73GTg,21294
|
|
10
|
+
evolve/hosted.py,sha256=6fxn2C7XJx3NTV4sVC-qaqRGvSVmVRReW0KPTrZhv9w,402058
|
|
11
|
+
evolve/integrations.py,sha256=d-aVO900Ebz8Gx0TjfMtNtCqaX1VIGavTuEcIgEvtf4,5270
|
|
12
|
+
evolve/managed_secrets.py,sha256=pDp0paF3Cy6H_2ZtahHBv--5lFrZwozrkSf2ZKJ-ntY,6651
|
|
13
|
+
evolve/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
|
+
evolve/results.py,sha256=w2Ciy3RpKmUx9u5kRDgKGuO20r1p1yatb7xfJA9HSLU,12188
|
|
15
|
+
evolve/retry.py,sha256=Sfnm21Qed8u4kfI85KD1qr2geNW6OSGIurbKDQBQSbg,4637
|
|
16
|
+
evolve/schema.py,sha256=hmmpBxdsI7FWNf7Gd8dDhIWICwVcowodMQ0mKiu9_xs,2988
|
|
17
|
+
evolve/sessions_client.py,sha256=I77OIMyk0xykfP-8dGsngxlOignkHFrTgnXrzgnGnSw,5910
|
|
18
|
+
evolve/storage_client.py,sha256=eMprWnt6j-CoYWjsueAp-tiReow9UdwczUgQAWvJ-hA,6325
|
|
19
|
+
evolve/utils.py,sha256=5ZHthhPMfNY9EoUcXDUhFxGqFg9q_ieaVRPCpr0l_6Y,8399
|
|
20
|
+
evolve/pipeline/__init__.py,sha256=FfRHkWeY1p7YruUJ9cqKlO64mkOngKyxi3GRaADU0ns,1134
|
|
21
|
+
evolve/pipeline/pipeline.py,sha256=FK7K_z7hl-XQZaKMKFDWlSDbKZv2f0ftgOHYjUsYqyY,19885
|
|
22
|
+
evolve/pipeline/types.py,sha256=iq1Nmyx2dMMCK4UT3Xz0emIuXRVoEvZVDJ9driKqMfQ,8605
|
|
23
|
+
evolve/prompts/__init__.py,sha256=fBJa9pNo_xIXEsQLlDWsmg8pVQf9KFEu13TdG7o0pv0,4971
|
|
24
|
+
evolve/prompts/agent_md/judge.md,sha256=RbBH58q-A_7ZyG3vMGEMMUI1V7owhvK17qAnjkFPdQs,1019
|
|
25
|
+
evolve/prompts/agent_md/reduce.md,sha256=nzG5cuIfoHhp-m80Z2CUA9kBYjggtagX1tA_ERPx2rs,117
|
|
26
|
+
evolve/prompts/agent_md/verify.md,sha256=96tNr4UOp8c64xqC6kSJPnH4RHW27l88oJRsU8lUYAY,1012
|
|
27
|
+
evolve/prompts/user/judge.md,sha256=voZSLTXCte2-94D_Wx0JrCPKjv093DBrnBrnkzQy5Tg,111
|
|
28
|
+
evolve/prompts/user/retry_feedback.md,sha256=-dUWfAbknKsrPArHd38jE1ShQ-3quKInrhcm6x1W4fc,237
|
|
29
|
+
evolve/prompts/user/verify.md,sha256=Tuq8FQotrBTFOm_lngEpNx8j7l12J96QrVKPnmuxQpU,109
|
|
30
|
+
evolve/swarm/__init__.py,sha256=3qLm8TqAPbcpXH7vuWLr3IqJ7bUj9hz_qpCdTjBjln4,1430
|
|
31
|
+
evolve/swarm/results.py,sha256=vNWCOkJ_fnEUsCipWq7xAADxg4hJdV3Wh4YI57drR8s,4516
|
|
32
|
+
evolve/swarm/swarm.py,sha256=sSkwjf-gF3IopiR3SIft23Um-t43mGxz8qTR3M121Lo,86301
|
|
33
|
+
evolve/swarm/types.py,sha256=ggHFGe4LiCbVYQFCdAzQKPytrgjvct1sD9V0jM15HxA,8751
|
|
34
|
+
evolvingmachines_evolve-0.0.55.dev1355.dist-info/licenses/LICENSE,sha256=QwcOLU5TJoTeUhuIXzhdCEEDDvorGiC6-3YTOl4TecE,11356
|
|
35
|
+
evolvingmachines_evolve-0.0.55.dev1355.dist-info/METADATA,sha256=n5F1aFHHcj6Y0ydIGyCYqhaHnNH8iCUZzZH1akl5YC4,2230
|
|
36
|
+
evolvingmachines_evolve-0.0.55.dev1355.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
37
|
+
evolvingmachines_evolve-0.0.55.dev1355.dist-info/top_level.txt,sha256=a89CrgZq2tVvkvvzaaJDSKWm_cU3G1fGB9i_qC6Fre0,14
|
|
38
|
+
evolvingmachines_evolve-0.0.55.dev1355.dist-info/RECORD,,
|