eve 0.52.3 → 0.52.5

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 (192) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/dist/src/cli/commands/init-agent-workspace.d.ts +2 -0
  3. package/dist/src/cli/commands/init-agent-workspace.js +1 -1
  4. package/dist/src/cli/commands/init-install.d.ts +8 -0
  5. package/dist/src/cli/commands/init-install.js +1 -0
  6. package/dist/src/cli/commands/init.d.ts +3 -4
  7. package/dist/src/cli/commands/init.js +1 -1
  8. package/dist/src/cli/commands/registry-add-command.d.ts +3 -0
  9. package/dist/src/cli/commands/registry-add-command.js +1 -0
  10. package/dist/src/cli/commands/registry-metadata.d.ts +4 -1
  11. package/dist/src/cli/commands/registry-metadata.js +1 -1
  12. package/dist/src/cli/commands/registry.d.ts +1 -2
  13. package/dist/src/cli/commands/registry.js +1 -1
  14. package/dist/src/cli/run.js +2 -2
  15. package/dist/src/cli/telemetry/index.d.ts +3 -0
  16. package/dist/src/cli/telemetry/index.js +1 -1
  17. package/dist/src/compiled/.vendor-stamp.json +3 -2
  18. package/dist/src/compiled/@workflow/world-local/index.js +1 -1
  19. package/dist/src/compiler/extension-compatibility.d.ts +4 -4
  20. package/dist/src/compiler/extension-compatibility.js +1 -1
  21. package/dist/src/context/dynamic-model-lifecycle.js +1 -1
  22. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  23. package/dist/src/context/keys.d.ts +11 -2
  24. package/dist/src/context/keys.js +1 -1
  25. package/dist/src/evals/mock-model.js +1 -1
  26. package/dist/src/evals/reporters/index.d.ts +1 -0
  27. package/dist/src/evals/reporters/index.js +1 -1
  28. package/dist/src/evals/runner/reporters/datadog.d.ts +137 -0
  29. package/dist/src/evals/runner/reporters/datadog.js +3 -0
  30. package/dist/src/evals/runner/run-evals.d.ts +1 -1
  31. package/dist/src/evals/runner/run-evals.js +1 -1
  32. package/dist/src/execution/activity-cohort.d.ts +20 -0
  33. package/dist/src/execution/activity-cohort.js +1 -0
  34. package/dist/src/execution/authorization-callback-match.d.ts +1 -0
  35. package/dist/src/execution/authorization-callback-match.js +1 -1
  36. package/dist/src/execution/parked-delivery-wait.js +1 -1
  37. package/dist/src/execution/sandbox/bindings/vercel-options.d.ts +10 -0
  38. package/dist/src/execution/sandbox/bindings/vercel-options.js +1 -0
  39. package/dist/src/execution/sandbox/bindings/vercel.js +2 -1
  40. package/dist/src/execution/sandbox/shell-quote.d.ts +1 -12
  41. package/dist/src/execution/sandbox/shell-quote.js +1 -1
  42. package/dist/src/execution/session-activity-projection.d.ts +2 -0
  43. package/dist/src/execution/session-activity-projection.js +1 -1
  44. package/dist/src/execution/session-command-inbox.js +1 -1
  45. package/dist/src/execution/skills/instructions.js +1 -1
  46. package/dist/src/execution/tasks/child/workflow.js +1 -1
  47. package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
  48. package/dist/src/execution/tool-auth.d.ts +4 -32
  49. package/dist/src/execution/tool-auth.js +1 -1
  50. package/dist/src/execution/tools/connection-search.js +2 -2
  51. package/dist/src/execution/tools/sleep-workflow.js +1 -1
  52. package/dist/src/execution/tools/subagent/accept-event-step.d.ts +1 -1
  53. package/dist/src/execution/tools/subagent/accept-event-step.js +1 -1
  54. package/dist/src/execution/tools/subagent/invoke-agent.js +1 -1
  55. package/dist/src/execution/tools/subagent/invoke-step.js +1 -1
  56. package/dist/src/execution/tools/workflow/ask.d.ts +3 -2
  57. package/dist/src/execution/tools/workflow/ask.js +1 -1
  58. package/dist/src/execution/tools/workflow/authorization-completion.d.ts +3 -0
  59. package/dist/src/execution/tools/workflow/authorization-completion.js +1 -0
  60. package/dist/src/execution/tools/workflow/body.d.ts +2 -0
  61. package/dist/src/execution/tools/workflow/body.js +1 -1
  62. package/dist/src/execution/tools/workflow/step-context.d.ts +31 -0
  63. package/dist/src/execution/tools/workflow/step-context.js +1 -0
  64. package/dist/src/execution/tools/workflow/step-execution.d.ts +3 -0
  65. package/dist/src/execution/tools/workflow/step-execution.js +1 -0
  66. package/dist/src/execution/tools/workflow/step.d.ts +3 -0
  67. package/dist/src/execution/tools/workflow/step.js +1 -0
  68. package/dist/src/execution/turn-workflow-tool-run.js +1 -1
  69. package/dist/src/execution/wire/session-inbox-contract.d.ts +7 -0
  70. package/dist/src/execution/wire/session-inbox-contract.js +1 -1
  71. package/dist/src/execution/wire/session-inbox-resume.d.ts +2 -0
  72. package/dist/src/execution/wire/session-inbox-resume.js +1 -1
  73. package/dist/src/execution/workflow-steps.js +1 -1
  74. package/dist/src/harness/approval-delivery-coordinator.js +1 -1
  75. package/dist/src/harness/authorization.d.ts +6 -2
  76. package/dist/src/harness/authorization.js +1 -1
  77. package/dist/src/harness/compaction.js +1 -1
  78. package/dist/src/harness/current-messages.d.ts +8 -2
  79. package/dist/src/harness/current-messages.js +1 -1
  80. package/dist/src/harness/hitl/approval-input-requests.js +1 -1
  81. package/dist/src/harness/input-requests.js +1 -1
  82. package/dist/src/harness/pending-input-batches.d.ts +4 -0
  83. package/dist/src/harness/pending-input-batches.js +1 -1
  84. package/dist/src/harness/tool-loop.js +2 -2
  85. package/dist/src/harness/turn-client-context.d.ts +1 -1
  86. package/dist/src/internal/application/package.js +1 -1
  87. package/dist/src/internal/authored-definition/connection.js +1 -1
  88. package/dist/src/internal/authored-package-boundary.js +1 -1
  89. package/dist/src/internal/mock-model-identity.d.ts +2 -0
  90. package/dist/src/internal/mock-model-identity.js +1 -0
  91. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  92. package/dist/src/internal/vercel/build-command.d.ts +2 -1
  93. package/dist/src/internal/vercel/build-command.js +1 -1
  94. package/dist/src/internal/workflow-bundle/builder-support.js +1 -1
  95. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  96. package/dist/src/internal/workflow-bundle/workflow-transformer.d.ts +3 -5
  97. package/dist/src/internal/workflow-bundle/workflow-transformer.js +4 -3
  98. package/dist/src/public/channels/github/checkout.js +1 -1
  99. package/dist/src/public/channels/slack/activity.js +1 -1
  100. package/dist/src/public/tools/index.d.ts +1 -0
  101. package/dist/src/public/tools/index.js +1 -1
  102. package/dist/src/runtime/authorization-context.d.ts +14 -0
  103. package/dist/src/runtime/authorization-context.js +1 -0
  104. package/dist/src/runtime/connections/mcp-client.js +1 -1
  105. package/dist/src/runtime/connections/scoped-authorization.d.ts +18 -2
  106. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  107. package/dist/src/runtime/resolve-connection.js +1 -1
  108. package/dist/src/runtime/sandbox/keys.js +1 -1
  109. package/dist/src/sandbox/backends/default.d.ts +2 -0
  110. package/dist/src/sandbox/backends/default.js +1 -1
  111. package/dist/src/self-modification/agent.d.ts +5 -2
  112. package/dist/src/self-modification/agent.js +1 -1
  113. package/dist/src/self-modification/config.d.ts +52 -0
  114. package/dist/src/self-modification/config.js +1 -0
  115. package/dist/src/self-modification/credentials.d.ts +18 -0
  116. package/dist/src/self-modification/credentials.js +1 -0
  117. package/dist/src/self-modification/extension/eve-add.d.ts +7 -2
  118. package/dist/src/self-modification/extension/eve-add.js +1 -1
  119. package/dist/src/self-modification/extension/extension.d.ts +46 -1
  120. package/dist/src/self-modification/extension/extension.js +1 -1
  121. package/dist/src/self-modification/extension/instructions.js +23 -9
  122. package/dist/src/self-modification/extension/production-registry-add.d.ts +42 -0
  123. package/dist/src/self-modification/extension/production-registry-add.js +1 -0
  124. package/dist/src/self-modification/extension/tools/edit_file.js +1 -1
  125. package/dist/src/self-modification/extension/tools/publish.d.ts +7 -0
  126. package/dist/src/self-modification/extension/tools/publish.js +1 -0
  127. package/dist/src/self-modification/extension/tools/registry_add.d.ts +39 -7
  128. package/dist/src/self-modification/extension/tools/registry_add.js +1 -1
  129. package/dist/src/self-modification/extension/tools/search_registry.d.ts +1 -0
  130. package/dist/src/self-modification/extension/tools/search_registry.js +1 -1
  131. package/dist/src/self-modification/filesystem.js +1 -1
  132. package/dist/src/self-modification/git-workspace.d.ts +31 -0
  133. package/dist/src/self-modification/git-workspace.js +1 -0
  134. package/dist/src/self-modification/git.d.ts +6 -0
  135. package/dist/src/self-modification/git.js +1 -0
  136. package/dist/src/self-modification/github-publisher.d.ts +27 -0
  137. package/dist/src/self-modification/github-publisher.js +2 -0
  138. package/dist/src/self-modification/identifiers.d.ts +4 -0
  139. package/dist/src/self-modification/identifiers.js +1 -0
  140. package/dist/src/self-modification/mode.d.ts +4 -0
  141. package/dist/src/self-modification/mode.js +1 -0
  142. package/dist/src/self-modification/network-policy.d.ts +1 -0
  143. package/dist/src/self-modification/network-policy.js +1 -0
  144. package/dist/src/self-modification/proposal.d.ts +39 -0
  145. package/dist/src/self-modification/proposal.js +2 -0
  146. package/dist/src/self-modification/sandbox.d.ts +25 -1
  147. package/dist/src/self-modification/sandbox.js +1 -1
  148. package/dist/src/self-modification/setup.d.ts +34 -0
  149. package/dist/src/self-modification/setup.js +22 -0
  150. package/dist/src/self-modification/workspace-lock.d.ts +2 -0
  151. package/dist/src/self-modification/workspace-lock.js +1 -0
  152. package/dist/src/setup/integrations/registry.js +1 -1
  153. package/dist/src/setup/integrations/runner.js +1 -1
  154. package/dist/src/setup/integrations/self-modification/setup.d.ts +29 -0
  155. package/dist/src/setup/integrations/self-modification/setup.js +1 -0
  156. package/dist/src/setup/integrations/types.d.ts +2 -0
  157. package/dist/src/setup/integrations/types.js +1 -1
  158. package/dist/src/setup/scaffold/create/project.js +1 -1
  159. package/dist/src/shared/empty-delivery.js +1 -1
  160. package/dist/src/shared/git.d.ts +16 -0
  161. package/dist/src/shared/git.js +1 -0
  162. package/dist/src/shared/shell-quote.d.ts +2 -0
  163. package/dist/src/shared/shell-quote.js +1 -0
  164. package/dist/src/shared/vercel-services.js +1 -1
  165. package/dist/src/tasks/delivery-context.d.ts +2 -2
  166. package/dist/src/tasks/delivery-context.js +2 -18
  167. package/dist/src/tasks/delivery-policy.js +1 -1
  168. package/dist/src/tasks/session-index.d.ts +1 -1
  169. package/dist/src/tasks/session-index.js +1 -1
  170. package/dist/src/tasks/session-task-cohorts.d.ts +10 -0
  171. package/dist/src/tasks/session-task-cohorts.js +1 -0
  172. package/dist/src/tools/durable-callbacks.d.ts +18 -1
  173. package/dist/src/tools/durable-callbacks.js +1 -1
  174. package/dist/src/tools/workflow-definition.d.ts +5 -2
  175. package/docs/channels/overview.mdx +2 -0
  176. package/docs/channels/slack.mdx +2 -0
  177. package/docs/concepts/sessions-runs-and-streaming.md +2 -0
  178. package/docs/evals/reporters.mdx +20 -1
  179. package/docs/evals/running.mdx +3 -1
  180. package/docs/guides/dynamic-capabilities.md +36 -1
  181. package/docs/guides/instrumentation.md +3 -2
  182. package/docs/instructions.mdx +1 -1
  183. package/docs/reference/cli.md +1 -1
  184. package/docs/reference/telemetry.md +1 -1
  185. package/docs/reference/typescript-api.md +36 -35
  186. package/docs/sandbox.mdx +2 -0
  187. package/docs/subagents/index.mdx +10 -0
  188. package/docs/tools/overview.mdx +4 -2
  189. package/docs/tools/workflows.mdx +61 -2
  190. package/package.json +17 -1
  191. package/dist/src/self-modification/extension/source-lock.d.ts +0 -2
  192. package/dist/src/self-modification/extension/source-lock.js +0 -1
