Skip to content

fix(next): discover exported agents without loading scripts - #28

Merged
pranaygp merged 2 commits into
mainfrom
pranaygp/codex/fix-agent-discovery
Oct 23, 2026
Merged

pranaygp merged 2 commits into
mainfrom
pranaygp/codex/fix-agent-discovery

Conversation

@pranaygp

@pranaygp pranaygp commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Automatic Next.js agent discovery matched imports and calls inside docs strings and standalone scripts, adding those files to the flow route and executing their top-level work during builds.

Parse JS/TS/TSX and follow real imported factory bindings to values exported from module scope. Preserve import aliases, default and named exports, containers and accessors for existing agents, static class registration, effect-only Pi opener registration, explicit agents, and mixed FX/harness modules. Document the explicit option for custom factories and registrations.

Fixes #20.

Validation:

  • pnpm install --frozen-lockfile and pnpm typecheck
  • Discovery/Next/Vercel/Pi-next tests: 150 passed
  • pnpm --filter durable-harness test: 422 passed, 12 skipped; an earlier virtual-workspace StorageFenced failure passed both its isolated rerun and the full rerun
  • pnpm --filter durable-harness build && pnpm --filter durable-harness check-dist (Linux-only relay caller authentication remains a CI check; local checks run on macOS)
  • Host-spawn lint, changeset validation, and generic public-hygiene checks
  • A minimal Next.js 16.3.8 Turbopack production build completed page collection and static generation. Its excluded drill would write a sentinel and throw if imported; the sentinel was absent and only the exported agent appeared in the generated flow route.

CI note: the first run stopped in the unchanged Codex R7 compaction test (expected the code word is heron, received compacted). Its isolated rerun and full Codex package rerun pass locally (58 passed, 1 skipped). The follow-up head passes CI: full monorepo tests (including the exact R7 regression), typecheck, public hygiene, and all local/Postgres/optional CLI lanes. The Vercel CLI lane is skipped by CI configuration; both app preview deployments succeed.

Copilot AI balanced review requested due to automatic review settings October 23, 2026 03:08
@vercel

vercel Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
durable-fx-example Ready Ready Preview, v0 Oct 23, 2026 3:18am UTC
harness-on-world Ready Ready Preview, v0 Oct 23, 2026 3:18am UTC

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@socket-security

socket-security Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​@​types/​babel__traverse@​7.28.01001007680100
Addednpm/​@​babel/​traverse@​7.29.101001007996100
Addednpm/​@​babel/​parser@​7.29.91001008095100

View full report

Comment thread packages/durable-harness/src/discovery.ts Outdated
pranaygp added a commit that referenced this pull request Oct 23, 2026
Explicit top-level help writes to stderr, and `sandbox --help` exits
with an error. Print `--help` and `-h` to stdout with exit 0 at both
levels, matching the existing leaf commands. Invalid commands retain
stderr and exit 1; invoking without arguments keeps its existing
behavior.

Fixes #17.

Validation:
- CLI subprocess regression: four expected failures before the fix; all
12 cases pass afterward. CLI/Vercel integration tests: 32 passed.
- Workspace typecheck, changesets, public hygiene and host-spawn lint
pass. Package build, local `check-dist`, and built CLI smoke checks
pass. Linux CI typecheck includes the full release gate and passes.
- Combined with #26, #27 and #28: all package suites pass (2,047 tests),
plus 24 scripted AI SDK example tests and nine CLI-check tests;
workspace typecheck/build/distribution checks pass. One optional
live-model example failed its workspace-tool status assertion; its
scripted suite passes without live credentials.

CI typecheck/release gate, hygiene, local/Postgres/optional CLI checks,
security, automated review and deployments pass. The full test job
remains red in unchanged `harness-world/src/budget-boundary.test.ts:86`
(extra `tool:5`), matching the failure on current main at ca4c420 in run
39885581630. The combined checkout passes all 374 kernel tests. This PR
changes only CLI help handling, subprocess tests and a patch changeset.
@pranaygp
pranaygp merged commit a5c24a1 into main Oct 23, 2026
14 checks passed
@pranaygp
pranaygp deleted the pranaygp/codex/fix-agent-discovery branch October 23, 2026 03:30
@github-actions github-actions Bot mentioned this pull request Oct 23, 2026
pranaygp pushed a commit that referenced this pull request Oct 23, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## durable-harness@0.0.1

