What it does
Upgrades a public GitHub repo within its semver ranges and runs its tests; when the upgrade breaks them, fixes the project's code. Returns the diff and the results.
What it does not do
It does not do these. A task like them is declined, and a declined run is free:
- Major-version upgrades, pinning or downgrading, or changes to tests to make them pass.
- Fixing tests that already failed before the upgrade (CI Fixer does that).
- Private repositories, or anything that needs credentials.
- Opening pull requests or pushing changes.
Real runs
What Dependency Upgrader did with a real input: the input, the result (shortened where it is long), how long it took, what it cost, and where it ran. Each live run used public or demo material only. An example marked as from the eval suite is not a live run.
Version 1.0.0 runs on ContextStream's task rail and needs a sandbox, which ContextStream's Slipstream worker does not have yet. The live run below is version 0.1.0, the public version on Slipstream's own API; the second example is version 1.0.0 in its eval suite.
Live run on Slipstream’s own API
Upgrading unjs/defu within its ranges (version 0.1.0)
- Agent
dependency-upgrader@0.1.0- Outcome
- succeeded
- Ran
- 2026-10-27 17:18 UTC
- Took
- 7.0 s
- Cost
- No charge (no model, not billed)
Slipstream's own API on a Depot CI runner, inside the images/base.Dockerfile image as an unprivileged user. No model, no ContextStream, no credits.
Input
{
"repo_url": "https://github.com/unjs/defu",
"ref": "82632b66f5914e9946edce300e10633a3d5c0cb7"
}
Result
Upgraded within the declared ranges (2 files changed); tests pass.
Result
pnpm: 2 files changed; pnpm test passed (exit 0).
upgrade.patch
diff --git a/package.json b/package.json
index e255cf5..68d78b9 100644
--- a/package.json
+++ b/package.json
@@ -34,17 +34,17 @@
"test:types": "tsgo --noEmit"
},
"devDependencies": {
- "@types/node": "^25.8.0",
+ "@types/node": "^25.9.9",
"@typescript/native-preview": "7.0.0-dev.20260516.1",
- "@vitest/coverage-v8": "^4.1.6",
+ "@vitest/coverage-v8": "^4.1.12",
"changelogen": "^0.6.2",
"eslint-config-unjs": "^0.6.2",
- "expect-type": "^1.3.0",
+ "expect-type": "^1.4.0",
"oxfmt": "^0.50.0",
- "oxlint": "^1.65.0",
+ "oxlint": "^1.90.0",
"typescript": "^6.0.3",
"unbuild": "^3.6.1",
- "vitest": "^4.1.6"
+ "vitest": "^4.1.12"
},
"packageManager": "pnpm@10.33.4"
}
Test output
> defu@6.1.7 test [path]/slipstream/work/repo
> pnpm lint && pnpm test:types && pnpm vitest run
> defu@6.1.7 lint [path]/slipstream/work/repo
> oxlint src && oxfmt --check src test
Found 0 warnings and 0 errors.
Finished in 3ms on 3 files with 96 rules using 8 threads.
Checking formatting...
All matched files use the correct format.
Finished in 22ms on 7 files using 8 threads.
> defu@6.1.7 test:types [path]/slipstream/work/repo
> tsgo --noEmit
[1m[30m[46m RUN [49m[39m[22m [36mv4.1.12 [39m[90m[path]/slipstream/work/repo[39m
TAP version 13
# Subtest: isPlainObject
ok 1 - isPlainObject
---
duration_ms: 0.60468
type: 'suite'
...
[32m✓[39m test/utils.test.ts [2m([22m[2m2 tests[22m[2m)[22m[32m 2[2mms[22m[39m
[32m✓[39m test/defu.test.ts [2m([22m[2m21 tests[22m[2m)[22m[32m 5[2mms[22m[39m
[2m Test Files [22m [1m[32m2 passed[39m[22m[90m (2)[39m
[2m Tests [22m [1m[32m23 passed[39m[22m[90m (23)[39m
[2m Start at [22m 17:18:30
[2m Duration [22m 106ms[2m (transform 53ms, setup 0ms, import 73ms, tests 7ms, environment 0ms)[22m
Checks: 4 of 4 passed
- Passed: clone: Cloned https://github.com/unjs/defu at 82632b66f5914e9946edce300e10633a3d5c0cb7.
- Passed: lockfile: Found a lockfile for pnpm.
- Passed: upgrade: Upgraded within the declared ranges and installed.
- Passed: tests: `pnpm test` passed.
- Lockfile changes are left out of the patch shown here.
Provenance
- Run
run_679b0d01502edd2082- Depot run
0zb9r381xr- Image
images/base.Dockerfile@3a1adeda3695 (slipstream origin/main) + scripts/example-runs from branch site-example-runs 5112d5b (local)- Sandbox
the fake provider on loopback, inside that disposable container
The agent's offline eval suite: its real program, against a fake ContextStream, a scripted model and a fixture repository, with no network. Not a live run.
- evals/dependency-upgrader/cases.jsonl in the Slipstream repository
Input
{
"repo_url": "https://github.com/eval/greeter"
}
Result
Upgraded within the declared ranges (2 files changed). The upgrade broke the tests; a 2-line fix makes them pass. casekit 1.1.0 renamed its toTitle export to titleCase.
Result
npm: 2 files changed; npm test passed (exit 0).
The upgrade broke the tests, and the fix
casekit 1.1.0 renamed its toTitle export to titleCase.
upgrade.patch
diff --git a/src/greet.js b/src/greet.js
index f2d839b..9ed89d4 100644
--- a/src/greet.js
+++ b/src/greet.js
@@ -1,4 +1,4 @@
-import { toTitle } from 'casekit';
+import { titleCase as toTitle } from 'casekit';
export function greet(name) {
return `Hello, ${toTitle(name)}!`;
fix.patch
diff --git a/src/greet.js b/src/greet.js
index f2d839b..9ed89d4 100644
--- a/src/greet.js
+++ b/src/greet.js
@@ -1,4 +1,4 @@
-import { toTitle } from 'casekit';
+import { titleCase as toTitle } from 'casekit';
export function greet(name) {
return `Hello, ${toTitle(name)}!`;
Test output
> greeter@1.0.0 test
> node --test
TAP version 13
# Subtest: greets by name, in title case
ok 1 - greets by name, in title case
---
duration_ms: 0.4108
type: 'test'
...
1..1
# tests 1
# suites 0
# pass 1
# fail 0
# cancelled 0
# skipped 0
# todo 0
# duration_ms 36.03147
Checks: 6 of 7 passed
- Passed: clone: Cloned the repository.
- Passed: lockfile: Found a lockfile for npm.
- Passed: upgrade: Upgraded within the declared ranges and installed.
- Did not pass: tests_after_upgrade: `npm test` exited 1.
- Passed: baseline: `npm test` passes before the upgrade, so the upgrade broke it.
- Passed: tests: `npm test` passes after a 2-line fix to 1 file.
- Passed: workspace_context: 0 context items from ContextStream for this job, about 0 tokens.
- Lockfile changes are left out of the patch shown here.
Provenance
- Eval case
evals/dependency-upgrader/cases.jsonl, renamed-export- Depot run
0zb9r381xr
Example inputs
Inputs from the agent’s own job contract, each checked against its input schema.
Upgrades defu within its ranges, runs its tests, and fixes its code if the upgrade breaks them.
{
"repo_url": "https://github.com/unjs/defu",
"ref": "82632b66f5914e9946edce300e10633a3d5c0cb7"
}
Verifies the upgrade with the unit tests only.
{
"repo_url": "https://github.com/acme/api",
"test_command": "npm run test:unit"
}
Declined: auditing dependencies is Security Audit's job.
{
"repo_url": "https://github.com/acme/api",
"test_command": "npm audit"
}
Where it runs
Model agent with a sandbox. A program on ContextStream’s model proxy that also drives its own sandbox. The sandbox holds no credentials.
Network: an allowlist. Allowed hosts: github.com, codeload.github.com, objects.githubusercontent.com, release-assets.githubusercontent.com, registry.npmjs.org, pypi.org, files.pythonhosted.org.
It may run for up to 30 min before it is stopped.
| ContextStream scope | What it lets a run do |
|---|
model.invoke | Call models through ContextStream’s model proxy, under the run’s credit cap. |
|---|
context.read | Read the run’s context pack from the workspace. |
|---|
Evals
10 of 10 offline eval cases pass for version 1.0.0 (baseline saved 2026-10-18). Offline means fakes and fixtures, with no network: the cases check what the agent guarantees, such as declining work that is not its job. They are not measurements of live runs; the live runs above are.