Skip to content

Add WebContainer agent example with sandbox tools - #1022

Open
sroussey wants to merge 8 commits into
mainfrom
claude/web-containers-agent-example-e3rqgv
Open

sroussey wants to merge 8 commits into
mainfrom
claude/web-containers-agent-example-e3rqgv

Conversation

@sroussey

Copy link
Copy Markdown
Collaborator

Add a complete example of a coding agent that runs inside a browser tab using WebContainer, with safe sandboxed execution of model-generated code.

Summary

This adds examples/webcontainer-agent, a fully functional web application where an AI agent writes and executes a small web project entirely within a WebContainer (Node.js compiled to run in the browser tab). The agent cannot reach the host filesystem, network, or processes—only the sandbox through four carefully bounded tools.

Key changes

  • sandboxPort.ts: Abstract interface for sandbox operations (readFile, writeFile, mkdir, readdir, spawn, onServerReady). Includes resolveSandboxPath() to validate and normalize paths, refusing escapes outside the project root.

  • sandboxTools.ts: Four AI tools built on SandboxPort:

    • write_file: Create/overwrite files with size limits and automatic parent directory creation
    • read_file: Read text files with truncation for large files
    • list_files: Recursively list project structure, skipping node_modules and .git
    • run_command: Execute programs (from an allow-list) with timeout, output buffering (tail-keeping), and background server support
    • Includes TailBuffer to keep the last N characters of output (important for long installs where the error is at the end)
  • webContainerPort.ts: Adapter from WebContainer API to SandboxPort interface. Handles cross-origin isolation checks and server readiness detection.

  • runSandboxAgent.ts: Orchestrates an AgentTask with sandbox tools, system prompt, and event streaming. Manages background server lifecycle and returns preview URLs.

  • sandboxPrompt.ts: System prompt explaining the sandbox environment to the model (no shell, no native addons, no git/Python/Docker).

  • ansi.ts: Utility to strip ANSI color codes from command output before sending to the model (saves tokens).

  • Web UI (main.ts, models.ts, index.html): Browser interface to select provider (Anthropic/OpenAI/Google), enter API key, describe what to build, and watch the agent work. Shows file tree and live preview iframe. Supports follow-up messages that edit the same project.

Notable implementation details

  • No shell: run_command takes program and arguments separately; no pipes, redirects, or && chains possible. This prevents shell injection and forces explicit step-by-step thinking.

  • Allow-list: Only node, npm, npx, pnpm, yarn, ls, cat, mkdir, rm, mv, cp, touch, pwd, echo are available by default.

  • Timeout handling: Foreground commands have a configurable timeout (default 90s); background servers wait for listening (default 45s). Uses AbortController and Promise.race() for clean cancellation.

  • Output buffering: TailBuffer keeps only the tail of output to stay within token budgets while preserving error messages that appear at the end of long installs.

  • Safe approval: Uses approval: "never" because all tools operate only within the sandbox—there is nothing outside it for a person to approve.

  • Key isolation: API keys live in page memory and go only to the provider SDK; sandbox code runs in a separate origin and cannot access them.

  • Cross-origin isolation: Vite config and HTML headers set Cross-Origin-Embedder-Policy: require-corp and Cross-Origin-Opener-Policy: same-origin so WebContainer can use SharedArrayBuffer.

Includes comprehensive tests (sandboxTools.test.ts) with a FakeSandbox test double.

https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

…dboxed in a WebContainer

The agent's write_file, read_file, list_files and run_command tools are host
functions over a SandboxPort, backed in the browser by a WebContainer, so
model-written code runs in the tab and cannot reach the host. The core is
framework-free for reuse by other hosts; a small Vite page demos it.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress ██████████ 15/15 files

Comment — found 3 issue(s) at 7a5559a.

