Skip to content

Add experimental tool.group() for Sandboxes - #1795

Open
jpwilliams wants to merge 4 commits into
jack/sandbox-tools2-stepfrom
jack/sandbox-tools2-group
Open

jpwilliams wants to merge 4 commits into
jack/sandbox-tools2-stepfrom
jack/sandbox-tools2-group

Conversation

@jpwilliams

Copy link
Copy Markdown
Member

Summary

Sandbox code can now call tool.group() tools, whose body is a group of steps. Run steps in parallel, invoke other functions and use their result, send events, or wait for one, all from a single tool call.

import { step } from "inngest";
import { tool } from "inngest/experimental";

const refund = tool.group({
  input: z.object({ orderId: z.string() }),
  run: async ({ orderId }) => {
    const result = await step.invoke("refund", {
      function: refundFn,
      data: { orderId },
    });

    await step.sendEvent("notify", { name: "order/refunded", data: result });

    return result;
  },
});

Checklist

  • Added a docs PR that references this PR N/A Later bump
  • Added unit/integration tests
  • Added changesets if applicable

jpwilliams and others added 2 commits October 15, 2026 20:11
Steps created inside the callback get the prefix before their IDs, so
concurrent callers can use the same IDs. They don't inherit the origin of
the span they are in, since the code that created them is the user's.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A group tool runs at handler level with the global step. It has no step of
its own: its inner steps are prefixed with the call's step ID, so two
calls at once don't collide.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jpwilliams jpwilliams self-assigned this Oct 15, 2026
@jpwilliams
jpwilliams added this pull request to stack #1792 October 15, 2026 21:23
@changeset-bot

changeset-bot Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 9f48b6b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
inngest Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@inngest-release-bot inngest-release-bot added the 📦 inngest Affects the `inngest` package label Oct 15, 2026
@greptile-apps

greptile-apps Bot commented Oct 15, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 4/5

[Medium impact] Adds experimental tool.group feature for sandbox execution.

Fix the shared-directory collision for nested sandbox commands before merging.

Findings

  1. P1 Nested commands share results ▶
  2. P2 Library step origins disappear ▶
Fix with agent prompt
### Issue 1
packages/inngest/src/components/sandbox/toolRunner.ts:290
If two calls to the same `tool.group()` run `sandbox.commands.run("inner", ..., { tools })` on a shared sandbox, this prefix separates their durable step IDs but not their working directories. The nested `followCommand()` builds its directory from the raw `"inner"` ID and `runId`. The wrapper treats the second command as a retry and skips starting it, so both callers can read the first command's requests and result.

Include the active prefix when deriving the command directory and tool idempotency keys.

### Issue 2
packages/inngest/src/components/InngestStepTools.ts:401-402
The `prefix` check drops origins from every span inside a group tool, including spans explicitly created by a library inside the tool body. A nested `group["~span"]({ id: "work", origin: "@inngest/ci@0.1.0" }, ...)` no longer passes that origin to its steps. This breaks the documented inheritance rule and makes library-created steps look like user-written work.

Suppress the outer tool span's origin without suppressing origins set by inner spans.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

Adds experimental tool.group() so sandbox tools can run several durable steps and return their combined result.

  • Sandbox tool calls can run a group of real steps.

Diagram

%%{init: {'theme': 'neutral'}}%%
flowchart TD
  A[Sandbox calls a tool] --> B[Check tool and arguments]
  B --> C{Group tool?}
  C -->|No| D[Run one durable tool step]
  C -->|Yes| E[Add tool span and call prefix]
  E --> F[Run body with inner durable steps]
  D --> G[Check output and build reply]
  F --> G
  G --> H[Durable wait step appends reply]
  H --> I[Sandbox continues]
Loading

Reviews (1) · Last reviewed commit: "feat(sandbox): tool.group, a tool whose ..." · Reviewed by Greptile

Comment thread packages/inngest/src/components/sandbox/toolRunner.ts Outdated
Comment thread packages/inngest/src/components/InngestStepTools.ts Outdated
jpwilliams and others added 2 commits October 15, 2026 21:34
…inner span origins

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

📦 inngest Affects the `inngest` package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants