eve 0.52.5 → 0.53.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/dist/src/cli/dev/tui/message-queue.js +1 -1
  3. package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
  4. package/dist/src/compiled/.vendor-stamp.json +16 -16
  5. package/dist/src/compiled/@ai-sdk/anthropic/index.d.ts +23 -2
  6. package/dist/src/compiled/@ai-sdk/anthropic/index.js +2 -4
  7. package/dist/src/compiled/@ai-sdk/google/index.d.ts +145 -33
  8. package/dist/src/compiled/@ai-sdk/google/index.js +10 -7
  9. package/dist/src/compiled/@ai-sdk/mcp/index.d.ts +176 -7
  10. package/dist/src/compiled/@ai-sdk/mcp/index.js +1 -1
  11. package/dist/src/compiled/@ai-sdk/openai/index.d.ts +71 -40
  12. package/dist/src/compiled/@ai-sdk/openai/index.js +8 -8
  13. package/dist/src/compiled/@ai-sdk/otel/index.js +1 -1
  14. package/dist/src/compiled/@ai-sdk/provider/index.d.ts +225 -3
  15. package/dist/src/compiled/@ai-sdk/provider-utils/index.d.ts +220 -151
  16. package/dist/src/compiled/@workflow/core/create-hook.d.ts +3 -0
  17. package/dist/src/compiled/@workflow/core/index.js +2 -2
  18. package/dist/src/compiled/@workflow/core/private.js +1 -1
  19. package/dist/src/compiled/@workflow/core/runtime/resume-hook.d.ts +59 -7
  20. package/dist/src/compiled/@workflow/core/runtime/run.d.ts +42 -0
  21. package/dist/src/compiled/@workflow/core/runtime/start.d.ts +31 -1
  22. package/dist/src/compiled/@workflow/core/runtime.d.ts +2 -2
  23. package/dist/src/compiled/@workflow/core/runtime.js +2 -2
  24. package/dist/src/compiled/@workflow/core/serialization.d.ts +22 -0
  25. package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
  26. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  27. package/dist/src/compiled/@workflow/errors/index.d.ts +37 -3
  28. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  29. package/dist/src/compiled/@workflow/world/attributes-validation.d.ts +68 -0
  30. package/dist/src/compiled/@workflow/world/index.d.ts +1 -1
  31. package/dist/src/compiled/@workflow/world/interfaces.d.ts +21 -0
  32. package/dist/src/compiled/@workflow/world-local/index.js +5 -5
  33. package/dist/src/compiled/@workflow/world-vercel/index.js +3 -3
  34. package/dist/src/compiled/_chunks/workflow/attribute-changes-C6H-fRVP.js +20 -0
  35. package/dist/src/compiled/_chunks/workflow/dist-DDeH-1ER.js +40 -0
  36. package/dist/src/compiled/_chunks/workflow/dist-DhncQSl7.js +74 -0
  37. package/dist/src/compiled/_chunks/workflow/{dist-BIO9Inoc.js → dist-xTushGCp.js} +1 -1
  38. package/dist/src/compiled/_chunks/workflow/frames-DsEqSDes.js +3 -0
  39. package/dist/src/compiled/_chunks/workflow/{private-aXEeo0fU.js → private-CFJkQA7R.js} +1 -1
  40. package/dist/src/compiled/_chunks/workflow/resume-hook-BRDLAb67.js +1 -0
  41. package/dist/src/compiled/_chunks/workflow/run-BM2OFphk.js +1 -0
  42. package/dist/src/compiled/_chunks/workflow/sleep-6cG0F99-.js +1 -0
  43. package/dist/src/compiled/_chunks/workflow/{ws-transport-M7uk8HV8.js → ws-transport-DuK82LLz.js} +1 -1
  44. package/dist/src/compiler/extension-compatibility.d.ts +5 -4
  45. package/dist/src/compiler/extension-compatibility.js +1 -1
  46. package/dist/src/compiler/manifest.d.ts +1 -1
  47. package/dist/src/compiler/manifest.js +1 -1
  48. package/dist/src/compiler/normalize-agent-config.js +1 -1
  49. package/dist/src/compiler/normalize-manifest-helpers.js +1 -1
  50. package/dist/src/execution/cancelled-model-call-batch.d.ts +15 -0
  51. package/dist/src/execution/cancelled-model-call-batch.js +1 -0
  52. package/dist/src/execution/coordination-dispatch-shared.js +1 -1
  53. package/dist/src/execution/dispatch-turn-step.js +1 -1
  54. package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +7 -0
  55. package/dist/src/execution/model-call-batching.d.ts +11 -0
  56. package/dist/src/execution/model-call-batching.js +1 -0
  57. package/dist/src/execution/sandbox/bindings/vercel-lifecycle.d.ts +5 -0
  58. package/dist/src/execution/sandbox/bindings/vercel-lifecycle.js +1 -1
  59. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  60. package/dist/src/execution/tools/sleep-workflow.js +1 -1
  61. package/dist/src/execution/tools/subagent/invoke-agent.d.ts +5 -5
  62. package/dist/src/execution/tools/subagent/invoke-agent.js +1 -1
  63. package/dist/src/execution/tools/subagent/start.js +1 -1
  64. package/dist/src/execution/tools/workflow/body.js +1 -1
  65. package/dist/src/execution/turn-dispatch.d.ts +2 -0
  66. package/dist/src/execution/turn-dispatch.js +1 -1
  67. package/dist/src/execution/turn-workflow.js +1 -1
  68. package/dist/src/execution/wire/session-inbox-resume.js +1 -1
  69. package/dist/src/execution/workflow-entry-crash.d.ts +39 -0
  70. package/dist/src/execution/workflow-entry-crash.js +1 -0
  71. package/dist/src/execution/workflow-entry.d.ts +2 -0
  72. package/dist/src/execution/workflow-entry.js +1 -1
  73. package/dist/src/execution/workflow-runtime.js +1 -1
  74. package/dist/src/execution/workflow-steps.d.ts +1 -1
  75. package/dist/src/execution/workflow-steps.js +1 -1
  76. package/dist/src/harness/provider-tool-history.d.ts +5 -5
  77. package/dist/src/harness/provider-tool-history.js +1 -1
  78. package/dist/src/instrumentation/providers.js +1 -1
  79. package/dist/src/internal/application/package.js +1 -1
  80. package/dist/src/internal/authored-definition/core.js +1 -1
  81. package/dist/src/internal/authored-package-boundary.js +1 -1
  82. package/dist/src/internal/vercel/build-agent-workspace.js +1 -1
  83. package/dist/src/internal/vercel-agent-summary.d.ts +24 -0
  84. package/dist/src/internal/vercel-agent-summary.js +1 -1
  85. package/dist/src/internal/workflow-bundle/authored-workflow-directives.js +1 -1
  86. package/dist/src/public/channels/slack/api.d.ts +2 -0
  87. package/dist/src/public/channels/slack/api.js +1 -1
  88. package/dist/src/public/channels/slack/defaults.d.ts +6 -0
  89. package/dist/src/public/channels/slack/defaults.js +3 -3
  90. package/dist/src/public/channels/slack/limits.d.ts +6 -0
  91. package/dist/src/public/channels/slack/limits.js +1 -1
  92. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  93. package/dist/src/public/definitions/agent.d.ts +1 -1
  94. package/dist/src/public/index.d.ts +1 -1
  95. package/dist/src/public/instrumentation/otel.d.ts +1 -1
  96. package/dist/src/runtime/agent/resolve-model.js +1 -1
  97. package/dist/src/runtime/resolve-agent.js +1 -1
  98. package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -1
  99. package/dist/src/self-modification/agent.d.ts +2 -2
  100. package/dist/src/self-modification/agent.js +1 -1
  101. package/dist/src/self-modification/config.d.ts +15 -0
  102. package/dist/src/self-modification/config.js +1 -1
  103. package/dist/src/self-modification/extension/extension.d.ts +3 -0
  104. package/dist/src/self-modification/extension/extension.js +1 -1
  105. package/dist/src/self-modification/setup.d.ts +3 -0
  106. package/dist/src/self-modification/setup.js +25 -4
  107. package/dist/src/setup/integrations/self-modification/setup.js +1 -1
  108. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  109. package/dist/src/setup/scaffold/create/project.js +2 -2
  110. package/dist/src/setup/scaffold/update/web-options.js +1 -1
  111. package/dist/src/shared/agent-definition.d.ts +46 -2
  112. package/dist/src/shared/agent-definition.js +1 -1
  113. package/dist/src/tools/workflow-definition.d.ts +38 -4
  114. package/dist/src/tracing/otel-declaration.d.ts +1 -1
  115. package/docs/agent-config.md +78 -8
  116. package/docs/channels/slack.mdx +5 -8
  117. package/docs/concepts/execution-model-and-durability.mdx +20 -2
  118. package/docs/guides/dev-tui.md +11 -11
  119. package/docs/guides/instrumentation-providers.md +1 -1
  120. package/docs/reference/typescript-api.md +1 -1
  121. package/docs/sandbox.mdx +1 -1
  122. package/docs/subagents/index.mdx +1 -1
  123. package/docs/tools/workflows.mdx +15 -10
  124. package/package.json +17 -17
  125. package/dist/src/compiled/_chunks/workflow/attribute-changes-DpruylJZ.js +0 -20
  126. package/dist/src/compiled/_chunks/workflow/dist-ChzQSWQA.js +0 -65
  127. package/dist/src/compiled/_chunks/workflow/dist-veFIAdWV.js +0 -40
  128. package/dist/src/compiled/_chunks/workflow/frames-DKxlMf3X.js +0 -3
  129. package/dist/src/compiled/_chunks/workflow/resume-hook-DWDi_wCN.js +0 -1
  130. package/dist/src/compiled/_chunks/workflow/run-vsAdI41O.js +0 -1
  131. package/dist/src/compiled/_chunks/workflow/sleep-BKxoNDRv.js +0 -1