Actionable comments posted: 3

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/README.md` (line 39, Important):
   The function returns a `SandboxTools` object (`{ tools: ToolDefinition[], dispose() }`), not an array with a `dispose` property. Embedders following this table will write `createSandboxTools(...).length` or `tools.dispose()` and get a runtime error. Reword the row to say it returns `{ tools, dispose }`.

2. In `@examples/webcontainer-agent/src/app/main.ts` (line 75, Important):
   `dispose?.()` runs before every follow-up, so the background server from the previous build is killed before the agent sees the new request. `runSandboxAgent`'s docstring says servers left running "stay up when this returns, so the user keeps a live preview; the caller ends them with `dispose` when it is done with the sandbox." A follow-up is not the end of the sandbox. Concrete failure: user builds a page (server running, iframe showing it), then asks "make the title blue". Clicking Build kills the server, the iframe still points at the now-dead URL, and if the model only edits files and does not restart the server (it is not told it must), the user sees a dead preview with no change. Consider disposing only when the run replaces the project, or leaving the server alive across follow-ups and letting the agent reuse it.

3. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 377, Important):
   `dispose()` kills every background process. `runSandboxAgent` documents that servers "stay up when this returns, so the user keeps a live preview," and that the caller ends them only when done with the sandbox. But `main.ts` calls the previous run's `dispose?.()` before each follow-up run (and `runSandboxAgent`'s catch disposes on any thrown error, including a provider failure or a Stop). So sending a follow-up message kills the dev server while `preview.src` still points at its URL, and the iframe goes dead. The agent's history still says "Server is running", so the model may not restart it. Consider disposing only when the sandbox is actually abandoned, or restarting the background servers after a follow-up edit.

Mergestorm: 30 free reviews a month

Comment thread examples/webcontainer-agent/README.md Outdated
Comment thread examples/webcontainer-agent/src/app/main.ts Outdated
Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts
…turns

The page created tools per turn and disposed the previous turn's before each
follow-up, and a failed or stopped run disposed its own, so a follow-up killed
the server the preview iframe was showing. The caller now owns the tools for
the life of the sandbox and passes them to every turn; a run given them never
stops their servers. A stop_servers tool lets the agent restart a server whose
own code changed without hitting EADDRINUSE. README corrects the return shape
of createSandboxTools.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad
The coverage gate pins the set of access:none workspaces, and the new example
is a Vite app behind no published entry point, like examples/web.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress █████████░ 16/17 files

Comment — found 4 issue(s) at 63bbce1.

Actionable comments posted: 4

Coverage is incomplete: reviewed 16/17 files; 0 skipped; 1 deferred and still unreviewed.

Comment @mergestorm-vortex review on this PR to review the remaining files.

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/README.md` (line 20, Important):
   `The model can only ... run_command` omits `stop_servers`, which `createSandboxTools()` also registers. The documented tool list is therefore incomplete; readers will miss that the model can stop the running preview server (and may assume the four listed tools are exhaustive).

2. In `@examples/webcontainer-agent/src/app/main.ts` (line 85, Important):
   `buildModelConfig(choice, modelInput.value.trim(), apiKey)` reads the model only after `await choice.register()`, while the provider selector remains enabled. If a user changes the provider during that async registration, `choice` still names the original provider but `syncModelDefault()` has changed the model to the new provider's default; the ensuing request is sent to the original provider with the incompatible model and can fail. Capture the selected model before awaiting registration, or otherwise keep provider and model selection fixed for the run.

3. In `@examples/webcontainer-agent/src/core/runSandboxAgent.ts` (line 76, Important):
   `run.sandboxTools ?? createSandboxTools(...)`
   When callers pass the reusable `sandboxTools` instance (the documented across-turn path), this runner never installs the callback that updates `previewUrl` and emits `type: "preview"`. A server can start and the caller’s own `onPreview` can fire, but `runSandboxAgent` still returns `previewUrl: undefined` and omits the preview event, contrary to the result/event contract.

4. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 329, Important):
   `context.signal.addEventListener("abort", stop, { once: true });`
   The listener is installed only after `await port.spawn(...)`. If the run is stopped while `spawn` is pending (or the signal was already aborted), this event is missed, so the process is not killed on cancellation and the tool can wait for its full timeout. For a background command that becomes ready, the server can also be left running when the shared, caller-owned tools survive the failed run.

Mergestorm: 30 free reviews a month

Comment thread examples/webcontainer-agent/README.md Outdated
Comment thread examples/webcontainer-agent/src/app/main.ts Outdated
Comment thread examples/webcontainer-agent/src/core/runSandboxAgent.ts Outdated
Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts Outdated
…ncel during spawn

runSandboxAgent subscribes to the tools' new onPreview for the length of the
run, so previewUrl and preview events work with caller-owned tools too. A
run_command now listens for cancellation before starting the program, so a
Stop clicked mid-spawn kills it instead of leaving it running. The page reads
the model before registering the provider and locks both controls for the
run. README lists stop_servers.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress █████████░ 16/17 files

Comment — found 1 issue(s) at ac19dc0.

Actionable comment posted: 1

Coverage is incomplete: reviewed 16/17 files; 0 skipped; 1 deferred and still unreviewed.