@@ -0,0 +1,22 @@
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";
2
+
3
+ export default defineSelfModificationConfig({});
4
+ `;let t=`import { defineSelfModificationConfig } from "eve/self-modification/config";
5
+
6
+ export default defineSelfModificationConfig({
7
+ deployed: {
8
+ source: {
9
+ git: {
10
+ repository: ${JSON.stringify(e.repository)},
11
+ directory: ${JSON.stringify(e.directory)},
12
+ },
13
+ },
14
+ target: { branch: ${JSON.stringify(e.branch)} },
15
+ credentials: {
16
+ vercelConnect: { connector: ${JSON.stringify(e.connector)} },
17
+ },
18
+ },
19
+ });
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(`
21
+ `);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};
@@ -0,0 +1,2 @@
1
+ /** Serializes operations that require an exclusive view of one self-modification workspace. */
2
+ export declare function withSelfModificationWorkspaceLock<T>(workspaceKey: string, operation: () => Promise<T>): Promise<T>;
@@ -0,0 +1 @@
1
+ const workspaceTails=new Map;async function withSelfModificationWorkspaceLock(e,t){let n=workspaceTails.get(e)??Promise.resolve(),r,i=new Promise(e=>{r=e}),a=n.then(()=>i);workspaceTails.set(e,a),await n;try{return await t()}finally{r(),workspaceTails.get(e)===a&&workspaceTails.delete(e)}}export{withSelfModificationWorkspaceLock};
@@ -1 +1 @@
1
- import{DISCORD_SETUP}from"./discord/setup.js";import{FILE_MEMORY_SETUP}from"./file-memory/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,FILE_MEMORY_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
1
+ import{DISCORD_SETUP}from"./discord/setup.js";import{FILE_MEMORY_SETUP}from"./file-memory/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SELF_MODIFICATION_PRODUCTION_SETUP,SELF_MODIFICATION_SETUP}from"./self-modification/setup.js";import{SHOPIFY_SETUP}from"./shopify/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,FILE_MEMORY_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP,SHOPIFY_SETUP,SELF_MODIFICATION_SETUP,SELF_MODIFICATION_PRODUCTION_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
@@ -1 +1 @@
1
- import{createSetupContexts}from"./shared/ui.js";import{setupIntegration}from"./registry.js";import{describeIntegrationSetupEnvironment,integrationSetupEnvironment}from"./shared/environment.js";import{resolveIntegrationVercelProject}from"./shared/vercel-project.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{interactiveAsker}from"#setup/ask.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultDeps={detectDeployment,getVercelAuthStatus};async function runIntegrationSetup(e,t,n=defaultDeps){let r=setupIntegration(e);t.prompter.intro(`Set up ${r.label}`,r.hint),t.prompter.log.message(`Checking Vercel setup...`);let[i,a]=await Promise.all([n.detectDeployment(t.appRoot,{signal:t.signal}),n.getVercelAuthStatus(t.appRoot,{signal:t.signal})]),o=projectResolutionFromDeployment(i),s=integrationSetupEnvironment(a,o);return t.prompter.log.info(describeIntegrationSetupEnvironment(s)),r.run(createSetupContexts({appRoot:t.appRoot,asker:t.asker??interactiveAsker(t.prompter),environment:s,prompter:t.prompter,resolveVercelProject:t.resolveVercelProject??(e=>resolveIntegrationVercelProject({appRoot:t.appRoot,integration:e,signal:t.signal})),signal:t.signal,force:t.force,beginExternalAction:t.beginExternalAction}))}export{runIntegrationSetup};
1
+ import{describeIntegrationSetupEnvironment,integrationSetupEnvironment}from"./shared/environment.js";import{createSetupContexts}from"./shared/ui.js";import{setupIntegration}from"./registry.js";import{resolveIntegrationVercelProject}from"./shared/vercel-project.js";import{detectDeployment,projectResolutionFromDeployment}from"#setup/project-resolution.js";import{interactiveAsker}from"#setup/ask.js";import{getVercelAuthStatus}from"#setup/vercel-project.js";const defaultDeps={detectDeployment,getVercelAuthStatus};async function runIntegrationSetup(e,t,n=defaultDeps){let r=setupIntegration(e);t.prompter.intro(`Set up ${r.label}`,r.hint),t.prompter.log.message(`Checking Vercel setup...`);let[i,a]=await Promise.all([n.detectDeployment(t.appRoot,{signal:t.signal}),n.getVercelAuthStatus(t.appRoot,{signal:t.signal})]),o=projectResolutionFromDeployment(i),s=integrationSetupEnvironment(a,o);return t.prompter.log.info(r.describeEnvironment?.(s)??describeIntegrationSetupEnvironment(s)),r.run(createSetupContexts({appRoot:t.appRoot,asker:t.asker??interactiveAsker(t.prompter),environment:s,prompter:t.prompter,resolveVercelProject:t.resolveVercelProject??(e=>resolveIntegrationVercelProject({appRoot:t.appRoot,integration:e,signal:t.signal})),signal:t.signal,force:t.force,beginExternalAction:t.beginExternalAction}))}export{runIntegrationSetup};
@@ -0,0 +1,29 @@
1
+ import { type SelfModificationSetupOperations, type SelfModificationSetupValues } from "#self-modification/setup.js";
2
+ import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
3
+ type SelfModificationSetupPlan = {
4
+ readonly kind: "authored";
5
+ } | {
6
+ readonly kind: "local";
7
+ } | {
8
+ readonly kind: "deployed";
9
+ readonly connectorName: string;
10
+ readonly values: SelfModificationSetupValues;
11
+ };
12
+ export declare function prepareSelfModificationSetup(context: SetupPrepareContext, operations?: SelfModificationSetupOperations): Promise<SelfModificationSetupPlan>;
13
+ export declare function applySelfModificationSetup(plan: SelfModificationSetupPlan, context: SetupApplyContext, operations?: SelfModificationSetupOperations): Promise<{
14
+ facts: {
15
+ label: string;
16
+ value: string;
17
+ }[];
18
+ deploymentRequired?: undefined;
19
+ } | {
20
+ deploymentRequired: true;
21
+ facts: {
22
+ label: string;
23
+ value: string;
24
+ }[];
25
+ }>;
26
+ export declare function prepareLocalSelfModificationSetup(context: SetupPrepareContext, operations?: SelfModificationSetupOperations): Promise<SelfModificationSetupPlan>;
27
+ export declare const SELF_MODIFICATION_SETUP: import("../types.js").SetupIntegration;
28
+ export declare const SELF_MODIFICATION_PRODUCTION_SETUP: import("../types.js").SetupIntegration;
29
+ export {};
@@ -0,0 +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};
@@ -39,6 +39,7 @@ interface SetupIntegrationDefinition<Plan> {
39
39
  readonly kind: string;
40
40
  readonly label: string;
41
41
  readonly hint?: string;
42
+ describeEnvironment?(environment: IntegrationSetupEnvironment): string;
42
43
  prepare(context: SetupPrepareContext): Promise<Plan>;
43
44
  apply(plan: Plan, context: SetupApplyContext): Promise<RegistrySetupCompletion>;
44
45
  }