@@ -1,9 +1,11 @@
1
1
  import { relative } from "node:path";
2
2
  export interface SelfModificationSetupValues {
3
3
  readonly branch: string;
4
+ readonly channelNames: readonly string[];
4
5
  readonly connector: string;
5
6
  readonly directory: string;
6
7
  readonly repository: string;
8
+ readonly vercelBackend: boolean;
7
9
  }
8
10
  export interface DetectedGitRepository {
9
11
  readonly branch?: string;
@@ -14,6 +16,7 @@ export interface DetectedGitRepository {
14
16
  }
15
17
  export interface SelfModificationSetupOperations {
16
18
  attachConnector(connector: string): Promise<void>;
19
+ detectChannelNames(): Promise<readonly string[]>;
17
20
  detectGitRepository(): Promise<DetectedGitRepository>;
18
21
  findOrCreateConnector(name: string): Promise<string>;
19
22
  readConfig(): Promise<string | undefined>;
@@ -1,7 +1,21 @@
1
- import{SELF_MODIFICATION_CONFIG_PATH}from"./git-workspace.js";import{createHash}from"node:crypto";import{readFile,writeFile}from"node:fs/promises";import{join,relative}from"node:path";import{execFile}from"node:child_process";import{promisify}from"node:util";const runFile=promisify(execFile);function connectorName(e,t){return`selfmod-${e}-${t}`.toLowerCase().replaceAll(/[^a-z0-9-]/gu,`-`)}function renderSelfModificationConfig(e){if(e===void 0)return`import { defineSelfModificationConfig } from "eve/self-modification/config";
1
+ import{SELF_MODIFICATION_CONFIG_PATH}from"./git-workspace.js";import{createHash}from"node:crypto";import{readFile,writeFile}from"node:fs/promises";import{join,relative}from"node:path";import{discoverAgent}from"#discover/discover-agent.js";import{execFile}from"node:child_process";import{promisify}from"node:util";import{stripLogicalPathExtension}from"#discover/filesystem.js";const runFile=promisify(execFile);function connectorName(e,t){return`selfmod-${e}-${t}`.toLowerCase().replaceAll(/[^a-z0-9-]/gu,`-`)}function renderSelfModificationConfig(e){if(e===void 0)return`import { defineSelfModificationConfig } from "eve/self-modification/config";
2
2
 
3
3
  export default defineSelfModificationConfig({});
4
- `;let t=`import { defineSelfModificationConfig } from "eve/self-modification/config";
4
+ `;let t=[...new Set(e.channelNames)].filter(e=>e!==`eve`).sort(),n=(e.vercelBackend?t:[]).map(e=>` case ${JSON.stringify(`channel:${e}`)}:
5
+ // Authorize trusted principals for this channel before returning true.
6
+ return false;`).join(`
7
+ `),r=`${e.vercelBackend?` case "http": {
8
+ const projectId = process.env.VERCEL_PROJECT_ID;
9
+ return (
10
+ projectId !== undefined &&
11
+ projectId.length > 0 &&
12
+ principal?.authenticator === "oidc" &&
13
+ (principal.issuer === "https://oidc.vercel.com" ||
14
+ principal.issuer?.startsWith("https://oidc.vercel.com/") === true) &&
15
+ principal.attributes.project_id === projectId
16
+ );
17
+ }
18
+ `:``}${n}`,i=`import { defineSelfModificationConfig } from "eve/self-modification/config";
5
19
 
6
20
  export default defineSelfModificationConfig({
7
21
  deployed: {
@@ -15,8 +29,15 @@ export default defineSelfModificationConfig({
15
29
  credentials: {
16
30
  vercelConnect: { connector: ${JSON.stringify(e.connector)} },
17
31
  },
32
+ authorize: ({ channel, principal }) => {
33
+ switch (channel.kind) {
34
+ ${r} default:
35
+ // Add another branch when you add a trusted channel.
36
+ return false;
37
+ }
38
+ },
18
39
  },
19
40
  });
20
- `;return`// eve-self-modification: generated-v1 digest:${createHash(`sha256`).update(t).digest(`hex`)}\n${t}`}function classifySelfModificationConfig(e){if(e===void 0)return`missing`;if(e===renderSelfModificationConfig())return`local`;let[t,...n]=e.split(`
41
+ `;return`// eve-self-modification: generated-v1 digest:${createHash(`sha256`).update(i).digest(`hex`)}\n${i}`}function classifySelfModificationConfig(e){if(e===void 0)return`missing`;if(e===renderSelfModificationConfig())return`local`;let[t,...n]=e.split(`
21
42
  `);return/^\/\/ eve-self-modification: generated-v1 digest:([a-f0-9]{64})$/u.exec(t??``)?.[1]===createHash(`sha256`).update(n.join(`
22
- `)).digest(`hex`)?`generated`:`authored`}function parseGitHubRemote(e){let t=e.trim().match(/^(?:https?:\/\/github\.com\/|git@github\.com:|ssh:\/\/git@github\.com\/)([^/]+)\/([^/]+?)(?:\.git)?$/u);return t?.[1]===void 0||t[2]===void 0?void 0:{owner:t[1],repo:t[2]}}function defaultSelfModificationSetupOperations(e){let t=join(e,SELF_MODIFICATION_CONFIG_PATH);return{async detectGitRepository(){let t=await gitOutput(e,[`config`,`--get`,`remote.origin.url`]),n=t===void 0?void 0:parseGitHubRemote(t),r=await gitOutput(e,[`symbolic-ref`,`--quiet`,`--short`,`refs/remotes/origin/HEAD`]),i=await gitOutput(e,[`rev-parse`,`--show-toplevel`]);return{...n,branch:r?.replace(/^origin\//u,``),directory:i===void 0?void 0:repositoryRelativeDirectory(i,e),remoteKind:t===void 0?`missing`:n===void 0?`other`:`github`}},async readConfig(){try{return await readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw e}},writeConfig:e=>writeFile(t,e,`utf8`),async findOrCreateConnector(t){let n=await vercel(e,[`connect`,`list`,`-F`,`json`]);if(!n.ok)throw Error(`Vercel Connect requires an authenticated Vercel CLI linked to this project.`);let r=parseConnectors(n.stdout),i=`github/${t}`,a=r.find(e=>e.uid===i);if(a!==void 0){if(a.type!==`github`)throw Error(`The existing connector ${i} is not a GitHub connector.`);return a.uid}let o=await vercel(e,[`connect`,`create`,`github`,`--name`,t,`-F`,`json`]),s=o.ok?parseCreatedConnector(o.stdout):void 0;if(s===void 0||!s.startsWith(`github/`))throw Error(`Could not create a GitHub Vercel Connect connector.`);return s},async attachConnector(t){let n=await readLinkedProject(e);if(n===void 0)throw Error("Vercel Connect requires this directory to be linked to a Vercel project. Run `vercel link` and retry.");if(!(await vercel(e,[`connect`,`attach`,t,`--project`,n.projectId,`--environment`,`production`,`--yes`])).ok)throw Error(`Could not attach ${t} to the linked Vercel project for Production.`)}}}function parseCreatedConnector(e){try{let t=JSON.parse(e);return typeof t.uid==`string`?t.uid:void 0}catch{return}}function parseConnectors(e){try{let t=JSON.parse(e);return(Array.isArray(t.connectors)?t.connectors:[t]).flatMap(e=>typeof e==`object`&&e&&typeof e.uid==`string`&&typeof e.type==`string`?[{uid:e.uid,type:e.type}]:[])}catch{return[]}}async function vercel(e,t){try{return{ok:!0,stdout:(await runFile(`vercel`,t,{cwd:e})).stdout}}catch{return{ok:!1,stdout:``}}}async function readLinkedProject(e){try{let t=JSON.parse(await readFile(join(e,`.vercel`,`project.json`),`utf8`));return typeof t.projectId==`string`?{projectId:t.projectId}:void 0}catch{return}}function repositoryRelativeDirectory(e,t,n=relative){return n(e,t).replaceAll(`\\`,`/`)||`.`}function repositoryPartError(e){return/^[A-Za-z0-9_.-]+$/u.test(e)?void 0:`Enter a valid GitHub owner or repository name.`}function directoryError(e){return e===`.`||e.length>0&&!e.startsWith(`/`)&&!e.includes(`\\`)&&e.split(`/`).every(e=>e!==``&&e!==`.`&&e!==`..`)?void 0:`Enter a safe repository-relative directory or ".".`}function gitRefError(e){return/^[A-Za-z0-9][A-Za-z0-9._/-]*$/u.test(e)&&!e.endsWith(`.`)&&!e.endsWith(`/`)&&!e.includes(`..`)&&!e.includes(`//`)&&!e.includes(`@{`)?void 0:`Enter a valid branch name.`}async function gitOutput(e,t){try{return(await runFile(`git`,t,{cwd:e})).stdout.trim()||void 0}catch{return}}export{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,parseGitHubRemote,renderSelfModificationConfig,repositoryPartError,repositoryRelativeDirectory};
43
+ `)).digest(`hex`)?`generated`:`authored`}function parseGitHubRemote(e){let t=e.trim().match(/^(?:https?:\/\/github\.com\/|git@github\.com:|ssh:\/\/git@github\.com\/)([^/]+)\/([^/]+?)(?:\.git)?$/u);return t?.[1]===void 0||t[2]===void 0?void 0:{owner:t[1],repo:t[2]}}function defaultSelfModificationSetupOperations(e){let t=join(e,SELF_MODIFICATION_CONFIG_PATH);return{async detectChannelNames(){return(await discoverAgent({appRoot:e,agentRoot:join(e,`agent`)})).manifest.channels.map(e=>stripLogicalPathExtension(e.logicalPath).replace(/^channels\//,``))},async detectGitRepository(){let t=await gitOutput(e,[`config`,`--get`,`remote.origin.url`]),n=t===void 0?void 0:parseGitHubRemote(t),r=await gitOutput(e,[`symbolic-ref`,`--quiet`,`--short`,`refs/remotes/origin/HEAD`]),i=await gitOutput(e,[`rev-parse`,`--show-toplevel`]);return{...n,branch:r?.replace(/^origin\//u,``),directory:i===void 0?void 0:repositoryRelativeDirectory(i,e),remoteKind:t===void 0?`missing`:n===void 0?`other`:`github`}},async readConfig(){try{return await readFile(t,`utf8`)}catch(e){if(e.code===`ENOENT`)return;throw e}},writeConfig:e=>writeFile(t,e,`utf8`),async findOrCreateConnector(t){let n=await vercel(e,[`connect`,`list`,`-F`,`json`]);if(!n.ok)throw Error(`Vercel Connect requires an authenticated Vercel CLI linked to this project.`);let r=parseConnectors(n.stdout),i=`github/${t}`,a=r.find(e=>e.uid===i);if(a!==void 0){if(a.type!==`github`)throw Error(`The existing connector ${i} is not a GitHub connector.`);return a.uid}let o=await vercel(e,[`connect`,`create`,`github`,`--name`,t,`-F`,`json`]),s=o.ok?parseCreatedConnector(o.stdout):void 0;if(s===void 0||!s.startsWith(`github/`))throw Error(`Could not create a GitHub Vercel Connect connector.`);return s},async attachConnector(t){let n=await readLinkedProject(e);if(n===void 0)throw Error("Vercel Connect requires this directory to be linked to a Vercel project. Run `vercel link` and retry.");if(!(await vercel(e,[`connect`,`attach`,t,`--project`,n.projectId,`--environment`,`production`,`--yes`])).ok)throw Error(`Could not attach ${t} to the linked Vercel project for Production.`)}}}function parseCreatedConnector(e){try{let t=JSON.parse(e);return typeof t.uid==`string`?t.uid:void 0}catch{return}}function parseConnectors(e){try{let t=JSON.parse(e);return(Array.isArray(t.connectors)?t.connectors:[t]).flatMap(e=>typeof e==`object`&&e&&typeof e.uid==`string`&&typeof e.type==`string`?[{uid:e.uid,type:e.type}]:[])}catch{return[]}}async function vercel(e,t){try{return{ok:!0,stdout:(await runFile(`vercel`,t,{cwd:e})).stdout}}catch{return{ok:!1,stdout:``}}}async function readLinkedProject(e){try{let t=JSON.parse(await readFile(join(e,`.vercel`,`project.json`),`utf8`));return typeof t.projectId==`string`?{projectId:t.projectId}:void 0}catch{return}}function repositoryRelativeDirectory(e,t,n=relative){return n(e,t).replaceAll(`\\`,`/`)||`.`}function repositoryPartError(e){return/^[A-Za-z0-9_.-]+$/u.test(e)?void 0:`Enter a valid GitHub owner or repository name.`}function directoryError(e){return e===`.`||e.length>0&&!e.startsWith(`/`)&&!e.includes(`\\`)&&e.split(`/`).every(e=>e!==``&&e!==`.`&&e!==`..`)?void 0:`Enter a safe repository-relative directory or ".".`}function gitRefError(e){return/^[A-Za-z0-9][A-Za-z0-9._/-]*$/u.test(e)&&!e.endsWith(`.`)&&!e.endsWith(`/`)&&!e.includes(`..`)&&!e.includes(`//`)&&!e.includes(`@{`)?void 0:`Enter a valid branch name.`}async function gitOutput(e,t){try{return(await runFile(`git`,t,{cwd:e})).stdout.trim()||void 0}catch{return}}export{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,parseGitHubRemote,renderSelfModificationConfig,repositoryPartError,repositoryRelativeDirectory};
@@ -1 +1 @@
1
- import{defineSetupIntegration}from"../types.js";import{describeIntegrationSetupEnvironment}from"../shared/environment.js";import{confirm,text}from"#setup/ask.js";import{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,renderSelfModificationConfig,repositoryPartError}from"#self-modification/setup.js";import{SELF_MODIFICATION_CONFIG_PATH}from"#self-modification/git-workspace.js";function validationResult(e){return e??null}async function prepareSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();if(classifySelfModificationConfig(n)===`authored`)return e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`};let r=await t.detectGitRepository(),i=await e.asker.ask(text({key:`self-modification-repository-owner`,message:`GitHub repository owner`,detected:r.owner,required:!0,validate:e=>validationResult(repositoryPartError(e))})),a=await e.asker.ask(text({key:`self-modification-repository-name`,message:`GitHub repository name`,detected:r.repo,required:!0,validate:e=>validationResult(repositoryPartError(e))})),o=await e.asker.ask(text({key:`self-modification-repository-directory`,message:`Application directory relative to the repository root`,detected:r.directory??`.`,required:!0,validate:e=>validationResult(directoryError(e))})),s=await e.asker.ask(text({key:`self-modification-target-branch`,message:`Target branch`,detected:r.branch??`main`,required:!0,validate:e=>validationResult(gitRefError(e))})),c=connectorName(i,a),l={branch:s,connector:`github/${c}`,directory:o,repository:`github.com/${i}/${a}`};return e.presenter.note(renderSelfModificationConfig(l),`Generated ${SELF_MODIFICATION_CONFIG_PATH}`),e.presenter.note(`Vercel Connect will issue short-lived GitHub App credentials restricted to this repository. Install the managed GitHub App and select only this repository. Review, merge, and deployment remain separate operator boundaries.`,`Security summary`),await e.asker.ask(confirm({key:`self-modification-confirm`,message:`Create or attach this GitHub connector and write this configuration?`,recommended:!1,required:!0}))?{kind:`deployed`,connectorName:c,values:l}:{kind:`local`}}async function applySelfModificationSetup(e,t,n=defaultSelfModificationSetupOperations(t.appRoot)){if(e.kind===`authored`)return{facts:[{label:`Self-modification`,value:`manual configuration update required`}]};if(e.kind===`local`)return{facts:[{label:`Self-modification`,value:`local editing`}]};let r=await n.findOrCreateConnector(e.connectorName);return await n.attachConnector(r),await n.writeConfig(renderSelfModificationConfig({...e.values,connector:r})),t.presenter.log.success(`Updated ${SELF_MODIFICATION_CONFIG_PATH}.`),t.presenter.nextSteps([`Install the managed GitHub App for the configured repository, then redeploy.`]),{deploymentRequired:!0,facts:[{label:`Repository`,value:e.values.repository},{label:`Application directory`,value:e.values.directory},{label:`Target branch`,value:e.values.branch},{label:`Credential`,value:r}]}}async function prepareLocalSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();return classifySelfModificationConfig(n)===`authored`?(e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`}):{kind:`local`}}function describeEnvironment(e){if(e.vercel.kind===`available`)return describeIntegrationSetupEnvironment(e);switch(e.vercel.reason){case`logged-out`:return`No authenticated Vercel account found. Local editing remains available; deployed proposals require Vercel Connect.`;case`cli-missing`:return`Vercel CLI not found. Local editing remains available; deployed proposals require Vercel Connect.`;case`unavailable`:return`Could not verify the Vercel account. Local editing remains available; deployed proposals require Vercel Connect.`}}const SELF_MODIFICATION_SETUP=defineSetupIntegration({kind:`self-modification`,label:`Self-modification`,hint:`Local source editing is enabled`,describeEnvironment,prepare:prepareLocalSelfModificationSetup,apply:applySelfModificationSetup}),SELF_MODIFICATION_PRODUCTION_SETUP=defineSetupIntegration({kind:`self-modification-production`,label:`Self-modification production`,hint:`Configure deployed draft pull requests`,describeEnvironment,prepare:prepareSelfModificationSetup,apply:applySelfModificationSetup});export{SELF_MODIFICATION_PRODUCTION_SETUP,SELF_MODIFICATION_SETUP,applySelfModificationSetup,prepareLocalSelfModificationSetup,prepareSelfModificationSetup};
1
+ import{defineSetupIntegration}from"../types.js";import{describeIntegrationSetupEnvironment}from"../shared/environment.js";import{confirm,text}from"#setup/ask.js";import{classifySelfModificationConfig,connectorName,defaultSelfModificationSetupOperations,directoryError,gitRefError,renderSelfModificationConfig,repositoryPartError}from"#self-modification/setup.js";import{SELF_MODIFICATION_CONFIG_PATH}from"#self-modification/git-workspace.js";function validationResult(e){return e??null}async function prepareSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();if(classifySelfModificationConfig(n)===`authored`)return e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`};let[r,i]=await Promise.all([t.detectGitRepository(),t.detectChannelNames()]),a=await e.asker.ask(text({key:`self-modification-repository-owner`,message:`GitHub repository owner`,detected:r.owner,required:!0,validate:e=>validationResult(repositoryPartError(e))})),o=await e.asker.ask(text({key:`self-modification-repository-name`,message:`GitHub repository name`,detected:r.repo,required:!0,validate:e=>validationResult(repositoryPartError(e))})),s=await e.asker.ask(text({key:`self-modification-repository-directory`,message:`Application directory relative to the repository root`,detected:r.directory??`.`,required:!0,validate:e=>validationResult(directoryError(e))})),c=await e.asker.ask(text({key:`self-modification-target-branch`,message:`Target branch`,detected:r.branch??`main`,required:!0,validate:e=>validationResult(gitRefError(e))})),l=connectorName(a,o),u={branch:c,channelNames:i,connector:`github/${l}`,directory:s,repository:`github.com/${a}/${o}`,vercelBackend:e.environment.vercel.kind===`available`&&e.environment.vercel.project.kind!==`unresolved`};return e.presenter.note(renderSelfModificationConfig(u),`Generated ${SELF_MODIFICATION_CONFIG_PATH}`),e.presenter.note(`Vercel Connect will issue short-lived GitHub App credentials restricted to this repository. Install the managed GitHub App and select only this repository. Review, merge, and deployment remain separate operator boundaries.`,`Security summary`),await e.asker.ask(confirm({key:`self-modification-confirm`,message:`Create or attach this GitHub connector and write this configuration?`,recommended:!1,required:!0}))?{kind:`deployed`,connectorName:l,values:u}:{kind:`local`}}async function applySelfModificationSetup(e,t,n=defaultSelfModificationSetupOperations(t.appRoot)){if(e.kind===`authored`)return{facts:[{label:`Self-modification`,value:`manual configuration update required`}]};if(e.kind===`local`)return{facts:[{label:`Self-modification`,value:`local editing`}]};let r=await n.findOrCreateConnector(e.connectorName);return await n.attachConnector(r),await n.writeConfig(renderSelfModificationConfig({...e.values,connector:r})),t.presenter.log.success(`Updated ${SELF_MODIFICATION_CONFIG_PATH}.`),t.presenter.nextSteps([`Install the managed GitHub App for the configured repository, then deploy or redeploy.`,e.values.vercelBackend?"After deployment, try self-modification by running `eve dev <deployment-url>` from this linked project. The generated policy admits its Vercel OIDC identity over HTTP; configured channels remain denied until you update `agent/subagents/self-modification/config.ts`.":"Before deployment, configure `deployed.authorize` in `agent/subagents/self-modification/config.ts` to admit a trusted principal for your deployment's channel. After deployment, use that channel to try self-modification."]),{deploymentRequired:!0,facts:[{label:`Repository`,value:e.values.repository},{label:`Application directory`,value:e.values.directory},{label:`Target branch`,value:e.values.branch},{label:`Credential`,value:r}]}}async function prepareLocalSelfModificationSetup(e,t=defaultSelfModificationSetupOperations(e.appRoot)){let n=await t.readConfig();return classifySelfModificationConfig(n)===`authored`?(e.presenter.note(`The existing ${SELF_MODIFICATION_CONFIG_PATH} contains authored configuration and was not overwritten.`,`Manual update required`,{tone:`warning`}),{kind:`authored`}):{kind:`local`}}function describeEnvironment(e){if(e.vercel.kind===`available`)return describeIntegrationSetupEnvironment(e);switch(e.vercel.reason){case`logged-out`:return`No authenticated Vercel account found. Local editing remains available; deployed proposals require Vercel Connect.`;case`cli-missing`:return`Vercel CLI not found. Local editing remains available; deployed proposals require Vercel Connect.`;case`unavailable`:return`Could not verify the Vercel account. Local editing remains available; deployed proposals require Vercel Connect.`}}const SELF_MODIFICATION_SETUP=defineSetupIntegration({kind:`self-modification`,label:`Self-modification`,hint:`Local source editing is enabled`,describeEnvironment,prepare:prepareLocalSelfModificationSetup,apply:applySelfModificationSetup}),SELF_MODIFICATION_PRODUCTION_SETUP=defineSetupIntegration({kind:`self-modification-production`,label:`Self-modification production`,hint:`Configure deployed draft pull requests`,describeEnvironment,prepare:prepareSelfModificationSetup,apply:applySelfModificationSetup});export{SELF_MODIFICATION_PRODUCTION_SETUP,SELF_MODIFICATION_SETUP,applySelfModificationSetup,prepareLocalSelfModificationSetup,prepareSelfModificationSetup};
@@ -1 +1 @@
1
- import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"../update/package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{readFile}from"node:fs/promises";import{join}from"node:path";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(e){let t=e.packageManager??`pnpm`,n=join(e.projectRoot,`package.json`);if(!await pathExists(n))throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Cannot add an eve agent because "${n}" is not valid JSON. No files were changed. Fix the file, then retry eve init. ${t}`)}let i=agentTemplateFiles(e.model,e.reasoning),a=[];for(let t of Object.keys(i))await pathExists(join(e.projectRoot,t))&&a.push(t);if(a.length===0&&await pathExists(join(e.projectRoot,`agent`))&&a.push(`agent/`),a.length>0)throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it already has: ${a.join(`, `)}.`);let o=resolveEvePackageContract(e.evePackage),s=resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.82`),c=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`1.0.0`),l=resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),u=[];for(let[t,n]of Object.entries(i)){let r=join(e.projectRoot,t);await writeTextFile(r,n),u.push(r)}let d={"@vercel/connect":c,ai:s,eve:formatEveDependencySpecifier(o.version),zod:l},f={};for(let[e,t]of Object.entries(d))hasDeclaredDependency(r,e)||(f[e]=t);let p={};Object.keys(f).length>0&&(p.dependencies=f),isPackageManagerWorkspaceMember(t,e.projectRoot)||(p.nodeEngineRequirement=o.nodeEngine);let m=await patchPackageJson(n,p),h=await patchWorkspaceRootPackageJson(t,e.projectRoot,{nodeEngineRequirement:o.nodeEngine}),g=h.nodeEngineOverride??m.nodeEngineOverride,_=await applyPackageManagerWorkspaceConfiguration({packageManager:t,projectRoot:e.projectRoot});return{filesWritten:u,dependenciesAdded:Object.keys(f).sort(),nodeEngineOverride:g,configurationFilesChanged:[...m.changed?[n]:[],...h.changed&&h.path!==void 0?[h.path]:[],..._.filesWritten]}}export{addAgentToProject};
1
+ import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{patchPackageJson}from"../update/package-json.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{agentTemplateFiles,formatEveDependencySpecifier,resolveEvePackageContract}from"./project.js";import{readFile}from"node:fs/promises";import{join}from"node:path";const DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`optionalDependencies`,`peerDependencies`];function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hasDeclaredDependency(e,t){if(!isJsonObject(e))return!1;for(let n of DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function addAgentToProject(e){let t=e.packageManager??`pnpm`,n=join(e.projectRoot,`package.json`);if(!await pathExists(n))throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it has no package.json. Run \`eve init <name>\` to create a new project instead.`);let r;try{r=JSON.parse(await readFile(n,`utf8`))}catch(e){let t=e instanceof Error?e.message:String(e);throw Error(`Cannot add an eve agent because "${n}" is not valid JSON. No files were changed. Fix the file, then retry eve init. ${t}`)}let i=agentTemplateFiles(e.model,e.reasoning),a=[];for(let t of Object.keys(i))await pathExists(join(e.projectRoot,t))&&a.push(t);if(a.length===0&&await pathExists(join(e.projectRoot,`agent`))&&a.push(`agent/`),a.length>0)throw Error(`Cannot add an eve agent to "${e.projectRoot}" because it already has: ${a.join(`, `)}.`);let o=resolveEvePackageContract(e.evePackage),s=resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.93`),c=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`1.0.0`),l=resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),u=[];for(let[t,n]of Object.entries(i)){let r=join(e.projectRoot,t);await writeTextFile(r,n),u.push(r)}let d={"@vercel/connect":c,ai:s,eve:formatEveDependencySpecifier(o.version),zod:l},f={};for(let[e,t]of Object.entries(d))hasDeclaredDependency(r,e)||(f[e]=t);let p={};Object.keys(f).length>0&&(p.dependencies=f),isPackageManagerWorkspaceMember(t,e.projectRoot)||(p.nodeEngineRequirement=o.nodeEngine);let m=await patchPackageJson(n,p),h=await patchWorkspaceRootPackageJson(t,e.projectRoot,{nodeEngineRequirement:o.nodeEngine}),g=h.nodeEngineOverride??m.nodeEngineOverride,_=await applyPackageManagerWorkspaceConfiguration({packageManager:t,projectRoot:e.projectRoot});return{filesWritten:u,dependenciesAdded:Object.keys(f).sort(),nodeEngineOverride:g,configurationFilesChanged:[...m.changed?[n]:[],...h.changed&&h.path!==void 0?[h.path]:[],..._.filesWritten]}}export{addAgentToProject};
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.52.5`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.93`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.53.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -117,4 +117,4 @@ __EVE_INIT_REASONING__ modelOptions: {
117
117
  },