Comment @mergestorm-vortex review on this PR to review the remaining files.

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/src/app/main.ts` (line 42, Important):
   `refreshFiles()` invokes this recursive walk after every completed tool call, but unlike `list_files` it has no depth or entry cap. A single `write_file` with a deeply nested path (whose parents are created recursively), or a generated project with many files, can make the UI issue unbounded `readdir` calls and build a huge string, freezing the page. Apply a bound to this walk as well.

Mergestorm: 30 free reviews a month

Comment thread examples/webcontainer-agent/src/app/main.ts Outdated
The page walked the project with no depth or entry cap after every tool call,
and the model chooses the paths. The walk is now one exported function,
listSandboxFiles, used by both the list_files tool and the page.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress ██████████ 17/17 files

Comment — found 3 issue(s) at 4148252.

Actionable comments posted: 3

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/src/app/main.ts` (line 89, Important):
   `void refreshFiles()` starts a recursive `readdir` walk without handling rejection. While that walk is in progress, a subsequent agent command can remove a directory it is about to enter; WebContainer's `readdir` then rejects, producing an unhandled promise rejection. The same walk is awaited in `finally` and can reject the run-button handler as well, so handle/report listing failures rather than letting a transient tree change escape.

2. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 94, Important):
   `return { lines, truncated: lines.length >= MAX_LISTED_ENTRIES }`
   This count-only flag has two concrete boundary errors: exactly 400 total entries are reported as truncated even when nothing was omitted, while a walk that stops descending at `depth === 6` can omit deeper files and still report `truncated: false` if it emitted fewer than 400 lines. The `list_files` tool and UI then tell the model/user the wrong completeness state; track whether either limit actually omitted entries.

3. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 319, Important):
   `if (wantsBackground && background.size >= maxBackground)`
   The slot check runs before `await port.spawn(...)`, but the process is not added to `background` until later. If these tools are used with parallel tool execution (supported by `AgentTask`'s `toolConcurrency`), two calls can both observe an empty set with a limit of 1, spawn, and then both register, leaving more servers running than the configured cap. Reserve the slot before awaiting spawn and release it on spawn failure or if startup does not become a background server.

Mergestorm: 30 free reviews a month

Comment thread examples/webcontainer-agent/src/app/main.ts
Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts Outdated
Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts Outdated
…s, tolerant tree refresh

listSandboxFiles reports truncation only when the entry cap or the depth limit
left something out. A background run_command claims its server slot before it
awaits spawn, so parallel tool calls cannot exceed the cap. The page's file
tree refresh no longer throws when a program removes a directory mid-walk.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress ██████████ 17/17 files

Comment — found 2 issue(s) at 86cca71.

Actionable comments posted: 2

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 252, Important):
   `port.readFile(path)` materializes the entire file before the 40,000-character truncation below. A model can create a very large file through an allowed `node` or package-manager command and then read it, forcing an unbounded allocation in the browser and potentially freezing or exhausting its memory; truncating the returned string does not bound this operation.

2. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 345, Important):
   `port.onServerReady` subscribes to a container-wide event, not an event associated with the `SandboxProcess` being started. If two background `run_command` calls overlap (for example, when an embedding AgentTask opts into `toolConcurrency`), the first server's event is recorded by both listeners, so both calls can return the same preview URL even if the second process has not started listening. The second tool call then reports a server as ready when it is not.

Mergestorm: 30 free reviews a month

const path = safePath(stringArg(input, "path"));
let content: string;
try {
content = await port.readFile(path);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue · Important

Truncation does not bound the file read

port.readFile(path) materializes the entire file before the 40,000-character truncation below. A model can create a very large file through an allowed node or package-manager command and then read it, forcing an unbounded allocation in the browser and potentially freezing or exhausting its memory; truncating the returned string does not bound this operation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 252, Important):
`port.readFile(path)` materializes the entire file before the 40,000-character truncation below. A model can create a very large file through an allowed `node` or package-manager command and then read it, forcing an unbounded allocation in the browser and potentially freezing or exhausting its memory; truncating the returned string does not bound this operation.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Leaving this as is. The path is real but the cost is bounded by the tab: a WebContainer's filesystem lives in the same tab's memory, so a file the model creates there already occupies it, and read_file duplicates that at most once before the 40,000-character cut. Bounding the read itself would need a stat or ranged read, which the WebContainer fs API does not offer, so the only fix is a size probe via a spawned process, which costs more code than the failure justifies in an example. If an embedder's port can stat, SandboxPort.readFile is the place to add a size check.


Generated by Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks for the reasoning. I can't dismiss this finding: it was raised on an earlier commit, so it stays open. At 4ae77a5 read_file still reads the whole file before the 40,000-character cut, so the point is still there. The tradeoff you describe is clear, and a maintainer can decide to accept it.

Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts Outdated
The container announces a listening port without saying which process owns it,
so two overlapping background run_command calls could both return the first
server's URL. Background starts now queue, so an announcement during a startup
belongs to that startup.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress ██████████ 17/17 files