@@ -46,6 +47,7 @@ export interface SetupIntegration {
46
47
  readonly kind: string;
47
48
  readonly label: string;
48
49
  hint?: string;
50
+ describeEnvironment?(environment: IntegrationSetupEnvironment): string;
49
51
  run(input: {
50
52
  prepare: SetupPrepareContext;
51
53
  apply: SetupApplyContext;
@@ -1 +1 @@
1
- import{WizardCancelledError}from"#setup/step.js";function defineSetupIntegration(e){let t={kind:e.kind,label:e.label,async run(t){try{let n=await e.prepare(t.prepare);return{kind:`done`,completion:await e.apply(n,t.apply)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}};return e.hint!==void 0&&(t.hint=e.hint),t}export{defineSetupIntegration};
1
+ import{WizardCancelledError}from"#setup/step.js";function defineSetupIntegration(e){let t={kind:e.kind,label:e.label,async run(t){try{let n=await e.prepare(t.prepare);return{kind:`done`,completion:await e.apply(n,t.apply)}}catch(e){if(e instanceof WizardCancelledError)return{kind:`cancelled`};throw e}}};return e.hint!==void 0&&(t.hint=e.hint),e.describeEnvironment!==void 0&&(t.describeEnvironment=e.describeEnvironment),t}export{defineSetupIntegration};
@@ -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.3`,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.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";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -1 +1 @@
1
- const EMPTY_DELIVERY_SENTINEL=`<eve-empty-delivery/>`,CONDITIONAL_DELIVERY_INSTRUCTION=`Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing new to report, reply with exactly ${EMPTY_DELIVERY_SENTINEL} and no other text. This includes results already delivered or incorporated into an earlier response; do not send an acknowledgement of that redundancy. Do not use this marker for ordinary conversations, after input or approval responses, or to omit commentary from a response that still needs delivery. Never return an empty response; use the marker to intentionally deliver nothing.`;function hasEmptyDeliverySentinel(e){return e?.includes(`<eve-empty-delivery/>`)===!0||e?.includes(`&lt;eve-empty-delivery/&gt;`)===!0}export{CONDITIONAL_DELIVERY_INSTRUCTION,EMPTY_DELIVERY_SENTINEL,hasEmptyDeliverySentinel};
1
+ const EMPTY_DELIVERY_SENTINEL=`<eve-empty-delivery/>`,CONDITIONAL_DELIVERY_INSTRUCTION=`Conditional delivery\nOnly when the current task explicitly makes delivery conditional and there is nothing new to report, reply with exactly ${EMPTY_DELIVERY_SENTINEL} and no other text. This includes results already delivered or incorporated into an earlier response; do not send an acknowledgement of that redundancy. Do not use this marker for ordinary conversations, after input or approval responses, or to omit commentary from a response that still needs delivery. Never return an empty response; use the marker to intentionally deliver nothing.`;function hasEmptyDeliverySentinel(e){let t=e?.trim();return t===`<eve-empty-delivery/>`||t===`&lt;eve-empty-delivery/&gt;`}export{CONDITIONAL_DELIVERY_INSTRUCTION,EMPTY_DELIVERY_SENTINEL,hasEmptyDeliverySentinel};
@@ -0,0 +1,16 @@
1
+ import type { SandboxNetworkPolicy } from "./sandbox-network-policy.js";
2
+ /** Returns whether a value is a complete Git object SHA. */
3
+ export declare function isFullGitSha(value: string): boolean;
4
+ /** Returns whether a value can safely be used as a Git ref. */
5
+ export declare function isValidGitRef(value: string): boolean;
6
+ /** Builds the token-free HTTPS remote used by GitHub fetches. */
7
+ export declare function gitHubRemoteUrl(input: {
8
+ readonly owner: string;
9
+ readonly repo: string;
10
+ }): string;
11
+ /**
12
+ * Brokers a GitHub installation token at the sandbox firewall without exposing
13
+ * it to the process running git. codeload.github.com is required for redirects
14
+ * from shallow fetches.
15
+ */
16
+ export declare function gitHubGitBrokerNetworkPolicy(token: string): SandboxNetworkPolicy;
@@ -0,0 +1 @@
1
+ import{Buffer}from"node:buffer";function isFullGitSha(e){return/^[a-f0-9]{40}$/iu.test(e)}function isValidGitRef(e){return!(e.length===0||e.startsWith(`-`)||e.endsWith(`.`)||e.endsWith(`/`)||e.includes(`..`)||e.includes(`//`)||e.includes(`@{`)||e.includes(`\\`)||e.split(`/`).some(e=>e.length===0||e.endsWith(`.lock`))||/[\x00-\x20~^:?*[]/u.test(e))}function gitHubRemoteUrl(e){return`https://github.com/${e.owner}/${e.repo}.git`}function gitHubGitBrokerNetworkPolicy(e){let t=[{transform:[{headers:{Authorization:`Basic ${Buffer.from(`x-access-token:${e}`).toString(`base64`)}`}}]}];return{allow:{"*":[],"github.com":t,"codeload.github.com":t}}}export{gitHubGitBrokerNetworkPolicy,gitHubRemoteUrl,isFullGitSha,isValidGitRef};
@@ -0,0 +1,2 @@
1
+ /** Wraps a value in POSIX single quotes, escaping embedded single quotes. */
2
+ export declare function shellQuote(value: string): string;
@@ -0,0 +1 @@
1
+ function shellQuote(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}export{shellQuote};
@@ -1 +1 @@
1
- import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function quoteShellArgument(e){return`'${e.replaceAll(`'`,`'\\''`)}'`}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e,t){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve ${t} integration cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.hostRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.hostRoot,`.vercel`,`output`),i=toPosixRelative(t,e.appRoot),a=toPosixRelative(e.appRoot,n),o=toPosixRelative(e.appRoot,r),s=e.eveBuildCommand??`node ${quoteShellArgument(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.hostRoot)))} build`;return{buildCommand:`cd ${quoteShellArgument(i)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(a)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${quoteShellArgument(o)} && ${s}`,root:toPosixRelative(e.hostRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(e){let t=await findClosestLinkedVercelDirectory(e.hostRoot),n=t===void 0?e.hostRoot:dirname(t),r=await readVercelJsonConfig(join(e.hostRoot,VERCEL_JSON_FILE_NAME)),i=n===e.hostRoot||Object.keys(createServiceConfigRecord(r.services)).length>0?r:await readVercelJsonConfig(join(n,VERCEL_JSON_FILE_NAME)),a=createServiceConfigRecord(i.services);if(Object.keys(a).length>0)return assertRootServicesIncludeEve(a,e.frameworkName),{mode:`root`};i.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve ${e.frameworkName} integration now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let o=createGeneratedServiceBuild(e);return await mkdir(o.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:o.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:o.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
1
+ import{mkdir,readFile}from"node:fs/promises";import{EVE_ROUTE_PREFIX}from"#protocol/routes.js";import{dirname,join,relative}from"node:path";import{EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV,EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}from"#internal/application/paths.js";import{shellQuote}from"#shared/shell-quote.js";import{findClosestLinkedVercelDirectory}from"#shared/vercel-output-directory.js";import{resolveEveBinaryPath}from"#shared/resolve-eve-binary.js";const VERCEL_JSON_FILE_NAME=`vercel.json`,EVE_SERVICE_ROUTE_SRC=`^${EVE_ROUTE_PREFIX}/(.*)$`,EVE_SERVICE_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/$1`;function isRecord(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function toPosixRelative(e,t){let n=relative(e,t);return n.length===0?`.`:n.replaceAll(`\\`,`/`)}function isNamedServiceConfigArray(e){return Array.isArray(e)}function createServiceConfigRecord(e){if(e===void 0)return{};if(isNamedServiceConfigArray(e)){let t={};for(let n of e)if(typeof n.name==`string`&&n.name.trim().length>0){let{name:e,...r}=n;t[e]=r}return t}return e}function normalizeVercelJsonConfig(e){if(!isRecord(e))throw Error(`${VERCEL_JSON_FILE_NAME} must contain a JSON object.`);let t=e.services;if(t!==void 0&&!isRecord(t)&&!(Array.isArray(t)&&t.every(e=>isRecord(e)&&typeof e.name==`string`&&e.name.trim().length>0)))throw Error(`${VERCEL_JSON_FILE_NAME} services must be a JSON object or named service array.`);return e}async function readVercelJsonConfig(e){try{return normalizeVercelJsonConfig(JSON.parse(await readFile(e,`utf8`)))}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return{};throw e}}function findEveService(e){return Object.values(e).find(e=>e.framework===`eve`)}function assertRootServicesIncludeEve(e,t){if(findEveService(e)===void 0)throw Error(`${VERCEL_JSON_FILE_NAME} already defines services, so the eve ${t} integration cannot add a generated eve service. Add an eve service (framework "eve") and a rewrite from ${EVE_ROUTE_PREFIX}/(.*) to it in ${VERCEL_JSON_FILE_NAME}, or remove services from ${VERCEL_JSON_FILE_NAME}.`)}function createEveServiceRoute(e=`eve`){return{destination:{service:e,type:`service`},src:EVE_SERVICE_ROUTE_SRC}}function createEveServiceRequestPathRoute(){return{src:EVE_SERVICE_ROUTE_SRC,transforms:[{args:EVE_SERVICE_ROUTE_PATH,op:`set`,type:`request.path`}]}}function isEveServiceRoute(e,t){let n=e.destination;return e.src===EVE_SERVICE_ROUTE_SRC&&isRecord(n)&&n.type===`service`&&n.service===t}function insertEveServiceRoute(e,t){let n=e.filter(e=>!(isRecord(e)&&isEveServiceRoute(e,t))),r=n.findIndex(e=>isRecord(e)&&e.handle===`filesystem`);return r===-1?[createEveServiceRoute(t),...n]:[...n.slice(0,r),createEveServiceRoute(t),...n.slice(r)]}function insertEveServiceRequestPathRoute(e){let t=(e??[]).filter(e=>e.src!==EVE_SERVICE_ROUTE_SRC);return[createEveServiceRequestPathRoute(),...t]}function createGeneratedServiceBuild(e){let t=join(e.hostRoot,`.eve/vercel-services`,`eve`),n=join(t,`.vercel`,`output`),r=join(e.hostRoot,`.vercel`,`output`),i=toPosixRelative(t,e.appRoot),a=toPosixRelative(e.appRoot,n),o=toPosixRelative(e.appRoot,r),s=e.eveBuildCommand??`node ${shellQuote(toPosixRelative(e.appRoot,resolveEveBinaryPath(e.hostRoot)))} build`;return{buildCommand:`cd ${shellQuote(i)} && export ${EVE_INTERNAL_BUILD_OUTPUT_DIRECTORY_ENV}=${shellQuote(a)} && export ${EVE_INTERNAL_HOST_BUILD_OUTPUT_DIRECTORY_ENV}=${shellQuote(o)} && ${s}`,root:toPosixRelative(e.hostRoot,t),rootDirectory:t}}async function ensureEveVercelServicesConfig(e){let t=await findClosestLinkedVercelDirectory(e.hostRoot),n=t===void 0?e.hostRoot:dirname(t),r=await readVercelJsonConfig(join(e.hostRoot,VERCEL_JSON_FILE_NAME)),i=n===e.hostRoot||Object.keys(createServiceConfigRecord(r.services)).length>0?r:await readVercelJsonConfig(join(n,VERCEL_JSON_FILE_NAME)),a=createServiceConfigRecord(i.services);if(Object.keys(a).length>0)return assertRootServicesIncludeEve(a,e.frameworkName),{mode:`root`};i.experimentalServices!==void 0&&console.warn(`[eve] ${VERCEL_JSON_FILE_NAME} defines experimentalServices, which Vercel no longer routes. The eve ${e.frameworkName} integration now generates the stable services config automatically — remove experimentalServices from ${VERCEL_JSON_FILE_NAME}.`);let o=createGeneratedServiceBuild(e);return await mkdir(o.rootDirectory,{recursive:!0}),{mode:`generated`,services:{eve:{buildCommand:o.buildCommand,framework:`eve`,routes:[createEveServiceRequestPathRoute()],root:o.root}}}}function mergeEveVercelConfig(e,t){let n=e?.services??{},r=Object.entries(n).find(([e,t])=>e===`eve`||t.framework===`eve`),i=r?.[0]??`eve`,a=r?{...n,[i]:{...r[1],routes:insertEveServiceRequestPathRoute(r[1].routes)}}:{...n,...t.services};return{version:3,...e,routes:insertEveServiceRoute(e?.routes??[],i),services:a}}export{createEveServiceRequestPathRoute,createEveServiceRoute,ensureEveVercelServicesConfig,mergeEveVercelConfig};
@@ -1,7 +1,6 @@
1
1
  import type { SessionStateMap } from "#harness/types.js";
2
2
  export declare const TASK_DELIVERY_CONTEXT_LABEL = "[Task state]";
3
- export declare const TASK_DELIVERY_INITIATING_INSTRUCTION = "Background task reporting: launch acknowledgement\nThe accompanying [Task state] system message is runtime-authored and lists background tasks accepted so far from the current turn. They continue independently after this turn.\n\nContinue carrying out the user's request, including starting any remaining background work. When no further tool calls are needed in this turn, send one brief user-facing acknowledgement that the background work has started. Do not wait for results or report results that are not available yet. End the turn after the acknowledgement.";
4
- export declare const TASK_DELIVERY_PENDING_INSTRUCTION = "Background task control: incomplete cohort\nThis framework-authored instruction overrides any earlier instruction to report, summarize, acknowledge, or otherwise handle background results.\n\nThe accompanying [Task state] message is runtime-authored and lists tasks started by the same parent turn. At least one of those tasks is still pending, so the combined report is not ready.\n\nAction:\n- You may call tools only if the newly delivered task result requires immediate action.\n- Otherwise, take no action.\n\nDelivery:\n- Do not report completed tasks or partial results.\n- Do not provide progress, status, an acknowledgement, or a waiting message.\n- After any necessary tool calls, your entire final text response must be exactly <eve-empty-delivery/> and no other text.\n\nIncorrect: \"Two of three tasks have completed.\"\nIncorrect: \"Still waiting for the remaining task.\"\nCorrect: <eve-empty-delivery/>";
3
+ export declare const TASK_DELIVERY_INITIATING_INSTRUCTION = "Background task reporting: launch acknowledgement\nThe latest [Task state] message is runtime-authored and lists background tasks accepted so far from the current turn. They continue independently after this turn.\n\nContinue carrying out the user's request, including starting any remaining background work. When no further tool calls are needed in this turn, send one brief user-facing acknowledgement that the background work has started. Do not wait for results or report results that are not available yet. End the turn after the acknowledgement.";
5
4
  export declare const TASK_DELIVERY_SETTLED_INSTRUCTION = "Background task reporting\nThis turn was triggered by background task activity. The accompanying [Task state] message is runtime-authored and lists tasks started by the same parent turn, all settled, with every available terminal output. Do not reply with <eve-empty-delivery/>. Send one user-facing response that combines their useful results.";
6
5
  /** Returns model context and cohort phase for tasks started by the same parent turn as this delivery. */
7
6
  export declare function resolveTaskDeliveryContext(input: {
@@ -10,6 +9,7 @@ export declare function resolveTaskDeliveryContext(input: {
10
9
  }): {
11
10
  readonly context: string;
12
11
  readonly phase: "pending" | "settled";
12
+ readonly rootTurnId: string;
13
13
  } | undefined;
14
14
  /** Returns model context for durable tasks launched by the active parent turn. */
15
15
  export declare function resolveInitiatingTaskContext(input: {
@@ -1,20 +1,4 @@
1
1
  import{getSessionTaskIndex}from"#tasks/session-index.js";import{EMPTY_DELIVERY_SENTINEL}from"#shared/empty-delivery.js";const TASK_DELIVERY_CONTEXT_LABEL=`[Task state]`,TASK_DELIVERY_INITIATING_INSTRUCTION=`Background task reporting: launch acknowledgement
2
- The accompanying ${TASK_DELIVERY_CONTEXT_LABEL} system message is runtime-authored and lists background tasks accepted so far from the current turn. They continue independently after this turn.
2
+ The latest ${TASK_DELIVERY_CONTEXT_LABEL} message is runtime-authored and lists background tasks accepted so far from the current turn. They continue independently after this turn.
3
3
 
4
- Continue carrying out the user's request, including starting any remaining background work. When no further tool calls are needed in this turn, send one brief user-facing acknowledgement that the background work has started. Do not wait for results or report results that are not available yet. End the turn after the acknowledgement.`,TASK_DELIVERY_PENDING_INSTRUCTION=`Background task control: incomplete cohort
5
- This framework-authored instruction overrides any earlier instruction to report, summarize, acknowledge, or otherwise handle background results.
6
-
7
- The accompanying ${TASK_DELIVERY_CONTEXT_LABEL} message is runtime-authored and lists tasks started by the same parent turn. At least one of those tasks is still pending, so the combined report is not ready.
8
-
9
- Action:
10
- - You may call tools only if the newly delivered task result requires immediate action.
11
- - Otherwise, take no action.
12
-
13
- Delivery:
14
- - Do not report completed tasks or partial results.
15
- - Do not provide progress, status, an acknowledgement, or a waiting message.
16
- - After any necessary tool calls, your entire final text response must be exactly ${EMPTY_DELIVERY_SENTINEL} and no other text.
17
-
18
- Incorrect: "Two of three tasks have completed."
19
- Incorrect: "Still waiting for the remaining task."
20
- Correct: ${EMPTY_DELIVERY_SENTINEL}`,TASK_DELIVERY_SETTLED_INSTRUCTION=`Background task reporting\nThis turn was triggered by background task activity. The accompanying ${TASK_DELIVERY_CONTEXT_LABEL} message is runtime-authored and lists tasks started by the same parent turn, all settled, with every available terminal output. Do not reply with ${EMPTY_DELIVERY_SENTINEL}. Send one user-facing response that combines their useful results.`;function resolveTaskDeliveryContext(e){let t=getSessionTaskIndex(e.state),n=t.find(t=>e.taskDeliveryId.startsWith(`${t.taskId}:`));return n===void 0?void 0:projectTaskCohort(t.filter(e=>e.createdByTurnId===n.createdByTurnId))}function resolveInitiatingTaskContext(e){let t=getSessionTaskIndex(e.state).filter(t=>t.createdByTurnId===e.turnId);if(t.some(e=>e.executor!==void 0&&e.terminalView===void 0))return{...projectTaskCohort(t),phase:`initiating`}}function projectTaskCohort(e){let t=e.every(e=>e.terminalView!==void 0),n=e.map(e=>({name:e.metadata.name,output:t?e.terminalView?.lastOutput:void 0,status:e.terminalView?.status??`pending`,taskId:e.taskId}));return{context:`${TASK_DELIVERY_CONTEXT_LABEL}\n${JSON.stringify({tasks:n})}`,phase:t?`settled`:`pending`}}export{TASK_DELIVERY_CONTEXT_LABEL,TASK_DELIVERY_INITIATING_INSTRUCTION,TASK_DELIVERY_PENDING_INSTRUCTION,TASK_DELIVERY_SETTLED_INSTRUCTION,resolveInitiatingTaskContext,resolveTaskDeliveryContext};
4
+ Continue carrying out the user's request, including starting any remaining background work. When no further tool calls are needed in this turn, send one brief user-facing acknowledgement that the background work has started. Do not wait for results or report results that are not available yet. End the turn after the acknowledgement.`,TASK_DELIVERY_SETTLED_INSTRUCTION=`Background task reporting\nThis turn was triggered by background task activity. The accompanying ${TASK_DELIVERY_CONTEXT_LABEL} message is runtime-authored and lists tasks started by the same parent turn, all settled, with every available terminal output. Do not reply with ${EMPTY_DELIVERY_SENTINEL}. Send one user-facing response that combines their useful results.`;function resolveTaskDeliveryContext(e){let t=getSessionTaskIndex(e.state),n=t.find(t=>e.taskDeliveryId.startsWith(`${t.taskId}:`));return n===void 0?void 0:{...projectTaskCohort(t.filter(e=>e.createdByTurnId===n.createdByTurnId)),rootTurnId:n.createdByTurnId}}function resolveInitiatingTaskContext(e){let t=getSessionTaskIndex(e.state).filter(t=>t.createdByTurnId===e.turnId);if(t.some(e=>e.executor!==void 0&&e.terminalView===void 0))return{...projectTaskCohort(t),phase:`initiating`}}function projectTaskCohort(e){let t=e.every(e=>e.terminalView!==void 0),n=e.map(e=>({name:e.metadata.name,output:t?e.terminalView?.lastOutput:void 0,status:e.terminalView?.status??`pending`,taskId:e.taskId}));return{context:`${TASK_DELIVERY_CONTEXT_LABEL}\n${JSON.stringify({tasks:n})}`,phase:t?`settled`:`pending`}}export{TASK_DELIVERY_CONTEXT_LABEL,TASK_DELIVERY_INITIATING_INSTRUCTION,TASK_DELIVERY_SETTLED_INSTRUCTION,resolveInitiatingTaskContext,resolveTaskDeliveryContext};
@@ -1 +1 @@
1
- import{TASK_DELIVERY_INITIATING_INSTRUCTION,TASK_DELIVERY_PENDING_INSTRUCTION,TASK_DELIVERY_SETTLED_INSTRUCTION}from"#tasks/delivery-context.js";import{CONDITIONAL_DELIVERY_INSTRUCTION}from"#shared/empty-delivery.js";const POLICIES={conditional:{allowsEmptyDelivery:!0,instruction:CONDITIONAL_DELIVERY_INSTRUCTION},initiating:{allowsEmptyDelivery:!1,instruction:TASK_DELIVERY_INITIATING_INSTRUCTION},normal:{allowsEmptyDelivery:!1},pending:{allowsEmptyDelivery:!0,instruction:TASK_DELIVERY_PENDING_INSTRUCTION},settled:{allowsEmptyDelivery:!1,instruction:TASK_DELIVERY_SETTLED_INSTRUCTION}};function resolveDeliveryPolicy(e){return e.hasOutputSchema||e.isChild?POLICIES.normal:e.taskDeliveryPhase===`pending`?POLICIES.pending:e.taskDeliveryPhase===`settled`?POLICIES.settled:e.isFirstTurn&&e.hasScheduleProvenance?POLICIES.conditional:e.taskDeliveryPhase===`initiating`?POLICIES.initiating:POLICIES.normal}export{resolveDeliveryPolicy};
1
+ import{TASK_DELIVERY_INITIATING_INSTRUCTION,TASK_DELIVERY_SETTLED_INSTRUCTION}from"#tasks/delivery-context.js";import{CONDITIONAL_DELIVERY_INSTRUCTION}from"#shared/empty-delivery.js";const POLICIES={conditional:{allowsEmptyDelivery:!0,instruction:CONDITIONAL_DELIVERY_INSTRUCTION},initiating:{allowsEmptyDelivery:!1,instruction:TASK_DELIVERY_INITIATING_INSTRUCTION},normal:{allowsEmptyDelivery:!1},pending:{allowsEmptyDelivery:!0},settled:{allowsEmptyDelivery:!1,instruction:TASK_DELIVERY_SETTLED_INSTRUCTION}};function resolveDeliveryPolicy(e){return e.hasOutputSchema||e.isChild?POLICIES.normal:e.taskDeliveryPhase===`pending`?POLICIES.pending:e.taskDeliveryPhase===`settled`?POLICIES.settled:e.isFirstTurn&&e.hasScheduleProvenance?POLICIES.conditional:e.taskDeliveryPhase===`initiating`?POLICIES.initiating:POLICIES.normal}export{resolveDeliveryPolicy};
@@ -10,7 +10,7 @@ import { type TaskMetadata, type TaskView } from "#tasks/types.js";
10
10
  * threads through step results, while callback routes and child
11
11
  * executors must update tasks without holding the current snapshot.
12
12
  */
13
- export declare const SESSION_TASKS_STATE_KEY = "eve.tasks";
13
+ export { SESSION_TASKS_STATE_KEY } from "#tasks/session-task-cohorts.js";
14
14
  /**
15
15
  * One task owned by this session. Immutable model-safe metadata keeps the
16
16
  * task-to-agent join available before the task run publishes its first view.
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{sameTaskMetadata}from"#tasks/types.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,taskMetadataSchema=z.looseObject({kind:z.string().min(1),name:z.string().min(1)}),taskViewBaseShape={executor:z.strictObject({binding:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),executor:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema),version:z.literal(2)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let t=e?.[SESSION_TASKS_STATE_KEY];if(t===void 0)return[];let n=typeof t==`object`&&t?Reflect.get(t,`version`):void 0;if(n!==2)throw Error(`Unsupported task index version ${JSON.stringify(n)} under session state key "${SESSION_TASKS_STATE_KEY}"; expected version 2.`);let r=sessionTaskIndexSchema.safeParse(t);if(!r.success)throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": ${r.error.message}`);return r.data.tasks}function cacheTerminalTaskView(e,t){if(!isValidTerminalView(t))throw Error(`Cannot cache invalid terminal task "${t.taskId}".`);let n=getSessionTaskIndex(e),r=n.findIndex(e=>e.taskId===t.taskId);if(r<0)return e;if(!sameTaskMetadata(n[r].metadata,t.metadata))throw Error(`Task view metadata does not match index entry "${t.taskId}".`);let i=[...n];return i[r]={...i[r],terminalView:t},{...e,[SESSION_TASKS_STATE_KEY]:{tasks:i,version:2}}}function isValidTerminalView(e){if(e.inputRequests!==void 0)return!1;switch(e.status){case`completed`:return e.lastOutput?.type===`result`;case`failed`:return e.lastOutput?.type===`error`;case`cancelled`:return e.lastOutput===void 0;case`working`:return!1}}function findSessionTaskEntry(e,t){return getSessionTaskIndex(e).find(e=>e.taskId===t)}function recordSessionTask(e,t){let n=[...getSessionTaskIndex(e.state).filter(e=>e.taskId!==t.taskId),t];return{...e,state:{...e.state,[SESSION_TASKS_STATE_KEY]:{tasks:n,version:2}}}}export{SESSION_TASKS_STATE_KEY,cacheTerminalTaskView,findSessionTaskEntry,getSessionTaskIndex,recordSessionTask};
1
+ import{z}from"#compiled/zod/index.js";import{SESSION_TASKS_STATE_KEY,SESSION_TASKS_STATE_KEY as SESSION_TASKS_STATE_KEY$1,SESSION_TASKS_STATE_VERSION}from"#tasks/session-task-cohorts.js";import{sameTaskMetadata}from"#tasks/types.js";const taskMetadataSchema=z.looseObject({kind:z.string().min(1),name:z.string().min(1)}),taskViewBaseShape={executor:z.strictObject({binding:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional()}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),usage:z.strictObject({cacheReadTokens:z.number().nonnegative(),cacheWriteTokens:z.number().nonnegative(),inputTokens:z.number().nonnegative(),outputTokens:z.number().nonnegative()}).optional()},taskViewSchema=z.discriminatedUnion(`status`,[z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`result`)}),status:z.literal(`completed`)}),z.strictObject({...taskViewBaseShape,lastOutput:z.strictObject({data:z.custom(),type:z.literal(`error`)}),status:z.literal(`failed`)}),z.strictObject({...taskViewBaseShape,status:z.literal(`cancelled`)})]),sessionTaskIndexEntrySchema=z.strictObject({taskInboxToken:z.string().min(1),createdByStepIndex:z.number().int().nonnegative().optional(),createdByTurnId:z.string().min(1),executor:z.strictObject({data:z.record(z.string(),z.custom()),kind:z.string().min(1)}).optional(),metadata:taskMetadataSchema,taskId:z.string().min(1),taskRunId:z.string().min(1),terminalView:taskViewSchema.optional()}),sessionTaskIndexSchema=z.strictObject({tasks:z.array(sessionTaskIndexEntrySchema),version:z.literal(SESSION_TASKS_STATE_VERSION)}).refine(e=>new Set(e.tasks.map(e=>e.taskId)).size===e.tasks.length,{message:`Task ids must be unique.`}).refine(e=>e.tasks.every(e=>e.terminalView===void 0||e.terminalView.taskId===e.taskId&&sameTaskMetadata(e.terminalView.metadata,e.metadata)),{message:`Cached terminal views must match their task index entry.`});function getSessionTaskIndex(e){let t=e?.[SESSION_TASKS_STATE_KEY$1];if(t===void 0)return[];let n=typeof t==`object`&&t?Reflect.get(t,`version`):void 0;if(n!==SESSION_TASKS_STATE_VERSION)throw Error(`Unsupported task index version ${JSON.stringify(n)} under session state key "${SESSION_TASKS_STATE_KEY$1}"; expected version ${SESSION_TASKS_STATE_VERSION}.`);let r=sessionTaskIndexSchema.safeParse(t);if(!r.success)throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY$1}": ${r.error.message}`);return r.data.tasks}function cacheTerminalTaskView(e,t){if(!isValidTerminalView(t))throw Error(`Cannot cache invalid terminal task "${t.taskId}".`);let n=getSessionTaskIndex(e),r=n.findIndex(e=>e.taskId===t.taskId);if(r<0)return e;if(!sameTaskMetadata(n[r].metadata,t.metadata))throw Error(`Task view metadata does not match index entry "${t.taskId}".`);let i=[...n];return i[r]={...i[r],terminalView:t},{...e,[SESSION_TASKS_STATE_KEY$1]:{tasks:i,version:SESSION_TASKS_STATE_VERSION}}}function isValidTerminalView(e){if(e.inputRequests!==void 0)return!1;switch(e.status){case`completed`:return e.lastOutput?.type===`result`;case`failed`:return e.lastOutput?.type===`error`;case`cancelled`:return e.lastOutput===void 0;case`working`:return!1}}function findSessionTaskEntry(e,t){return getSessionTaskIndex(e).find(e=>e.taskId===t)}function recordSessionTask(e,t){let n=[...getSessionTaskIndex(e.state).filter(e=>e.taskId!==t.taskId),t];return{...e,state:{...e.state,[SESSION_TASKS_STATE_KEY$1]:{tasks:n,version:SESSION_TASKS_STATE_VERSION}}}}export{SESSION_TASKS_STATE_KEY,cacheTerminalTaskView,findSessionTaskEntry,getSessionTaskIndex,recordSessionTask};
@@ -0,0 +1,10 @@
1
+ import type { SessionStateMap } from "#harness/types.js";
2
+ /** Session-state key for the parent's task index; mutable task records live in task runs. */
3
+ export declare const SESSION_TASKS_STATE_KEY = "eve.tasks";
4
+ export declare const SESSION_TASKS_STATE_VERSION = 2;
5
+ /**
6
+ * Reads only the identities needed for workflow-side completion batching.
7
+ * Full task validation stays in getSessionTaskIndex on the step side, so
8
+ * the workflow bundle does not retain the task schemas and their dependencies.
9
+ */
10
+ export declare function getSessionTaskCohorts(state: SessionStateMap | undefined): ReadonlyMap<string, string>;
@@ -0,0 +1 @@
1
+ import{isNonEmptyString,isObject}from"#shared/guards.js";const SESSION_TASKS_STATE_KEY=`eve.tasks`,SESSION_TASKS_STATE_VERSION=2;function getSessionTaskCohorts(e){let t=new Map,n=e?.[SESSION_TASKS_STATE_KEY];if(n===void 0)return t;if(!isObject(n)||n.version!==2)throw Error(`Unsupported task index version under session state key "${SESSION_TASKS_STATE_KEY}".`);if(!Array.isArray(n.tasks))throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": expected tasks array.`);for(let e of n.tasks){if(!isObject(e)||!isNonEmptyString(e.taskId)||!isNonEmptyString(e.createdByTurnId)||t.has(e.taskId))throw Error(`Corrupt task index under session state key "${SESSION_TASKS_STATE_KEY}": invalid task cohort identity.`);t.set(e.taskId,e.createdByTurnId)}return t}export{SESSION_TASKS_STATE_KEY,SESSION_TASKS_STATE_VERSION,getSessionTaskCohorts};
@@ -1,5 +1,5 @@
1
1
  import type { Approval } from "#approval/definition.js";
2
- import type { JsonObject } from "#shared/json.js";
2
+ import type { JsonObject, JsonPrimitive } from "#shared/json.js";
3
3
  export type DurableDynamicCallbackPhase = "labelComplete" | "labelDelta" | "labelStart" | "approvalKey" | "approvalRequest" | "approvalResponse" | "execute" | "toModelOutput";
4
4
  export type DurableDynamicCallbackFn = (closure: JsonObject, ...args: never[]) => unknown;
5
5
  /**
@@ -71,6 +71,22 @@ export declare function hasUnregisteredDurableDynamicCallbacks(metadata: readonl
71
71
  resolverSlug: string;
72
72
  entryKey: string;
73
73
  }[], scope: Pick<DynamicToolCallbackOwner, "sessionId" | "scope">): boolean;
74
+ type DurableCallbackJsonValue<T> = T extends (...args: never[]) => unknown ? never : T extends JsonPrimitive ? T : T extends readonly (infer TItem)[] ? readonly DurableCallbackJsonValue<TItem>[] : T extends object ? DurableCallbackJsonObject<T> : never;
75
+ type DurableCallbackJsonObject<T extends object> = Extract<keyof T, symbol> extends never ? {
76
+ readonly [TKey in keyof T]: DurableCallbackJsonValue<Exclude<T[TKey], undefined>> | Extract<T[TKey], undefined>;
77
+ } : never;
78
+ /**
79
+ * Defines a replayable callback for tools created outside eve's authored-source
80
+ * transform, such as tools returned by a provider package.
81
+ *
82
+ * Put every per-tool value in `closure`. eve snapshots that JSON-serializable
83
+ * object when the dynamic tool resolves and passes it as the first argument to
84
+ * the current callback implementation during both live execution and replay.
85
+ */
86
+ export declare function defineDurableCallback<TClosure extends object, TArgs extends unknown[], TResult>(input: {
87
+ readonly callback: (closure: TClosure, ...args: TArgs) => TResult;
88
+ readonly closure: TClosure & DurableCallbackJsonObject<TClosure>;
89
+ }): (...args: TArgs) => TResult;
74
90
  /** Marks a live callback with the descriptor needed to register it at resolve time. */
75
91
  export declare function stampDurableDynamicCallback<TCallback extends (...args: never[]) => unknown>(callback: TCallback, descriptor: StampedDurableDynamicCallback): TCallback;
76
92
  export declare function readDurableDynamicCallback(callback: unknown): StampedDurableDynamicCallback | undefined;
@@ -88,3 +104,4 @@ export declare function collectDurableDynamicToolCallbacks(input: {
88
104
  readonly toModelOutput?: (...args: never[]) => unknown;
89
105
  }): LiveDurableDynamicToolCallbacks;
90
106
  export declare function readDurableDynamicToolCallbacks(definition: object): LiveDurableDynamicToolCallbacks | undefined;
107
+ export {};
@@ -1 +1 @@
1
- import{resolveApprovalPolicy}from"#approval/definition.js";const STAMPED_CALLBACK=Symbol.for(`eve:durable-dynamic-callback`),DURABLE_DYNAMIC_TOOL_CALLBACKS=Symbol.for(`eve:durable-dynamic-tool-callbacks`),REGISTRY=Symbol.for(`eve:scoped-dynamic-tool-callbacks`);function getRegistry(){let e=globalThis;return e[REGISTRY]??=new Map}function getSessionBindings(e){let t=getRegistry(),n=t.get(e);return n!==void 0&&(t.delete(e),t.set(e,n)),n}function callbackKey(e,t){return JSON.stringify([e.scope,e.resolverSlug,e.entryKey,e.name,t])}function registerDurableDynamicCallback(e){let t=getRegistry(),n=getSessionBindings(e.owner.sessionId);n===void 0&&(n=new Map,t.set(e.owner.sessionId,n),t.size>1024&&t.delete(t.keys().next().value)),n.set(callbackKey(e.owner,e.phase),e.callback)}function lookupDurableDynamicCallback(e,t){return getSessionBindings(e.sessionId)?.get(callbackKey(e,t))}function clearDurableDynamicCallbacks(e,t){if(t===void 0){getRegistry().delete(e);return}let n=getSessionBindings(e);if(n===void 0)return;let r=JSON.stringify([t.scope,t.resolverSlug]).slice(0,-1)+`,`;for(let e of n.keys())e.startsWith(r)&&n.delete(e)}function callDurableDynamicCallback(e,t,...n){return e(t,...n)}function hasUnregisteredDurableDynamicCallbacks(e,t){return e.some(e=>durableCallbackPhases(e.callbacks).some(n=>lookupDurableDynamicCallback({...e,...t},n)===void 0))}function durableCallbackPhases(e){return[[`execute`,e.execute],[`labelComplete`,e.label?.complete],[`labelDelta`,e.label?.delta],[`labelStart`,e.label?.start],[`approvalKey`,e.approvalKey],[`approvalRequest`,e.approvalRequest],[`approvalResponse`,e.approvalResponse],[`toModelOutput`,e.toModelOutput]].flatMap(([e,t])=>t===void 0?[]:[e])}function stampDurableDynamicCallback(e,t){return Object.defineProperty(e,STAMPED_CALLBACK,{configurable:!0,value:t}),e}function readDurableDynamicCallback(e){if(typeof e==`function`)return Reflect.get(e,STAMPED_CALLBACK)}function stampDurableDynamicToolCallbacks(e,t){Object.defineProperty(e,DURABLE_DYNAMIC_TOOL_CALLBACKS,{configurable:!0,value:t})}function collectDurableDynamicToolCallbacks(e){let t=readDurableDynamicCallback(e.label?.complete),n=readDurableDynamicCallback(e.label?.delta),r=readDurableDynamicCallback(e.label?.start),i=e.approval===void 0?void 0:readDurableDynamicCallback(resolveApprovalPolicy(e.approval)),a=e.approval===void 0||typeof e.approval==`function`?void 0:readDurableDynamicCallback(e.approval.response),o=readDurableDynamicCallback(e.approvalKey),s=readDurableDynamicCallback(e.execute),c=readDurableDynamicCallback(e.toModelOutput),l={};return s!==void 0&&(l.execute=s),(t!==void 0||n!==void 0||r!==void 0)&&(l.label={complete:t,delta:n,start:r}),o!==void 0&&(l.approvalKey=o),i!==void 0&&(l.approvalRequest=i),a!==void 0&&(l.approvalResponse=a),c!==void 0&&(l.toModelOutput=c),l}function readDurableDynamicToolCallbacks(e){return e[DURABLE_DYNAMIC_TOOL_CALLBACKS]}export{DURABLE_DYNAMIC_TOOL_CALLBACKS,callDurableDynamicCallback,clearDurableDynamicCallbacks,collectDurableDynamicToolCallbacks,hasUnregisteredDurableDynamicCallbacks,lookupDurableDynamicCallback,readDurableDynamicCallback,readDurableDynamicToolCallbacks,registerDurableDynamicCallback,stampDurableDynamicCallback,stampDurableDynamicToolCallbacks};
1
+ import{resolveApprovalPolicy}from"#approval/definition.js";const STAMPED_CALLBACK=Symbol.for(`eve:durable-dynamic-callback`),DURABLE_DYNAMIC_TOOL_CALLBACKS=Symbol.for(`eve:durable-dynamic-tool-callbacks`),REGISTRY=Symbol.for(`eve:scoped-dynamic-tool-callbacks`);function getRegistry(){let e=globalThis;return e[REGISTRY]??=new Map}function getSessionBindings(e){let t=getRegistry(),n=t.get(e);return n!==void 0&&(t.delete(e),t.set(e,n)),n}function callbackKey(e,t){return JSON.stringify([e.scope,e.resolverSlug,e.entryKey,e.name,t])}function registerDurableDynamicCallback(e){let t=getRegistry(),n=getSessionBindings(e.owner.sessionId);n===void 0&&(n=new Map,t.set(e.owner.sessionId,n),t.size>1024&&t.delete(t.keys().next().value)),n.set(callbackKey(e.owner,e.phase),e.callback)}function lookupDurableDynamicCallback(e,t){return getSessionBindings(e.sessionId)?.get(callbackKey(e,t))}function clearDurableDynamicCallbacks(e,t){if(t===void 0){getRegistry().delete(e);return}let n=getSessionBindings(e);if(n===void 0)return;let r=JSON.stringify([t.scope,t.resolverSlug]).slice(0,-1)+`,`;for(let e of n.keys())e.startsWith(r)&&n.delete(e)}function callDurableDynamicCallback(e,t,...n){return e(t,...n)}function hasUnregisteredDurableDynamicCallbacks(e,t){return e.some(e=>durableCallbackPhases(e.callbacks).some(n=>lookupDurableDynamicCallback({...e,...t},n)===void 0))}function durableCallbackPhases(e){return[[`execute`,e.execute],[`labelComplete`,e.label?.complete],[`labelDelta`,e.label?.delta],[`labelStart`,e.label?.start],[`approvalKey`,e.approvalKey],[`approvalRequest`,e.approvalRequest],[`approvalResponse`,e.approvalResponse],[`toModelOutput`,e.toModelOutput]].flatMap(([e,t])=>t===void 0?[]:[e])}function defineDurableCallback(e){return stampDurableDynamicCallback((...t)=>e.callback(e.closure,...t),{callback:(t,...n)=>Reflect.apply(e.callback,void 0,[t,...n]),closure:e.closure})}function stampDurableDynamicCallback(e,t){return Object.defineProperty(e,STAMPED_CALLBACK,{configurable:!0,value:t}),e}function readDurableDynamicCallback(e){if(typeof e==`function`)return Reflect.get(e,STAMPED_CALLBACK)}function stampDurableDynamicToolCallbacks(e,t){Object.defineProperty(e,DURABLE_DYNAMIC_TOOL_CALLBACKS,{configurable:!0,value:t})}function collectDurableDynamicToolCallbacks(e){let t=readDurableDynamicCallback(e.label?.complete),n=readDurableDynamicCallback(e.label?.delta),r=readDurableDynamicCallback(e.label?.start),i=e.approval===void 0?void 0:readDurableDynamicCallback(resolveApprovalPolicy(e.approval)),a=e.approval===void 0||typeof e.approval==`function`?void 0:readDurableDynamicCallback(e.approval.response),o=readDurableDynamicCallback(e.approvalKey),s=readDurableDynamicCallback(e.execute),c=readDurableDynamicCallback(e.toModelOutput),l={};return s!==void 0&&(l.execute=s),(t!==void 0||n!==void 0||r!==void 0)&&(l.label={complete:t,delta:n,start:r}),o!==void 0&&(l.approvalKey=o),i!==void 0&&(l.approvalRequest=i),a!==void 0&&(l.approvalResponse=a),c!==void 0&&(l.toModelOutput=c),l}function readDurableDynamicToolCallbacks(e){return e[DURABLE_DYNAMIC_TOOL_CALLBACKS]}export{DURABLE_DYNAMIC_TOOL_CALLBACKS,callDurableDynamicCallback,clearDurableDynamicCallbacks,collectDurableDynamicToolCallbacks,defineDurableCallback,hasUnregisteredDurableDynamicCallbacks,lookupDurableDynamicCallback,readDurableDynamicCallback,readDurableDynamicToolCallbacks,registerDurableDynamicCallback,stampDurableDynamicCallback,stampDurableDynamicToolCallbacks};
@@ -11,8 +11,11 @@ export interface AgentInput {
11
11
  readonly outputSchema?: JsonObject;
12
12
  readonly target: string;
13
13
  }
14
- /** Context supplied only to a defineWorkflowTool executor, inside its durable run. */
15
- export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName"> & {
14
+ /**
15
+ * Context supplied to a workflow tool. Pass it directly to a step helper for
16
+ * getToken/requireAuth; those capabilities throw in the workflow body itself.
17
+ */
18
+ export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName" | "getToken" | "requireAuth"> & {
16
19
  /** Invoke a visible subagent. The key must be unique within this workflow run. */
17
20
  agent(input: AgentInput): Promise<JsonValue>;
18
21
  /** Ask the human on the session's channel; awaiting the answer suspends the run. */
@@ -28,6 +28,8 @@ export default defineChannel({
28
28
  });
29
29
  ```
30
30
 
31
+ Adjacent queued messages can combine into one turn only when their full auth contexts match, including identity, issuer, authenticator, and authorization attributes. Their attachments and context stay in payload order. A different auth context ends the batch; eve does not regroup messages across intervening senders. Anonymous deliveries stay separate. Turns still share the session's conversation history.
32
+
31
33
  `from(address).send(...)`, fixed `Session.send(...)`, cross-channel sends, and Chat SDK bridge sends also accept a per-send `turnPolicy` override. Pure `inputResponses` deliveries answer their pending request without steering. Explicit `cancel()` remains the stop-without-replacement operation.
32
34
 
33
35
  Channel admission still runs first. Ignored mentions, rejected signatures, duplicates, and any other dropped platform events never affect the active turn.
@@ -294,6 +294,8 @@ export default slackChannel({
294
294
  });
295
295
  ```
296
296
 
297
+ With `"queue"`, adjacent messages with matching full auth contexts can combine into one turn, keeping their attachments and context in order. Messages from different users, or from the same user with different authorization attributes, stay separate. Anonymous deliveries also stay separate. Batching follows session-inbox order, and turns still share the thread's session history.
298
+
297
299
  Message hooks (`onMessage`, `onAppMention`, and `onDirectMessage`) also receive thread-bound session operations directly on `ctx`. `ctx.cancel({ turnId? })` remains useful for a Stop button: it cancels without sending replacement input. `"accepted"` means the live thread session durably queued that request; a parked session consumes it as a no-op, and `"no_active_turn"` means the thread has no active session owner.
298
300
 
299
301
  Message and interaction hooks expose every current-owner operation directly on `ctx`:
@@ -95,6 +95,8 @@ Note: consider the privacy, confidentiality, and user-experience implications fo
95
95
 
96
96
  `message.completed` can fire more than once in a turn: the agent often emits interim assistant text before a tool call. To tell tool-call narration from a terminal reply, check `message.completed.data.finishReason`. `step.completed.data.finishReason` mirrors the step outcome, and usage lives on `step.completed`.
97
97
 
98
+ When a task explicitly requires conditional delivery and there is nothing new to report, the agent can finish with exactly `<eve-empty-delivery/>`. eve emits `message.completed` with `message: null` for that intentional silence. The marker must be the entire response, apart from surrounding whitespace; the HTML-escaped form `&lt;eve-empty-delivery/&gt;` is also accepted. A response that quotes the marker in prose or code is delivered normally.
99
+
98
100
  A delegated subagent publishes progress on its own child-session stream. The parent emits `subagent.called` with a `childSessionId`, which a client uses to attach. `subagent.completed` carries a working task receipt after admission; later updates and outcomes arrive as task-triggered `message.received` notifications.
99
101
 
100
102
  `step.failed` and `turn.failed` carry `{ code, message, details? }` for the failed fragment or turn, and `session.failed` is the terminal session-level variant. `turn.cancelled` is not a failure: the cancelled turn ends without any failure event, `session.waiting` follows, and the session accepts the next message normally. Whatever the turn streamed before cancellation stays on the stream. Durable history keeps the accepted user input and previously settled work, but discards incomplete assistant output and unfinished tool state. When a turn requested an output schema, the finalized payload lands on `result.completed` as `data.result` before the turn boundary. `authorization.required` carries the sign-in challenge (`data.authorization` may include `url`, `userCode`, `expiresAt`, `instructions`), and `authorization.completed` carries `data.outcome` (`"authorized" | "declined" | "failed" | "timed-out"`).
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "Reporters"
3
- description: "Ship eval results to Braintrust experiments or JUnit XML. eve runs and scores everything itself."
3
+ description: "Ship eval results to Braintrust, Datadog, or JUnit XML. eve runs and scores everything itself."
4
4
  ---
5
5
 
6
6
  eve runs and grades everything itself; reporters ship the results out. The CLI prints a console summary by default (one line per eval, with failed assertions and their messages), and reporters from `eve/evals/reporters` add destinations on top.
@@ -44,6 +44,25 @@ A reporter instance observes the evals that reference it. Share one instance acr
44
44
 
45
45
  Braintrust needs its SDK installed in the app and credentials in the environment: install the `braintrust` package (`npm install braintrust`) and set `BRAINTRUST_API_KEY`. Pass `--skip-report` to run the eval without shipping results, which also suppresses config reporters and is useful locally when iterating.
46
46
 
47
+ ## Datadog
48
+
49
+ `Datadog(...)` uploads eval assertion scores to a Datadog LLM Observability Experiment. Put one instance in the config so it covers the whole run:
50
+
51
+ ```ts title="evals/evals.config.ts"
52
+ import { defineEvalConfig } from "eve/evals";
53
+ import { Datadog } from "eve/evals/reporters";
54
+
55
+ export default defineEvalConfig({
56
+ reporters: [Datadog({ projectName: "weather-agent" })],
57
+ });
58
+ ```
59
+
60
+ The reporter creates one Datadog Experiment, submits one synthetic experiment span per completed eve eval, associates that eval's assertion scores as experiment metrics, and prints the Datadog Experiment URL after the run completes. Without input recording, the external Experiment uses a placeholder dataset and spans are submitted as evals finish. With `recordInputs: true`, the reporter instead creates and pushes a versioned Datadog dataset after the evals finish, adds one record per eval, starts the Experiment against that dataset version, passes each dataset record id to its corresponding experiment span, and prints both Dataset and Experiment URLs. Buffering is necessary because an imperative eval's first `t.send(...)` input is only known after that eval executes. `dd-trace` generates dataset record, experiment trace, and experiment span identifiers; the reporter does not mutate or link the agent runtime's OpenTelemetry spans.
61
+
62
+ Assertion metrics use descriptive assertion names by default: characters outside letters, numbers, underscores, and hyphens are normalized to underscores, gate labels receive a `gate_` prefix, and repeated or reserved labels receive numeric suffixes. For example, `succeeded` becomes `gate_succeeded` and `calledTool(get_stock_quote)` becomes `gate_calledTool_get_stock_quote`. Authors can use `.label("stable name")` on an assertion handle to choose a stable metric name. Because assertion names can contain authored expectations, review them before exporting sensitive evals. Pass `recordAssertionDetails: true` only when the destination is also approved for raw assertion-name tags and failed assertion messages in row metadata.
63
+
64
+ Datadog needs `dd-trace` installed in the app and Datadog credentials in the environment. The reporter is tested against `dd-trace@6.13.0`; install it with `npm install dd-trace@6.13.0` and set `DD_API_KEY`, `DD_APP_KEY`, and `DD_SITE` as appropriate. By default, the reporter records assertion scores, eval metadata, and the target URL origin only. Pass `recordInputs: true`, `recordOutputs: true`, `recordExpectedOutputs: true`, or `recordErrors: true` if your destination is approved for eval prompts, outputs, authored expectations, or execution error messages. `recordInputs` stores the eval input in both the linked dataset record and experiment span. Input is read from the eval's first `t.send(...)` message, falling back to the eval description when no message event is available. When `recordExpectedOutputs` is enabled, expected output is read from eval `metadata.expectedOutput`, `metadata.expected`, or `metadata.expected_output` and stored in both the dataset record and experiment span; when no expected output is authored, the input-only dataset record is still valid. Those expected-output keys are excluded from the general metadata payload. Target URL credentials, paths, query parameters, and fragments are never reported.
65
+
47
66
  ## JUnit
48
67
 
49
68
  `JUnit({ filePath })` writes JUnit XML for CI annotations. The `--junit <path>` CLI flag does the same thing without touching the eval file, usually the better fit because CI owns the output path, not the eval:
@@ -16,7 +16,7 @@ eve eval --timeout 60000 # per-eval timeout in milliseconds
16
16
  eve eval --max-concurrency 4 # cap concurrent eval executions (default 8)
17
17
  eve eval --junit .eve/junit.xml # write JUnit XML
18
18
  eve eval --list # print discovered evals without running
19
- eve eval --verbose # stream per-eval t.log lines to stdout
19
+ eve eval --verbose # stream per-eval logs and workflow run IDs
20
20
  eve eval --json # machine-readable output
21
21
  eve eval --skip-report # skip config and eval-defined reporters (e.g. Braintrust)
22
22
  ```
@@ -37,6 +37,8 @@ An eval that calls `t.skip(reason)` is reported as skipped, does not count as pa
37
37
 
38
38
  `eve eval --json` flushes the complete report before exiting, including when stdout is piped to another process or redirected to a file.
39
39
 
40
+ With `--verbose`, eve prefixes each line with its eval ID. It streams authored `t.log()` lines as they occur, then prints the workflow run ID for every captured primary and secondary session. Use those `wrun_...` IDs to find the corresponding runs in your workflow provider.
41
+
40
42
  ## Artifacts
41
43
 
42
44
  Each run drops artifacts under `.eve/evals/<timestamp>/`: a run `summary.json`, a `results.jsonl` index, and per-eval assertion results, verdicts, captured event streams, and `t.log` lines under `evals/`. The console output stays tight on purpose; when an eval fails, the artifact has the full story.
@@ -253,7 +253,42 @@ Write callback properties as inline function expressions, arrows, method shortha
253
253
 
254
254
  Closure values must be JSON-serializable. Plain objects, arrays, strings, finite numbers, booleans, and `null` are supported; `undefined` object properties are omitted. Functions, class instances, `Date`, `Map`, symbols, non-finite numbers, and cyclic values fail resolution with the tool name and callback phase instead of being serialized lossily.
255
255
 
256
- Call expressions such as `execute: makeExecutor()` are not transformed. Put the callback body directly in `defineTool()` inside an authored module; eve-provided factories, including [memory provider tools](../memory), may also supply pre-registered callbacks. eve rejects a dynamic tool if any present callback lacks durable metadata.
256
+ Call expressions such as `execute: makeExecutor()` are not transformed. Put the callback body directly in `defineTool()` inside an authored module; eve rejects a dynamic tool if a callback lacks durable metadata.
257
+
258
+ ### Create dynamic tools in a package
259
+
260
+ Prefer an [extension](../extensions) for reusable eve integrations. Extensions contribute a namespaced set of capabilities that consumers can override. Author the final `defineTool()` calls in the extension source. Then build the package with `eve extension build` so eve transforms its callbacks.
261
+
262
+ Use `defineDurableCallback` when a provider package must return dynamic `defineTool()` values directly. eve cannot transform callback code inside an installed dependency. Put every per-tool value in the helper's `closure`. The callback receives that snapshot as its first argument. The closure follows the same JSON-serializability rules as transformed captures.
263
+
264
+ ```ts title="provider-package/search.ts"
265
+ import { defineDurableCallback, defineTool } from "eve/tools";
266
+ import { z } from "zod";
267
+
268
+ interface SearchInput {
269
+ query: string;
270
+ }
271
+
272
+ export function createSearchTool(baseUrl: string) {
273
+ return defineTool({
274
+ description: "Search the provider catalog.",
275
+ inputSchema: z.object({ query: z.string() }),
276
+ execute: defineDurableCallback({
277
+ closure: { baseUrl },
278
+ callback: async ({ baseUrl }, { query }: SearchInput) => {
279
+ const response = await fetch(`${baseUrl}/search?q=${encodeURIComponent(query)}`);
280
+ return response.json();
281
+ },
282
+ }),
283
+ });
284
+ }
285
+ ```
286
+
287
+ Wrap every callback property with the helper. This includes labels, approval policies, `approvalKey`, `execute`, and `toModelOutput`.
288
+
289
+ `closure` is the callback's only durable snapshot. Store the identifiers and configuration needed to reproduce the call there. Reconstruct clients or look up live runtime state when the callback runs. The callback may call stable imported functions, but it must not capture runtime objects outside `closure`. Those values disappear on a cold start.
290
+
291
+ eve-provided factories, including [memory provider tools](../memory), use the same durable callback mechanism.
257
292
 
258
293
  ### Identity and redeploys
259
294
 
@@ -69,8 +69,9 @@ Instrumentation providers receive `channel.delivery.started` followed by
69
69
  `channel.delivery.failed` for every inbound channel operation. The lifecycle
70
70
  covers durable processing through the terminal state of the resulting turn, not
71
71
  messages an adapter sends back to Slack, Telegram, Twilio, or another platform.
72
- Several deliveries can coalesce into one turn while retaining separate lifecycle
73
- pairs, and an adapter can consume a delivery without starting a turn.
72
+ Adjacent queued messages with matching authenticated identities and authorization
73
+ attributes can share a turn while retaining separate lifecycle pairs. An adapter
74
+ can also consume a delivery without starting a turn.
74
75
 
75
76
  Each operation has a framework-owned `deliveryId` distinct from its optional
76
77
  platform request ID. Metadata-only providers receive identity, channel, session,
@@ -86,7 +86,7 @@ See [Dynamic capabilities](./guides/dynamic-capabilities) for examples and failu
86
86
 
87
87
  [Compaction](./concepts/sessions-runs-and-streaming#compact-clear-and-reset) treats user-role instructions like ordinary conversation history, so a summary may replace their original text. Clear removes them with the rest of model-message history and does not rerun static or dynamic instructions. System-role instructions remain because they are outside history.
88
88
 
89
- Keep system-role content stable and place it before frequently changing context when practical. That gives providers the best opportunity to reuse a prompt prefix, but cache behavior and billing remain provider-specific. User-role instructions preserve the normal append-only message prefix. Framework context such as dynamic skill announcements also keeps its position before the current request across tool steps, including when a durable step resumes. eve does not promise a cache hit.
89
+ Keep system-role content stable and place it before frequently changing context when practical. That gives providers the best opportunity to reuse a prompt prefix, but cache behavior and billing remain provider-specific. User-role instructions preserve the normal append-only message prefix. Framework announcements about available skills and background tasks are retained in user-role history: changed snapshots append after earlier steps instead of replacing the context sent with those steps. Unchanged announcements are skipped until history is cleared or compacted. eve does not promise a cache hit.
90
90
 
91
91
  ## Disclaimer
92
92
 
@@ -372,7 +372,7 @@ Runs all discovered evals when no eval ids are given; ids match exactly or by di
372
372
  | `--json` | flag | off | Output results as JSON |
373
373
  | `--junit <path>` | string | none | Write JUnit XML results to a file |
374
374
  | `--skip-report` | flag | off | Skip eval-defined reporters (e.g. Braintrust) |
375
- | `--verbose` | flag | off | Stream per-eval `t.log` lines to stdout |
375
+ | `--verbose` | flag | off | Stream per-eval logs and workflow run IDs to stdout |
376
376
 
377
377
  See [Evals](../evals/overview) for authoring evals.
378
378
 
@@ -12,7 +12,7 @@ eve collects usage data from its CLI to help improve its commands and developmen
12
12
  eve sends the following information to Vercel:
13
13
 
14
14
  - The eve version, operating system, CPU architecture, and whether stdin is a terminal.
15
- - The command you ran, its outcome, and setup or onboarding steps when applicable.
15
+ - The command you ran, its outcome, and setup or onboarding steps when applicable. When setup or onboarding fails, eve sends a bounded failure category such as target resolution, scaffolding, package-manager startup, workspace probing, dependency installation, Git initialization, handoff, or onboarding. It does not send the underlying error.
16
16
  - For `eve dev`, whether you connected to a local or remote agent and whether the UI was interactive or headless.
17
17
  - Random identifiers for the CLI session, installation, and project, plus whether the installation and project identifiers are ephemeral or persistent.
18
18