@evolvingmachines/evolve 0.0.55-project-sable.20260916.db0bc0bb
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/LICENSE +201 -0
- package/README.md +25 -0
- package/dist/chunk-5GVMBEYI.js +11 -0
- package/dist/chunk-HQJI3HHU.js +1 -0
- package/dist/chunk-JS2UTK2I.js +427 -0
- package/dist/cli/index.cjs +73 -0
- package/dist/cli/index.d.cts +270 -0
- package/dist/cli/index.d.ts +270 -0
- package/dist/cli/index.js +54 -0
- package/dist/index.cjs +669 -0
- package/dist/index.d.cts +5023 -0
- package/dist/index.d.ts +5023 -0
- package/dist/index.js +230 -0
- package/dist/managed-modal-IJW62SSK.js +4 -0
- package/dist/resumable-HFSICSH3.js +1 -0
- package/dist/tar-GVC4KE52.js +1 -0
- package/dist/types-DlpTxdR_.d.cts +4777 -0
- package/dist/types-DlpTxdR_.d.ts +4777 -0
- package/dist/upload-KPYDMWFJ.js +1 -0
- package/docs-agents/SKILL.md +138 -0
- package/docs-agents/index.md +81 -0
- package/docs-agents/python/01-getting-started.md +511 -0
- package/docs-agents/python/02-configuration.md +855 -0
- package/docs-agents/python/03-runtime.md +899 -0
- package/docs-agents/python/04-streaming.md +451 -0
- package/docs-agents/python/05-swarm-pipeline.md +953 -0
- package/docs-agents/python/index.md +122 -0
- package/docs-agents/typescript/01-getting-started.md +494 -0
- package/docs-agents/typescript/02-configuration.md +841 -0
- package/docs-agents/typescript/03-runtime.md +864 -0
- package/docs-agents/typescript/04-streaming.md +478 -0
- package/docs-agents/typescript/05-swarm-pipeline.md +957 -0
- package/docs-agents/typescript/index.md +121 -0
- package/docs-evals/SKILL.md +112 -0
- package/docs-evals/cli-reference/agent.mdx +67 -0
- package/docs-evals/cli-reference/analysis.mdx +91 -0
- package/docs-evals/cli-reference/analyze.mdx +74 -0
- package/docs-evals/cli-reference/auth.mdx +60 -0
- package/docs-evals/cli-reference/check.mdx +146 -0
- package/docs-evals/cli-reference/dataset.mdx +133 -0
- package/docs-evals/cli-reference/index.mdx +108 -0
- package/docs-evals/cli-reference/job.mdx +239 -0
- package/docs-evals/cli-reference/run.mdx +196 -0
- package/docs-evals/cli-reference/secrets.mdx +95 -0
- package/docs-evals/cli-reference/skill.mdx +51 -0
- package/docs-evals/cli-reference/skills.mdx +81 -0
- package/docs-evals/cli-reference/trial.mdx +112 -0
- package/docs-evals/cli-reference/upload.mdx +36 -0
- package/docs-evals/core-concepts/agents.mdx +106 -0
- package/docs-evals/core-concepts/analyze.mdx +86 -0
- package/docs-evals/core-concepts/check.mdx +51 -0
- package/docs-evals/core-concepts/datasets.mdx +138 -0
- package/docs-evals/core-concepts/index.mdx +42 -0
- package/docs-evals/core-concepts/jobs.mdx +136 -0
- package/docs-evals/core-concepts/models.mdx +68 -0
- package/docs-evals/core-concepts/sandboxes.mdx +52 -0
- package/docs-evals/core-concepts/secrets.mdx +41 -0
- package/docs-evals/core-concepts/skills.mdx +42 -0
- package/docs-evals/core-concepts/tasks.mdx +216 -0
- package/docs-evals/core-concepts/trial-outputs.mdx +103 -0
- package/docs-evals/core-concepts/trials.mdx +103 -0
- package/docs-evals/core-concepts/upload.mdx +45 -0
- package/docs-evals/dashboard/checks.mdx +15 -0
- package/docs-evals/dashboard/datasets.mdx +24 -0
- package/docs-evals/dashboard/jobs.mdx +65 -0
- package/docs-evals/dashboard/traces.mdx +15 -0
- package/docs-evals/dashboard/trial-viewer.mdx +30 -0
- package/docs-evals/docs.json +180 -0
- package/docs-evals/getting-started/installation.mdx +56 -0
- package/docs-evals/getting-started/quick-start.mdx +85 -0
- package/docs-evals/index.mdx +36 -0
- package/docs-evals/sdk/python.mdx +139 -0
- package/docs-evals/sdk/typescript.mdx +141 -0
- package/docs-evals/sdk-reference/agents.mdx +105 -0
- package/docs-evals/sdk-reference/analyses.mdx +125 -0
- package/docs-evals/sdk-reference/auth.mdx +76 -0
- package/docs-evals/sdk-reference/checks.mdx +166 -0
- package/docs-evals/sdk-reference/datasets.mdx +305 -0
- package/docs-evals/sdk-reference/errors.mdx +199 -0
- package/docs-evals/sdk-reference/index.mdx +58 -0
- package/docs-evals/sdk-reference/jobs.mdx +731 -0
- package/docs-evals/sdk-reference/meta.mdx +52 -0
- package/docs-evals/sdk-reference/skills.mdx +68 -0
- package/docs-evals/sdk-reference/trials.mdx +232 -0
- package/docs-evals/sdk-reference/types.mdx +272 -0
- package/docs-evals/snippets/global-options.mdx +13 -0
- package/docs-evals/snippets/list-flags.mdx +23 -0
- package/harness-capabilities.json +430 -0
- package/hosted-error-codes.json +120 -0
- package/package.json +163 -0
- package/skills/create-adapter/SKILL.md +287 -0
- package/skills/create-task/SKILL.md +491 -0
- package/skills/evolve/SKILL.md +39 -0
- package/skills/publish/SKILL.md +142 -0
- package/skills/rewardkit/SKILL.md +330 -0
- package/spec/atif/README.md +45 -0
- package/spec/atif/trajectory.schema.json +865 -0
- package/spec/openapi.yaml +13447 -0
|
@@ -0,0 +1,841 @@
|
|
|
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 `.withSandbox()` 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
|
+
```ts
|
|
39
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
40
|
+
|
|
41
|
+
// No .withSandbox() needed — SDK picks the right provider from env
|
|
42
|
+
const evolve = new Evolve()
|
|
43
|
+
.withAgent({ type: "claude" });
|
|
44
|
+
|
|
45
|
+
await evolve.run({ prompt: "Hello" });
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Only use explicit provider creation (below) if you need custom settings like timeout or app name.
|
|
49
|
+
|
|
50
|
+
Setting `EVOLVE_API_KEY` together with your own sandbox key is how you control sandbox billing
|
|
51
|
+
separately: the sandbox is created and billed on your provider account, while model traffic still
|
|
52
|
+
routes through the Evolve gateway on a session-scoped token. One bound to remember — on your own
|
|
53
|
+
sandbox account the routing token expires 24 hours after the sandbox comes up, so a single
|
|
54
|
+
session is bounded at a day; reconnecting to the sandbox starts a fresh one. Platform-managed
|
|
55
|
+
sandboxes carry no such clock; their tokens live and die with the sandbox.
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
### Managed Sandboxes
|
|
60
|
+
|
|
61
|
+
With `EVOLVE_API_KEY` and no provider key, the platform runs the sandbox for you: Evolve
|
|
62
|
+
authenticates your key, creates the box on its own account, and records who owns it. You never
|
|
63
|
+
hold an E2B, Daytona, or Modal credential, and you are never billed by them directly.
|
|
64
|
+
|
|
65
|
+
That is already what auto-resolution does when only `EVOLVE_API_KEY` is set — it gives you a
|
|
66
|
+
managed **E2B** sandbox. To run on a different provider, say which one:
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { Evolve, managedSandbox } from "@evolvingmachines/evolve";
|
|
70
|
+
|
|
71
|
+
const evolve = new Evolve()
|
|
72
|
+
.withAgent({ type: "claude" })
|
|
73
|
+
.withSandbox(await managedSandbox("daytona"));
|
|
74
|
+
|
|
75
|
+
await evolve.run({ prompt: "Hello" });
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`managedSandbox()` with no argument is managed E2B — the same sandbox auto-resolution gives you.
|
|
79
|
+
The provider is an argument rather than an environment variable on purpose: which provider your
|
|
80
|
+
program runs on is part of the program.
|
|
81
|
+
|
|
82
|
+
The second argument is an options bag: the Evolve key (when it should not come from
|
|
83
|
+
`EVOLVE_API_KEY`) plus sandbox-shape defaults applied to every sandbox the provider creates.
|
|
84
|
+
Per-run options from `.withSandboxCreateOptions()` still win, and every default rides the same
|
|
85
|
+
validated path as a create-time option — a provider or managed door that cannot enforce a value
|
|
86
|
+
refuses it loudly, never silently ignores it:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const provider = await managedSandbox("daytona", {
|
|
90
|
+
apiKey: "sk-...", // (optional) Default: EVOLVE_API_KEY
|
|
91
|
+
timeoutMs: 7_200_000, // (optional) Lifetime cap for every create
|
|
92
|
+
resources: { cpu: 2 }, // (optional) Sizing; refused where not enforceable
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Managed Daytona carries both of Daytona's planes through the Dashboard — creating and listing
|
|
97
|
+
sandboxes, and every command and file operation the agent performs, including streamed command
|
|
98
|
+
output. Images come from the snapshots the platform publishes: a managed create names one and
|
|
99
|
+
never builds one, so a `resources` request that an existing snapshot cannot honor is refused
|
|
100
|
+
rather than silently ignored.
|
|
101
|
+
|
|
102
|
+
Managed Modal — `managedSandbox("modal")` — runs commands and file operations through the
|
|
103
|
+
Dashboard's Modal door. Command output streams live, chunk by chunk, and each command's
|
|
104
|
+
duration is bounded by the door: 60 minutes by default, 120 minutes at most — a longer
|
|
105
|
+
`timeoutMs` is refused with an error naming the bound, never silently shortened. Two Modal
|
|
106
|
+
traits carry over: there is no pause — persist progress with Evolve checkpoints instead — and
|
|
107
|
+
a running command cannot be interrupted. Sizing, network policy, and the sandbox user are the
|
|
108
|
+
platform's; a create that asks for them is refused rather than silently ignored. File writes
|
|
109
|
+
ride the door one JSON body at a time, capped at 1 MiB per request — and the cap is on WIRE
|
|
110
|
+
bytes, base64 inflation included, so the largest binary payload one write can carry is about
|
|
111
|
+
768 KiB (text rides as-is and gets the full 1 MiB). An over-cap write is refused with a typed
|
|
112
|
+
error before anything is sent; split the payload into smaller writes.
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
### E2B (default)
|
|
117
|
+
```bash
|
|
118
|
+
# .env - Gateway mode
|
|
119
|
+
EVOLVE_API_KEY=sk-...
|
|
120
|
+
E2B_API_KEY=e2b_... # Optional with EVOLVE_API_KEY (auto-resolves)
|
|
121
|
+
|
|
122
|
+
# .env - Direct Provider Key Mode
|
|
123
|
+
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
124
|
+
E2B_API_KEY=e2b_... # Required in Direct Provider Key Mode
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
```ts
|
|
128
|
+
import { Evolve, createE2BProvider } from "@evolvingmachines/evolve";
|
|
129
|
+
|
|
130
|
+
const sandbox = createE2BProvider({
|
|
131
|
+
apiKey: process.env.E2B_API_KEY, // (optional) Auto-resolves from env
|
|
132
|
+
defaultTimeoutMs: 3600000, // (optional) Default: 3600000 (1 hour)
|
|
133
|
+
templateId: "my-custom-template", // (optional) E2B template ID. Default: "evolve-all"
|
|
134
|
+
});
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Modal
|
|
138
|
+
```bash
|
|
139
|
+
# .env - Gateway mode
|
|
140
|
+
EVOLVE_API_KEY=sk-...
|
|
141
|
+
MODAL_TOKEN_ID=ak-...
|
|
142
|
+
MODAL_TOKEN_SECRET=as-...
|
|
143
|
+
|
|
144
|
+
# .env - Direct Provider Key Mode
|
|
145
|
+
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
146
|
+
MODAL_TOKEN_ID=ak-...
|
|
147
|
+
MODAL_TOKEN_SECRET=as-...
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
```ts
|
|
151
|
+
import { Evolve, createModalProvider } from "@evolvingmachines/evolve";
|
|
152
|
+
|
|
153
|
+
const sandbox = createModalProvider({
|
|
154
|
+
tokenId: process.env.MODAL_TOKEN_ID, // (optional) Auto-resolves from env
|
|
155
|
+
tokenSecret: process.env.MODAL_TOKEN_SECRET, // (optional) Auto-resolves from env
|
|
156
|
+
appName: "my-app", // (optional) Default: "evolve-sandbox"
|
|
157
|
+
defaultTimeoutMs: 3600000, // (optional) Default: 3600000 (1 hour)
|
|
158
|
+
endpoint: "https://api.modal.com:443", // (optional) Default: https://api.modal.com:443
|
|
159
|
+
imageName: "evolve-all", // (optional) Default: "evolve-all"
|
|
160
|
+
});
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Daytona
|
|
164
|
+
```bash
|
|
165
|
+
# .env - Gateway mode
|
|
166
|
+
EVOLVE_API_KEY=sk-...
|
|
167
|
+
DAYTONA_API_KEY=...
|
|
168
|
+
|
|
169
|
+
# .env - Direct Provider Key Mode
|
|
170
|
+
ANTHROPIC_API_KEY=sk-ant-... # Or OPENAI_API_KEY, GEMINI_API_KEY, CLAUDE_CODE_OAUTH_TOKEN
|
|
171
|
+
DAYTONA_API_KEY=...
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
import { Evolve, createDaytonaProvider } from "@evolvingmachines/evolve";
|
|
176
|
+
|
|
177
|
+
const sandbox = createDaytonaProvider({
|
|
178
|
+
apiKey: process.env.DAYTONA_API_KEY, // (optional) Auto-resolves from env
|
|
179
|
+
apiUrl: "https://app.daytona.io/api", // (optional) Default: https://app.daytona.io/api
|
|
180
|
+
target: "us", // (optional) Target region. Default: "us"
|
|
181
|
+
defaultTimeoutMs: 3600000, // (optional) Default: 3600000 (1 hour) - converted to minutes for auto-stop
|
|
182
|
+
snapshotName: "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
|
|
183
|
+
});
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
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`.
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
## Sandbox Create Options
|
|
192
|
+
|
|
193
|
+
`.withSandboxCreateOptions()` 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:
|
|
194
|
+
|
|
195
|
+
```ts
|
|
196
|
+
const evolve = new Evolve()
|
|
197
|
+
.withSandboxCreateOptions({
|
|
198
|
+
image: "my-eval-template", // (optional) Sandbox image/template ID (provider default if omitted)
|
|
199
|
+
envs: { TASK_ID: "swe-042" }, // (optional) Extra env vars (Evolve-owned runtime vars win on conflict)
|
|
200
|
+
metadata: { suite: "nightly" }, // (optional) Provider metadata
|
|
201
|
+
timeoutMs: 3_600_000, // (optional) Sandbox timeout
|
|
202
|
+
workingDirectory: "/repo", // (optional) Working directory for agent commands
|
|
203
|
+
network: { // (optional) Outbound network policy applied at boot
|
|
204
|
+
outbound: "blocked", // "open" | "blocked"
|
|
205
|
+
allowedDestinations: ["registry.npmjs.org", "10.0.0.0/8"],
|
|
206
|
+
},
|
|
207
|
+
user: "root", // (optional) Run all commands and file ops as this user
|
|
208
|
+
homeDir: "/root", // (optional) Home dir for agent config paths
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**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.
|
|
213
|
+
|
|
214
|
+
**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`.
|
|
215
|
+
|
|
216
|
+
Constraints:
|
|
217
|
+
|
|
218
|
+
- A `user` can only be enforced at sandbox creation — combining it with `.withSession()`/`setSession()` (an existing sandbox) throws.
|
|
219
|
+
- Checkpoint storage (`.withStorage()`) and managed browser features require the default `/home/user` home; combining them with a custom `user`/`homeDir` throws.
|
|
220
|
+
- `envs` entries are validated like `.withSecrets()` values — Evolve-reserved variable names are rejected.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Workspace Modes
|
|
225
|
+
|
|
226
|
+
`.withWorkspaceMode()` controls what Evolve sets up in the working directory on first run:
|
|
227
|
+
|
|
228
|
+
| Mode | Workspace setup | Use it for |
|
|
229
|
+
|------|-----------------|------------|
|
|
230
|
+
| `"knowledge"` (default) | Creates `context/`, `scripts/`, `temp/`, `output/` + writes the system prompt file | General agent work with structured deliverables |
|
|
231
|
+
| `"swe"` | Same as knowledge + `repo/` for code repositories | Software-engineering tasks on cloned repos |
|
|
232
|
+
|
|
233
|
+
```ts
|
|
234
|
+
const evolve = new Evolve()
|
|
235
|
+
.withWorkspaceMode("swe")
|
|
236
|
+
.withSandboxCreateOptions({ image: "my-ci-template" });
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## Evolve Instance
|
|
242
|
+
|
|
243
|
+
```ts
|
|
244
|
+
const evolve = new Evolve()
|
|
245
|
+
|
|
246
|
+
// Agent configuration (optional if EVOLVE_API_KEY set, defaults to claude)
|
|
247
|
+
.withAgent({
|
|
248
|
+
type: "codex", // "claude" | "codex" | "gemini" | "qwen" | "kimi" | "opencode" | "droid" - defaults to "claude"
|
|
249
|
+
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)
|
|
250
|
+
reasoningEffort: "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)
|
|
251
|
+
// maxContextSize: 128000, // (optional) Context/completion ceiling for CLIs that must be told one (see Getting Started → Harness and Model Pairing)
|
|
252
|
+
apiKey: process.env.EVOLVE_API_KEY!, // (optional) Gateway mode - auto-resolves from env
|
|
253
|
+
// providerApiKey: process.env.ANTHROPIC_API_KEY!, // (optional) Direct Provider Key Mode
|
|
254
|
+
// oauthToken: process.env.CLAUDE_CODE_OAUTH_TOKEN!, // (optional) Claude Max subscription
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Sandbox provider (see 2.1 above, or auto-resolves from env)
|
|
258
|
+
.withSandbox(sandbox)
|
|
259
|
+
|
|
260
|
+
// (optional) Workspace mode: "knowledge" (default) | "swe" (see Workspace Modes above)
|
|
261
|
+
.withWorkspaceMode("knowledge")
|
|
262
|
+
|
|
263
|
+
// (optional) Uploads to /home/user/workspace/context/ on first run
|
|
264
|
+
.withContext({
|
|
265
|
+
"docs/readme.txt": "User provided context...",
|
|
266
|
+
"data.json": JSON.stringify({ key: "value" }),
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
// (optional) System prompt appended to default instructions
|
|
270
|
+
.withSystemPrompt("You are a careful pair programmer.")
|
|
271
|
+
|
|
272
|
+
// (optional) Schema for structured output (agent writes result.json, validated on getOutputFiles())
|
|
273
|
+
// Accepts Zod schemas or JSON Schema objects
|
|
274
|
+
.withSchema(z.object({
|
|
275
|
+
summary: z.string(),
|
|
276
|
+
score: z.number(),
|
|
277
|
+
}))
|
|
278
|
+
|
|
279
|
+
// Or with JSON Schema:
|
|
280
|
+
// .withSchema({
|
|
281
|
+
// type: "object",
|
|
282
|
+
// properties: {
|
|
283
|
+
// summary: { type: "string" },
|
|
284
|
+
// score: { type: "number" },
|
|
285
|
+
// },
|
|
286
|
+
// required: ["summary", "score"],
|
|
287
|
+
// })
|
|
288
|
+
|
|
289
|
+
// (optional) Gateway browser automation (.withBrowser() defaults to remote managed agent-browser)
|
|
290
|
+
.withBrowser()
|
|
291
|
+
|
|
292
|
+
// (optional) Install plugins/extensions for the selected agent before first run
|
|
293
|
+
.withPlugins({
|
|
294
|
+
marketplace: "https://github.com/org/codex-plugins.git",
|
|
295
|
+
sparse: [".agents/plugins"],
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
// (optional) Skills for the agent — skills.sh / git / local references
|
|
299
|
+
.withSkills(["anthropics/skills", "./my-skill"])
|
|
300
|
+
|
|
301
|
+
// (optional) Managed integrations (gateway mode only)
|
|
302
|
+
.withIntegrations({
|
|
303
|
+
userId: "root",
|
|
304
|
+
apps: ["github", "gmail"],
|
|
305
|
+
})
|
|
306
|
+
|
|
307
|
+
// (optional) Dashboard-stored managed secrets (gateway mode only)
|
|
308
|
+
.withManagedSecrets([
|
|
309
|
+
{ name: "GITHUB_TOKEN" },
|
|
310
|
+
{ name: "SLACK_BOT_TOKEN", as: "SLACK_TOKEN" },
|
|
311
|
+
])
|
|
312
|
+
|
|
313
|
+
// (optional) Prefix for observability logs
|
|
314
|
+
.withSessionTagPrefix("my-agent")
|
|
315
|
+
|
|
316
|
+
// (optional) Storage for checkpoint persistence (gateway feature — requires EVOLVE_API_KEY)
|
|
317
|
+
.withStorage()
|
|
318
|
+
|
|
319
|
+
// ─── Advanced ───────────────────────────────────────────────────────────────
|
|
320
|
+
|
|
321
|
+
// (optional) Provider-neutral options for fresh sandbox creation (see Sandbox Create Options above)
|
|
322
|
+
.withSandboxCreateOptions({
|
|
323
|
+
image: "my-task-image",
|
|
324
|
+
network: { outbound: "blocked", allowedDestinations: ["pypi.org"] },
|
|
325
|
+
user: "root",
|
|
326
|
+
})
|
|
327
|
+
|
|
328
|
+
// (optional) MCP servers for agent tools
|
|
329
|
+
.withMcpServers({
|
|
330
|
+
exa: {
|
|
331
|
+
command: "npx",
|
|
332
|
+
args: ["-y", "exa-mcp-server"],
|
|
333
|
+
env: { EXA_API_KEY: "..." },
|
|
334
|
+
},
|
|
335
|
+
api: {
|
|
336
|
+
type: "http",
|
|
337
|
+
url: "https://example.com/mcp",
|
|
338
|
+
headers: { "x-api-key": "..." },
|
|
339
|
+
},
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
// (optional) Environment variables injected into sandbox
|
|
343
|
+
.withSecrets({
|
|
344
|
+
GITHUB_TOKEN: process.env.GITHUB_TOKEN!
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
// (optional) Uploads to /home/user/workspace/ on first run
|
|
348
|
+
.withFiles({
|
|
349
|
+
"scripts/setup.sh": "#!/bin/bash\necho hello",
|
|
350
|
+
});
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
**Note:**
|
|
354
|
+
- Configuration methods can be chained in any order.
|
|
355
|
+
- The sandbox is created on the first `run()` or `executeCommand()` call (see below).
|
|
356
|
+
- Context files, workspace files, MCP servers, and system prompt are set up once on the first call.
|
|
357
|
+
- Using `.withSession()` to reconnect skips setup since the sandbox already exists.
|
|
358
|
+
- `withSchema()` accepts both Zod schemas and JSON Schema objects.
|
|
359
|
+
|
|
360
|
+
**McpServerConfig** — MCP server connection (STDIO or HTTP/SSE):
|
|
361
|
+
|
|
362
|
+
| Fields | Transport |
|
|
363
|
+
|--------|-----------|
|
|
364
|
+
| `command` | stdio (local subprocess) |
|
|
365
|
+
| `url` + `type: "http"` | HTTP (remote) |
|
|
366
|
+
| `url` (no type) | SSE (remote, default) |
|
|
367
|
+
|
|
368
|
+
```ts
|
|
369
|
+
interface McpServerConfig {
|
|
370
|
+
type?: "stdio" | "http" | "sse";
|
|
371
|
+
command?: string; args?: string[]; cwd?: string; // STDIO
|
|
372
|
+
url?: string; headers?: Record<string, string>; // HTTP/SSE
|
|
373
|
+
env?: Record<string, string>; // Common
|
|
374
|
+
}
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
## Browser Automation
|
|
378
|
+
|
|
379
|
+
Browser automation is opt-in. Use `.withBrowser()` for browser, QA, dogfooding, and website automation tasks.
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
new Evolve().withBrowser(); // managed browser with dashboard live view and replay
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
Evolve automatically configures the browser runtime. In Gateway mode, the managed browser gives you:
|
|
386
|
+
|
|
387
|
+
- `event.browser.liveUrl` from the `browser_ready` lifecycle event
|
|
388
|
+
- `result.browser?.liveUrl` after `run()` returns
|
|
389
|
+
- `result.sessionId`, which is the id to use for traces and browser replay
|
|
390
|
+
- `sessions().browserReplay(sessionId)`, which returns replay and raw `.mp4` download URLs after cleanup
|
|
391
|
+
- `replay.suggestedStartSeconds`, when present, which is the recommended replay start time in seconds
|
|
392
|
+
- `replay.sizeBytes` and `replay.readyAt`, when present, which describe the raw recording size and replay readiness time
|
|
393
|
+
|
|
394
|
+
`remote` controls where the browser session runs:
|
|
395
|
+
|
|
396
|
+
- `.withBrowser()` uses `remote: true` by default. Evolve creates and manages a cloud browser session, wires it into the sandbox, and exposes dashboard live view plus replay.
|
|
397
|
+
- `remote: false` runs browser automation locally inside the sandbox. Use it only when you do not need managed live view or replay.
|
|
398
|
+
|
|
399
|
+
Use the default unless you have a reason not to:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
new Evolve().withBrowser();
|
|
403
|
+
// recommended: managed remote browser
|
|
404
|
+
|
|
405
|
+
new Evolve().withBrowser({
|
|
406
|
+
provider: "agent-browser",
|
|
407
|
+
remote: false,
|
|
408
|
+
});
|
|
409
|
+
// local agent-browser, no managed live/replay
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Use a browser profile to reuse logged-in browser state across managed browser sessions:
|
|
413
|
+
|
|
414
|
+
```ts
|
|
415
|
+
const evolve = new Evolve()
|
|
416
|
+
.withBrowser({
|
|
417
|
+
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 `lastUsedAt`.
|
|
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 `Evolve.browserProfiles().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 `accountLabel`.
|
|
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
|
+
```ts
|
|
438
|
+
const evolve = new Evolve()
|
|
439
|
+
.withBrowser({
|
|
440
|
+
profile: "ramp-qa",
|
|
441
|
+
})
|
|
442
|
+
.withBrowserCredentials({
|
|
443
|
+
allow: [{ website: "github.com", accountLabel: "qa-admin" }],
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
try {
|
|
447
|
+
await evolve.run({
|
|
448
|
+
prompt: "Open GitHub, sign in with the saved qa-admin login, and confirm the account is authenticated.",
|
|
449
|
+
});
|
|
450
|
+
} finally {
|
|
451
|
+
await evolve.kill();
|
|
452
|
+
}
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Future runs can reuse the saved state with `.withBrowser({ profile: "ramp-qa" })`; include `.withBrowserCredentials()` again only when the agent needs access to saved login tools.
|
|
456
|
+
|
|
457
|
+
List or delete profiles from the SDK:
|
|
458
|
+
|
|
459
|
+
```ts
|
|
460
|
+
const profiles = await Evolve.browserProfiles().list();
|
|
461
|
+
|
|
462
|
+
await Evolve.browserProfiles().delete({
|
|
463
|
+
profile: "ramp-qa",
|
|
464
|
+
});
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
To disable browser automation, omit `.withBrowser()`.
|
|
468
|
+
|
|
469
|
+
Full browser run with live view and replay:
|
|
470
|
+
|
|
471
|
+
```ts
|
|
472
|
+
import { Evolve, sessions } from "@evolvingmachines/evolve";
|
|
473
|
+
|
|
474
|
+
const evolve = new Evolve()
|
|
475
|
+
.withBrowser()
|
|
476
|
+
.withSessionTagPrefix("checkout-qa");
|
|
477
|
+
|
|
478
|
+
let sessionId: string | undefined;
|
|
479
|
+
|
|
480
|
+
evolve.on("lifecycle", (event) => {
|
|
481
|
+
if (event.reason === "browser_ready" && event.browser) {
|
|
482
|
+
showLiveBrowser(event.browser.liveUrl);
|
|
483
|
+
sessionId = event.browser.sessionId;
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
try {
|
|
488
|
+
const result = await evolve.run({
|
|
489
|
+
prompt: "Open the app, test the checkout flow, and report issues.",
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
sessionId = result.sessionId ?? sessionId;
|
|
493
|
+
if (result.browser?.liveUrl) {
|
|
494
|
+
showLiveBrowser(result.browser.liveUrl);
|
|
495
|
+
}
|
|
496
|
+
} finally {
|
|
497
|
+
await evolve.kill();
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (!sessionId) throw new Error("Missing dashboard session id");
|
|
501
|
+
|
|
502
|
+
const replay = await sessions().browserReplay(sessionId, {
|
|
503
|
+
timeoutMs: 600_000,
|
|
504
|
+
intervalMs: 5_000,
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
showReplay(replay.replayUrl);
|
|
508
|
+
saveDownloadLink(replay.downloadUrl);
|
|
509
|
+
setReplayStartTime(replay.suggestedStartSeconds ?? 0);
|
|
510
|
+
showReplayMetadata({
|
|
511
|
+
sizeBytes: replay.sizeBytes,
|
|
512
|
+
readyAt: replay.readyAt,
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Replay processing starts when the managed browser is cleaned up, usually during `kill()`.
|
|
517
|
+
If replay is not ready before `timeoutMs`, call `browserReplay()` again later with the same `sessionId`.
|
|
518
|
+
The `replayUrl` already applies `suggestedStartSeconds`; use the field separately only if your UI needs to display or store the recommended start time.
|
|
519
|
+
The `status` is `"ready"` once `browserReplay()` returns.
|
|
520
|
+
|
|
521
|
+
## Browser Credentials
|
|
522
|
+
|
|
523
|
+
Browser credentials let managed remote `agent-browser` runs sign in with saved website logins without exposing passwords to the agent.
|
|
524
|
+
|
|
525
|
+
Availability:
|
|
526
|
+
|
|
527
|
+
- Requires Gateway mode and managed remote `agent-browser`.
|
|
528
|
+
- `.withBrowser()` uses that recommended remote setup by default.
|
|
529
|
+
- Not available with local browser mode, Direct Provider Key Mode, or `.withSession()`.
|
|
530
|
+
|
|
531
|
+
Dashboard setup:
|
|
532
|
+
|
|
533
|
+
1. Open the Evolve Dashboard.
|
|
534
|
+
2. Go to **Secrets**.
|
|
535
|
+
3. Add a browser login with `Account label`, `Website`, `Email`, and `Password`.
|
|
536
|
+
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.
|
|
537
|
+
|
|
538
|
+
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.
|
|
539
|
+
|
|
540
|
+
Expose saved logins to a run:
|
|
541
|
+
|
|
542
|
+
```ts
|
|
543
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
544
|
+
|
|
545
|
+
const evolve = new Evolve()
|
|
546
|
+
.withBrowser()
|
|
547
|
+
.withBrowserCredentials({
|
|
548
|
+
allow: [{ website: "github.com", accountLabel: "qa-admin" }],
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
await evolve.run({
|
|
552
|
+
prompt: "Open GitHub, sign in with the saved qa-admin login, and verify the repository settings page.",
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
await evolve.kill();
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
If `allow` is omitted, all enabled browser logins for the Evolve account are available to that run:
|
|
559
|
+
|
|
560
|
+
```ts
|
|
561
|
+
const evolve = new Evolve()
|
|
562
|
+
.withBrowser()
|
|
563
|
+
.withBrowserCredentials();
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
The agent receives a run-scoped `browser-login` MCP server with these tools:
|
|
567
|
+
|
|
568
|
+
- `browser_list_logins` lists available website logins: website, account_label, and email only.
|
|
569
|
+
- `browser_login` fills the stored password and submits the current browser sign-in tab.
|
|
570
|
+
- `browser_complete_signup` generates a password, submits the current browser signup tab, and saves the new login.
|
|
571
|
+
|
|
572
|
+
Manage browser logins from the SDK:
|
|
573
|
+
|
|
574
|
+
```ts
|
|
575
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
576
|
+
|
|
577
|
+
const credentials = Evolve.browserCredentials();
|
|
578
|
+
|
|
579
|
+
await credentials.create({
|
|
580
|
+
website: "github.com",
|
|
581
|
+
accountLabel: "qa-admin",
|
|
582
|
+
email: "qualityassurance@example.com",
|
|
583
|
+
password: process.env.QA_GITHUB_PASSWORD!,
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
const page = await credentials.list({ website: "github.com" });
|
|
587
|
+
|
|
588
|
+
await credentials.delete({
|
|
589
|
+
website: "github.com",
|
|
590
|
+
accountLabel: "qa-admin",
|
|
591
|
+
});
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
## Agent Plugins
|
|
595
|
+
|
|
596
|
+
`.withPlugins()` installs plugins/extensions into the sandbox user profile before the first agent command. The currently selected agent determines the accepted shape:
|
|
597
|
+
|
|
598
|
+
```ts
|
|
599
|
+
// droid
|
|
600
|
+
.withPlugins({
|
|
601
|
+
marketplace: "https://github.com/Factory-AI/factory-plugins",
|
|
602
|
+
plugin: "droid-control@factory-plugins",
|
|
603
|
+
})
|
|
604
|
+
|
|
605
|
+
// claude
|
|
606
|
+
.withPlugins({
|
|
607
|
+
marketplace: "anthropics/claude-code",
|
|
608
|
+
plugin: "commit-commands@anthropics-claude-code",
|
|
609
|
+
})
|
|
610
|
+
|
|
611
|
+
// gemini
|
|
612
|
+
.withPlugins({
|
|
613
|
+
source: "https://github.com/org/gemini-extension",
|
|
614
|
+
ref: "main",
|
|
615
|
+
})
|
|
616
|
+
|
|
617
|
+
// codex marketplace registration
|
|
618
|
+
.withPlugins({
|
|
619
|
+
marketplace: "https://github.com/org/codex-plugins.git",
|
|
620
|
+
sparse: [".agents/plugins"],
|
|
621
|
+
})
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
If `.withAgent()` is omitted, plugins target the default agent (`claude`).
|
|
625
|
+
|
|
626
|
+
## Agent Skills
|
|
627
|
+
|
|
628
|
+
Skills are folders of instructions and helper files — a `SKILL.md` manifest plus anything it needs — that the agent's harness discovers natively. `.withSkills()` takes real references; there is no built-in catalog:
|
|
629
|
+
|
|
630
|
+
```ts
|
|
631
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
632
|
+
|
|
633
|
+
const evolve = new Evolve()
|
|
634
|
+
.withSkills([
|
|
635
|
+
"skills.sh/vercel-labs/agent-skills/frontend-design", // one named skill from a skills.sh-listed repo
|
|
636
|
+
"anthropics/skills", // every skill a GitHub repo publishes
|
|
637
|
+
"anthropics/skills@main", // pinned to a branch, tag, or commit
|
|
638
|
+
"https://github.com/org/repo/tree/main/skills/my-skill", // any https git URL, down to a subfolder
|
|
639
|
+
"./my-skill", // a local folder containing SKILL.md
|
|
640
|
+
]);
|
|
641
|
+
|
|
642
|
+
await evolve.run({ prompt: "Create a slide deck summarizing the uploaded notes." });
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
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).
|
|
646
|
+
|
|
647
|
+
How references resolve:
|
|
648
|
+
|
|
649
|
+
- 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.
|
|
650
|
+
- 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/`.
|
|
651
|
+
- 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.
|
|
652
|
+
- 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.
|
|
653
|
+
|
|
654
|
+
After a run, `evolve.resolvedSkills()` reports exactly what mounted: each skill's name, source reference, exact git commit for git-backed skills, and content digest.
|
|
655
|
+
|
|
656
|
+
## Managed Secrets
|
|
657
|
+
|
|
658
|
+
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.
|
|
659
|
+
|
|
660
|
+
The delivery mode is chosen when the secret is saved and decides how the value reaches the sandbox:
|
|
661
|
+
|
|
662
|
+
- **`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.
|
|
663
|
+
- **`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.
|
|
664
|
+
|
|
665
|
+
```ts
|
|
666
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
667
|
+
|
|
668
|
+
const secrets = await Evolve.managedSecrets().list(); // includes label + delivery
|
|
669
|
+
|
|
670
|
+
const evolve = new Evolve()
|
|
671
|
+
.withManagedSecrets([
|
|
672
|
+
{ name: "GITHUB_TOKEN" }, // 'default'-labeled row
|
|
673
|
+
{ name: "API_KEY", label: "prod" }, // a specific labeled row
|
|
674
|
+
{ name: "SLACK_BOT_TOKEN", as: "SLACK_TOKEN" }, // renamed in the sandbox
|
|
675
|
+
]);
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
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.
|
|
679
|
+
|
|
680
|
+
Runtime behavior:
|
|
681
|
+
|
|
682
|
+
- 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.
|
|
683
|
+
- 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.
|
|
684
|
+
- `.withSecrets()` is still for local raw env injection; `.withManagedSecrets()` is for Dashboard-stored values.
|
|
685
|
+
|
|
686
|
+
### Storing secrets programmatically
|
|
687
|
+
|
|
688
|
+
`Evolve.managedSecrets()` 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.
|
|
689
|
+
|
|
690
|
+
```ts
|
|
691
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
692
|
+
|
|
693
|
+
const secrets = Evolve.managedSecrets();
|
|
694
|
+
|
|
695
|
+
await secrets.set({
|
|
696
|
+
name: "GITHUB_TOKEN",
|
|
697
|
+
value: process.env.GITHUB_TOKEN!,
|
|
698
|
+
delivery: "brokered",
|
|
699
|
+
allowedHosts: ["api.github.com"],
|
|
700
|
+
allowedPathPrefixes: ["/"],
|
|
701
|
+
allowedMethods: ["GET"],
|
|
702
|
+
});
|
|
703
|
+
|
|
704
|
+
await secrets.set({
|
|
705
|
+
name: "STRIPE_KEY",
|
|
706
|
+
label: "staging",
|
|
707
|
+
value: process.env.STRIPE_TEST_KEY!,
|
|
708
|
+
delivery: "direct", // direct secrets carry no scoping
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
await secrets.delete({ name: "STRIPE_KEY", label: "staging" });
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
Or from the terminal — the value comes from `--value` or piped stdin (piping keeps it out of shell history):
|
|
715
|
+
|
|
716
|
+
```bash
|
|
717
|
+
printf %s "$GITHUB_TOKEN" | evolve secrets set GITHUB_TOKEN \
|
|
718
|
+
--delivery brokered \
|
|
719
|
+
--allowed-host api.github.com --allowed-path-prefix / --allowed-method GET
|
|
720
|
+
|
|
721
|
+
evolve secrets list
|
|
722
|
+
evolve secrets delete GITHUB_TOKEN
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
The write rules, all typed and machine-readable (the HTTP error body carries a `code`):
|
|
726
|
+
|
|
727
|
+
- `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.
|
|
728
|
+
- 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.
|
|
729
|
+
- `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).
|
|
730
|
+
- A **read-only API key** can `list` but not `set`/`delete` (`read_only_key`, HTTP 403).
|
|
731
|
+
- **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.
|
|
732
|
+
|
|
733
|
+
---
|
|
734
|
+
|
|
735
|
+
## Managed Integrations
|
|
736
|
+
|
|
737
|
+
Managed integrations are available only in gateway mode (`EVOLVE_API_KEY`); integration credentials stay server-side and agents receive an Evolve-scoped MCP proxy.
|
|
738
|
+
|
|
739
|
+
Available apps:
|
|
740
|
+
|
|
741
|
+
| `apps` value | App | What agents can do |
|
|
742
|
+
| --- | --- | --- |
|
|
743
|
+
| `gmail` | Gmail | Read, search, draft, and send email. |
|
|
744
|
+
| `agent_mail` | Agent Mail | Use an agent inbox to send, receive, and act on email. |
|
|
745
|
+
| `slack` | Slack | Search channels, read conversations, and send team messages. |
|
|
746
|
+
| `github` | GitHub | Work with repositories, issues, pull requests, and code. |
|
|
747
|
+
| `googlecalendar` | Google Calendar | Read and manage calendar events. |
|
|
748
|
+
| `notion` | Notion | Read and update pages, databases, docs, and workspace content. |
|
|
749
|
+
| `linear` | Linear | Read and manage issues, teams, projects, and comments. |
|
|
750
|
+
|
|
751
|
+
```bash
|
|
752
|
+
# .env
|
|
753
|
+
EVOLVE_API_KEY=sk-...
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
```ts
|
|
757
|
+
import { Evolve } from "@evolvingmachines/evolve";
|
|
758
|
+
|
|
759
|
+
const evolve = new Evolve()
|
|
760
|
+
.withIntegrations({
|
|
761
|
+
userId: "customer_123",
|
|
762
|
+
apps: ["github", "gmail"],
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
await evolve.run({ prompt: "Create a GitHub issue for the login bug" });
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
### Root vs SDK Users
|
|
769
|
+
|
|
770
|
+
Use `userId: "root"` for accounts connected in the Evolve dashboard for private agents and test accounts.
|
|
771
|
+
|
|
772
|
+
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.
|
|
773
|
+
|
|
774
|
+
```ts
|
|
775
|
+
const link = await Evolve.integrations.auth({
|
|
776
|
+
userId: "customer_123",
|
|
777
|
+
app: "gmail",
|
|
778
|
+
accountLabel: "work",
|
|
779
|
+
});
|
|
780
|
+
|
|
781
|
+
// Show link.url to the user.
|
|
782
|
+
const evolve = new Evolve()
|
|
783
|
+
.withIntegrations({
|
|
784
|
+
userId: "customer_123",
|
|
785
|
+
apps: ["gmail"],
|
|
786
|
+
});
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
### Account Helpers
|
|
790
|
+
|
|
791
|
+
```ts
|
|
792
|
+
const accounts = await Evolve.integrations.accounts.list({
|
|
793
|
+
userIds: ["customer_123"],
|
|
794
|
+
app: "gmail",
|
|
795
|
+
statuses: ["ACTIVE"],
|
|
796
|
+
});
|
|
797
|
+
|
|
798
|
+
await Evolve.integrations.accounts.update({
|
|
799
|
+
accountId: "account_id_from_list",
|
|
800
|
+
accountLabel: "work",
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// If the user connected multiple Gmail accounts, choose an account label or account ID returned by accounts.list().
|
|
804
|
+
const evolve = new Evolve()
|
|
805
|
+
.withIntegrations({
|
|
806
|
+
userId: "customer_123",
|
|
807
|
+
apps: ["gmail"],
|
|
808
|
+
accounts: { gmail: ["work"] },
|
|
809
|
+
});
|
|
810
|
+
|
|
811
|
+
// Disconnect by account ID.
|
|
812
|
+
await Evolve.integrations.accounts.delete({ accountId: "account_id_from_list" });
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
### Custom Auth Configs and API Keys
|
|
816
|
+
|
|
817
|
+
Use `authConfigs` 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.
|
|
818
|
+
|
|
819
|
+
```ts
|
|
820
|
+
const evolve = new Evolve()
|
|
821
|
+
.withIntegrations({
|
|
822
|
+
userId: "customer_123",
|
|
823
|
+
apps: ["github"],
|
|
824
|
+
authConfigs: { github: "ac_custom_github" },
|
|
825
|
+
keys: { github: process.env.GITHUB_TOKEN! },
|
|
826
|
+
});
|
|
827
|
+
```
|
|
828
|
+
|
|
829
|
+
### Type Reference
|
|
830
|
+
|
|
831
|
+
```ts
|
|
832
|
+
interface IntegrationsSetup {
|
|
833
|
+
userId: string; // "root" or your stable SDK user ID
|
|
834
|
+
apps: string[];
|
|
835
|
+
accounts?: Record<string, string[]>; // app -> account labels or account IDs
|
|
836
|
+
authConfigs?: Record<string, string>; // app -> custom auth config ID
|
|
837
|
+
keys?: Record<string, string>; // app -> API key, requires authConfigs[app]
|
|
838
|
+
}
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
---
|