Comment — found 2 issue(s) at 4ae77a5.

Actionable comments posted: 2

🤖 Prompt for AI agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

Findings to address:
1. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 82, Important):
   `[...(await port.readdir(dir))].sort(...)` materializes and sorts every child before the 400-entry cap is checked. A project with a very large single directory (which allowed `node` commands can create) therefore still allocates and sorts the entire listing on each `list_files` call and UI refresh, potentially freezing or exhausting the browser despite the advertised entry bound.

2. In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 446, Important):
   `killBackground()` only sees processes already in `background`; a background `run_command` may still be waiting on `serverStartups` or `port.spawn()` and is not registered yet. With AgentTask `toolConcurrency > 1`, `stop_servers` can return `Stopped 0 server(s)` while a start is pending, after which that command starts and leaves a server running despite the explicit stop.

Mergestorm: 30 free reviews a month

* `readdir` calls. Shared by the `list_files` tool and any UI showing the tree.
*/
export async function listSandboxFiles(port: SandboxPort, root = "."): Promise<SandboxListing> {
const lines: string[] = [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue · Important

Bound the directory read, not just emitted entries

[...(await port.readdir(dir))].sort(...) materializes and sorts every child before the 400-entry cap is checked. A project with a very large single directory (which allowed node commands can create) therefore still allocates and sorts the entire listing on each list_files call and UI refresh, potentially freezing or exhausting the browser despite the advertised entry bound.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid concrete bugs, skip the
rest with a brief reason, keep changes minimal, and validate. Skip Decision required,
policy forks, and "consider X" alternatives. Do not add new features, refactors, or
architecture beyond the fix; prefer the smallest diff.

In `@examples/webcontainer-agent/src/core/sandboxTools.ts` (line 82, Important):
`[...(await port.readdir(dir))].sort(...)` materializes and sorts every child before the 400-entry cap is checked. A project with a very large single directory (which allowed `node` commands can create) therefore still allocates and sorts the entire listing on each `list_files` call and UI refresh, potentially freezing or exhausting the browser despite the advertised entry bound.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Leaving this as is, for the same reason as the read_file thread: the allocation happens inside port.readdir, which hands back the full array before this code sees it, and the WebContainer API has no paged or streaming readdir. The sort adds an O(n log n) pass over an array that already exists in the same tab's memory, so bounding it would not bound the allocation that matters. The 400-entry cap bounds what is returned to the model and rendered, which is what it is for.


Generated by Claude Code

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Thanks. The allocation inside port.readdir is outside this code, so I agree that part can't be bounded here. The spread copy and the sort still run over every entry before the 400-entry cap, though. The finding was raised on 4ae77a5, so it stays open for now.

Comment thread examples/webcontainer-agent/src/core/sandboxTools.ts Outdated
…ill in flight

A background run_command waiting in the startup queue or inside spawn was not
yet registered, so stop_servers could report nothing stopped and the start
would then complete. Every stop now bumps an epoch that a start checks before
and after spawning, and the count includes pending starts.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AzKiEhbKvifSdRKSddoMad

Copy link
Copy Markdown
Collaborator Author

test-vitest-ai-provider-hft failed on 5bbce5c, and it is not caused by this PR. The job died in bun install: onnxruntime-node's postinstall could not reach its download host (ETIMEDOUT / ENETUNREACH), so it ended before any test ran. This PR touches only examples/webcontainer-agent, the workspace-source test list and a comment in vitest.config.ts. No fix to port exists, since it is a runner network failure. A re-run of the failed job was refused (403, the workflow run is still in progress); I will re-run it once the run completes and keep watching until it is green.


Generated by Claude Code

@mergestorm-vortex mergestorm-vortex Bot 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.

Auto land this PR in Mergestorm

Review progress ██████████ 17/17 files

Approve — reviewed files look good at 5bbce5c.

✅ All clear — nothing to fix.


Mergestorm: 30 free reviews a month

Copy link
Copy Markdown
Collaborator Author

test-vitest-ai-provider-api also failed on 5bbce5c, and it is not caused by this PR either. The one failing test is the live xAI integration test Xai_Generic.integration.test.ts > Tool-call multi-turn, which got a server-side RetryableJobError: The model is currently at capacity due to high demand from xAI's API; the other 125 tests in the job passed. This PR does not touch providers/xai, packages/ai or any test in that job, so there is no fix to port. The failed jobs of that workflow run (this one and test-vitest-ai-provider-hft above) get one re-run once the run completes; I am keeping the PR watched until it is green.


Generated by Claude Code

This branch has not been deployed

No deployments
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.

2 participants