@evolvingmachines/evolve 0.0.55-project-sable.20260916.db0bc0bb → 0.0.56
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/dist/cli/index.cjs +32 -32
- package/dist/cli/index.js +27 -27
- package/package.json +4 -6
- package/skills/evolve/SKILL.md +4 -3
- package/skills/evolve-evals/SKILL.md +112 -0
- package/{docs-evals → skills/evolve-evals/references}/cli-reference/run.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/cli-reference/skills.mdx +4 -4
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/agents.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/analyze.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/jobs.mdx +3 -3
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/models.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/sandboxes.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/secrets.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/core-concepts/trial-outputs.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/getting-started/quick-start.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/index.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk/python.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk/typescript.mdx +1 -1
- package/{docs-evals → skills/evolve-evals/references}/sdk-reference/errors.mdx +2 -2
- package/{docs-evals → skills/evolve-evals/references}/sdk-reference/jobs.mdx +2 -2
- package/docs-agents/SKILL.md +0 -138
- package/docs-agents/index.md +0 -81
- package/docs-agents/python/01-getting-started.md +0 -511
- package/docs-agents/python/02-configuration.md +0 -855
- package/docs-agents/python/03-runtime.md +0 -899
- package/docs-agents/python/04-streaming.md +0 -451
- package/docs-agents/python/05-swarm-pipeline.md +0 -953
- package/docs-agents/python/index.md +0 -122
- package/docs-agents/typescript/01-getting-started.md +0 -494
- package/docs-agents/typescript/02-configuration.md +0 -841
- package/docs-agents/typescript/03-runtime.md +0 -864
- package/docs-agents/typescript/04-streaming.md +0 -478
- package/docs-agents/typescript/05-swarm-pipeline.md +0 -957
- package/docs-agents/typescript/index.md +0 -121
- package/docs-evals/SKILL.md +0 -112
- package/docs-evals/docs.json +0 -180
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/agent.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analysis.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/analyze.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/auth.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/check.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/dataset.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/job.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/secrets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/skill.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/trial.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/cli-reference/upload.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/check.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/skills.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/tasks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/trials.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/core-concepts/upload.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/checks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/jobs.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/traces.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/dashboard/trial-viewer.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/getting-started/installation.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/agents.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/analyses.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/auth.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/checks.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/datasets.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/index.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/meta.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/skills.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/trials.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/sdk-reference/types.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/snippets/global-options.mdx +0 -0
- /package/{docs-evals → skills/evolve-evals/references}/snippets/list-flags.mdx +0 -0
|
@@ -1,855 +0,0 @@
|
|
|
1
|
-
# Configuration
|
|
2
|
-
|
|
3
|
-
## Sandbox Providers
|
|
4
|
-
|
|
5
|
-
Works with both Gateway mode (`EVOLVE_API_KEY`) and Direct Provider Key Mode (local BYOK provider keys). With `EVOLVE_API_KEY` only, sandbox defaults to **E2B**. Add a sandbox provider key to auto-resolve to that provider.
|
|
6
|
-
|
|
7
|
-
All providers use the `evolve-all` image with pre-installed CLIs.
|
|
8
|
-
|
|
9
|
-
| Provider | Env Vars | Auto-Resolves When | First Time Setup |
|
|
10
|
-
|----------|----------|-------------------|------------------|
|
|
11
|
-
| E2B | `E2B_API_KEY` | Default, or `E2B_API_KEY` set | None — instant |
|
|
12
|
-
| Modal | `MODAL_TOKEN_ID` + `MODAL_TOKEN_SECRET` | Both Modal vars set | None — auto-builds image on first run (~2 min) |
|
|
13
|
-
| Daytona | `DAYTONA_API_KEY` | `DAYTONA_API_KEY` set | None — auto-creates snapshot on first run (~5 min) |
|
|
14
|
-
|
|
15
|
-
See [assets/README.md](https://github.com/evolving-machines-lab/evolve/blob/main/assets/README.md) for detailed setup instructions.
|
|
16
|
-
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
### Auto-Resolution
|
|
20
|
-
|
|
21
|
-
Set env vars and the SDK auto-resolves the provider—no `sandbox=` needed:
|
|
22
|
-
|
|
23
|
-
```bash
|
|
24
|
-
# .env - Gateway mode with Modal (auto-resolves to Modal)
|
|
25
|
-
EVOLVE_API_KEY=sk-...
|
|
26
|
-
MODAL_TOKEN_ID=ak-...
|
|
27
|
-
MODAL_TOKEN_SECRET=as-...
|
|
28
|
-
|
|
29
|
-
# .env - Gateway mode with Daytona (auto-resolves to Daytona)
|
|
30
|
-
EVOLVE_API_KEY=sk-...
|
|
31
|
-
DAYTONA_API_KEY=...
|
|
32
|
-
|
|
33
|
-
# .env - Direct Provider Key Mode with E2B (auto-resolves to E2B)
|
|
34
|
-
ANTHROPIC_API_KEY=sk-ant-...
|
|
35
|
-
E2B_API_KEY=e2b_...
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
```python
|
|
39
|
-
from evolve import Evolve, AgentConfig
|
|
40
|
-
|
|
41
|
-
# No sandbox= needed — SDK picks the right provider from env
|
|
42
|
-
evolve = Evolve(
|
|
43
|
-
agent=AgentConfig(type="claude"),
|
|
44
|
-
)
|
|
45
|
-
|
|
46
|
-
await evolve.run(prompt="Hello")
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
Only use explicit provider creation (below) if you need custom settings like timeout or app name.
|
|
50
|
-
|
|
51
|
-
Setting `EVOLVE_API_KEY` together with your own sandbox key is how you control sandbox billing
|
|
52
|
-
separately: the sandbox is created and billed on your provider account, while model traffic still
|
|
53
|
-
routes through the Evolve gateway on a session-scoped token. One bound to remember — on your own
|
|
54
|
-
sandbox account the routing token expires 24 hours after the sandbox comes up, so a single
|
|
55
|
-
session is bounded at a day; reconnecting to the sandbox starts a fresh one. Platform-managed
|
|
56
|
-
sandboxes carry no such clock; their tokens live and die with the sandbox.
|
|
57
|
-
|
|
58
|
-
---
|
|
59
|
-
|
|
60
|
-
### Managed Sandboxes
|
|
61
|
-
|
|
62
|
-
With `EVOLVE_API_KEY` and no provider key, the platform runs the sandbox for you: Evolve
|
|
63
|
-
authenticates your key, creates the box on its own account, and records who owns it. You never
|
|
64
|
-
hold an E2B, Daytona, or Modal credential, and you are never billed by them directly.
|
|
65
|
-
|
|
66
|
-
That is already what auto-resolution does when only `EVOLVE_API_KEY` is set — it gives you a
|
|
67
|
-
managed **E2B** sandbox. To run on a different provider, say which one:
|
|
68
|
-
|
|
69
|
-
```python
|
|
70
|
-
from evolve import AgentConfig, Evolve, ManagedProvider
|
|
71
|
-
|
|
72
|
-
evolve = Evolve(
|
|
73
|
-
config=AgentConfig(type='claude'),
|
|
74
|
-
sandbox=ManagedProvider(provider='daytona'),
|
|
75
|
-
)
|
|
76
|
-
|
|
77
|
-
await evolve.run(prompt='Hello')
|
|
78
|
-
```
|
|
79
|
-
|
|
80
|
-
`ManagedProvider()` with no argument is managed E2B — the same sandbox auto-resolution gives you.
|
|
81
|
-
The provider is an argument rather than an environment variable on purpose: which provider your
|
|
82
|
-
program runs on is part of the program.
|
|
83
|
-
|
|
84
|
-
Beyond the provider name, `ManagedProvider` carries the Evolve key (when it should not come
|
|
85
|
-
from `EVOLVE_API_KEY`) plus sandbox-shape defaults applied to every sandbox it creates.
|
|
86
|
-
Every default rides the same validated path as a create-time option — a provider or managed
|
|
87
|
-
door that cannot enforce a value refuses it loudly, never silently ignores it:
|
|
88
|
-
|
|
89
|
-
```python
|
|
90
|
-
sandbox = ManagedProvider(
|
|
91
|
-
provider='daytona',
|
|
92
|
-
api_key='sk-...', # (optional) Default: EVOLVE_API_KEY
|
|
93
|
-
timeout_ms=7_200_000, # (optional) Lifetime cap for every create
|
|
94
|
-
resources={'cpu': 2}, # (optional) Sizing; refused where not enforceable
|
|
95
|
-
)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Managed Daytona carries both of Daytona's planes through the Dashboard — creating and listing
|
|
99
|
-
sandboxes, and every command and file operation the agent performs, including streamed command
|
|
100
|
-
output. Images come from the snapshots the platform publishes: a managed create names one and
|
|
101
|
-
never builds one, so a `resources` request that an existing snapshot cannot honor is refused
|
|
102
|
-
rather than silently ignored.
|
|
103
|
-
|
|
104
|
-
Managed Modal — `ManagedProvider(provider='modal')` — runs commands and file operations through
|
|
105
|
-
the Dashboard's Modal door. Command output streams live, chunk by chunk, and each command's
|
|
106
|
-
duration is bounded by the door: 60 minutes by default, 120 minutes at most — a longer
|
|
107
|
-
`timeout_ms` is refused with an error naming the bound, never silently shortened. Two Modal
|
|
108
|
-
traits carry over: there is no pause — persist progress with Evolve checkpoints instead — and
|
|
109
|
-
a running command cannot be interrupted. Sizing, network policy, and the sandbox user are the
|
|
110
|
-
platform's; a create that asks for them is refused rather than silently ignored. File writes
|
|
111
|
-
ride the door one JSON body at a time, capped at 1 MiB per request — and the cap is on WIRE
|
|
112
|
-
bytes, base64 inflation included, so the largest binary payload one write can carry is about
|
|
113
|
-
768 KiB (text rides as-is and gets the full 1 MiB). An over-cap write is refused with a typed
|
|
114
|
-
error before anything is sent; split the payload into smaller writes.
|
|
115
|
-
|
|
116
|
-
---
|
|
117
|
-
|
|
118
|
-
### E2B (default)
|
|
119
|
-
```bash
|
|
120
|
-
# .env - Gateway mode
|
|
121
|
-
EVOLVE_API_KEY=sk-...
|
|
122
|
-
E2B_API_KEY=e2b_... # Optional with EVOLVE_API_KEY (auto-resolves)
|
|
123
|
-
|
|
124
|
-
# .env - Direct Provider Key Mode
|
|
125
|
-
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
126
|
-
E2B_API_KEY=e2b_... # Required in Direct Provider Key Mode
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
```python
|
|
130
|
-
from evolve import E2BProvider
|
|
131
|
-
|
|
132
|
-
sandbox = E2BProvider(
|
|
133
|
-
api_key=os.getenv('E2B_API_KEY'), # (optional) Auto-resolves from env
|
|
134
|
-
timeout_ms=3600000, # (optional) Default: 3600000 (1 hour)
|
|
135
|
-
template_id='my-custom-template', # (optional) E2B template ID. Default: 'evolve-all'
|
|
136
|
-
)
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Modal
|
|
140
|
-
```bash
|
|
141
|
-
# .env - Gateway mode
|
|
142
|
-
EVOLVE_API_KEY=sk-...
|
|
143
|
-
MODAL_TOKEN_ID=ak-...
|
|
144
|
-
MODAL_TOKEN_SECRET=as-...
|
|
145
|
-
|
|
146
|
-
# .env - Direct Provider Key Mode
|
|
147
|
-
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
148
|
-
MODAL_TOKEN_ID=ak-...
|
|
149
|
-
MODAL_TOKEN_SECRET=as-...
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
```python
|
|
153
|
-
from evolve import ModalProvider
|
|
154
|
-
|
|
155
|
-
sandbox = ModalProvider(
|
|
156
|
-
token_id=os.getenv('MODAL_TOKEN_ID'), # (optional) Auto-resolves from env
|
|
157
|
-
token_secret=os.getenv('MODAL_TOKEN_SECRET'), # (optional) Auto-resolves from env
|
|
158
|
-
app_name='my-app', # (optional) Default: 'evolve-sandbox'
|
|
159
|
-
timeout_ms=3600000, # (optional) Default: 3600000 (1 hour)
|
|
160
|
-
endpoint='https://api.modal.com:443', # (optional) Default: https://api.modal.com:443
|
|
161
|
-
image_name='evolve-all', # (optional) Default: 'evolve-all'
|
|
162
|
-
)
|
|
163
|
-
```
|
|
164
|
-
|
|
165
|
-
### Daytona
|
|
166
|
-
```bash
|
|
167
|
-
# .env - Gateway mode
|
|
168
|
-
EVOLVE_API_KEY=sk-...
|
|
169
|
-
DAYTONA_API_KEY=...
|
|
170
|
-
|
|
171
|
-
# .env - Direct Provider Key Mode
|
|
172
|
-
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
173
|
-
DAYTONA_API_KEY=...
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
```python
|
|
177
|
-
from evolve import DaytonaProvider
|
|
178
|
-
|
|
179
|
-
sandbox = DaytonaProvider(
|
|
180
|
-
api_key=os.getenv('DAYTONA_API_KEY'), # (optional) Auto-resolves from env
|
|
181
|
-
api_url='https://app.daytona.io/api', # (optional) Default: https://app.daytona.io/api
|
|
182
|
-
target='us', # (optional) Target region. Default: 'us'
|
|
183
|
-
timeout_ms=3600000, # (optional) Default: 3600000 (1 hour) - converted to minutes for auto-stop
|
|
184
|
-
snapshot_name='my-snapshot', # (optional) Default: the current release snapshot ('evolve-all-c-<12hex>', tag derived from the image build inputs); explicit names pass through untouched. Custom snapshots via build.sh daytona
|
|
185
|
-
)
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
If a snapshot is found in a terminally failed state, the SDK deletes it and rebuilds it, so one bad build does not leave the name unusable. It only does this when it can rebuild the image itself — the reference carries a real tag or digest — and never for a bare name that resolves to no image, such as `my-team-env`.
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
---
|
|
192
|
-
|
|
193
|
-
## Sandbox Create Options
|
|
194
|
-
|
|
195
|
-
`sandbox_create_options` sets provider-neutral options used whenever Evolve creates a fresh sandbox — image, env vars, metadata, timeout, working directory, outbound network policy, and the user/home the agent runs as:
|
|
196
|
-
|
|
197
|
-
```python
|
|
198
|
-
from evolve import Evolve
|
|
199
|
-
|
|
200
|
-
evolve = Evolve(
|
|
201
|
-
sandbox_create_options={
|
|
202
|
-
'image': 'my-eval-template', # (optional) Sandbox image/template ID (provider default if omitted)
|
|
203
|
-
'envs': {'TASK_ID': 'swe-042'}, # (optional) Extra env vars (Evolve-owned runtime vars win on conflict)
|
|
204
|
-
'metadata': {'suite': 'nightly'}, # (optional) Provider metadata
|
|
205
|
-
'timeoutMs': 3600000, # (optional) Sandbox timeout
|
|
206
|
-
'workingDirectory': '/repo', # (optional) Working directory for agent commands
|
|
207
|
-
'network': { # (optional) Outbound network policy applied at boot
|
|
208
|
-
'outbound': 'blocked', # 'open' | 'blocked'
|
|
209
|
-
'allowedDestinations': ['registry.npmjs.org', '10.0.0.0/8'],
|
|
210
|
-
},
|
|
211
|
-
'user': 'root', # (optional) Run all commands and file ops as this user
|
|
212
|
-
'homeDir': '/root', # (optional) Home dir for agent config paths
|
|
213
|
-
},
|
|
214
|
-
)
|
|
215
|
-
```
|
|
216
|
-
|
|
217
|
-
**Network policy.** `'outbound': 'blocked'` denies all outbound traffic except `allowedDestinations` (hostnames, IPs, or CIDR ranges). Providers that cannot enforce a requested policy reject it with an error — a policy is never silently ignored.
|
|
218
|
-
|
|
219
|
-
**User and home directory.** `user` runs every command and file operation as that user; providers that cannot enforce it reject it (E2B supports run-as-root). `homeDir` controls where agent config files (settings, session state, skills) are written. Defaults: `/root` when `user` is `'root'`, `/home/<user>` for other users, `/home/user` when no user is given. The default working directory follows as `<homeDir>/workspace`.
|
|
220
|
-
|
|
221
|
-
Constraints:
|
|
222
|
-
|
|
223
|
-
- A `user` can only be enforced at sandbox creation — combining it with `sandbox_id=`/`set_session()` (an existing sandbox) raises.
|
|
224
|
-
- Checkpoint storage (`storage=`) and managed browser features require the default `/home/user` home; combining them with a custom `user`/`homeDir` raises.
|
|
225
|
-
- `envs` entries are validated like `secrets=` values — Evolve-reserved variable names are rejected.
|
|
226
|
-
|
|
227
|
-
---
|
|
228
|
-
|
|
229
|
-
## Workspace Modes
|
|
230
|
-
|
|
231
|
-
`workspace_mode` controls what Evolve sets up in the working directory on first run:
|
|
232
|
-
|
|
233
|
-
| Mode | Workspace setup | Use it for |
|
|
234
|
-
|------|-----------------|------------|
|
|
235
|
-
| `'knowledge'` (default) | Creates `context/`, `scripts/`, `temp/`, `output/` + writes the system prompt file | General agent work with structured deliverables |
|
|
236
|
-
| `'swe'` | Same as knowledge + `repo/` for code repositories | Software-engineering tasks on cloned repos |
|
|
237
|
-
|
|
238
|
-
```python
|
|
239
|
-
evolve = Evolve(
|
|
240
|
-
workspace_mode='swe',
|
|
241
|
-
sandbox_create_options={'image': 'my-ci-template'},
|
|
242
|
-
)
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
---
|
|
246
|
-
|
|
247
|
-
## Evolve Instance
|
|
248
|
-
|
|
249
|
-
```python
|
|
250
|
-
import os
|
|
251
|
-
from evolve import Evolve, AgentConfig, E2BProvider, StorageConfig, IntegrationsSetup, ManagedSecretRef
|
|
252
|
-
|
|
253
|
-
# Sandbox provider (auto-resolved from E2B_API_KEY, or explicit)
|
|
254
|
-
sandbox = E2BProvider(
|
|
255
|
-
api_key=os.getenv('E2B_API_KEY'), # (optional) Auto-resolves from E2B_API_KEY env var
|
|
256
|
-
timeout_ms=3600000, # (optional) Default sandbox timeout (default: 1 hour)
|
|
257
|
-
)
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
```python
|
|
261
|
-
import os
|
|
262
|
-
|
|
263
|
-
evolve = Evolve(
|
|
264
|
-
|
|
265
|
-
# Agent configuration (optional if EVOLVE_API_KEY set, defaults to claude)
|
|
266
|
-
config=AgentConfig(
|
|
267
|
-
type='codex', # 'claude' | 'codex' | 'gemini' | 'qwen' | 'kimi' | 'opencode' | 'droid' - defaults to 'claude'
|
|
268
|
-
model='gpt-5.3-codex', # (optional) Uses default if omitted. Use 'fable' for Claude Fable 5.1 or 'sonnet[1m]' / 'opus[1m]' for 1M context (Claude only)
|
|
269
|
-
reasoning_effort='medium', # (optional) Native reasoning/thinking control; valid values vary by agent/model. Omitted = Evolve stamps its pinned per-harness default (see Getting Started → Agent Reference)
|
|
270
|
-
# max_context_size=128000, # (optional) Context/completion ceiling for CLIs that must be told one (see Getting Started → Harness and Model Pairing)
|
|
271
|
-
api_key=os.getenv('EVOLVE_API_KEY'), # (optional) Gateway mode - auto-resolves from env
|
|
272
|
-
# provider_api_key=os.getenv('ANTHROPIC_API_KEY'), # (optional) Direct Provider Key Mode
|
|
273
|
-
# oauth_token=os.getenv('CLAUDE_CODE_OAUTH_TOKEN'), # (optional) Claude Max subscription
|
|
274
|
-
),
|
|
275
|
-
|
|
276
|
-
# Sandbox provider (auto-resolved from E2B_API_KEY, or use sandbox from above)
|
|
277
|
-
sandbox=sandbox,
|
|
278
|
-
|
|
279
|
-
# (optional) Workspace mode: 'knowledge' (default) | 'swe' (see Workspace Modes above)
|
|
280
|
-
workspace_mode='knowledge',
|
|
281
|
-
|
|
282
|
-
# (optional) Provider-neutral options for fresh sandbox creation (see Sandbox Create Options above)
|
|
283
|
-
sandbox_create_options={
|
|
284
|
-
'image': 'my-task-image',
|
|
285
|
-
'network': {'outbound': 'blocked', 'allowedDestinations': ['pypi.org']},
|
|
286
|
-
'user': 'root',
|
|
287
|
-
},
|
|
288
|
-
|
|
289
|
-
# (optional) Uploads to /home/user/workspace/context/ on first run
|
|
290
|
-
context={
|
|
291
|
-
'docs/readme.txt': 'User provided context...',
|
|
292
|
-
'data.json': '{"key": "value"}',
|
|
293
|
-
},
|
|
294
|
-
|
|
295
|
-
# (optional) System prompt appended to default instructions
|
|
296
|
-
system_prompt='You are a careful pair programmer.',
|
|
297
|
-
|
|
298
|
-
# (optional) Schema for structured output (agent writes result.json, validated on get_output_files())
|
|
299
|
-
# Accepts Pydantic models or JSON Schema dicts
|
|
300
|
-
schema=MyPydanticModel,
|
|
301
|
-
|
|
302
|
-
# (optional) Gateway browser automation
|
|
303
|
-
browser={'provider': 'agent-browser', 'remote': True},
|
|
304
|
-
|
|
305
|
-
# (optional) Install plugins/extensions for the selected agent before first run
|
|
306
|
-
plugins={
|
|
307
|
-
'marketplace': 'https://github.com/org/codex-plugins.git',
|
|
308
|
-
'sparse': ['.agents/plugins'],
|
|
309
|
-
},
|
|
310
|
-
|
|
311
|
-
# (optional) Skills for the agent — skills.sh / git / local references
|
|
312
|
-
skills=['anthropics/skills', './my-skill'],
|
|
313
|
-
|
|
314
|
-
# (optional) Managed integrations (gateway mode only)
|
|
315
|
-
integrations=IntegrationsSetup(user_id='root', apps=['gmail', 'notion']),
|
|
316
|
-
|
|
317
|
-
# (optional) Dashboard-stored managed secrets (gateway mode only)
|
|
318
|
-
managed_secrets=[
|
|
319
|
-
ManagedSecretRef(name='GITHUB_TOKEN'),
|
|
320
|
-
ManagedSecretRef(name='SLACK_BOT_TOKEN', as_name='SLACK_TOKEN'),
|
|
321
|
-
],
|
|
322
|
-
|
|
323
|
-
# (optional) Prefix for observability logs
|
|
324
|
-
session_tag_prefix='my-agent',
|
|
325
|
-
|
|
326
|
-
# (optional) Storage for checkpoint persistence (gateway feature — requires EVOLVE_API_KEY)
|
|
327
|
-
storage=StorageConfig(),
|
|
328
|
-
|
|
329
|
-
# ─────────────────────────────────────────────────────────────
|
|
330
|
-
# Advanced
|
|
331
|
-
# ─────────────────────────────────────────────────────────────
|
|
332
|
-
|
|
333
|
-
# (optional) MCP servers for agent tools
|
|
334
|
-
mcp_servers={
|
|
335
|
-
'exa': {
|
|
336
|
-
'command': 'npx',
|
|
337
|
-
'args': ['-y', 'exa-mcp-server'],
|
|
338
|
-
'env': {'EXA_API_KEY': '...'},
|
|
339
|
-
},
|
|
340
|
-
'api': {
|
|
341
|
-
'type': 'http',
|
|
342
|
-
'url': 'https://example.com/mcp',
|
|
343
|
-
'headers': {'x-api-key': '...'},
|
|
344
|
-
},
|
|
345
|
-
},
|
|
346
|
-
|
|
347
|
-
# (optional) Environment variables injected into sandbox
|
|
348
|
-
secrets={'GITHUB_TOKEN': os.getenv('GITHUB_TOKEN')},
|
|
349
|
-
|
|
350
|
-
# (optional) Uploads to /home/user/workspace/ on first run
|
|
351
|
-
files={
|
|
352
|
-
'scripts/setup.sh': '#!/bin/bash\necho hello',
|
|
353
|
-
},
|
|
354
|
-
)
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
**Note:**
|
|
358
|
-
- Configuration parameters can be combined in any order.
|
|
359
|
-
- The sandbox is created on the first `run()` or `execute_command()` call (see below).
|
|
360
|
-
- Context files, workspace files, MCP servers, and system prompt are set up once on the first call.
|
|
361
|
-
- Using `sandbox_id` parameter to reconnect skips setup since the sandbox already exists.
|
|
362
|
-
- `schema` accepts both Pydantic model classes and JSON Schema dicts.
|
|
363
|
-
|
|
364
|
-
**McpServerConfig** — MCP server connection (STDIO or HTTP/SSE):
|
|
365
|
-
|
|
366
|
-
| Fields | Transport |
|
|
367
|
-
|--------|-----------|
|
|
368
|
-
| `command` | stdio (local subprocess) |
|
|
369
|
-
| `url` + `type: "http"` | HTTP (remote) |
|
|
370
|
-
| `url` (no type) | SSE (remote, default) |
|
|
371
|
-
|
|
372
|
-
```python
|
|
373
|
-
McpServerConfig = {
|
|
374
|
-
'type': str, # "stdio" | "http" | "sse" (auto-detected)
|
|
375
|
-
'command': str, 'args': list, 'cwd': str, # STDIO
|
|
376
|
-
'url': str, 'headers': dict[str, str], # HTTP/SSE
|
|
377
|
-
'env': dict[str, str], # Common
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
## Browser Automation
|
|
382
|
-
|
|
383
|
-
Browser automation is opt-in. Use `browser={'provider': 'agent-browser', 'remote': True}` for browser, QA, dogfooding, and website automation tasks.
|
|
384
|
-
|
|
385
|
-
```python
|
|
386
|
-
Evolve(browser={'provider': 'agent-browser', 'remote': True}) # managed browser with dashboard live view and replay
|
|
387
|
-
```
|
|
388
|
-
|
|
389
|
-
Evolve automatically configures the browser runtime. In Gateway mode, the managed browser gives you:
|
|
390
|
-
|
|
391
|
-
- `event["browser"]["live_url"]` from the `browser_ready` lifecycle event
|
|
392
|
-
- `result.browser["live_url"]` after `run()` returns
|
|
393
|
-
- `result.session_id`, which is the id to use for traces and browser replay
|
|
394
|
-
- `sessions().browser_replay(session_id)`, which returns replay and raw `.mp4` download URLs after cleanup
|
|
395
|
-
- `replay.suggested_start_seconds`, when present, which is the recommended replay start time in seconds
|
|
396
|
-
- `replay.size_bytes` and `replay.ready_at`, when present, which describe the raw recording size and replay readiness time
|
|
397
|
-
|
|
398
|
-
`remote` controls where the browser session runs:
|
|
399
|
-
|
|
400
|
-
- `remote: True` creates an Evolve-managed cloud browser session, wires it into the sandbox, and exposes dashboard live view plus replay.
|
|
401
|
-
- `remote: False` runs browser automation locally inside the sandbox. Use it only when you do not need managed live view or replay.
|
|
402
|
-
|
|
403
|
-
Use the default managed remote browser unless you have a reason not to:
|
|
404
|
-
|
|
405
|
-
```python
|
|
406
|
-
Evolve(browser={'provider': 'agent-browser', 'remote': True})
|
|
407
|
-
# recommended: managed remote browser
|
|
408
|
-
|
|
409
|
-
Evolve(browser={'provider': 'agent-browser', 'remote': False})
|
|
410
|
-
# local agent-browser, no managed live/replay
|
|
411
|
-
```
|
|
412
|
-
|
|
413
|
-
Use a browser profile to reuse logged-in browser state across managed browser sessions:
|
|
414
|
-
|
|
415
|
-
```python
|
|
416
|
-
evolve = Evolve(
|
|
417
|
-
browser={'profile': 'ramp-qa'},
|
|
418
|
-
)
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
Profiles are gateway-only and work only with managed remote browser sessions. Evolve stores and resolves profile state server-side; the SDK never receives raw browser state.
|
|
422
|
-
|
|
423
|
-
Profile lifecycle:
|
|
424
|
-
|
|
425
|
-
- First use: if the profile does not exist for the authenticated Evolve user, Dashboard creates an empty server-side browser profile and starts the managed browser with it.
|
|
426
|
-
- Reuse: if the profile already exists, Dashboard starts the browser with the existing state and updates `last_used_at`.
|
|
427
|
-
- Persist: browser state changes made during the session, such as successful logins, are saved when the managed browser is stopped. Call `kill()` when done so cleanup and replay processing run.
|
|
428
|
-
- Visibility: the profile appears in Dashboard **Secrets** under Browser Profiles and in `browser_profiles().list()`. Only metadata is returned; cookies and storage stay server-side.
|
|
429
|
-
|
|
430
|
-
Recommended profile creation flow:
|
|
431
|
-
|
|
432
|
-
1. Add the browser login in Dashboard **Secrets**, or manage browser logins from the SDK and note the `account_label`.
|
|
433
|
-
2. Start a managed browser with both a `profile` and scoped browser credentials.
|
|
434
|
-
3. Ask the agent to sign in with the saved login.
|
|
435
|
-
4. Call `kill()` when done so the authenticated browser state is saved into the profile.
|
|
436
|
-
|
|
437
|
-
```python
|
|
438
|
-
from evolve import Evolve, BrowserCredentialsConfig
|
|
439
|
-
|
|
440
|
-
evolve = Evolve(
|
|
441
|
-
browser={'profile': 'ramp-qa'},
|
|
442
|
-
browser_credentials=BrowserCredentialsConfig(
|
|
443
|
-
allow=[{'website': 'github.com', 'account_label': 'qa-admin'}],
|
|
444
|
-
),
|
|
445
|
-
)
|
|
446
|
-
|
|
447
|
-
try:
|
|
448
|
-
await evolve.run(
|
|
449
|
-
prompt='Open GitHub, sign in with the saved qa-admin login, and confirm the account is authenticated.'
|
|
450
|
-
)
|
|
451
|
-
finally:
|
|
452
|
-
await evolve.kill()
|
|
453
|
-
```
|
|
454
|
-
|
|
455
|
-
Future runs can reuse the saved state with `browser={'profile': 'ramp-qa'}`; include `browser_credentials` again only when the agent needs access to saved login tools.
|
|
456
|
-
|
|
457
|
-
List or delete profiles from the SDK:
|
|
458
|
-
|
|
459
|
-
```python
|
|
460
|
-
from evolve import browser_profiles
|
|
461
|
-
|
|
462
|
-
profiles = await browser_profiles().list()
|
|
463
|
-
|
|
464
|
-
await browser_profiles().delete(profile='ramp-qa')
|
|
465
|
-
```
|
|
466
|
-
|
|
467
|
-
To disable browser automation, omit the `browser` argument.
|
|
468
|
-
|
|
469
|
-
Full browser run with live view and replay:
|
|
470
|
-
|
|
471
|
-
```python
|
|
472
|
-
from evolve import Evolve, sessions
|
|
473
|
-
|
|
474
|
-
evolve = Evolve(
|
|
475
|
-
browser={'provider': 'agent-browser', 'remote': True},
|
|
476
|
-
session_tag_prefix='checkout-qa',
|
|
477
|
-
)
|
|
478
|
-
|
|
479
|
-
browser_session = {'id': None}
|
|
480
|
-
session_id = None
|
|
481
|
-
|
|
482
|
-
def on_lifecycle(event):
|
|
483
|
-
if event['reason'] == 'browser_ready' and event.get('browser'):
|
|
484
|
-
show_live_browser(event['browser']['live_url'])
|
|
485
|
-
browser_session['id'] = event['browser']['session_id']
|
|
486
|
-
|
|
487
|
-
evolve.on('lifecycle', on_lifecycle)
|
|
488
|
-
|
|
489
|
-
try:
|
|
490
|
-
result = await evolve.run(
|
|
491
|
-
prompt='Open the app, test the checkout flow, and report issues.'
|
|
492
|
-
)
|
|
493
|
-
|
|
494
|
-
session_id = result.session_id or browser_session['id']
|
|
495
|
-
if result.browser and result.browser.get('live_url'):
|
|
496
|
-
show_live_browser(result.browser['live_url'])
|
|
497
|
-
finally:
|
|
498
|
-
await evolve.kill()
|
|
499
|
-
|
|
500
|
-
if not session_id:
|
|
501
|
-
raise RuntimeError('Missing dashboard session id')
|
|
502
|
-
|
|
503
|
-
async with sessions() as session:
|
|
504
|
-
replay = await session.browser_replay(
|
|
505
|
-
session_id,
|
|
506
|
-
timeout_ms=600_000,
|
|
507
|
-
interval_ms=5_000,
|
|
508
|
-
)
|
|
509
|
-
|
|
510
|
-
show_replay(replay.replay_url)
|
|
511
|
-
save_download_link(replay.download_url)
|
|
512
|
-
set_replay_start_time(replay.suggested_start_seconds or 0)
|
|
513
|
-
show_replay_metadata(
|
|
514
|
-
size_bytes=replay.size_bytes,
|
|
515
|
-
ready_at=replay.ready_at,
|
|
516
|
-
)
|
|
517
|
-
```
|
|
518
|
-
|
|
519
|
-
Replay processing starts when the managed browser is cleaned up, usually during `kill()`.
|
|
520
|
-
If replay is not ready before `timeout_ms`, call `browser_replay()` again later with the same `session_id`.
|
|
521
|
-
The `replay_url` already applies `suggested_start_seconds`; use the field separately only if your UI needs to display or store the recommended start time.
|
|
522
|
-
The `status` is `'ready'` once `browser_replay()` returns.
|
|
523
|
-
|
|
524
|
-
## Browser Credentials
|
|
525
|
-
|
|
526
|
-
Browser credentials let managed remote `agent-browser` runs sign in with saved website logins without exposing passwords to the agent.
|
|
527
|
-
|
|
528
|
-
Availability:
|
|
529
|
-
|
|
530
|
-
- Requires Gateway mode and managed remote `agent-browser`.
|
|
531
|
-
- Use `browser={'provider': 'agent-browser', 'remote': True}`.
|
|
532
|
-
- Not available with local browser mode, Direct Provider Key Mode, or existing sandbox sessions.
|
|
533
|
-
|
|
534
|
-
Dashboard setup:
|
|
535
|
-
|
|
536
|
-
1. Open the Evolve Dashboard.
|
|
537
|
-
2. Go to **Secrets**.
|
|
538
|
-
3. Add a browser login with `Account label`, `Website`, `Email`, and `Password`.
|
|
539
|
-
4. Use `Website` for the domain, such as `github.com`; use `Account label` as one word with no spaces, such as `qa-admin`, `work`, or `personal`, to distinguish multiple saved accounts for the same website. It is not the website username or email.
|
|
540
|
-
|
|
541
|
-
Passwords are encrypted client-side with RSA-OAEP-SHA256 against the dashboard's published public key before upload — the SDK verifies it is handed a genuine `rsaEncryption` key before encrypting, and a plaintext password never leaves the machine. The dashboard and SDK list only login metadata: account label, website, email, and last-used time.
|
|
542
|
-
|
|
543
|
-
Expose saved logins to a run:
|
|
544
|
-
|
|
545
|
-
```python
|
|
546
|
-
from evolve import Evolve, BrowserCredentialsConfig
|
|
547
|
-
|
|
548
|
-
evolve = Evolve(
|
|
549
|
-
browser={'provider': 'agent-browser', 'remote': True},
|
|
550
|
-
browser_credentials=BrowserCredentialsConfig(
|
|
551
|
-
allow=[{'website': 'github.com', 'account_label': 'qa-admin'}],
|
|
552
|
-
),
|
|
553
|
-
)
|
|
554
|
-
|
|
555
|
-
await evolve.run(
|
|
556
|
-
prompt='Open GitHub, sign in with the saved qa-admin login, and verify the repository settings page.'
|
|
557
|
-
)
|
|
558
|
-
|
|
559
|
-
await evolve.kill()
|
|
560
|
-
```
|
|
561
|
-
|
|
562
|
-
If `allow` is omitted, all enabled browser logins for the Evolve account are available to that run:
|
|
563
|
-
|
|
564
|
-
```python
|
|
565
|
-
from evolve import Evolve, BrowserCredentialsConfig
|
|
566
|
-
|
|
567
|
-
evolve = Evolve(
|
|
568
|
-
browser={'provider': 'agent-browser', 'remote': True},
|
|
569
|
-
browser_credentials=BrowserCredentialsConfig(),
|
|
570
|
-
)
|
|
571
|
-
```
|
|
572
|
-
|
|
573
|
-
The agent receives a run-scoped `browser-login` MCP server with these tools:
|
|
574
|
-
|
|
575
|
-
- `browser_list_logins` lists available website logins: website, account_label, and email only.
|
|
576
|
-
- `browser_login` fills the stored password and submits the current browser sign-in tab.
|
|
577
|
-
- `browser_complete_signup` generates a password, submits the current browser signup tab, and saves the new login.
|
|
578
|
-
|
|
579
|
-
Manage browser logins from the SDK:
|
|
580
|
-
|
|
581
|
-
```python
|
|
582
|
-
import os
|
|
583
|
-
from evolve import browser_credentials
|
|
584
|
-
|
|
585
|
-
credentials = browser_credentials()
|
|
586
|
-
|
|
587
|
-
await credentials.create(
|
|
588
|
-
website='github.com',
|
|
589
|
-
account_label='qa-admin',
|
|
590
|
-
email='qualityassurance@example.com',
|
|
591
|
-
password=os.environ['QA_GITHUB_PASSWORD'],
|
|
592
|
-
)
|
|
593
|
-
|
|
594
|
-
page = await credentials.list(website='github.com')
|
|
595
|
-
|
|
596
|
-
await credentials.delete(
|
|
597
|
-
website='github.com',
|
|
598
|
-
account_label='qa-admin',
|
|
599
|
-
)
|
|
600
|
-
```
|
|
601
|
-
|
|
602
|
-
## Agent Plugins
|
|
603
|
-
|
|
604
|
-
`plugins=` installs plugins/extensions into the sandbox user profile before the first agent command. The selected agent determines the accepted shape:
|
|
605
|
-
|
|
606
|
-
```python
|
|
607
|
-
# droid
|
|
608
|
-
plugins={
|
|
609
|
-
'marketplace': 'https://github.com/Factory-AI/factory-plugins',
|
|
610
|
-
'plugin': 'droid-control@factory-plugins',
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
# claude
|
|
614
|
-
plugins={
|
|
615
|
-
'marketplace': 'anthropics/claude-code',
|
|
616
|
-
'plugin': 'commit-commands@anthropics-claude-code',
|
|
617
|
-
}
|
|
618
|
-
|
|
619
|
-
# gemini
|
|
620
|
-
plugins={
|
|
621
|
-
'source': 'https://github.com/org/gemini-extension',
|
|
622
|
-
'ref': 'main',
|
|
623
|
-
}
|
|
624
|
-
|
|
625
|
-
# codex marketplace registration
|
|
626
|
-
plugins={
|
|
627
|
-
'marketplace': 'https://github.com/org/codex-plugins.git',
|
|
628
|
-
'sparse': ['.agents/plugins'],
|
|
629
|
-
}
|
|
630
|
-
```
|
|
631
|
-
|
|
632
|
-
If `config=AgentConfig(...)` is omitted, plugins target the default agent (`claude`).
|
|
633
|
-
|
|
634
|
-
## Agent Skills
|
|
635
|
-
|
|
636
|
-
Skills are folders of instructions and helper files — a `SKILL.md` manifest plus anything it needs — that the agent's harness discovers natively. The `skills` option takes real references; there is no built-in catalog:
|
|
637
|
-
|
|
638
|
-
```python
|
|
639
|
-
from evolve import Evolve
|
|
640
|
-
|
|
641
|
-
evolve = Evolve(
|
|
642
|
-
skills=[
|
|
643
|
-
'skills.sh/vercel-labs/agent-skills/frontend-design', # one named skill from a skills.sh-listed repo
|
|
644
|
-
'anthropics/skills', # every skill a GitHub repo publishes
|
|
645
|
-
'anthropics/skills@main', # pinned to a branch, tag, or commit
|
|
646
|
-
'https://github.com/org/repo/tree/main/skills/my-skill', # any https git URL, down to a subfolder
|
|
647
|
-
'./my-skill', # a local folder containing SKILL.md
|
|
648
|
-
],
|
|
649
|
-
)
|
|
650
|
-
|
|
651
|
-
await evolve.run(prompt='Create a slide deck summarizing the uploaded notes.')
|
|
652
|
-
```
|
|
653
|
-
|
|
654
|
-
Browse [skills.sh](https://skills.sh) for published skills. The SKILL.md format is the open standard described at [agentskills.io](https://agentskills.io/home).
|
|
655
|
-
|
|
656
|
-
How references resolve:
|
|
657
|
-
|
|
658
|
-
- Git references are pinned to their exact commit, fetched as a sparse checkout of only the skill content, and cached by commit under `~/.cache/evolve/skills` — the same reference always mounts the same bytes.
|
|
659
|
-
- A whole-repo reference discovers skills in the ecosystem's standard places: a `SKILL.md` at the repo root (one skill, named after the repo), `skills/`, `skills/.curated/`, `skills/.experimental/`, `skills/.system/`, and `.claude/skills/`.
|
|
660
|
-
- A local path, or an explicit `/tree/<ref>/<subdir>` URL, must be one skill folder containing `SKILL.md` — or a root whose immediate child directories each contain one. A child without `SKILL.md` is a loud refusal naming the child.
|
|
661
|
-
- Duplicate skill names resolve last-wins, and each skill mounts into the harness's native skills directory (for example `~/.claude/skills/<name>`), where the agent discovers it on its own.
|
|
662
|
-
|
|
663
|
-
## Managed Secrets
|
|
664
|
-
|
|
665
|
-
Managed secrets are available only in gateway mode (`EVOLVE_API_KEY`). Store the secret with a **Name**, an optional **Label**, and a **delivery mode** — in Dashboard **Secrets**, or programmatically through the SDK's `set()` / the CLI's `evolve secrets set` (below). Secrets are unique by `(name, label)` — several values of one name live side by side (`API_KEY` at `staging` and at `prod`) and a run attaches one by label. The SDK can list available names and attach the selected secrets to a run.
|
|
666
|
-
|
|
667
|
-
The delivery mode is chosen when the secret is saved and decides how the value reaches the sandbox:
|
|
668
|
-
|
|
669
|
-
- **`brokered`** — the value never enters any sandbox. The sandbox sees an opaque placeholder, and Evolve substitutes the real value only for HTTPS egress toward the secret's allowed hosts, paths, and methods (required for brokered secrets). This works for header-based HTTPS APIs.
|
|
670
|
-
- **`direct`** — the raw value is placed in the sandbox environment. This is the mode for keys the HTTPS broker cannot carry: URL-parameter keys, gRPC, websockets. Direct secrets carry no host/path/method scoping — nothing brokers a raw env value.
|
|
671
|
-
|
|
672
|
-
```python
|
|
673
|
-
from evolve import Evolve, ManagedSecretRef, managed_secrets
|
|
674
|
-
|
|
675
|
-
available = await managed_secrets().list() # includes label + delivery
|
|
676
|
-
|
|
677
|
-
evolve = Evolve(
|
|
678
|
-
managed_secrets=[
|
|
679
|
-
ManagedSecretRef(name='GITHUB_TOKEN'), # 'default'-labeled row
|
|
680
|
-
ManagedSecretRef(name='API_KEY', label='prod'), # a specific labeled row
|
|
681
|
-
ManagedSecretRef(name='SLACK_BOT_TOKEN', as_name='SLACK_TOKEN'), # renamed in the sandbox
|
|
682
|
-
],
|
|
683
|
-
)
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
An omitted `label` resolves by the server's one shared law (the same law hosted-evals job secrets use): the `default`-labeled row when one exists, the single row when exactly one exists, and a typed refusal naming every label when several match and none is `default` — never a guess.
|
|
687
|
-
|
|
688
|
-
Runtime behavior:
|
|
689
|
-
|
|
690
|
-
- Brokered secrets: the sandbox receives the requested env var names with opaque sandbox-scoped values; code and tools read them normally, and Evolve validates allowed host, path, method, and live sandbox binding before substituting the real value on egress. Request and response bodies are limited to 10 MiB each.
|
|
691
|
-
- Direct secrets: the sandbox receives the raw value as a plain env var. When every attached secret is direct, the in-sandbox egress proxy is not started at all.
|
|
692
|
-
- `secrets` is still for local raw env injection; `managed_secrets` is for Dashboard-stored values.
|
|
693
|
-
|
|
694
|
-
### Storing secrets programmatically
|
|
695
|
-
|
|
696
|
-
`managed_secrets()` also writes: `set()` creates an env secret (or updates one — see the collision rule), and `delete()` removes one. The value travels in the HTTPS request body and is sealed server-side with the platform vault cipher; no read ever returns it. Values are limited to 190 bytes.
|
|
697
|
-
|
|
698
|
-
```python
|
|
699
|
-
import os
|
|
700
|
-
from evolve import managed_secrets
|
|
701
|
-
|
|
702
|
-
secrets = managed_secrets()
|
|
703
|
-
|
|
704
|
-
await secrets.set(
|
|
705
|
-
name='GITHUB_TOKEN',
|
|
706
|
-
value=os.environ['GITHUB_TOKEN'],
|
|
707
|
-
delivery='brokered',
|
|
708
|
-
allowed_hosts=['api.github.com'],
|
|
709
|
-
allowed_path_prefixes=['/'],
|
|
710
|
-
allowed_methods=['GET'],
|
|
711
|
-
)
|
|
712
|
-
|
|
713
|
-
await secrets.set(
|
|
714
|
-
name='STRIPE_KEY',
|
|
715
|
-
label='staging',
|
|
716
|
-
value=os.environ['STRIPE_TEST_KEY'],
|
|
717
|
-
delivery='direct', # direct secrets carry no scoping
|
|
718
|
-
)
|
|
719
|
-
|
|
720
|
-
await secrets.delete(name='STRIPE_KEY', label='staging')
|
|
721
|
-
```
|
|
722
|
-
|
|
723
|
-
Or from the terminal — the value comes from `--value` or piped stdin (piping keeps it out of shell history):
|
|
724
|
-
|
|
725
|
-
```bash
|
|
726
|
-
printf %s "$GITHUB_TOKEN" | evolve secrets set GITHUB_TOKEN \
|
|
727
|
-
--delivery brokered \
|
|
728
|
-
--allowed-host api.github.com --allowed-path-prefix / --allowed-method GET
|
|
729
|
-
|
|
730
|
-
evolve secrets list
|
|
731
|
-
evolve secrets delete GITHUB_TOKEN
|
|
732
|
-
```
|
|
733
|
-
|
|
734
|
-
The write rules, all typed and machine-readable (the HTTP error body carries a `code`):
|
|
735
|
-
|
|
736
|
-
- `delivery` is required. `brokered` requires at least one allowed host, path prefix, and method; `direct` refuses scoping fields — an unscoped value in the sandbox environment cannot honor them.
|
|
737
|
-
- An existing `(name, label)` is **never overwritten with a different value**: the request is refused (`secret_exists`, HTTP 409). Rotate by `delete` + `set`, or store the new value under another label. Restating the **same value byte-for-byte** succeeds as an update — that is where the delivery mode and scoping are editable, and every runtime grant already minted against the row is revoked.
|
|
738
|
-
- `delete` with a bare name resolves the label like everything else (the `default` row, else the single row, else a typed ambiguity refusal naming every label).
|
|
739
|
-
- A **read-only API key** can `list` but not `set`/`delete` (`read_only_key`, HTTP 403).
|
|
740
|
-
- **LLM provider keys (BYOK) cannot be stored through this door.** A provider key gates billing — the routing preference behind it decides whose account pays for model traffic — so provider keys are managed only in the signed-in Dashboard **Secrets** page.
|
|
741
|
-
|
|
742
|
-
---
|
|
743
|
-
|
|
744
|
-
## Managed Integrations
|
|
745
|
-
|
|
746
|
-
Managed integrations are available only in gateway mode (`EVOLVE_API_KEY`); integration credentials stay server-side and agents receive an Evolve-scoped MCP proxy.
|
|
747
|
-
|
|
748
|
-
Available apps:
|
|
749
|
-
|
|
750
|
-
| `apps` value | App | What agents can do |
|
|
751
|
-
| --- | --- | --- |
|
|
752
|
-
| `gmail` | Gmail | Read, search, draft, and send email. |
|
|
753
|
-
| `agent_mail` | Agent Mail | Use an agent inbox to send, receive, and act on email. |
|
|
754
|
-
| `slack` | Slack | Search channels, read conversations, and send team messages. |
|
|
755
|
-
| `github` | GitHub | Work with repositories, issues, pull requests, and code. |
|
|
756
|
-
| `googlecalendar` | Google Calendar | Read and manage calendar events. |
|
|
757
|
-
| `notion` | Notion | Read and update pages, databases, docs, and workspace content. |
|
|
758
|
-
| `linear` | Linear | Read and manage issues, teams, projects, and comments. |
|
|
759
|
-
|
|
760
|
-
```bash
|
|
761
|
-
# .env
|
|
762
|
-
EVOLVE_API_KEY=sk-...
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
```python
|
|
766
|
-
from evolve import Evolve, IntegrationsSetup
|
|
767
|
-
|
|
768
|
-
evolve = Evolve(
|
|
769
|
-
integrations=IntegrationsSetup(
|
|
770
|
-
user_id='root',
|
|
771
|
-
apps=['github', 'gmail'],
|
|
772
|
-
),
|
|
773
|
-
)
|
|
774
|
-
|
|
775
|
-
await evolve.run(prompt='Create a GitHub issue for the login bug')
|
|
776
|
-
```
|
|
777
|
-
|
|
778
|
-
### Root vs SDK Users
|
|
779
|
-
|
|
780
|
-
Use `user_id='root'` for accounts connected in the Evolve dashboard for private agents and test accounts.
|
|
781
|
-
|
|
782
|
-
For an application with end users, pass your stable SDK user ID. Evolve namespaces that ID under the authenticated Evolve account before creating private integration sessions.
|
|
783
|
-
|
|
784
|
-
```python
|
|
785
|
-
from evolve import Evolve, IntegrationsSetup
|
|
786
|
-
|
|
787
|
-
link = await Evolve.integrations.auth(
|
|
788
|
-
user_id='customer_123',
|
|
789
|
-
app='gmail',
|
|
790
|
-
account_label='work',
|
|
791
|
-
)
|
|
792
|
-
|
|
793
|
-
evolve = Evolve(
|
|
794
|
-
integrations=IntegrationsSetup(
|
|
795
|
-
user_id='customer_123',
|
|
796
|
-
apps=['gmail'],
|
|
797
|
-
),
|
|
798
|
-
)
|
|
799
|
-
```
|
|
800
|
-
|
|
801
|
-
### Account Helpers
|
|
802
|
-
|
|
803
|
-
```python
|
|
804
|
-
accounts = await Evolve.integrations.accounts.list(
|
|
805
|
-
user_ids=['customer_123'],
|
|
806
|
-
app='gmail',
|
|
807
|
-
statuses=['ACTIVE'],
|
|
808
|
-
)
|
|
809
|
-
|
|
810
|
-
await Evolve.integrations.accounts.update(
|
|
811
|
-
account_id='account_id_from_list',
|
|
812
|
-
account_label='work',
|
|
813
|
-
)
|
|
814
|
-
|
|
815
|
-
# If the user connected multiple Gmail accounts, choose an account label or account ID returned by accounts.list().
|
|
816
|
-
evolve = Evolve(
|
|
817
|
-
integrations=IntegrationsSetup(
|
|
818
|
-
user_id='customer_123',
|
|
819
|
-
apps=['gmail'],
|
|
820
|
-
accounts={'gmail': ['work']},
|
|
821
|
-
),
|
|
822
|
-
)
|
|
823
|
-
|
|
824
|
-
# Disconnect by account ID.
|
|
825
|
-
await Evolve.integrations.accounts.delete(account_id='account_id_from_list')
|
|
826
|
-
```
|
|
827
|
-
|
|
828
|
-
### Custom Auth Configs and API Keys
|
|
829
|
-
|
|
830
|
-
Use `auth_configs` to select a custom auth config for an app. For apps with an API-key auth config, pass the matching key in `keys`; Evolve creates the connected account server-side and does not store the raw key in the session.
|
|
831
|
-
|
|
832
|
-
```python
|
|
833
|
-
evolve = Evolve(
|
|
834
|
-
integrations=IntegrationsSetup(
|
|
835
|
-
user_id='customer_123',
|
|
836
|
-
apps=['github'],
|
|
837
|
-
auth_configs={'github': 'ac_custom_github'},
|
|
838
|
-
keys={'github': os.environ['GITHUB_TOKEN']},
|
|
839
|
-
),
|
|
840
|
-
)
|
|
841
|
-
```
|
|
842
|
-
|
|
843
|
-
### Type Reference
|
|
844
|
-
|
|
845
|
-
```python
|
|
846
|
-
@dataclass
|
|
847
|
-
class IntegrationsSetup:
|
|
848
|
-
user_id: str # "root" or your stable SDK user ID
|
|
849
|
-
apps: List[str]
|
|
850
|
-
accounts: Optional[Dict[str, List[str]]] = None # app -> account labels or account IDs
|
|
851
|
-
auth_configs: Optional[Dict[str, str]] = None # app -> custom auth config ID
|
|
852
|
-
keys: Optional[Dict[str, str]] = None # app -> API key, requires auth_configs[app]
|
|
853
|
-
```
|
|
854
|
-
|
|
855
|
-
---
|