### Patch Changes

- [#10](#10)
[`9b1ed08`](9b1ed08)
Thanks [@chadhietala](https://github.com/chadhietala)! - Agent Runs
tracing (`agentRuns()` from `/instrumentation/otel`) records sessions
with `@vercel/agent-runs@0.0.1`, the library eve uses: a turn per
prompt, a step per model call with the tool calls it asks for under it,
in the schema Agent Runs reads. A turn that goes on in a later
invocation (out of time, a crash, a wake, a lane handoff) stays one
turn, its checkpoint kept with the session. A session's `traceAudience`
decides what its spans record (`public`: inputs and outputs; anything
else: metadata only), and `agentRuns({ capture })` changes that per
audience; `exportPolicy` and `filteringProcessor` are removed. Claude
Code, Codex and OpenCode record each model request through the Gateway
with its prompt, reply and usage.
  
Recovery applies the current capture policy to restored operations,
keeping newly private content out of checkpoints and exports. Recorded
tool definitions exclude provider credentials, untraced proxy requests
stream without buffering, and tracing failures cannot change agent
results. Checkpoint waits are bounded without discarding final updates
after a soft budget expires or a write slows down; queued follow-ups
retain their own turn identity.
  
Agent Runs is an optional peer with inlined declaration types. Tracing
requires Node.js 24 and optional tracing peers; other entrypoints retain
Node.js 22 support.

- [#25](#25)
[`9f42806`](9f42806)
Thanks [@pranaygp](https://github.com/pranaygp)! - Explicit CLI help
prints to stdout and succeeds at every command level, including sandbox.

-
[`0bb39d7`](0bb39d7)
Thanks [@pranaygp](https://github.com/pranaygp)! - First release:
durable coding-agent harnesses on a Workflow SDK World. Claude Code
(`durable-harness/claude-code`), Codex (`/codex`), OpenCode
(`/opencode`) and Pi (`/pi`) each run as an agent whose session is a
workflow run, its event log the source of truth: every model and tool
call is a step in the log, so a crash anywhere resumes the turn from the
log on another machine, and a tool that is not safe to rerun comes back
to the model as interrupted instead of running twice. Claude Code and
Codex run only in the session's own Vercel Sandbox (`workspace:
sandbox()`, the default): the CLI runs in a VM per session with the
session's Drive at `/workspace`, holds no credential (the Function makes
its model calls, within the session's `sandbox({ budget })`), and a
session restarted on a new VM keeps its files and resumes from the log.
Both are tool-less by default: the app's tools are the only ones the CLI
is offered; `builtins: true` turns its own tools on in the VM, each call
in the log before it runs. `durable-harness/sandbox` deletes a session's
VM and Drive (`deleteSessionSandbox`), cleans up idle ones
(`sandboxCleanup`, opt-in), and prepares the base snapshot ahead of time
(`npx durable-harness sandbox prepare`); a public chat route for such an
agent needs `allowPublicSandbox: true`. OpenCode is tool-less too,
starts no process and reads no file of the machine that drives the
session for the model, and never changes the process's environment (so
it runs beside libfx's agents in one process); `workspace: virtual()` on
`opencode()` gives it its own shell, read, write, edit, patch, glob and
grep (OpenCode's own tool code, names and schemas) on a virtual
workspace, each call's file changes committed with its result, never on
the Function's disk (`builtins` narrows them); `workspace: sandbox()`
runs the same tools in the session's own Vercel Sandbox, its files on
the session's Drive, the VM booted at the first call that needs it. A
turn whose installed OpenCode or `effect` isn't the pinned version fails
with both versions and the install line. Each agent has a streaming chat
route (`agent.chatRoute()`, with an `authorize` check required in
production). For apps already built on Pi 1.0's own durable `Harness`
(pi-durable), `durable-harness/pi-durable` adds to your code instead of
replacing it: open the storage with `openWorldStorage()` where you
opened SQLite, JSONL or memory storage, register how a session is
reopened with `resumeWith(open)`, and if the process dies mid-turn a
wake reopens the session and Pi finishes the turn; `CodingTools` and
`env: virtualEnv()` from the same module run Pi 1.0's own coding tools
on a virtual workspace, each call's file changes committed with its
result, never on the Function's disk, and `env: sandboxEnv()` runs them
in the session's own Vercel Sandbox, its files on the session's Drive,
armed with the session's own fencing token; a chat route, a shared
Harness per session and a read-only follower are optional helpers.
`withDurableHarness` (`/next`) sets up the queue's route for Next.js and
also serves libfx's durable agents (several, each with its own `name`,
with libfx 0.0.14 and later); `/vercel` does the same for Vercel
Functions. Self-hosted on world-postgres or world-local, a process that
starts the World without making agents (a worker of its own) forwards
durable-harness's queue to the app's flow route with
`forwardQueue(world)`. Sessions show up in Vercel Agent Runs with their
model and tool calls (`agentRuns()` from `/instrumentation/otel`, with
OpenTelemetry's SDK installed next to it: optional peers, which nothing
else loads), pi-durable's included: a `traceAudience` on
`openWorldStorage()` or `resumeWith()` says who sees their content. Pi
is tool-less by default; `createCodingTools(virtual())` from `/pi` gives
it Pi's own `read`, `bash`, `edit` and `write` (pi-coding-agent's names,
schemas and descriptions) on a virtual workspace, or with
`createCodingTools(sandbox())` in the session's own Vercel Sandbox (Pi
stays in the Function, the VM is attached on the first call), and `pi()`
refuses pi-coding-agent's own tools, which run on the host. Also
included: documents (typed JSON state per session, `defineDoc`) and
example workspace tools (`/tools`) on a virtual workspace (`virtual()`):
not real Linux, and nothing of the machine that drives the session (its
shell runs in a worker thread leased to that session alone, with an
empty environment and a time limit per command), its files in the log,
or with `virtual({ durable: false })` in memory for one turn. For
libfx's own durable agent (`createFxAgent`), `durable-harness/fx` adds
libfx's kernel tools on a virtual workspace (`tools:
[...fxTools(virtual())]`): fx's names and schemas, each call's file
changes kept with the session and never applied twice;
`fxTools(sandbox())` runs them in the session's own Vercel Sandbox,
armed with the libfx lease of the worker that runs the call, so a server
that was taken over runs nothing more there. Experimental: patch
releases only while on 0.0.x.

- [#11](#11)
[`31c87e8`](31c87e8)
Thanks [@chadhietala](https://github.com/chadhietala)! - libfx's own
durable agents show up in Vercel Agent Runs: `createFxAgent({ hooks:
agentRunsHooks() })` with `agentRunsHooks` from `durable-harness/fx`
records each libfx turn, its steps with their model calls, and its tool
calls and the approvals they wait on, from libfx's semantic hooks (libfx
0.0.14 and later). A turn libfx yields, pauses or hands to another
worker stays one turn, continued by the execution that resumes it in any
process.
  
Handed-off and fenced turns stay open for recovery; actual user
interruption and cancellation finish the turn. Interrupted tool and
approval identities are checkpointed so final cleanup also settles
recovered calls the engine does not rerun. Execution IDs isolate
overlapping deliveries, and ended session bookkeeping is released.
Capture follows policy, hook failures use the tracing error handler, and
provider/reasoning metadata and turn ordering are preserved. Unawaited
hooks and checkpoint flushing remain best-effort.

- [#26](#26)
[`7b2a18d`](7b2a18d)
Thanks [@pranaygp](https://github.com/pranaygp)! - Discard interrupted
Pi-durable streaming partials before sending their replacement answers
on reconnect.

- [#27](#27)
[`ff32c13`](ff32c13)
Thanks [@pranaygp](https://github.com/pranaygp)! - Pi signals when a
recovered reply replaces interrupted streamed text, retaining completed
text from the turn.

- [#28](#28)
[`a5c24a1`](a5c24a1)
Thanks [@pranaygp](https://github.com/pranaygp)! - Discover exported
agents from source syntax without importing scripts or code samples into
the generated flow route.

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

This branch was successfully deployed

2 active deployments
Preview – harness-on-world — 58d330d9 Deployed Oct 23, 2026 by vercel[bot]
Preview – durable-fx-example — 58d330d9 Deployed Oct 23, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

withDurableHarness: default agent discovery imports scripts and pages into the flow route, and next build runs them

2 participants