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/config.py
ADDED
|
@@ -0,0 +1,600 @@
|
|
|
1
|
+
"""Configuration types for Evolve SDK."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
from typing import Any, Dict, List, Literal, Optional, Protocol, TypedDict, Union, runtime_checkable
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
AgentType = Literal['codex', 'claude', 'gemini', 'qwen', 'kimi', 'opencode', 'droid']
|
|
8
|
+
WorkspaceMode = Literal['knowledge', 'swe', 'task']
|
|
9
|
+
BrowserProvider = Literal['browser-use', 'actionbook', 'agent-browser']
|
|
10
|
+
BrowserConfig = Union[BrowserProvider, Dict[str, Any]]
|
|
11
|
+
AgentPluginConfig = Dict[str, Any]
|
|
12
|
+
ReasoningEffort = Literal['off', 'minimal', 'low', 'medium', 'high', 'xhigh', 'max', 'thinking', 'no-thinking']
|
|
13
|
+
#: The platform's named agent-settings presets - exactly two at launch:
|
|
14
|
+
#: 'no-internet' (vendor server-side web tools off) and 'pinned-context'
|
|
15
|
+
#: (one fixed effective context window). See AgentConfig.preset.
|
|
16
|
+
AgentPreset = Literal['no-internet', 'pinned-context']
|
|
17
|
+
ValidationMode = Literal['strict', 'loose']
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class SandboxNetworkPolicy(TypedDict, total=False):
|
|
21
|
+
outbound: Literal['open', 'blocked']
|
|
22
|
+
allowedDestinations: List[str]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SandboxCreateOptions(TypedDict, total=False):
|
|
26
|
+
image: str
|
|
27
|
+
envs: Dict[str, str]
|
|
28
|
+
metadata: Dict[str, str]
|
|
29
|
+
timeoutMs: int
|
|
30
|
+
workingDirectory: str
|
|
31
|
+
network: SandboxNetworkPolicy
|
|
32
|
+
# Run all commands and file operations as this user; providers must reject
|
|
33
|
+
# it if they cannot enforce it, never silently ignore it.
|
|
34
|
+
user: str
|
|
35
|
+
# Home directory for agent config paths. Default: "/root" when user is
|
|
36
|
+
# "root", "/home/<user>" otherwise, "/home/user" when no user is given.
|
|
37
|
+
homeDir: str
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class SchemaOptions:
|
|
42
|
+
"""Validation options for schema validation.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
mode: Validation mode - 'strict' (exact types) or 'loose' (coerce types, default)
|
|
46
|
+
"""
|
|
47
|
+
mode: ValidationMode = 'loose'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@dataclass
|
|
51
|
+
class BrowserCredentialScopeEntry:
|
|
52
|
+
"""Saved browser login selector for a run.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
website: Website/domain, e.g. "github.com"
|
|
56
|
+
account_label: Optional one-word label for a saved credential, such as "qa-admin" or "work"; not the website username or email
|
|
57
|
+
"""
|
|
58
|
+
website: str
|
|
59
|
+
account_label: Optional[str] = None
|
|
60
|
+
|
|
61
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
62
|
+
result: Dict[str, Any] = {'website': self.website}
|
|
63
|
+
if self.account_label:
|
|
64
|
+
result['account_label'] = self.account_label
|
|
65
|
+
return result
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
@dataclass
|
|
69
|
+
class BrowserCredentialsConfig:
|
|
70
|
+
"""Browser login MCP configuration for managed remote agent-browser runs.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
allow: Optional list of website/account_label selectors. None or [] exposes all enabled browser logins.
|
|
74
|
+
"""
|
|
75
|
+
allow: Optional[List[Union[BrowserCredentialScopeEntry, Dict[str, Any]]]] = None
|
|
76
|
+
|
|
77
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
78
|
+
result: Dict[str, Any] = {}
|
|
79
|
+
if self.allow:
|
|
80
|
+
result['allow'] = [
|
|
81
|
+
entry.to_dict() if isinstance(entry, BrowserCredentialScopeEntry) else dict(entry)
|
|
82
|
+
for entry in self.allow
|
|
83
|
+
]
|
|
84
|
+
return result
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class HostedClientConfig:
|
|
89
|
+
"""Standalone hosted evals client configuration (datasets/jobs).
|
|
90
|
+
|
|
91
|
+
Args:
|
|
92
|
+
api_key: Evolve API key override (default: EVOLVE_API_KEY)
|
|
93
|
+
base_url: API base URL override (default: the Evolve dashboard API)
|
|
94
|
+
"""
|
|
95
|
+
api_key: Optional[str] = None
|
|
96
|
+
base_url: Optional[str] = None
|
|
97
|
+
|
|
98
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
99
|
+
result: Dict[str, Any] = {}
|
|
100
|
+
if self.api_key:
|
|
101
|
+
result['api_key'] = self.api_key
|
|
102
|
+
if self.base_url:
|
|
103
|
+
result['base_url'] = self.base_url
|
|
104
|
+
return result
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
@dataclass
|
|
108
|
+
class BrowserCredentialsClientConfig:
|
|
109
|
+
"""Standalone browser credentials client configuration.
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
api_key: Evolve API key override
|
|
113
|
+
dashboard_url: Dashboard URL override
|
|
114
|
+
"""
|
|
115
|
+
api_key: Optional[str] = None
|
|
116
|
+
dashboard_url: Optional[str] = None
|
|
117
|
+
|
|
118
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
119
|
+
result: Dict[str, Any] = {}
|
|
120
|
+
if self.api_key:
|
|
121
|
+
result['api_key'] = self.api_key
|
|
122
|
+
if self.dashboard_url:
|
|
123
|
+
result['dashboard_url'] = self.dashboard_url
|
|
124
|
+
return result
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass
|
|
128
|
+
class BrowserProfilesClientConfig:
|
|
129
|
+
"""Standalone browser profiles client configuration.
|
|
130
|
+
|
|
131
|
+
Args:
|
|
132
|
+
api_key: Evolve API key override
|
|
133
|
+
dashboard_url: Dashboard URL override
|
|
134
|
+
"""
|
|
135
|
+
api_key: Optional[str] = None
|
|
136
|
+
dashboard_url: Optional[str] = None
|
|
137
|
+
|
|
138
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
139
|
+
result: Dict[str, Any] = {}
|
|
140
|
+
if self.api_key:
|
|
141
|
+
result['api_key'] = self.api_key
|
|
142
|
+
if self.dashboard_url:
|
|
143
|
+
result['dashboard_url'] = self.dashboard_url
|
|
144
|
+
return result
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
@dataclass
|
|
148
|
+
class ManagedSecretRef:
|
|
149
|
+
"""Dashboard-stored managed secret to attach to a sandbox session.
|
|
150
|
+
|
|
151
|
+
How the value reaches the sandbox is the STORED secret's delivery mode
|
|
152
|
+
(chosen when the secret is saved): 'brokered' keeps the value out of the
|
|
153
|
+
sandbox (opaque placeholder env + egress-proxy swap toward the secret's
|
|
154
|
+
allowed hosts) and 'direct' places the raw value in the sandbox
|
|
155
|
+
environment (URL-parameter keys, gRPC, websockets).
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
name: Stable Dashboard secret name, e.g. "GITHUB_TOKEN"
|
|
159
|
+
label: Optional labeled row of that name. Omitted = the server's
|
|
160
|
+
shared resolution law: the 'default'-labeled row when one
|
|
161
|
+
exists, the single row when exactly one exists, and a typed
|
|
162
|
+
ambiguity refusal naming every label otherwise.
|
|
163
|
+
as_name: Optional env var alias in the sandbox. Defaults to name.
|
|
164
|
+
"""
|
|
165
|
+
name: str
|
|
166
|
+
label: Optional[str] = None
|
|
167
|
+
as_name: Optional[str] = None
|
|
168
|
+
|
|
169
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
170
|
+
result: Dict[str, Any] = {'name': self.name}
|
|
171
|
+
if self.label:
|
|
172
|
+
result['label'] = self.label
|
|
173
|
+
if self.as_name:
|
|
174
|
+
result['as'] = self.as_name
|
|
175
|
+
return result
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
@dataclass
|
|
179
|
+
class ManagedSecretsClientConfig:
|
|
180
|
+
"""Standalone managed secrets client configuration.
|
|
181
|
+
|
|
182
|
+
Args:
|
|
183
|
+
api_key: Evolve API key override
|
|
184
|
+
dashboard_url: Dashboard URL override
|
|
185
|
+
"""
|
|
186
|
+
api_key: Optional[str] = None
|
|
187
|
+
dashboard_url: Optional[str] = None
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@dataclass
|
|
191
|
+
class AgentConfig:
|
|
192
|
+
"""Agent configuration.
|
|
193
|
+
|
|
194
|
+
Three modes of operation:
|
|
195
|
+
- Gateway mode: Use `api_key` (Evolve key) for dashboard observability
|
|
196
|
+
- Direct mode: Use `provider_api_key` (BYOK) to connect directly to providers
|
|
197
|
+
- OAuth mode: Use `oauth_token` for Claude Max subscription (Claude only)
|
|
198
|
+
|
|
199
|
+
All fields are optional - TS SDK auto-detects from environment variables.
|
|
200
|
+
|
|
201
|
+
Args:
|
|
202
|
+
type: Agent type (codex, claude, gemini, qwen, kimi, opencode, droid) - defaults to 'claude'
|
|
203
|
+
api_key: Evolve API key for gateway mode (defaults to EVOLVE_API_KEY env var)
|
|
204
|
+
provider_api_key: Provider API key for direct mode / BYOK (defaults to provider env var)
|
|
205
|
+
oauth_token: OAuth token for Claude Max subscription (defaults to CLAUDE_CODE_OAUTH_TOKEN env var)
|
|
206
|
+
provider_base_url: Provider base URL for direct mode (auto-detected for Qwen)
|
|
207
|
+
model: Model name (optional - uses agent's default if not specified). Use 'fable' for Claude Fable 5.1 or 'sonnet[1m]' / 'opus[1m]' for 1M context window (Claude only).
|
|
208
|
+
reasoning_effort: Reasoning effort for models that support it (optional)
|
|
209
|
+
max_context_size: Context/completion ceiling for CLIs that must be told one
|
|
210
|
+
(Kimi Code reads it as max_context_size and sends it as the request's
|
|
211
|
+
max_tokens). Set it to the model's real ceiling when driving a harness
|
|
212
|
+
against a model from another family - e.g. Kimi Code against 'gpt-5.5'
|
|
213
|
+
through an OpenAI-compatible gateway, where an oversized max_tokens is
|
|
214
|
+
rejected with a 400. When set it is used verbatim. When omitted, the
|
|
215
|
+
harness's own models keep their registry value and any other model falls
|
|
216
|
+
back to a conservative 128000. Harnesses that never send a ceiling ignore it.
|
|
217
|
+
"""
|
|
218
|
+
type: Optional[AgentType] = None
|
|
219
|
+
api_key: Optional[str] = None
|
|
220
|
+
provider_api_key: Optional[str] = None
|
|
221
|
+
oauth_token: Optional[str] = None
|
|
222
|
+
provider_base_url: Optional[str] = None
|
|
223
|
+
model: Optional[str] = None
|
|
224
|
+
reasoning_effort: Optional[ReasoningEffort] = None
|
|
225
|
+
max_context_size: Optional[int] = None
|
|
226
|
+
#: Native agent settings - Harbor's ``config`` agent kwarg. A local file
|
|
227
|
+
#: path or an inline dict, converted into the harness's native settings
|
|
228
|
+
#: document inside the sandbox (Claude: settings JSON via --settings;
|
|
229
|
+
#: Codex: the base ~/.codex/config.toml). The user document is the BASE;
|
|
230
|
+
#: platform routing/MCP/model/effort are stamped on top. Only claude and
|
|
231
|
+
#: codex support it; any other agent type refuses loudly.
|
|
232
|
+
config: Optional[Union[str, Dict[str, Any]]] = None
|
|
233
|
+
#: Named agent-settings preset, delivered through the same channel as
|
|
234
|
+
#: ``config`` and stamped ON TOP of it: ``"no-internet"`` turns off the
|
|
235
|
+
#: vendor's server-side web tools (Claude settings deny WebSearch/WebFetch;
|
|
236
|
+
#: Codex ``-c web_search=disabled``), ``"pinned-context"`` pins one fixed
|
|
237
|
+
#: effective context window. Only claude and codex can guarantee them; any
|
|
238
|
+
#: other combination refuses loudly - never a run silently missing its
|
|
239
|
+
#: guarantee.
|
|
240
|
+
preset: Optional[AgentPreset] = None
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
@runtime_checkable
|
|
244
|
+
class SandboxProvider(Protocol):
|
|
245
|
+
"""Sandbox provider protocol.
|
|
246
|
+
|
|
247
|
+
Any sandbox provider must implement this protocol.
|
|
248
|
+
Currently supported: E2BProvider, DaytonaProvider, ModalProvider
|
|
249
|
+
|
|
250
|
+
To add a new provider:
|
|
251
|
+
1. Create a class with `type` and `config` properties
|
|
252
|
+
2. Add handling in bridge/src/adapter.ts
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
@property
|
|
256
|
+
def type(self) -> str:
|
|
257
|
+
"""Provider type identifier (e.g., 'e2b', 'daytona')."""
|
|
258
|
+
...
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def config(self) -> dict:
|
|
262
|
+
"""Provider configuration dict for the bridge."""
|
|
263
|
+
...
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
@dataclass
|
|
267
|
+
class ManagedProvider:
|
|
268
|
+
"""A sandbox the Evolve platform runs for you.
|
|
269
|
+
|
|
270
|
+
Managed mode means you hold an Evolve API key and no provider credential at
|
|
271
|
+
all: the Dashboard authenticates the key, records ownership, and makes the
|
|
272
|
+
provider call with platform credentials.
|
|
273
|
+
|
|
274
|
+
Which provider backs the sandbox is an argument here — never an
|
|
275
|
+
environment variable — so a program says what it runs on.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
provider: 'e2b' (default), 'daytona', or 'modal'.
|
|
279
|
+
api_key: Evolve API key (defaults to the EVOLVE_API_KEY env var)
|
|
280
|
+
timeout_ms: Lifetime cap (ms) applied to every sandbox this provider
|
|
281
|
+
creates; per-create options still win.
|
|
282
|
+
resources: Compute sizing applied to every create, as a dict with
|
|
283
|
+
'cpu' (cores), 'memory' and 'disk' (GiB) keys. Providers and the
|
|
284
|
+
managed doors reject entries they cannot enforce — never
|
|
285
|
+
silently ignored.
|
|
286
|
+
|
|
287
|
+
Example:
|
|
288
|
+
>>> evolve = Evolve(sandbox=ManagedProvider(provider='daytona', timeout_ms=7_200_000))
|
|
289
|
+
"""
|
|
290
|
+
provider: Literal['e2b', 'daytona', 'modal'] = 'e2b'
|
|
291
|
+
api_key: Optional[str] = None
|
|
292
|
+
timeout_ms: Optional[int] = None
|
|
293
|
+
resources: Optional[dict] = None
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def type(self) -> Literal['managed']:
|
|
297
|
+
"""Provider type."""
|
|
298
|
+
return 'managed'
|
|
299
|
+
|
|
300
|
+
@property
|
|
301
|
+
def config(self) -> dict:
|
|
302
|
+
"""Provider configuration dict."""
|
|
303
|
+
result: dict = {'provider': self.provider}
|
|
304
|
+
if self.api_key:
|
|
305
|
+
result['apiKey'] = self.api_key
|
|
306
|
+
if self.timeout_ms is not None:
|
|
307
|
+
result['timeoutMs'] = self.timeout_ms
|
|
308
|
+
if self.resources is not None:
|
|
309
|
+
result['resources'] = self.resources
|
|
310
|
+
return result
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
@dataclass
|
|
314
|
+
class E2BProvider:
|
|
315
|
+
"""E2B sandbox provider configuration.
|
|
316
|
+
|
|
317
|
+
Args:
|
|
318
|
+
api_key: E2B API key (defaults to E2B_API_KEY env var)
|
|
319
|
+
timeout_ms: Sandbox timeout in milliseconds (default: 3600000 = 1 hour)
|
|
320
|
+
template_id: E2B template ID (default: 'evolve-all'). Create custom templates at https://e2b.dev/docs/sandbox-template
|
|
321
|
+
"""
|
|
322
|
+
api_key: Optional[str] = None
|
|
323
|
+
timeout_ms: int = 3600000
|
|
324
|
+
template_id: Optional[str] = None
|
|
325
|
+
|
|
326
|
+
@property
|
|
327
|
+
def type(self) -> Literal['e2b']:
|
|
328
|
+
"""Provider type."""
|
|
329
|
+
return 'e2b'
|
|
330
|
+
|
|
331
|
+
@property
|
|
332
|
+
def config(self) -> dict:
|
|
333
|
+
"""Provider configuration dict."""
|
|
334
|
+
result = {}
|
|
335
|
+
if self.api_key:
|
|
336
|
+
result['apiKey'] = self.api_key
|
|
337
|
+
if self.timeout_ms:
|
|
338
|
+
result['defaultTimeoutMs'] = self.timeout_ms
|
|
339
|
+
if self.template_id:
|
|
340
|
+
result['templateId'] = self.template_id
|
|
341
|
+
return result
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
@dataclass
|
|
345
|
+
class DaytonaProvider:
|
|
346
|
+
"""Daytona sandbox provider configuration.
|
|
347
|
+
|
|
348
|
+
Args:
|
|
349
|
+
api_key: Daytona API key (defaults to DAYTONA_API_KEY env var)
|
|
350
|
+
api_url: API URL (defaults to https://app.daytona.io/api)
|
|
351
|
+
target: Target region (defaults to 'us')
|
|
352
|
+
timeout_ms: Sandbox timeout in milliseconds (default: 3600000 = 1 hour)
|
|
353
|
+
snapshot_name: Daytona snapshot name (default: the current release
|
|
354
|
+
snapshot, 'evolve-all-c-<12hex>' with the tag derived from the
|
|
355
|
+
image build inputs; explicit names pass through untouched).
|
|
356
|
+
Custom snapshots via ``cd assets && ./build.sh daytona``
|
|
357
|
+
"""
|
|
358
|
+
api_key: Optional[str] = None
|
|
359
|
+
api_url: Optional[str] = None
|
|
360
|
+
target: Optional[str] = None
|
|
361
|
+
timeout_ms: int = 3600000
|
|
362
|
+
snapshot_name: Optional[str] = None
|
|
363
|
+
|
|
364
|
+
@property
|
|
365
|
+
def type(self) -> Literal['daytona']:
|
|
366
|
+
"""Provider type."""
|
|
367
|
+
return 'daytona'
|
|
368
|
+
|
|
369
|
+
@property
|
|
370
|
+
def config(self) -> dict:
|
|
371
|
+
"""Provider configuration dict."""
|
|
372
|
+
result = {}
|
|
373
|
+
if self.api_key:
|
|
374
|
+
result['apiKey'] = self.api_key
|
|
375
|
+
if self.api_url:
|
|
376
|
+
result['apiUrl'] = self.api_url
|
|
377
|
+
if self.target:
|
|
378
|
+
result['target'] = self.target
|
|
379
|
+
if self.timeout_ms:
|
|
380
|
+
result['defaultTimeoutMs'] = self.timeout_ms
|
|
381
|
+
if self.snapshot_name:
|
|
382
|
+
result['snapshotName'] = self.snapshot_name
|
|
383
|
+
return result
|
|
384
|
+
|
|
385
|
+
|
|
386
|
+
@dataclass
|
|
387
|
+
class ModalProvider:
|
|
388
|
+
"""Modal sandbox provider configuration.
|
|
389
|
+
|
|
390
|
+
Args:
|
|
391
|
+
app_name: Modal app namespace (defaults to 'evolve-sandbox')
|
|
392
|
+
timeout_ms: Sandbox timeout in milliseconds (default: 3600000 = 1 hour)
|
|
393
|
+
token_id: Modal token ID (defaults to MODAL_TOKEN_ID env var)
|
|
394
|
+
token_secret: Modal token secret (defaults to MODAL_TOKEN_SECRET env var)
|
|
395
|
+
endpoint: Modal API endpoint (defaults to https://api.modal.com:443)
|
|
396
|
+
image_name: Docker image name (default: 'evolve-all'). Resolved through IMAGE_MAP or used as-is.
|
|
397
|
+
"""
|
|
398
|
+
app_name: Optional[str] = None
|
|
399
|
+
timeout_ms: int = 3600000
|
|
400
|
+
token_id: Optional[str] = None
|
|
401
|
+
token_secret: Optional[str] = None
|
|
402
|
+
endpoint: Optional[str] = None
|
|
403
|
+
image_name: Optional[str] = None
|
|
404
|
+
|
|
405
|
+
@property
|
|
406
|
+
def type(self) -> Literal['modal']:
|
|
407
|
+
"""Provider type."""
|
|
408
|
+
return 'modal'
|
|
409
|
+
|
|
410
|
+
@property
|
|
411
|
+
def config(self) -> dict:
|
|
412
|
+
"""Provider configuration dict."""
|
|
413
|
+
result = {}
|
|
414
|
+
if self.app_name:
|
|
415
|
+
result['appName'] = self.app_name
|
|
416
|
+
if self.timeout_ms:
|
|
417
|
+
result['defaultTimeoutMs'] = self.timeout_ms
|
|
418
|
+
if self.token_id:
|
|
419
|
+
result['tokenId'] = self.token_id
|
|
420
|
+
if self.token_secret:
|
|
421
|
+
result['tokenSecret'] = self.token_secret
|
|
422
|
+
if self.endpoint:
|
|
423
|
+
result['endpoint'] = self.endpoint
|
|
424
|
+
if self.image_name:
|
|
425
|
+
result['imageName'] = self.image_name
|
|
426
|
+
return result
|
|
427
|
+
|
|
428
|
+
|
|
429
|
+
# =============================================================================
|
|
430
|
+
# STORAGE / CHECKPOINTING
|
|
431
|
+
# =============================================================================
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@dataclass
|
|
435
|
+
class StorageCredentials:
|
|
436
|
+
"""S3 credentials for BYOK storage.
|
|
437
|
+
|
|
438
|
+
Args:
|
|
439
|
+
access_key_id: AWS access key ID
|
|
440
|
+
secret_access_key: AWS secret access key
|
|
441
|
+
"""
|
|
442
|
+
access_key_id: str
|
|
443
|
+
secret_access_key: str
|
|
444
|
+
|
|
445
|
+
|
|
446
|
+
@dataclass
|
|
447
|
+
class StorageConfig:
|
|
448
|
+
"""Storage configuration for checkpoint persistence.
|
|
449
|
+
|
|
450
|
+
Two modes of operation:
|
|
451
|
+
- BYOK mode: Provide `url` (S3 bucket URL) with optional credentials
|
|
452
|
+
- Gateway mode: Leave empty — Evolve-managed storage via EVOLVE_API_KEY
|
|
453
|
+
|
|
454
|
+
Args:
|
|
455
|
+
url: S3 bucket URL (e.g., 's3://my-bucket/prefix/')
|
|
456
|
+
bucket: S3 bucket name (alternative to url)
|
|
457
|
+
prefix: Key prefix within bucket
|
|
458
|
+
region: AWS region (default: auto-detect)
|
|
459
|
+
endpoint: Custom S3 endpoint (e.g., Cloudflare R2, MinIO)
|
|
460
|
+
credentials: Explicit S3 credentials (defaults to env AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY)
|
|
461
|
+
"""
|
|
462
|
+
url: Optional[str] = None
|
|
463
|
+
bucket: Optional[str] = None
|
|
464
|
+
prefix: Optional[str] = None
|
|
465
|
+
region: Optional[str] = None
|
|
466
|
+
endpoint: Optional[str] = None
|
|
467
|
+
credentials: Optional[StorageCredentials] = None
|
|
468
|
+
|
|
469
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
470
|
+
"""Convert to dict for JSON-RPC transport."""
|
|
471
|
+
result: Dict[str, Any] = {}
|
|
472
|
+
if self.url:
|
|
473
|
+
result['url'] = self.url
|
|
474
|
+
if self.bucket:
|
|
475
|
+
result['bucket'] = self.bucket
|
|
476
|
+
if self.prefix:
|
|
477
|
+
result['prefix'] = self.prefix
|
|
478
|
+
if self.region:
|
|
479
|
+
result['region'] = self.region
|
|
480
|
+
if self.endpoint:
|
|
481
|
+
result['endpoint'] = self.endpoint
|
|
482
|
+
if self.credentials:
|
|
483
|
+
result['credentials'] = {
|
|
484
|
+
'accessKeyId': self.credentials.access_key_id,
|
|
485
|
+
'secretAccessKey': self.credentials.secret_access_key,
|
|
486
|
+
}
|
|
487
|
+
return result
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
@dataclass
|
|
491
|
+
class SessionsConfig:
|
|
492
|
+
"""Configuration for the standalone sessions() client.
|
|
493
|
+
|
|
494
|
+
Gateway-only historical trace access. If omitted, the TypeScript sessions()
|
|
495
|
+
client resolves credentials from ``EVOLVE_API_KEY`` and dashboard defaults.
|
|
496
|
+
|
|
497
|
+
Args:
|
|
498
|
+
api_key: Explicit Evolve API key override
|
|
499
|
+
dashboard_url: Dashboard URL override (for staging/self-hosted setups)
|
|
500
|
+
"""
|
|
501
|
+
api_key: Optional[str] = None
|
|
502
|
+
dashboard_url: Optional[str] = None
|
|
503
|
+
|
|
504
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
505
|
+
"""Convert to dict for JSON-RPC transport."""
|
|
506
|
+
result: Dict[str, Any] = {}
|
|
507
|
+
if self.api_key:
|
|
508
|
+
result['apiKey'] = self.api_key
|
|
509
|
+
if self.dashboard_url:
|
|
510
|
+
result['dashboardUrl'] = self.dashboard_url
|
|
511
|
+
return result
|
|
512
|
+
|
|
513
|
+
|
|
514
|
+
# =============================================================================
|
|
515
|
+
# MANAGED INTEGRATIONS
|
|
516
|
+
# =============================================================================
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
class EnableFilter(TypedDict):
|
|
520
|
+
"""Enable only specific tools."""
|
|
521
|
+
enable: List[str]
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
class DisableFilter(TypedDict):
|
|
525
|
+
"""Disable specific tools."""
|
|
526
|
+
disable: List[str]
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class TagsFilter(TypedDict):
|
|
530
|
+
"""Filter by behavior tags."""
|
|
531
|
+
tags: List[str]
|
|
532
|
+
|
|
533
|
+
|
|
534
|
+
# Tool filter configuration per app - matches TS SDK IntegrationToolsFilter
|
|
535
|
+
IntegrationToolsFilter = Union[List[str], EnableFilter, DisableFilter, TagsFilter]
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
@dataclass(kw_only=True)
|
|
539
|
+
class IntegrationsConfig:
|
|
540
|
+
"""Managed integrations configuration.
|
|
541
|
+
|
|
542
|
+
Args:
|
|
543
|
+
apps: Apps to expose to the agent (e.g., ["github", "gmail"])
|
|
544
|
+
tools: Per-app tool filtering
|
|
545
|
+
accounts: Pin connected accounts by account ID or account label
|
|
546
|
+
keys: API keys for apps that use API-key auth
|
|
547
|
+
auth_configs: Custom auth config IDs per app
|
|
548
|
+
"""
|
|
549
|
+
apps: List[str]
|
|
550
|
+
tools: Optional[Dict[str, IntegrationToolsFilter]] = None
|
|
551
|
+
accounts: Optional[Dict[str, List[str]]] = None
|
|
552
|
+
keys: Optional[Dict[str, str]] = None
|
|
553
|
+
auth_configs: Optional[Dict[str, str]] = None
|
|
554
|
+
|
|
555
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
556
|
+
"""Convert to dict for JSON-RPC transport."""
|
|
557
|
+
result: Dict[str, Any] = {'apps': self.apps}
|
|
558
|
+
if self.tools:
|
|
559
|
+
result['tools'] = self.tools
|
|
560
|
+
if self.accounts:
|
|
561
|
+
result['accounts'] = self.accounts
|
|
562
|
+
if self.keys:
|
|
563
|
+
result['keys'] = self.keys
|
|
564
|
+
if self.auth_configs:
|
|
565
|
+
result['auth_configs'] = self.auth_configs
|
|
566
|
+
return result
|
|
567
|
+
|
|
568
|
+
|
|
569
|
+
@dataclass(kw_only=True)
|
|
570
|
+
class IntegrationsSetup:
|
|
571
|
+
"""Managed integrations setup.
|
|
572
|
+
|
|
573
|
+
Args:
|
|
574
|
+
user_id: Integration user ID. Use "root" for dashboard-owned/private accounts,
|
|
575
|
+
or your app's stable end-user ID for per-user accounts.
|
|
576
|
+
apps: Apps to expose to the agent
|
|
577
|
+
tools: Per-app tool filtering
|
|
578
|
+
accounts: Pin connected accounts by account ID or account label
|
|
579
|
+
keys: API keys for apps that use API-key auth
|
|
580
|
+
auth_configs: Custom auth config IDs per app
|
|
581
|
+
"""
|
|
582
|
+
user_id: str
|
|
583
|
+
apps: List[str]
|
|
584
|
+
tools: Optional[Dict[str, IntegrationToolsFilter]] = None
|
|
585
|
+
accounts: Optional[Dict[str, List[str]]] = None
|
|
586
|
+
keys: Optional[Dict[str, str]] = None
|
|
587
|
+
auth_configs: Optional[Dict[str, str]] = None
|
|
588
|
+
|
|
589
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
590
|
+
"""Convert to dict for JSON-RPC transport."""
|
|
591
|
+
result: Dict[str, Any] = {'user_id': self.user_id, 'apps': self.apps}
|
|
592
|
+
if self.tools:
|
|
593
|
+
result['tools'] = self.tools
|
|
594
|
+
if self.accounts:
|
|
595
|
+
result['accounts'] = self.accounts
|
|
596
|
+
if self.keys:
|
|
597
|
+
result['keys'] = self.keys
|
|
598
|
+
if self.auth_configs:
|
|
599
|
+
result['auth_configs'] = self.auth_configs
|
|
600
|
+
return result
|