Skip to content

Add Vercel eve agent adapter (@executor-js/host-eve)#1114

Open
jackulau wants to merge 1 commit into
RhysSullivan:mainfrom
jackulau:feat/host-eve-adapter
Open

Add Vercel eve agent adapter (@executor-js/host-eve)#1114
jackulau wants to merge 1 commit into
RhysSullivan:mainfrom
jackulau:feat/host-eve-adapter

Conversation

@jackulau

Copy link
Copy Markdown

Expose Executor's codemode surface to a Vercel eve agent as two tools, execute and resume, mirroring the MCP host. Backed by the promise execution engine, so the package has no eve runtime dependency: the factory returns plain objects shaped for eve's defineTool.

Includes unit tests plus integration tests that drive the adapter against the real execution engine and QuickJS sandbox.

Expose Executor's codemode surface to a Vercel eve agent as two tools, execute and resume, mirroring the MCP host. Backed by the promise execution engine, so the package has no eve runtime dependency: the factory returns plain objects shaped for eve's defineTool.

Includes unit tests plus integration tests that drive the adapter against the real execution engine and QuickJS sandbox.
@jackulau

Copy link
Copy Markdown
Author

wip - taking feedback.

@greptile-apps

greptile-apps Bot commented Jun 24, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces @executor-js/host-eve, a new adapter package that exposes Executor's codemode surface to a Vercel eve agent as two tools (execute and resume), mirroring the existing MCP host design without taking a runtime dependency on eve itself.

  • The adapter follows the MCP host pattern closely: shared Promise-based engine instance, runEnvelope for defect isolation, formatExecuteResult/formatPausedExecution for result rendering, and parseJsonContent (Effect Schema) for safe JSON decoding of resume content.
  • Unit tests cover all envelope shapes (completed, paused, defect, missing-execution), schema validation, and description override; integration tests drive the real QuickJS sandbox to verify end-to-end execution, tools runtime injection, error surfacing, and resume recovery.

Confidence Score: 4/5

Safe to merge. The new package is private and isolated with no cross-package side effects; the adapter correctly never throws to the agent and the pause/resume wiring is sound.

The adapter is well-structured and the test coverage (unit + real QuickJS integration) is thorough for the core paths. The one notable gap is that emit() output items (files, images, audio) produced during code execution are not included in ExecutorToolEnvelope.data — only a count surfaces in text — which differs from the MCP host's rich-content handling. Whether this matters depends on whether eve-hosted workflows use emit() for binary outputs, but it is a silent data loss rather than a crash.

packages/hosts/eve/src/index.ts — specifically toCompletedEnvelope, which delegates to formatExecuteResult without inspecting result.output[].

Important Files Changed

Filename Overview
packages/hosts/eve/src/index.ts Core adapter implementation: clean structure mirroring the MCP host, correct pause/resume wiring, proper defect isolation via runEnvelope. emit() output items (files, images) are dropped from the structured envelope — only the count surfaces in text.
packages/hosts/eve/src/index.test.ts Unit tests covering completed/paused/defect envelopes, JSON content parsing edge cases, description override, and schema validation. Good use of @effect/vitest throughout.
packages/hosts/eve/src/index.integration.test.ts Integration tests drive the real QuickJS sandbox and a real Executor; verifies code evaluation, tools runtime injection, error surfacing, and missing-execution recovery. Only tests the { engine } config branch, not { executor, codeExecutor }.
packages/hosts/eve/package.json Correct workspace dependencies; zod pinned at 4.3.6 matching the MCP host pattern; private: true appropriate for a workspace-only adapter.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Model as eve Model
    participant ET as execute tool
    participant RT as resume tool
    participant Engine as ExecutionEngine (Promise)
    participant QJS as QuickJS Sandbox

    Model->>ET: "execute({ code })"
    ET->>Engine: executeWithPause(code)
    Engine->>QJS: run code
    alt completed
        QJS-->>Engine: ExecuteResult
        Engine-->>ET: "{ status: completed, result }"
        ET-->>Model: "ExecutorToolEnvelope { status: completed, text, data }"
    else paused (auth/approval)
        QJS-->>Engine: pause (elicitationContext)
        Engine-->>ET: "{ status: paused, execution }"
        ET-->>Model: "ExecutorToolEnvelope { status: waiting_for_interaction, executionId, text }"
        Model->>RT: "resume({ executionId, action, content })"
        RT->>Engine: "resume(executionId, { action, content })"
        Engine->>QJS: continue from pause
        QJS-->>Engine: ExecuteResult
        Engine-->>RT: "{ status: completed, result }"
        RT-->>Model: "ExecutorToolEnvelope { status: completed, text, data }"
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Model as eve Model
    participant ET as execute tool
    participant RT as resume tool
    participant Engine as ExecutionEngine (Promise)
    participant QJS as QuickJS Sandbox

    Model->>ET: "execute({ code })"
    ET->>Engine: executeWithPause(code)
    Engine->>QJS: run code
    alt completed
        QJS-->>Engine: ExecuteResult
        Engine-->>ET: "{ status: completed, result }"
        ET-->>Model: "ExecutorToolEnvelope { status: completed, text, data }"
    else paused (auth/approval)
        QJS-->>Engine: pause (elicitationContext)
        Engine-->>ET: "{ status: paused, execution }"
        ET-->>Model: "ExecutorToolEnvelope { status: waiting_for_interaction, executionId, text }"
        Model->>RT: "resume({ executionId, action, content })"
        RT->>Engine: "resume(executionId, { action, content })"
        Engine->>QJS: continue from pause
        QJS-->>Engine: ExecuteResult
        Engine-->>RT: "{ status: completed, result }"
        RT-->>Model: "ExecutorToolEnvelope { status: completed, text, data }"
    end
Loading

Comments Outside Diff (1)

  1. packages/hosts/eve/src/index.ts, line 651-656 (link)

    P2 emit() output items are silently dropped from structured data

    toCompletedEnvelope delegates entirely to formatExecuteResult, which writes only { status, result, emitted (count), logs } into structured. The actual output items in result.output[] (files, images, audio produced by emit()) are never copied into data. The MCP host explicitly branches on result.output && result.output.length > 0 and calls toMcpOutputResult to surface them.

    A consumer relying on data for file content would silently see { emitted: 1 } with no payload. The model only sees "(no return value; 1 item emitted to the user)" — it is told content exists but cannot read it. If any code execution is expected to produce files or images via emit(), those outputs are permanently lost through this host.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "Add Vercel eve agent adapter (@executor-..." | Re-trigger Greptile

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.

1 participant