118
118
  },
119
119
  });
120
- `:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(e.includeRootOnlyPackageJsonFields)}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let n=await readdir(e),r=blockingCreateInPlaceEntries(n);if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let t=resolve(e.targetDirectory??process.cwd(),e.projectName),n=e.projectName===`.`,r=e.overwriteExisting??!1,i=e.byokProvider??!1,a=e.packageManager??`pnpm`,o=resolveEvePackageContract(e.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c=resolve(e.workspaceProbeDirectory??t),l=isPackageManagerWorkspaceMember(a,c);if(n)await assertCanCreateInPlace(t,r);else if(await pathExists(t))throw Error(`Cannot create project because "${t}" already exists.`);let u={appName:basename(t),model:e.model,reasoning:e.reasoning,eveVersion:o.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.82`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`1.0.0`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,e.typescriptPackageVersion??`7.0.2`),nodeTypesVersion:s,nodeEngine:s};await mkdir(t,{recursive:!0});for(let[a,o]of Object.entries(templateFiles({byokProvider:i,includeRootOnlyPackageJsonFields:!l}))){let i=`${t}/${a}`,s=await pathExists(i);await writeTextFile(i,renderTemplate(o,u),{force:n&&r}),s&&await e.onOverwriteFile?.(i)}return await applyPackageManagerWorkspaceConfiguration({packageManager:a,projectRoot:t,workspaceProbeRoot:c,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(a,c,{nodeEngineRequirement:o.nodeEngine,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),t}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
120
+ `:BASE_AGENT_TEMPLATE,...SHARED_TEMPLATE_FILES,"package.json":packageJsonTemplate(e.includeRootOnlyPackageJsonFields)}}async function assertCanCreateInPlace(e,t){if(!await pathExists(e))return;let n=await readdir(e),r=blockingCreateInPlaceEntries(n);if(r.length>0&&!t){let e=r.slice(0,5).join(`, `),t=r.length>5?`, and ${r.length-5} more`:``;throw Error(`Cannot create project in current directory because it is not empty. Found: ${e}${t}. Use an empty directory.`)}}async function scaffoldBaseProject(e){let t=resolve(e.targetDirectory??process.cwd(),e.projectName),n=e.projectName===`.`,r=e.overwriteExisting??!1,i=e.byokProvider??!1,a=e.packageManager??`pnpm`,o=resolveEvePackageContract(e.evePackage),s=pinnedNodeEngineMajor(o.nodeEngine),c=resolve(e.workspaceProbeDirectory??t),l=isPackageManagerWorkspaceMember(a,c);if(n)await assertCanCreateInPlace(t,r);else if(await pathExists(t))throw Error(`Cannot create project because "${t}" already exists.`);let u={appName:basename(t),model:e.model,reasoning:e.reasoning,eveVersion:o.version,aiPackageVersion:resolveVersionToken(`aiPackageVersion`,e.aiPackageVersion??`^7.0.93`),connectPackageVersion:resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`1.0.0`),zodPackageVersion:resolveVersionToken(`zodPackageVersion`,e.zodPackageVersion??`4.5.4`),typescriptPackageVersion:resolveVersionToken(`typescriptPackageVersion`,e.typescriptPackageVersion??`7.0.2`),nodeTypesVersion:s,nodeEngine:s};await mkdir(t,{recursive:!0});for(let[a,o]of Object.entries(templateFiles({byokProvider:i,includeRootOnlyPackageJsonFields:!l}))){let i=`${t}/${a}`,s=await pathExists(i);await writeTextFile(i,renderTemplate(o,u),{force:n&&r}),s&&await e.onOverwriteFile?.(i)}return await applyPackageManagerWorkspaceConfiguration({packageManager:a,projectRoot:t,workspaceProbeRoot:c,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),await patchWorkspaceRootPackageJson(a,c,{nodeEngineRequirement:o.nodeEngine,onWorkspaceRootMutation:e.onWorkspaceRootMutation}),t}async function isEveProject(e){for(let t of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)try{return await stat(join(e,`agent`,`agent${t}`)),!0}catch{}return!1}export{CURRENT_DIRECTORY_PROJECT_NAME,DEFAULT_AI_PACKAGE_VERSION,DEFAULT_CONNECT_PACKAGE_VERSION,DEFAULT_EVE_PACKAGE_CONTRACT,DEFAULT_ZOD_PACKAGE_VERSION,ROOT_ONLY_PACKAGE_JSON_TEMPLATE_SUFFIX,agentTemplateFiles,byokProviderEnvVar,formatEveDependencySpecifier,isEveProject,modelProviderSlug,resolveEvePackageContract,scaffoldBaseProject};
@@ -1 +1 @@
1
- import{DEFAULT_EVE_PACKAGE_CONTRACT}from"../create/project.js";function resolveWebPackageVersions(e,t){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`^7.0.82`,betterAuthPackageVersion:e?.betterAuthPackageVersion??`1.6.26`,nextPackageVersion:e?.nextPackageVersion??(t===`sign-in-with-vercel`?`16.3.0`:`16.3.4`),reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.5.4`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}export{resolveWebPackageVersions};
1
+ import{DEFAULT_EVE_PACKAGE_CONTRACT}from"../create/project.js";function resolveWebPackageVersions(e,t){return{evePackage:e?.evePackage??DEFAULT_EVE_PACKAGE_CONTRACT,aiPackageVersion:e?.aiPackageVersion??`^7.0.93`,betterAuthPackageVersion:e?.betterAuthPackageVersion??`1.6.26`,nextPackageVersion:e?.nextPackageVersion??(t===`sign-in-with-vercel`?`16.3.0`:`16.3.4`),reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.5.4`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}export{resolveWebPackageVersions};
@@ -194,8 +194,7 @@ export interface AgentExperimentalDefinition {
194
194
  */
195
195
  readonly tasks?: boolean;
196
196
  /**
197
- * Durable Workflow runtime configuration. Root agents may use this to select
198
- * the Workflow world backing sessions and runs.
197
+ * Durable Workflow runtime configuration.
199
198
  */
200
199
  readonly workflow?: AgentWorkflowDefinition;
201
200
  }
@@ -225,10 +224,55 @@ export interface AgentBuildDefinition {
225
224
  * options can come from environment variables instead of the compiled manifest.
226
225
  */
227
226
  export type AgentWorkflowWorldDefinition = string;
227
+ /**
228
+ * Accepted values for `experimental.workflow.retention`.
229
+ *
230
+ * Declared as eve's own tuple so the authored type, the manifest schema, and
231
+ * the authored-definition normalizer share one source of truth. A drift test
232
+ * keeps it aligned with what the Workflow SDK accepts.
233
+ */
234
+ export declare const AGENT_WORKFLOW_RETENTION_VALUES: readonly [0, "default"];
235
+ /**
236
+ * How long the durable runtime keeps a run's data after the run finishes.
237
+ *
238
+ * The value is a duration, and zero is currently the only one besides the
239
+ * world's default.
240
+ */
241
+ export type AgentWorkflowRetentionDefinition = (typeof AGENT_WORKFLOW_RETENTION_VALUES)[number];
228
242
  /**
229
243
  * Advanced durable-runtime configuration for eve's Workflow SDK integration.
230
244
  */
231
245
  export interface AgentWorkflowDefinition {
246
+ /**
247
+ * Maximum number of turn-model calls eve may run inside one durable Workflow step.
248
+ *
249
+ * Values greater than one reduce Workflow checkpoint overhead but widen the
250
+ * replay unit: if the Workflow step is interrupted, earlier model calls and
251
+ * inline tool executions in the same step may run again.
252
+ *
253
+ * @default 1
254
+ */
255
+ readonly modelCallsPerStep?: number;
256
+ /**
257
+ * How long the agent's run data is kept after the run finishes.
258
+ * Applied to both the session run and every turn run.
259
+ *
260
+ * - `"default"`: same as omission. The Workflow SDK World decides.
261
+ * On Vercel this follows your team's plan.
262
+ * - `0`: the world deletes run payloads and stream chunks as soon as the run
263
+ * completes or fails. Metadata such as run IDs, status, and timestamps may
264
+ * persist up to the default period.
265
+ *
266
+ * The World you are using with the Workflow SDK might not support every
267
+ * option. A World that does not recognize the value keeps the data.
268
+ *
269
+ * Note that with retention set to `0`, data deletion can race reads of a finished
270
+ * run, so results and transcripts of completed sessions generally become
271
+ * unreadable. Persist anything you need to keep from inside a tool.
272
+ *
273
+ * @default "default"
274
+ */
275
+ readonly retention?: AgentWorkflowRetentionDefinition;
232
276
  /**
233
277
  * Workflow world module used for durable workflow storage, queueing, hooks,
234
278
  * and streaming.
@@ -1 +1 @@
1
- import{isDynamicSentinel}from"#dynamic/definition.js";function isDynamicModelDefinition(e){return isDynamicSentinel(e)}export{isDynamicModelDefinition};
1
+ import{isDynamicSentinel}from"#dynamic/definition.js";function isDynamicModelDefinition(e){return isDynamicSentinel(e)}const AGENT_WORKFLOW_RETENTION_VALUES=[0,`default`];export{AGENT_WORKFLOW_RETENTION_VALUES,isDynamicModelDefinition};
@@ -6,18 +6,52 @@ import type { TaskExec } from "#tools/task.js";
6
6
  import type { ToolModelOutput } from "#tools/model-output.js";
7
7
  export interface AgentInput {
8
8
  readonly agentId?: string;
9
- readonly key: string;
10
9
  readonly message: string;
11
10
  readonly outputSchema?: JsonObject;
12
- readonly target: string;
11
+ }
12
+ type JsonSchemaProperties = Readonly<Record<string, JsonObject>>;
13
+ type JsonSchemaRequiredKeys<TProperties extends JsonSchemaProperties, TRequired> = TRequired extends readonly string[] ? Extract<TRequired[number], keyof TProperties> : never;
14
+ type Simplify<TValue> = {
15
+ [TKey in keyof TValue]: TValue[TKey];
16
+ };
17
+ type JsonSchemaObjectOutput<TProperties extends JsonSchemaProperties, TRequired> = Simplify<{
18
+ -readonly [TKey in JsonSchemaRequiredKeys<TProperties, TRequired>]-?: JsonSchemaOutput<TProperties[TKey]>;
19
+ } & {
20
+ -readonly [TKey in Exclude<keyof TProperties, JsonSchemaRequiredKeys<TProperties, TRequired>>]?: JsonSchemaOutput<TProperties[TKey]>;
21
+ }>;
22
+ type JsonSchemaOutput<TSchema> = TSchema extends {
23
+ readonly const: infer TValue;
24
+ } ? Extract<TValue, JsonValue> : TSchema extends {
25
+ readonly enum: readonly (infer TValue)[];
26
+ } ? Extract<TValue, JsonValue> : TSchema extends {
27
+ readonly type: "object";
28
+ readonly properties: infer TProperties extends JsonSchemaProperties;
29
+ readonly required?: infer TRequired;
30
+ } ? JsonSchemaObjectOutput<TProperties, TRequired> : TSchema extends {
31
+ readonly type: "array";
32
+ readonly items: infer TItems extends JsonObject;
33
+ } ? JsonSchemaOutput<TItems>[] : TSchema extends {
34
+ readonly type: "string";
35
+ } ? string : TSchema extends {
36
+ readonly type: "integer" | "number";
37
+ } ? number : TSchema extends {
38
+ readonly type: "boolean";
39
+ } ? boolean : TSchema extends {
40
+ readonly type: "null";
41
+ } ? null : JsonValue;
42
+ interface WorkflowAgent {
43
+ <const TOutputSchema extends JsonObject>(target: string, input: AgentInput & {
44
+ readonly outputSchema: TOutputSchema;
45
+ }): Promise<JsonSchemaOutput<TOutputSchema>>;
46
+ (target: string, input: AgentInput): Promise<JsonValue>;
13
47
  }
14
48
  /**
15
49
  * Context supplied to a workflow tool. Pass it directly to a step helper for
16
50
  * getToken/requireAuth; those capabilities throw in the workflow body itself.
17
51
  */
18
52
  export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName" | "getToken" | "requireAuth"> & {
19
- /** Invoke a visible subagent. The key must be unique within this workflow run. */
20
- agent(input: AgentInput): Promise<JsonValue>;
53
+ /** Invoke a visible subagent by its model-visible name. */
54
+ agent: WorkflowAgent;
21
55
  /** Ask the human on the session's channel; awaiting the answer suspends the run. */
22
56
  ask(request: ToolInputRequest): PromiseLike<ToolInputResponse>;
23
57
  };
@@ -150,7 +150,7 @@ export declare function otel(options?: OtelOptions): OtelDeclaration;
150
150
  export declare function otelIntegration(options?: OtelIntegrationOptions): OtelIntegration;
151
151
  /** @internal Local and Agent Runs destination declaration. */
152
152
  export declare function managedOtelIntegration(options?: OtelIntegrationOptions & ManagedTraceOptions): OtelIntegration;
153
- /** Vercel Agent Runs through the production request-context transport. @internal */
153
+ /** Vercel Agent Runs through the hosted request-context transport. @internal */
154
154
  export declare function agentRunsIntegration(options?: ManagedTraceOptions): OtelIntegration;
155
155
  export declare function resolveContentOptions(options: ContentOptions): ResolvedContentOptions;
156
156
  export declare function isOtelDeclaration(value: unknown): value is OtelDeclaration;
@@ -247,18 +247,88 @@ putting the connection string or credentials in the env vars it reads. If the
247
247
  installed package must stay external in hosted output, list it in
248
248
  `build.externalDependencies`.
249
249
 
250
+ ## Workflow checkpoint batching
251
+
252
+ By default, eve commits a durable Workflow step after every model call and its
253
+ inline tool calls. You can experimentally let one Workflow step run several
254
+ sequential model calls:
255
+
256
+ ```ts title="agent/agent.ts"
257
+ import { defineAgent } from "eve";
258
+
259
+ export default defineAgent({
260
+ model: "anthropic/claude-opus-4.8",
261
+ experimental: {
262
+ workflow: {
263
+ modelCallsPerStep: 4,
264
+ },
265
+ },
266
+ });
267
+ ```
268
+
269
+ `experimental.workflow.modelCallsPerStep` is a positive-integer ceiling. It defaults to
270
+ `1` and applies independently to each root agent or declared subagent. A higher
271
+ value can reduce Workflow checkpoint overhead in sequential tool loops, but it
272
+ widens the replay unit: if the Workflow step is interrupted, its earlier model
273
+ calls and inline tool executions can run again. That can repeat provider costs,
274
+ events, and side effects. Use stable idempotency keys for non-idempotent tools.
275
+
276
+ eve ends a batch before it waits for input, authorization, or blocking
277
+ coordination, and before it acknowledges a background task. A batch can also
278
+ end below the configured ceiling when the turn completes. Steering cancels the
279
+ active model-and-tool cycle, commits earlier completed cycles in the batch, and
280
+ starts the replacement turn from that state. It does not roll the session back
281
+ to the beginning of the batch. This option is experimental and may change or
282
+ disappear in any release. See [Execution model and
283
+ durability](./concepts/execution-model-and-durability#resuming-after-a-crash)
284
+ for the retry behavior.
285
+
286
+ ## Run data retention
287
+
288
+ The runtime keeps each run's data after the run finishes: model and tool
289
+ payloads, streamed output, and the event log eve replays from. How long it keeps
290
+ them is the World's decision, and on Vercel that follows your team's plan. Set
291
+ `experimental.workflow.retention` to `0` to have it deleted as soon as the run
292
+ finishes instead:
293
+
294
+ ```ts title="agent/agent.ts"
295
+ import { defineAgent } from "eve";
296
+
297
+ export default defineAgent({
298
+ model: "anthropic/claude-opus-4.8",
299
+ experimental: {
300
+ workflow: {
301
+ retention: 0,
302
+ },
303
+ },
304
+ });
305
+ ```
306
+
307
+ This will be applied to the session run and every turn run the session
308
+ dispatches, as well as the run that collects session activity. Runs eve
309
+ starts for other purposes keep the world's default: session timeouts,
310
+ background tasks, and [workflow tools](./tools/workflows).
311
+
312
+ The value applies per agent. A [subagent](./subagents) that runs its own session
313
+ uses its own value, unlike `experimental.workflow.world`, which is root-only.
314
+
315
+ Custom Worlds used with eve might not support this feature, in which case
316
+ it falls back to the World's default retention period.
317
+
318
+ > ⚠️ **At `0`, a finished session's output is usually gone before you can read it.** Since data is deleted immediately before it can be read back, results and transcripts become unreadable and a client polling for a finished session's output can see it disappear.
319
+
250
320
  ## Other defineAgent fields
251
321
 
252
322
  `defineAgent` takes a few more fields, all optional. For the exported types, see the [TypeScript API Reference](./reference/typescript-api).
253
323
 
254
- | Field | Type | Default | Description |
255
- | -------------- | --------------------------------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
256
- | `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
257
- | `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
258
- | `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. Sessions complete after 30 days by default; usage-limit defaults and inheritance are described above. Set a limit to `false` to disable it. |
259
- | `experimental` | `{ workflow?: { world?: string } }` | unset | Opt-in settings that can change or disappear in any release. Treat them as unstable. `workflow.world` selects the Workflow world package backing session state, queues, hooks, and streams on the root agent. |
260
- | `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for function-like invocations such as a subagent turn, schedule, or remote job. Ordinary interactive turns ignore it unless the client supplies a per-message schema. |
261
- | `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
324
+ | Field | Type | Default | Description |
325
+ | -------------- | --------------------------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
326
+ | `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
327
+ | `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
328
+ | `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. Sessions complete after 30 days by default; usage-limit defaults and inheritance are described above. Set a limit to `false` to disable it. |
329
+ | `experimental` | `AgentExperimentalDefinition` | unset | Unstable opt-ins. `workflow.world` selects the Workflow world package on the root agent; `workflow.modelCallsPerStep` batches sequential model calls into a wider replay unit; `workflow.retention` controls how long the durable runtime keeps run data. |
330
+ | `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for function-like invocations such as a subagent turn, schedule, or remote job. Ordinary interactive turns ignore it unless the client supplies a per-message schema. |
331
+ | `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
262
332
 
263
333
  `externalDependencies` is a packaging control only. It keeps selected packages as runtime dependencies in the hosted output; it does not authorize, configure, or review any third-party service those packages may call.
264
334
 
@@ -53,7 +53,7 @@ Use this fallback when the agent does not run on Vercel or Vercel Connect is una
53
53
 
54
54
  This option does not create or install the Slack app. Configure it in [Slack app settings](https://api.slack.com/apps):
55
55
 
56
- 1. Add the `app_mentions:read` and `chat:write` bot scopes. Add `im:history` for DMs, `files:read` for inbound attachments, and `files:write` when the agent uploads files.
56
+ 1. Add the `app_mentions:read` and `chat:write` bot scopes. Add `im:history` for DMs, `files:read` for inbound attachments, and `files:write` for explicit uploads and automatic long-response snippets.
57
57
  2. Install or reinstall the app, copy its Bot User OAuth Token to `SLACK_BOT_TOKEN`, and copy the signing secret from **Basic Information** to `SLACK_SIGNING_SECRET`.
58
58
  3. Set both values in `.env.local` for local development or in the target runtime's environment, then start or deploy the agent at a public URL.
59
59
  4. Under **Event Subscriptions**, set the Request URL to `https://your-agent.example/eve/v1/slack`. Subscribe to `app_mention`, plus `message.im` for DMs.
@@ -133,6 +133,7 @@ Check the delivery path in order so you can identify where a Slack event stops:
133
133
  | Setup says it could not remove an existing trigger destination | Check the connector's destinations in the Connect dashboard. `vercel connect detach` removes project token access, not trigger destinations. | Edit or remove the stale destination in the dashboard, then register `/eve/v1/slack` with `vercel connect attach`. |
134
134
  | Mentions never reach the deployment | Confirm that the connector trigger destination uses the intended project and branch, enables triggers, and points to `/eve/v1/slack`. | Edit or remove stale destinations in the Connect dashboard, then register the intended destination with `vercel connect attach`. |
135
135
  | Mentions work but DMs or thread replies do not | Check the Slack app's Event Subscriptions and OAuth scopes. DMs require `message.im` and `im:history`; channel replies require the matching message event and history scope. | Add the missing events or scopes, then reinstall the Slack app if Slack requires it. |
136
+ | A long response cannot be uploaded as a snippet | Check whether the installed Slack app has the `files:write` bot scope. | Add `files:write`, then reinstall the Slack app so the new scope takes effect. |
136
137
  | A preview request receives an authentication page or protection error | Check whether the branch domain is exempt or the direct Slack request URL includes `x-vercel-protection-bypass`. Slack cannot complete an interactive Vercel Authentication challenge. | Add a Deployment Protection Exception for the branch domain, or add the automation bypass query parameter to a Slack app that uses environment-variable credentials. |
137
138
  | The webhook reaches the deployment but the agent does not reply | Open the project's Vercel runtime logs, then inspect the session in **Agent Runs** when your team has access. | Use the first missing or failed stage to narrow the issue to channel dispatch, the agent run, or outbound Slack delivery. |
138
139
 
@@ -414,11 +415,13 @@ when you need the bearer token itself.
414
415
 
415
416
  The default handlers reply in-thread and show activity. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, a truncated reasoning snippet on `reasoning.appended`, and an action label on `actions.requested` — the tool name plus its most telling argument (`grep useEveAgent`, `read_file agent/agent.ts`), the subagent or remote-agent name for dispatched calls, and `+N more` when the model requests several actions at once. The model's own pre-tool narration, when present, takes precedence over the derived label. Reasoning snippets build progressively: extensions of at least four characters appear immediately, while smaller streamed deltas use the five-second refresh interval to avoid one Slack request per token. Override `events["reasoning.appended"]` if you prefer generic wording. Override an inbound handler or the `events` handlers to customize.
416
417
 
418
+ The built-in `message.completed` handler renders responses up to 12,000 characters inline. Longer responses are uploaded unchanged as a Markdown snippet named `eve-response.md` with a short in-thread note, which requires the `files:write` bot scope. Upload failures are logged by the channel dispatcher; they do not trigger a model retry. An authored `events["message.completed"]` handler replaces this behavior and owns its own delivery limits.
419
+
417
420
  Outbound text preserves bare `@` tokens as literal text. To mention a user, embed Slack's `<@USER_ID>` syntax directly or use `channel.thread.mentionUser(userId)`.
418
421
 
419
422
  When a session starts without a `threadTs` (say, from a schedule's `to(slack, target).send(...)`), eve gives it a unique temporary continuation token. The first agent post anchors the session to the Slack message timestamp, and later posts and mentions resume that same session. Pass `initialMessage` with a `Card` to land a structured anchor first instead. `threadTs` and `initialMessage` are mutually exclusive.
420
423
 
421
- The example below overrides `onAppMention` to gate on an authored message and posts the completed reply to the thread. Event handlers receive `(eventData, channel, ctx)`, with Slack platform handles on `channel.thread` and `channel.slack`:
424
+ The example below overrides `onAppMention` to gate on an authored message. The built-in completion handler still posts the reply and uploads long responses as snippets. Event handlers receive `(eventData, channel, ctx)`, with Slack platform handles on `channel.thread` and `channel.slack`:
422
425
 
423
426
  ```ts
424
427
  import { defaultSlackAuth, slackChannel } from "eve/channels/slack";
@@ -428,12 +431,6 @@ export default slackChannel({
428
431
  credentials: connectSlackCredentials("slack/my-agent"),
429
432
  onAppMention: (ctx, message) =>
430
433
  message.author ? { auth: defaultSlackAuth(message, ctx) } : null,
431
- events: {
432
- "message.completed"(eventData, channel, ctx) {
433
- if (eventData.finishReason === "tool-calls") return;
434
- if (eventData.message) channel.thread.post(eventData.message);
435
- },
436
- },
437
434
  });
438
435
  ```
439
436
 
@@ -11,10 +11,16 @@ Work nests in three levels:
11
11
 
12
12
  - **session**: the whole durable conversation or task. It's long-lived and can span many requests over days or weeks without losing context.
13
13
  - **turn**: one user message and all the work it triggers (model calls, tool calls, reasoning) until the agent produces its response.
14
- - **step**: a durable checkpoint inside a turn (one model call and the tool calls it makes).
14
+ - **step**: a durable checkpoint inside a turn. By default, it contains one model call and the inline tool calls that follow it.
15
15
 
16
16
  Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). eve checkpoints progress and serializes durable state at each step boundary. Your code runs inside a managed step, so tools, the sandbox, and subagents feel synchronous even though the session underneath them is durable.
17
17
 
18
+ The experimental
19
+ [`workflow.modelCallsPerStep`](../agent-config#workflow-checkpoint-batching)
20
+ agent setting can group several sequential model-and-tool cycles into one
21
+ Workflow step. This reduces checkpoint overhead but makes the entire group one
22
+ replay unit.
23
+
18
24
  The Workflow SDK is not inherently tied to Vercel. In local development and in a self-deployed `eve start` process, eve uses the SDK's local world by default; that world persists workflow runs on disk under `.eve/.workflow-data` and dispatches through the same Nitro-hosted workflow routes. On Vercel, the same workflow code runs against Vercel Workflow instead, which adds platform features such as latest production deployment routing and dashboard run metadata.
19
25
 
20
26
  When a Vercel production deployment changes, the next model turn in an existing session uses that deployment's current system-role instructions, model, and tools. Static user-role instructions stay pinned in the durable conversation history and are not seeded again. Identity-based channels such as Telegram private chats and Twilio phone-number conversations therefore adopt agent behavior updates without duplicating or rewriting their existing context.
@@ -58,7 +64,19 @@ Provider keys, tool secrets, and MCP, OpenAPI, and connection credentials stay i
58
64
 
59
65
  Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Completed steps never re-run; eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects like charges or emails idempotent, or gate them with approval. Whatever that step already wrote to the session stream stays there, and the re-run emits its events again under new ids, so a stream consumer sees both attempts — see [the event envelope](./sessions-runs-and-streaming#the-event-envelope).
60
66
 
61
- There's nothing to configure. eve owns the workflow lifecycle, and sessions are durable by default.
67
+ With `experimental.workflow.modelCallsPerStep` greater than `1`, an
68
+ interrupted Workflow step can also repeat earlier model calls and inline tool
69
+ executions from the same batch. Approval, input, blocking coordination, and
70
+ background-task boundaries still force a checkpoint before eve waits or
71
+ acknowledges the work.
72
+
73
+ Steering does not replay or discard the whole batch. eve aborts the active
74
+ model-and-tool cycle, commits earlier completed cycles in the batch, and starts
75
+ the replacement turn from that state in the next Workflow step.
76
+
77
+ Durability itself needs no configuration. eve owns the workflow lifecycle, and
78
+ sessions are durable by default; checkpoint batching is an explicit
79
+ experimental opt-in.
62
80
 
63
81
  For ordinary tools, eve manages the workflow around your executor. Use [`defineWorkflowTool`](../tools/workflows) when your own tool body needs durable waits, such as a timer, webhook, or human answer. Two surfaces give your own code session data: tools read the current session's metadata (id, turn, auth, parent lineage) via `ctx.session`, and [`defineState`](./state) reads or writes session-scoped durable state. See [State](./state) for the read/write model.
64
82
 
@@ -59,17 +59,17 @@ The UI installs planner selections in order and offers deployment once after the
59
59
 
60
60
  Type a message and press `Enter` to send it. When the agent asks a question or requests tool approval, respond in the prompt shown by the UI. Connection authorization can open a browser; keep local `eve dev` running until the browser returns to it.
61
61
 
62
- While a turn is running, `Enter` queues a follow-up message. Press `Esc` or `Ctrl+C` to cancel the turn; when messages are queued, this uses the oldest queued message as the next turn instead. At an idle prompt, press `Ctrl+C` twice to exit.
63
-
64
- | Key | Action |
65
- | ------------- | ----------------------------------------------------------------------------------- |
66
- | `Enter` | Send the current message or answer. |
67
- | `Shift+Enter` | Insert a newline. Requires a terminal that reports modified keys. |
68
- | `Esc` | Cancel a running turn, or steer with the oldest queued message. |
69
- | `Ctrl+C` | Cancel or steer during a turn; clear input, then exit on a second press, when idle. |
70
- | `↑` / `↓` | Move through input lines or sent-message history. |
71
- | `Ctrl+L` | Cycle log display modes. |
72
- | `Ctrl+R` | Redraw the screen. |
62
+ While a turn is running, `Enter` queues a follow-up message. Press `Esc` or `Ctrl+C` to cancel the turn; when messages are queued, this uses the oldest queued message as the next turn instead. If a direct cancellation requested with `/cancel` or `Ctrl+C` does not settle, press `Ctrl+C` to stop waiting. The UI then returns to the prompt and asks you to press `Ctrl+C` again to exit. At an idle prompt, press `Ctrl+C` twice to exit.
63
+
64
+ | Key | Action |
65
+ | ------------- | ----------------------------------------------------------------------------------------------------------------------- |
66
+ | `Enter` | Send the current message or answer. |
67
+ | `Shift+Enter` | Insert a newline. Requires a terminal that reports modified keys. |
68
+ | `Esc` | Cancel a running turn, or steer with the oldest queued message. |
69
+ | `Ctrl+C` | Cancel or steer during a turn; stop a pending cancellation, then exit on the next press; press twice to exit when idle. |
70
+ | `↑` / `↓` | Move through input lines or sent-message history. |
71
+ | `Ctrl+L` | Cycle log display modes. |
72
+ | `Ctrl+R` | Redraw the screen. |
73
73
 
74
74
  ## Logs and traces
75
75
 
@@ -217,7 +217,7 @@ Policies run in declaration order. A later policy sees the filtered span produce
217
217
  The provider layout adds two environment-specific defaults:
218
218
 
219
219
  - `local` records local traces during `eve dev`.
220
- - `agent-runs` exports to Vercel Agent Runs in production.
220
+ - `agent-runs` exports to Vercel Agent Runs in preview and production deployments.
221
221
 
222
222
  Omitting these files preserves the defaults. Reconfigure a slot by exporting `localTraces()` or `agentRuns()` from the matching file. Disable one explicitly:
223
223
 
@@ -57,7 +57,7 @@ export default defineTool({
57
57
 
58
58
  Tool-wide authoring helpers and types such as `defineTool`, `defineWorkflowTool`, `defineDurableCallback`, `defineDynamic`, `disableTool`, and `ToolLabelDefinition` come from `eve/tools`. Capability-specific definitions and helpers use their own subpaths (see [Built-in tools](../concepts/built-in-tools)): reusable definitions such as `bash` and `glob` come from `eve/tools/<name>`, `webSearch` comes from `eve/tools/web_search`, `experimental_workflow` comes from `eve/tools/workflow`, `sleep` comes from `eve/tools/sleep`, and approval policies and types come from `eve/tools/approval`. The route verbs `GET`/`HEAD`/`POST`/`PUT`/`PATCH`/`DELETE`/`OPTIONS`/`WS` plus `disableRoute` come from `eve/channels`, and the channel auth helpers `localDev`/`vercelOidc`/`placeholderAuth` come from `eve/channels/auth`.
59
59
 
60
- `AgentReasoningDefinition` is exported from `eve` for the top-level `defineAgent({ reasoning })` setting. `AgentLimitsDefinition` is exported for `defineAgent({ limits })`. `AgentWorkflowDefinition` and `AgentWorkflowWorldDefinition` are exported from `eve` for the `defineAgent({ experimental: { workflow } })` config shape. `ExperimentalWorkflowToolInput` is exported from `eve/tools/workflow`; `WebSearchToolInput` and `WebSearchProvider` are exported from `eve/tools/web_search`.
60
+ `AgentReasoningDefinition` is exported from `eve` for the top-level `defineAgent({ reasoning })` setting. `AgentLimitsDefinition` is exported for `defineAgent({ limits })`. `AgentWorkflowDefinition`, `AgentWorkflowRetentionDefinition`, and `AgentWorkflowWorldDefinition` are exported from `eve` for the `defineAgent({ experimental: { workflow } })` config shape. `ExperimentalWorkflowToolInput` is exported from `eve/tools/workflow`; `WebSearchToolInput` and `WebSearchProvider` are exported from `eve/tools/web_search`.
61
61
 
62
62
  `defineInstructions` accepts `{ content: string, role?: "system" | "user" }`; omitted `role` means `"system"`. Its `eve/instructions` version of `defineDynamic` accepts only `session.started` and `turn.started` handlers returning `defineInstructions(...)` or `null`. The legacy `{ markdown: string }` definition remains available as a deprecated system-role form.
63
63
 
package/docs/sandbox.mdx CHANGED
@@ -291,7 +291,7 @@ Session sandboxes are keyed per durable session, not per deployment, so redeploy
291
291
 
292
292
  For sandboxes with `bootstrap`, unrelated agent changes preserve the template and session sandbox keys even when there are no skill or workspace seed files. You do not need to add a seed file or `revalidationKey` solely to preserve reuse across those changes.
293
293
 
294
- Reattachment still depends on the backend retaining its physical sandbox state. If a persisted Vercel sandbox is no longer available, eve creates a replacement, using the current template when one is configured. Files and other changes made after the original sandbox was created are not restored automatically. Because the durable session still has the same sandbox key, `onSession` does not run again for this replacement. Persist important artifacts outside the sandbox, and do not rely on `onSession` as the only place that applies security-critical configuration.
294
+ Reattachment still depends on the backend retaining its physical sandbox state. If a persisted Vercel sandbox is missing or its saved filesystem snapshot is no longer available, eve deletes the unusable record and creates a replacement from the current template when one is configured. Files and other changes made after the original sandbox was created are not restored automatically. Because the durable session still has the same sandbox key, `onSession` does not run again for this replacement. Persist important artifacts outside the sandbox, and do not rely on `onSession` as the only place that applies security-critical configuration.
295
295
 
296
296
  When the eve server stops, no sandbox compute outlives it. `eve dev` stops the sandboxes it started when the dev server closes, and a self-hosted production server stops every open sandbox on shutdown (`SIGTERM`/`SIGINT`). Session state persists across the stop — the next server start reattaches each durable session from its stopped container, VM, or snapshot. Custom `SandboxBackend` adapters implement `stop()` for authored runtime calls and `shutdown()` for server teardown. Both stop the underlying compute while keeping the session reattachable from persisted state where the backend supports it; authored `stop()` failures reject, while process-wide shutdown collects and logs failures without blocking teardown.
297
297
 
@@ -183,7 +183,7 @@ Each delegated subagent spins up its own child session and stream. The parent st
183
183
 
184
184
  A background task that was already admitted survives cancellation of the turn that started it; background work that has not yet been admitted is rejected with the cancelled step. Use `task_cancel` to stop an admitted task. Cancellation delivers the task's final notification to an active parent even if the task must be stopped forcibly. Parent-session finalization cancels remaining live tasks.
185
185
 
186
- Subagent model calls automatically retry classified transient provider failures, including overload errors delivered after a stream starts. eve makes at most three fresh model-call attempts, repeating only the current uncommitted call so completed earlier steps, tool results, and sandbox work remain available to the child. Other recoverable task errors fall back to Workflow's durable step retry from the last committed session snapshot. Exhausting the transient model-call attempts or the dedicated empty-response reissue returns one failed task result instead of stacking both retry budgets; terminal errors fail immediately.
186
+ Subagent model calls automatically retry classified transient provider failures, including overload errors delivered after a stream starts. eve makes at most three fresh model-call attempts, repeating only the current uncommitted call by default so completed earlier Workflow steps, tool results, and sandbox work remain available to the child. A declared subagent that opts into [Workflow checkpoint batching](./agent-config#workflow-checkpoint-batching) can instead repeat the uncommitted calls and inline tool executions in its current batch. Other recoverable task errors fall back to Workflow's durable step retry from the last committed session snapshot. Exhausting the transient model-call attempts or the dedicated empty-response reissue returns one failed task result instead of stacking both retry budgets; terminal errors fail immediately.
187
187
 
188
188
  ## Agent messaging
189
189