Summary
@github-tools/sdk/connect/eve’s one-liner (export default connectGithubTools(...)) registers tools via defineDynamic + buildEveToolMap inside the SDK package. On eve durable agents (Slack multi-turn sessions), those tools appear in the tool map briefly (or not at all on later turns) and then get stripped at step time with:
[eve:dynamic-tools] Dynamic tool "getFileContent" references step function
"eve:framework-dynamic:github:getFileContent" which is not registered — skipping on this step.
Same for createIssue, searchCode, getRepository, etc. Static authored tools in the consumer (e.g. list_accessible_repos) keep working. The model correctly reports that only inventory is available.
This matches eve’s documented durable-tool contract: defineTool({ execute }) must be an inline function in an authored agent/tools/*.ts (or extension) file so the bundler transform can hoist __executeStepFn / __closureVars. Eve’s workflow input scan ignores node_modules, so defineTool calls buried in @github-tools/sdk never get hoisted. Eve falls back to an in-process registerStepFunction on session.started; later workflow steps / isolates replay from metadata, look up an empty registry, and skip.
@github-tools/eve-extension (1.8.2) still does return buildEveToolMap(...) inside session.started, so it looks like the same footgun unless eve treats extension packages differently end-to-end.
Environment
eve 0.27.1
@github-tools/sdk 1.8.1 (also reviewed 1.8.2 / eve-extension source — same buildEveToolMap pattern)
@vercel/connect 0.3.3
- Deployed on Vercel (serverless / Workflow steps)
- Consumer:
agent/tools/github.ts was:
import { connectGithubTools } from "@github-tools/sdk/connect/eve";
export default connectGithubTools("github/fnaagent-gh", {
preset: ["repo-explorer", "issue-triage"],
connect: { installationId: "…" },
});
Evidence
Production logs on a multi-turn Slack session (sessionId reused across turns):
[eve:dynamic-tools] Dynamic tool "getFileContent" references step function
"eve:framework-dynamic:github:getFileContent" which is not registered — skipping on this step.
[eve:dynamic-tools] Dynamic tool "createIssue" references step function
"eve:framework-dynamic:github:createIssue" which is not registered — skipping on this step.
… (entire preset map)
Audit: assistant states only list_accessible_repos is callable.
Relevant eve behavior (from dynamic-tool-lifecycle / docs):
- Transform expects inline
execute in authored sources (Dynamic capabilities — “execute must be an inline function”).
- Runtime fallback registers
eve:framework-dynamic:<slug>:<key> in-memory when __executeStepFn is missing.
- Replay looks up that id later → miss → skip.
Workaround (works for us)
Keep using @github-tools/sdk/connect (AI SDK tools + Connect token), but put defineDynamic / defineTool in the consumer file with a for…of loop and inline execute that only closes over a serializable name, then resolves the AI SDK tool from a module-level map:
import { connectGithubTools } from "@github-tools/sdk/connect";
import { defineDynamic, defineTool } from "eve/tools";
import { always } from "eve/tools/approval";
const aiTools = connectGithubTools("github/…", {
preset: ["repo-explorer", "issue-triage"],
connect: { /* … */ },
});
async function runGithubAiTool(name: string, input: unknown) {
const tool = aiTools[name];
if (!tool?.execute) throw new Error(`GitHub tool ${name} has no execute`);
return tool.execute(input, { toolCallId: name, messages: [], context: {} });
}
export default defineDynamic({
events: {
"session.started": async () => {
const tools = {};
for (const name of Object.keys(aiTools)) {
tools[name] = defineTool({
description: /* string */,
inputSchema: aiTools[name].inputSchema,
...(writeTools.has(name) ? { approval: always() } : {}),
execute: async (input) => runGithubAiTool(name, input),
});
}
return tools;
},
},
});
After eve build, the bundle shows a hoisted step with __closureVars: { name } only (JSON-safe). Closing over the live Tool object must be avoided — durable replay serializes closure vars.
Ask
- Document that
connect/eve / createGithubTools from @github-tools/sdk/eve is not durable under current eve unless defineTool is visible to the consumer transform (or fix the helper so it is).
- Prefer a supported recipe: either ship the authored-file pattern above in docs/examples, or change
buildEveToolMap / connect/eve / eve-extension so tools are registered in a way eve’s durable transform (or Workflow "use step" registry) survives multi-isolate replay.
- If the intended fix is on eve (transform dependency
defineDynamic / extension packages), please say so — happy to open/cross-link a vercel/eve issue. From the consumer side the broken advertised API is this package’s connect/eve one-liner.
Summary
@github-tools/sdk/connect/eve’s one-liner (export default connectGithubTools(...)) registers tools viadefineDynamic+buildEveToolMapinside the SDK package. On eve durable agents (Slack multi-turn sessions), those tools appear in the tool map briefly (or not at all on later turns) and then get stripped at step time with:Same for
createIssue,searchCode,getRepository, etc. Static authored tools in the consumer (e.g.list_accessible_repos) keep working. The model correctly reports that only inventory is available.This matches eve’s documented durable-tool contract:
defineTool({ execute })must be an inline function in an authoredagent/tools/*.ts(or extension) file so the bundler transform can hoist__executeStepFn/__closureVars. Eve’s workflow input scan ignoresnode_modules, sodefineToolcalls buried in@github-tools/sdknever get hoisted. Eve falls back to an in-processregisterStepFunctiononsession.started; later workflow steps / isolates replay from metadata, look up an empty registry, and skip.@github-tools/eve-extension(1.8.2) still doesreturn buildEveToolMap(...)insidesession.started, so it looks like the same footgun unless eve treats extension packages differently end-to-end.Environment
eve0.27.1@github-tools/sdk1.8.1(also reviewed1.8.2/ eve-extension source — samebuildEveToolMappattern)@vercel/connect0.3.3agent/tools/github.tswas:Evidence
Production logs on a multi-turn Slack session (
sessionIdreused across turns):Audit: assistant states only
list_accessible_reposis callable.Relevant eve behavior (from
dynamic-tool-lifecycle/ docs):executein authored sources (Dynamic capabilities — “executemust be an inline function”).eve:framework-dynamic:<slug>:<key>in-memory when__executeStepFnis missing.Workaround (works for us)
Keep using
@github-tools/sdk/connect(AI SDK tools + Connect token), but putdefineDynamic/defineToolin the consumer file with afor…ofloop and inlineexecutethat only closes over a serializablename, then resolves the AI SDK tool from a module-level map:After
eve build, the bundle shows a hoisted step with__closureVars: { name }only (JSON-safe). Closing over the liveToolobject must be avoided — durable replay serializes closure vars.Ask
connect/eve/createGithubToolsfrom@github-tools/sdk/eveis not durable under current eve unlessdefineToolis visible to the consumer transform (or fix the helper so it is).buildEveToolMap/connect/eve/ eve-extension so tools are registered in a way eve’s durable transform (or Workflow"use step"registry) survives multi-isolate replay.defineDynamic/ extension packages), please say so — happy to open/cross-link a vercel/eve issue. From the consumer side the broken advertised API is this package’sconnect/eveone-liner.