eve 0.20.0 → 0.21.0

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 (136) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/src/channel/types.d.ts +9 -5
  3. package/dist/src/chunks/{use-eve-agent-Dvy_Wjvq.js → use-eve-agent-CM24ZUEI.js} +48 -34
  4. package/dist/src/chunks/{use-eve-agent-Bh1NmXO9.js → use-eve-agent-CxcKypLZ.js} +48 -34
  5. package/dist/src/client/index.d.ts +1 -1
  6. package/dist/src/client/message-reducer-types.d.ts +11 -3
  7. package/dist/src/client/message-reducer.js +1 -1
  8. package/dist/src/compiler/manifest.js +1 -1
  9. package/dist/src/compiler/normalize-agent-config.js +1 -1
  10. package/dist/src/compiler/workspace-resources.js +1 -1
  11. package/dist/src/context/dynamic-skill-lifecycle.js +1 -1
  12. package/dist/src/context/keys.d.ts +0 -1
  13. package/dist/src/context/keys.js +1 -1
  14. package/dist/src/discover/sandbox.d.ts +0 -6
  15. package/dist/src/discover/sandbox.js +1 -1
  16. package/dist/src/execution/create-session-step.d.ts +2 -1
  17. package/dist/src/execution/create-session-step.js +1 -1
  18. package/dist/src/execution/delegated-parent-notification.d.ts +6 -0
  19. package/dist/src/execution/delegated-parent-notification.js +1 -1
  20. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  21. package/dist/src/execution/dispatch-workflow-runtime-actions-step.js +1 -1
  22. package/dist/src/execution/durable-session-store.d.ts +1 -0
  23. package/dist/src/execution/next-driver-action.d.ts +3 -0
  24. package/dist/src/execution/node-step.d.ts +6 -0
  25. package/dist/src/execution/node-step.js +1 -1
  26. package/dist/src/execution/run-session-limits.d.ts +21 -0
  27. package/dist/src/execution/run-session-limits.js +1 -0
  28. package/dist/src/execution/runtime-context.js +1 -1
  29. package/dist/src/execution/sandbox/bindings/local-backend-utils.d.ts +1 -1
  30. package/dist/src/execution/sandbox/bindings/local-backend-utils.js +1 -1
  31. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  32. package/dist/src/execution/sandbox/prewarm.js +1 -1
  33. package/dist/src/execution/session-callback-step.d.ts +6 -0
  34. package/dist/src/execution/session-callback-step.js +1 -1
  35. package/dist/src/execution/session.d.ts +14 -3
  36. package/dist/src/execution/session.js +2 -4
  37. package/dist/src/execution/skills/instructions.d.ts +8 -4
  38. package/dist/src/execution/skills/instructions.js +2 -2
  39. package/dist/src/execution/subagent-tool.d.ts +7 -0
  40. package/dist/src/execution/subagent-tool.js +1 -1
  41. package/dist/src/execution/subagent-usage-span.d.ts +9 -0
  42. package/dist/src/execution/subagent-usage-span.js +1 -0
  43. package/dist/src/execution/turn-execution-cursor.d.ts +2 -0
  44. package/dist/src/execution/turn-workflow.js +1 -1
  45. package/dist/src/execution/workflow-entry.d.ts +1 -0
  46. package/dist/src/execution/workflow-entry.js +1 -1
  47. package/dist/src/execution/workflow-runtime.js +1 -1
  48. package/dist/src/execution/workflow-skill-root.d.ts +6 -0
  49. package/dist/src/execution/workflow-skill-root.js +1 -0
  50. package/dist/src/execution/workflow-steps.d.ts +3 -0
  51. package/dist/src/execution/workflow-steps.js +1 -1
  52. package/dist/src/harness/advertised-tools.d.ts +1 -0
  53. package/dist/src/harness/advertised-tools.js +1 -1
  54. package/dist/src/harness/input-requests.d.ts +8 -0
  55. package/dist/src/harness/input-requests.js +1 -1
  56. package/dist/src/harness/runtime-actions.js +1 -1
  57. package/dist/src/harness/session-limit-continuation.d.ts +55 -0
  58. package/dist/src/harness/session-limit-continuation.js +1 -0
  59. package/dist/src/harness/session-limit-enforcement.d.ts +55 -0
  60. package/dist/src/harness/session-limit-enforcement.js +1 -0
  61. package/dist/src/harness/subagent-depth.d.ts +1 -4
  62. package/dist/src/harness/subagent-depth.js +1 -1
  63. package/dist/src/harness/subagent-token-budget.d.ts +14 -0
  64. package/dist/src/harness/subagent-token-budget.js +1 -0
  65. package/dist/src/harness/tool-loop.js +1 -1
  66. package/dist/src/harness/turn-tag-state.d.ts +31 -0
  67. package/dist/src/harness/turn-tag-state.js +1 -1
  68. package/dist/src/harness/types.d.ts +21 -4
  69. package/dist/src/harness/workflow-sandbox.d.ts +1 -0
  70. package/dist/src/harness/workflow-sandbox.js +1 -1
  71. package/dist/src/harness/workflow-subagent-limit.d.ts +38 -0
  72. package/dist/src/harness/workflow-subagent-limit.js +1 -0
  73. package/dist/src/harness/workflow-tool-description.d.ts +6 -1
  74. package/dist/src/harness/workflow-tool-description.js +5 -3
  75. package/dist/src/internal/application/package.js +1 -1
  76. package/dist/src/internal/authored-definition/core.js +1 -1
  77. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  78. package/dist/src/protocol/message.d.ts +19 -2
  79. package/dist/src/protocol/message.js +2 -2
  80. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +34 -3
  81. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  82. package/dist/src/public/channels/chat-sdk/index.d.ts +2 -0
  83. package/dist/src/public/channels/chat-sdk/index.js +1 -1
  84. package/dist/src/public/channels/chat-sdk/messageToUserContent.d.ts +13 -0
  85. package/dist/src/public/channels/chat-sdk/messageToUserContent.js +1 -0
  86. package/dist/src/public/channels/chat-sdk/notImplemented.d.ts +7 -0
  87. package/dist/src/public/channels/chat-sdk/notImplemented.js +1 -0
  88. package/dist/src/public/channels/slack/api.d.ts +14 -12
  89. package/dist/src/public/channels/slack/api.js +1 -1
  90. package/dist/src/public/definitions/tool.d.ts +37 -0
  91. package/dist/src/public/definitions/tool.js +1 -1
  92. package/dist/src/public/tools/index.d.ts +1 -1
  93. package/dist/src/public/tools/index.js +1 -1
  94. package/dist/src/runtime/actions/types.d.ts +9 -0
  95. package/dist/src/runtime/actions/types.js +1 -1
  96. package/dist/src/runtime/agent/bootstrap.d.ts +2 -0
  97. package/dist/src/runtime/agent/bootstrap.js +1 -1
  98. package/dist/src/runtime/resolve-agent.js +1 -1
  99. package/dist/src/runtime/sandbox/keys.js +1 -1
  100. package/dist/src/runtime/sandbox/template-plan.js +1 -1
  101. package/dist/src/runtime/session-callback-route.js +1 -1
  102. package/dist/src/runtime/skills/sandbox-access.d.ts +1 -1
  103. package/dist/src/runtime/skills/sandbox-access.js +1 -1
  104. package/dist/src/runtime/workspace/seed-files.js +1 -1
  105. package/dist/src/setup/scaffold/create/project.js +1 -1
  106. package/dist/src/setup/scaffold/create/web-template.d.ts +2 -2
  107. package/dist/src/setup/scaffold/create/web-template.js +77 -3
  108. package/dist/src/shared/agent-definition.d.ts +31 -3
  109. package/dist/src/shared/skill-package.d.ts +2 -2
  110. package/dist/src/shared/skill-package.js +1 -1
  111. package/dist/src/shared/skill-paths.d.ts +28 -0
  112. package/dist/src/shared/skill-paths.js +2 -0
  113. package/dist/src/shared/token-usage.d.ts +22 -0
  114. package/dist/src/shared/token-usage.js +1 -0
  115. package/dist/src/svelte/index.js +1 -1
  116. package/dist/src/svelte/use-eve-agent.js +1 -1
  117. package/dist/src/vue/index.js +1 -1
  118. package/dist/src/vue/use-eve-agent.js +1 -1
  119. package/docs/agent-config.md +32 -15
  120. package/docs/channels/chat-sdk.mdx +209 -0
  121. package/docs/channels/meta.json +1 -0
  122. package/docs/concepts/context-control.md +2 -2
  123. package/docs/concepts/default-harness.md +10 -0
  124. package/docs/concepts/sessions-runs-and-streaming.md +1 -1
  125. package/docs/guides/client/messages.mdx +4 -0
  126. package/docs/guides/client/streaming.mdx +17 -12
  127. package/docs/guides/dynamic-workflows.md +87 -0
  128. package/docs/guides/frontend/overview.mdx +5 -1
  129. package/docs/guides/meta.json +1 -0
  130. package/docs/guides/remote-agents.md +1 -0
  131. package/docs/reference/project-layout.md +5 -4
  132. package/docs/reference/typescript-api.md +26 -26
  133. package/docs/sandbox.mdx +1 -1
  134. package/docs/skills.mdx +3 -1
  135. package/docs/subagents.mdx +2 -1
  136. package/package.json +1 -1
@@ -1 +1 @@
1
- import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{resolveConnectionDefinition}from"#runtime/resolve-connection.js";import{resolveHookDefinition}from"#runtime/resolve-hook.js";import{resolveSandboxDefinition}from"#runtime/resolve-sandbox.js";import{resolveDynamicInstructionsDefinition}from"#runtime/resolve-dynamic-instructions.js";import{resolveDynamicSkillDefinition}from"#runtime/resolve-dynamic-skill.js";import{resolveDynamicToolDefinition}from"#runtime/resolve-dynamic-tool.js";import{resolveToolDefinition}from"#runtime/resolve-tool.js";async function resolveAgent(e){let t=e.manifest.skills.map(e=>({...e,metadata:e.metadata===void 0?void 0:{...e.metadata}})),r=[],i=[];for(let t of e.manifest.channels){if(t.kind===`disabled`){i.push(t.name);continue}r.push(await resolveChannelDefinition(t,e.moduleMap,e.nodeId))}let a=await Promise.all(e.manifest.tools.map(t=>resolveToolDefinition(t,e.moduleMap,e.nodeId))),o=await Promise.all((e.manifest.dynamicInstructions??[]).map(t=>resolveDynamicInstructionsDefinition(t,e.moduleMap,e.nodeId))),s=await Promise.all((e.manifest.dynamicSkills??[]).map(t=>resolveDynamicSkillDefinition(t,e.moduleMap,e.nodeId))),c=await Promise.all(e.manifest.dynamicTools.map(t=>resolveDynamicToolDefinition(t,e.moduleMap,e.nodeId))),l=await Promise.all(e.manifest.hooks.map(t=>resolveHookDefinition(t,e.moduleMap,e.nodeId))),u=await Promise.all(e.manifest.connections.map(t=>resolveConnectionDefinition(t,e.moduleMap,e.nodeId))),d=e.manifest.sandbox===null?null:await resolveSandboxDefinition(e.manifest.sandbox,e.moduleMap,e.nodeId),f=createResolvedInstructions(e.manifest.instructions),p=e.manifest.workspaceResourceRoot,m={channels:r,config:createResolvedAgentConfig(e.manifest),connections:u,disabledFrameworkChannels:i,disabledFrameworkTools:[...e.manifest.disabledFrameworkTools],workflowEnabled:e.manifest.workflowEnabled,dynamicInstructionsResolvers:o,dynamicSkillResolvers:s,dynamicToolResolvers:c,hooks:l,metadata:{agentRoot:e.manifest.agentRoot,appRoot:e.manifest.appRoot,diagnosticsSummary:e.manifest.diagnosticsSummary},sandbox:d,workspaceResourceRoot:p,skills:t,tools:a,workspaceSpec:{rootEntries:[...p.rootEntries]}};return f===void 0?m:{...m,instructions:f}}function createResolvedInstructions(e){if(e!==void 0)return{name:e.name,logicalPath:e.logicalPath,markdown:e.markdown,sourceId:e.sourceId,sourceKind:e.sourceKind}}function createResolvedAgentConfig(e){let n={model:e.config.model.source===void 0?{id:e.config.model.id,contextWindowTokens:e.config.model.contextWindowTokens,providerOptions:e.config.model.providerOptions}:{contextWindowTokens:e.config.model.contextWindowTokens,id:e.config.model.id,providerOptions:e.config.model.providerOptions,source:{exportName:e.config.model.source.exportName,sourceKind:`module`,logicalPath:e.config.model.source.logicalPath,sourceId:e.config.model.source.sourceId}},name:e.config.name};if(e.config.compaction!==void 0){let t={};e.config.compaction.model!==void 0&&(t.model=e.config.compaction.model.source===void 0?{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,providerOptions:e.config.compaction.model.providerOptions}:{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,providerOptions:e.config.compaction.model.providerOptions,source:{exportName:e.config.compaction.model.source.exportName,sourceKind:`module`,logicalPath:e.config.compaction.model.source.logicalPath,sourceId:e.config.compaction.model.source.sourceId}}),e.config.compaction.thresholdPercent!==void 0&&(t.thresholdPercent=e.config.compaction.thresholdPercent),n.compaction=t}return e.config.experimental!==void 0&&(n.experimental={workflow:e.config.experimental.workflow===void 0?void 0:{world:e.config.experimental.workflow.world}}),e.config.outputSchema!==void 0&&(n.outputSchema=e.config.outputSchema),e.config.reasoning!==void 0&&(n.reasoning=e.config.reasoning),e.config.source!==void 0&&(n.source=createResolvedModuleSourceRef(e.config.source)),e.config.limits!==void 0&&(n.limits={maxSubagentDepth:e.config.limits.maxSubagentDepth,maxInputTokensPerSession:e.config.limits.maxInputTokensPerSession,maxOutputTokensPerSession:e.config.limits.maxOutputTokensPerSession}),n}export{ResolveAgentError,resolveAgent};
1
+ import{ResolveAgentError,createResolvedModuleSourceRef}from"#runtime/resolve-helpers.js";import{resolveChannelDefinition}from"#runtime/resolve-channel.js";import{resolveConnectionDefinition}from"#runtime/resolve-connection.js";import{resolveHookDefinition}from"#runtime/resolve-hook.js";import{resolveSandboxDefinition}from"#runtime/resolve-sandbox.js";import{resolveDynamicInstructionsDefinition}from"#runtime/resolve-dynamic-instructions.js";import{resolveDynamicSkillDefinition}from"#runtime/resolve-dynamic-skill.js";import{resolveDynamicToolDefinition}from"#runtime/resolve-dynamic-tool.js";import{resolveToolDefinition}from"#runtime/resolve-tool.js";async function resolveAgent(e){let t=e.manifest.skills.map(e=>({...e,metadata:e.metadata===void 0?void 0:{...e.metadata}})),r=[],i=[];for(let t of e.manifest.channels){if(t.kind===`disabled`){i.push(t.name);continue}r.push(await resolveChannelDefinition(t,e.moduleMap,e.nodeId))}let a=await Promise.all(e.manifest.tools.map(t=>resolveToolDefinition(t,e.moduleMap,e.nodeId))),o=await Promise.all((e.manifest.dynamicInstructions??[]).map(t=>resolveDynamicInstructionsDefinition(t,e.moduleMap,e.nodeId))),s=await Promise.all((e.manifest.dynamicSkills??[]).map(t=>resolveDynamicSkillDefinition(t,e.moduleMap,e.nodeId))),c=await Promise.all(e.manifest.dynamicTools.map(t=>resolveDynamicToolDefinition(t,e.moduleMap,e.nodeId))),l=await Promise.all(e.manifest.hooks.map(t=>resolveHookDefinition(t,e.moduleMap,e.nodeId))),u=await Promise.all(e.manifest.connections.map(t=>resolveConnectionDefinition(t,e.moduleMap,e.nodeId))),d=e.manifest.sandbox===null?null:await resolveSandboxDefinition(e.manifest.sandbox,e.moduleMap,e.nodeId),f=createResolvedInstructions(e.manifest.instructions),p=e.manifest.workspaceResourceRoot,m={channels:r,config:createResolvedAgentConfig(e.manifest),connections:u,disabledFrameworkChannels:i,disabledFrameworkTools:[...e.manifest.disabledFrameworkTools],workflowEnabled:e.manifest.workflowEnabled,dynamicInstructionsResolvers:o,dynamicSkillResolvers:s,dynamicToolResolvers:c,hooks:l,metadata:{agentRoot:e.manifest.agentRoot,appRoot:e.manifest.appRoot,diagnosticsSummary:e.manifest.diagnosticsSummary},sandbox:d,workspaceResourceRoot:p,skills:t,tools:a,workspaceSpec:{rootEntries:[...p.rootEntries]}};return f===void 0?m:{...m,instructions:f}}function createResolvedInstructions(e){if(e!==void 0)return{name:e.name,logicalPath:e.logicalPath,markdown:e.markdown,sourceId:e.sourceId,sourceKind:e.sourceKind}}function createResolvedAgentConfig(e){let n={model:e.config.model.source===void 0?{id:e.config.model.id,contextWindowTokens:e.config.model.contextWindowTokens,providerOptions:e.config.model.providerOptions}:{contextWindowTokens:e.config.model.contextWindowTokens,id:e.config.model.id,providerOptions:e.config.model.providerOptions,source:{exportName:e.config.model.source.exportName,sourceKind:`module`,logicalPath:e.config.model.source.logicalPath,sourceId:e.config.model.source.sourceId}},name:e.config.name};if(e.config.compaction!==void 0){let t={};e.config.compaction.model!==void 0&&(t.model=e.config.compaction.model.source===void 0?{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,providerOptions:e.config.compaction.model.providerOptions}:{contextWindowTokens:e.config.compaction.model.contextWindowTokens,id:e.config.compaction.model.id,providerOptions:e.config.compaction.model.providerOptions,source:{exportName:e.config.compaction.model.source.exportName,sourceKind:`module`,logicalPath:e.config.compaction.model.source.logicalPath,sourceId:e.config.compaction.model.source.sourceId}}),e.config.compaction.thresholdPercent!==void 0&&(t.thresholdPercent=e.config.compaction.thresholdPercent),n.compaction=t}return e.config.experimental!==void 0&&(n.experimental={workflow:e.config.experimental.workflow===void 0?void 0:{world:e.config.experimental.workflow.world}}),e.config.outputSchema!==void 0&&(n.outputSchema=e.config.outputSchema),e.config.reasoning!==void 0&&(n.reasoning=e.config.reasoning),e.config.source!==void 0&&(n.source=createResolvedModuleSourceRef(e.config.source)),e.config.limits!==void 0&&(n.limits={maxSubagentDepth:e.config.limits.maxSubagentDepth,maxSubagents:e.config.limits.maxSubagents,maxInputTokensPerSession:e.config.limits.maxInputTokensPerSession,maxOutputTokensPerSession:e.config.limits.maxOutputTokensPerSession}),n}export{ResolveAgentError,resolveAgent};
@@ -1 +1 @@
1
- import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{realpath}from"node:fs/promises";import{createHash}from"node:crypto";import{getRuntimeCompiledArtifactsCacheKey,getRuntimeCompiledArtifactsSandboxAppRoot}from"#runtime/compiled-artifacts-source.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";async function createRuntimeSandboxKeys(e){return{sessionKey:await createRuntimeSandboxSessionKey(e),templateKey:await createRuntimeSandboxTemplateKey(e)}}async function createRuntimeSandboxTemplateKey(e){if(e.templatePlan.kind===`none`)return null;let t=await loadCompileMetadataForKeys(e.compiledArtifactsSource),n=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:e.templatePlan.kind===`source-graph`?`deployment`:`stable`}),r=resolveRuntimeSandboxVersionHash({compiledArtifactsSource:e.compiledArtifactsSource,metadata:t,nodeId:e.nodeId,sourceId:e.sourceId,templatePlan:e.templatePlan}),i=createStableHash(`${resolvePackageVersionForTemplateKey(t)}:6:${r}`).slice(0,20);return sanitizeRuntimeSandboxKey(`eve-sbx-tpl-${e.backendName}-${n}-${i}`)}function resolvePackageVersionForTemplateKey(t){return t?.generator.version??resolveInstalledPackageInfo().version}async function loadCompileMetadataForKeys(e){try{return await loadCompileMetadata({compiledArtifactsSource:e})}catch{return null}}async function createRuntimeSandboxSessionKey(e){let t=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:`deployment`}),n=sanitizeRuntimeSandboxKey(e.nodeId);return sanitizeRuntimeSandboxKey(`eve-sbx-ses-${e.backendName}-${t}-${e.sessionId}-${n}`)}async function resolveRuntimeSandboxScope(e){if(e.backendName===`vercel`){if(e.scopeKind===`stable`){let e=resolveVercelProjectScope();if(e!==void 0)return createStableHash(e).slice(0,16)}let t=process.env.VERCEL_DEPLOYMENT_ID?.trim();if(t!==void 0&&t.length>0)return createStableHash(t).slice(0,16)}let n=getRuntimeCompiledArtifactsSandboxAppRoot(e.compiledArtifactsSource);return n===void 0?createStableHash(getRuntimeCompiledArtifactsCacheKey(e.compiledArtifactsSource)).slice(0,16):createStableHash(await realpath(n)).slice(0,16)}function resolveRuntimeSandboxVersionHash(e){if(e.templatePlan.kind===`bootstrap`){let t=e.templatePlan.contentHash??resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource);return createStableHash(`bootstrap:${e.templatePlan.revalidationKey??``}:${e.templatePlan.sourceHash}:${t}:${e.nodeId}:${e.sourceId}`)}return e.templatePlan.kind===`workspace-content`?createStableHash(`workspace-content:${e.templatePlan.contentHash??resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`):createStableHash(`source-graph:${resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`)}function resolveSourceGraphHash(e,t){return e?.discovery.sourceGraphHash??getRuntimeCompiledArtifactsCacheKey(t)}function resolveVercelProjectScope(){let e=process.env.VERCEL_PROJECT_ID?.trim();if(!(e===void 0||e.length===0))return`vercel-project:${e}`}function createStableHash(e){return createHash(`sha256`).update(e).digest(`hex`)}function sanitizeRuntimeSandboxKey(e){return e.replaceAll(/[^a-zA-Z0-9._-]+/g,`-`).slice(0,120)}export{createRuntimeSandboxKeys,createRuntimeSandboxTemplateKey};
1
+ import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{realpath}from"node:fs/promises";import{createHash}from"node:crypto";import{getRuntimeCompiledArtifactsCacheKey,getRuntimeCompiledArtifactsSandboxAppRoot}from"#runtime/compiled-artifacts-source.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";async function createRuntimeSandboxKeys(e){return{sessionKey:await createRuntimeSandboxSessionKey(e),templateKey:await createRuntimeSandboxTemplateKey(e)}}async function createRuntimeSandboxTemplateKey(e){if(e.templatePlan.kind===`none`)return null;let t=await loadCompileMetadataForKeys(e.compiledArtifactsSource),n=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:e.templatePlan.kind===`source-graph`?`deployment`:`stable`}),r=resolveRuntimeSandboxVersionHash({compiledArtifactsSource:e.compiledArtifactsSource,metadata:t,nodeId:e.nodeId,sourceId:e.sourceId,templatePlan:e.templatePlan}),i=createStableHash(`${resolvePackageVersionForTemplateKey(t)}:7:${r}`).slice(0,20);return sanitizeRuntimeSandboxKey(`eve-sbx-tpl-${e.backendName}-${n}-${i}`)}function resolvePackageVersionForTemplateKey(t){return t?.generator.version??resolveInstalledPackageInfo().version}async function loadCompileMetadataForKeys(e){try{return await loadCompileMetadata({compiledArtifactsSource:e})}catch{return null}}async function createRuntimeSandboxSessionKey(e){let t=await resolveRuntimeSandboxScope({backendName:e.backendName,compiledArtifactsSource:e.compiledArtifactsSource,scopeKind:`deployment`}),n=sanitizeRuntimeSandboxKey(e.nodeId);return sanitizeRuntimeSandboxKey(`eve-sbx-ses-${e.backendName}-${t}-${e.sessionId}-${n}`)}async function resolveRuntimeSandboxScope(e){if(e.backendName===`vercel`){if(e.scopeKind===`stable`){let e=resolveVercelProjectScope();if(e!==void 0)return createStableHash(e).slice(0,16)}let t=process.env.VERCEL_DEPLOYMENT_ID?.trim();if(t!==void 0&&t.length>0)return createStableHash(t).slice(0,16)}let n=getRuntimeCompiledArtifactsSandboxAppRoot(e.compiledArtifactsSource);return n===void 0?createStableHash(getRuntimeCompiledArtifactsCacheKey(e.compiledArtifactsSource)).slice(0,16):createStableHash(await realpath(n)).slice(0,16)}function resolveRuntimeSandboxVersionHash(e){if(e.templatePlan.kind===`bootstrap`){let t=e.templatePlan.contentHash??resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource);return createStableHash(`bootstrap:${e.templatePlan.revalidationKey??``}:${e.templatePlan.sourceHash}:${t}:${e.nodeId}:${e.sourceId}`)}return e.templatePlan.kind===`workspace-content`?createStableHash(`workspace-content:${e.templatePlan.contentHash??resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`):createStableHash(`source-graph:${resolveSourceGraphHash(e.metadata,e.compiledArtifactsSource)}:${e.nodeId}:${e.sourceId}`)}function resolveSourceGraphHash(e,t){return e?.discovery.sourceGraphHash??getRuntimeCompiledArtifactsCacheKey(t)}function resolveVercelProjectScope(){let e=process.env.VERCEL_PROJECT_ID?.trim();if(!(e===void 0||e.length===0))return`vercel-project:${e}`}function createStableHash(e){return createHash(`sha256`).update(e).digest(`hex`)}function sanitizeRuntimeSandboxKey(e){return e.replaceAll(/[^a-zA-Z0-9._-]+/g,`-`).slice(0,120)}export{createRuntimeSandboxKeys,createRuntimeSandboxTemplateKey};
@@ -1 +1 @@
1
- function createRuntimeSandboxTemplatePlan(e){if(e.definition.bootstrap!==void 0){if(e.definition.sourceHash===void 0)throw Error(`Sandbox "${e.definition.logicalPath}" defines bootstrap() but has no compiled sourceHash.`);return{contentHash:e.workspaceResourceRoot.contentHash,kind:`bootstrap`,revalidationKey:e.definition.revalidationKey,sourceHash:e.definition.sourceHash}}return e.workspaceResourceRoot.rootEntries.length===0?{kind:`none`}:{contentHash:e.workspaceResourceRoot.contentHash,kind:`workspace-content`}}export{createRuntimeSandboxTemplatePlan};
1
+ function createRuntimeSandboxTemplatePlan(e){if(e.definition.bootstrap!==void 0){if(e.definition.sourceHash===void 0)throw Error(`Sandbox "${e.definition.logicalPath}" defines bootstrap() but has no compiled sourceHash.`);return{contentHash:e.workspaceResourceRoot.contentHash,kind:`bootstrap`,revalidationKey:e.definition.revalidationKey,sourceHash:e.definition.sourceHash}}return e.workspaceResourceRoot.contentHash===void 0&&e.workspaceResourceRoot.rootEntries.length===0?{kind:`none`}:{contentHash:e.workspaceResourceRoot.contentHash,kind:`workspace-content`}}export{createRuntimeSandboxTemplatePlan};
@@ -1 +1 @@
1
- import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#internal/workflow/runtime.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`];function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:session-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,n){let r=n.params.token;if(typeof r!=`string`||r.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let i;try{i=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let a=projectSessionCallbackResult(i);if(a instanceof Response)return a;try{await resumeHook(r,{kind:`runtime-action-result`,results:[a]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=e;return typeof t.callId!=`string`||t.callId.length===0?Response.json({error:`Missing callback callId.`,ok:!1},{status:400}):typeof t.subagentName!=`string`||t.subagentName.length===0?Response.json({error:`Missing callback subagentName.`,ok:!1},{status:400}):t.kind===`session.completed`?{callId:t.callId,kind:`subagent-result`,output:t.output??``,subagentName:t.subagentName}:t.kind===`session.failed`?{callId:t.callId,isError:!0,kind:`subagent-result`,output:t.error===void 0?{code:`REMOTE_AGENT_FAILED`,message:`Remote agent failed.`}:t.error,subagentName:t.subagentName}:Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400})}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
1
+ import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{resumeHook}from"#internal/workflow/runtime.js";import{tokenUsageSchema}from"#shared/token-usage.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`];function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(t){let n=channelNameForMethod(t);return{name:n,method:t,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:session-callback-${t.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,n){let r=n.params.token;if(typeof r!=`string`||r.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let i;try{i=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let a=projectSessionCallbackResult(i);if(a instanceof Response)return a;try{await resumeHook(r,{kind:`runtime-action-result`,results:[a]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=e;if(typeof t.callId!=`string`||t.callId.length===0)return Response.json({error:`Missing callback callId.`,ok:!1},{status:400});if(typeof t.subagentName!=`string`||t.subagentName.length===0)return Response.json({error:`Missing callback subagentName.`,ok:!1},{status:400});if(t.kind===`session.completed`){let e={callId:t.callId,kind:`subagent-result`,output:t.output??``,subagentName:t.subagentName},n=parseCallbackUsage(t.usage);return n===void 0?e:{...e,usage:n}}return t.kind===`session.failed`?{callId:t.callId,isError:!0,kind:`subagent-result`,output:t.error===void 0?{code:`REMOTE_AGENT_FAILED`,message:`Remote agent failed.`}:t.error,subagentName:t.subagentName}:Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400})}function parseCallbackUsage(e){if(e===void 0)return;let t=tokenUsageSchema.safeParse(e);return t.success?t.data:void 0}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
@@ -2,7 +2,7 @@ import type { SandboxAccess } from "#sandbox/state.js";
2
2
  import type { SkillHandle } from "#execution/skills/types.js";
3
3
  /**
4
4
  * Validates a skill id before it is used as one path segment under
5
- * `/workspace/skills`.
5
+ * the sandbox skill root.
6
6
  */
7
7
  export declare function assertSafeSkillId(id: string): asserts id is string;
8
8
  /**
@@ -1 +1 @@
1
- import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";const FRONTMATTER_PATTERN=/^---\r?\n[\s\S]*?\r?\n---\r?\n?/;function assertSafeSkillId(e){if(e.length===0||e.trim()!==e||e.startsWith(`.`)||e.includes(`/`)||e.includes(`\\`)||e.includes(`..`)||/^[A-Za-z]:/.test(e))throw Error(`Expected skill id to be a non-empty safe path segment without whitespace, separators, "." prefix, or "..".`)}async function loadSkillFromSandbox(e,n,r=[]){assertSafeSkillId(n);let i=await requireSandboxSession(e),a=skillFilePath(n,`SKILL.md`),o=await i.readTextFile({path:a});if(o===null){let e=r.length>0?` Available skills: ${r.join(`, `)}.`:``;throw Error(`No skill named "${n}" at ${a}.${e}`)}return o.replace(FRONTMATTER_PATTERN,``)}function createSandboxSkillHandle(e,t){return assertSafeSkillId(t),{name:t,file(n){assertSafeSkillRelativePath(n);let r=skillFilePath(t,n);return{async bytes(){let t=await(await requireSandboxSession(e)).readBinaryFile({path:r});if(t===null)throw Error(`Skill file not found: ${r}`);return t},async text(){let t=await(await requireSandboxSession(e)).readTextFile({path:r});if(t===null)throw Error(`Skill file not found: ${r}`);return t}}}}}function assertSafeSkillRelativePath(e){if(e.length===0||e.startsWith(`/`)||e.includes(`\\`)||e.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw Error(`Expected skill file path to be a relative path inside the skill directory.`)}async function requireSandboxSession(e){let t=await e.get();if(t===null)throw Error(`The sandbox is not available in the current authored runtime context.`);return t}function skillFilePath(t,n){return`${WORKSPACE_ROOT}/skills/${t}/${n}`}export{assertSafeSkillId,createSandboxSkillHandle,loadSkillFromSandbox};
1
+ import{resolveSandboxSkillReadPaths}from"#shared/skill-paths.js";const FRONTMATTER_PATTERN=/^---\r?\n[\s\S]*?\r?\n---\r?\n?/;function assertSafeSkillId(e){if(e.length===0||e.trim()!==e||e.startsWith(`.`)||e.includes(`/`)||e.includes(`\\`)||e.includes(`..`)||/^[A-Za-z]:/.test(e))throw Error(`Expected skill id to be a non-empty safe path segment without whitespace, separators, "." prefix, or "..".`)}async function loadSkillFromSandbox(n,r,i=[]){assertSafeSkillId(r);let a=await requireSandboxSession(n),o=await resolveSandboxSkillReadPaths({name:r,relativePath:`SKILL.md`,sandbox:a});for(let e of o){let n=await a.readTextFile({path:e});if(n!==null)return n.replace(FRONTMATTER_PATTERN,``)}let s=i.length>0?` Available skills: ${i.join(`, `)}.`:``;throw Error(`No skill named "${r}" at ${o[0]}.${s}`)}function createSandboxSkillHandle(t,n){return assertSafeSkillId(n),{name:n,file(r){return assertSafeSkillRelativePath(r),{async bytes(){let i=await requireSandboxSession(t),a=await resolveSandboxSkillReadPaths({name:n,relativePath:r,sandbox:i});for(let e of a){let t=await i.readBinaryFile({path:e});if(t!==null)return t}throw Error(`Skill file not found: ${a[0]}`)},async text(){let i=await requireSandboxSession(t),a=await resolveSandboxSkillReadPaths({name:n,relativePath:r,sandbox:i});for(let e of a){let t=await i.readTextFile({path:e});if(t!==null)return t}throw Error(`Skill file not found: ${a[0]}`)}}}}}function assertSafeSkillRelativePath(e){if(e.length===0||e.startsWith(`/`)||e.includes(`\\`)||e.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw Error(`Expected skill file path to be a relative path inside the skill directory.`)}async function requireSandboxSession(e){let t=await e.get();if(t===null)throw Error(`The sandbox is not available in the current authored runtime context.`);return t}export{assertSafeSkillId,createSandboxSkillHandle,loadSkillFromSandbox};
@@ -1 +1 @@
1
- import{join,posix}from"node:path";import{readFile,readdir}from"node:fs/promises";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";async function materializeWorkspaceDirectory(e){let t=[];return await addMaterializedDirectoryFiles({files:t,logicalDirectoryPath:`.`,sourceDirectoryPath:e}),t.sort((e,t)=>e.path.localeCompare(t.path)),t}async function addMaterializedDirectoryFiles(r){let i=await readdir(r.sourceDirectoryPath,{withFileTypes:!0});for(let n of i){if(!n.isDirectory()&&!n.isFile())continue;let i=join(r.sourceDirectoryPath,n.name),a=posix.join(r.logicalDirectoryPath,n.name);if(n.isDirectory()){await addMaterializedDirectoryFiles({files:r.files,logicalDirectoryPath:a,sourceDirectoryPath:i});continue}r.files.push({content:await readFile(i),path:posix.join(WORKSPACE_ROOT,a)})}}export{materializeWorkspaceDirectory};
1
+ import{join,posix}from"node:path";import{readFile,readdir}from"node:fs/promises";import{MODEL_SKILL_ROOT}from"#shared/skill-paths.js";import{WORKSPACE_ROOT}from"#runtime/workspace/types.js";const RESOURCE_WORKSPACE_DIRECTORY=`workspace`,RESOURCE_SKILLS_DIRECTORY=`skills`;async function materializeWorkspaceDirectory(t){let n=[],s=await readdir(t,{withFileTypes:!0}),c=s.find(e=>e.name===RESOURCE_WORKSPACE_DIRECTORY&&e.isDirectory()),l=s.find(e=>e.name===RESOURCE_SKILLS_DIRECTORY&&e.isDirectory());return c!==void 0||l!==void 0?(c!==void 0&&await addMaterializedDirectoryFiles({files:n,logicalDirectoryPath:`.`,sourceDirectoryPath:join(t,RESOURCE_WORKSPACE_DIRECTORY),targetRoot:WORKSPACE_ROOT}),l!==void 0&&await addMaterializedDirectoryFiles({files:n,logicalDirectoryPath:`.`,sourceDirectoryPath:join(t,RESOURCE_SKILLS_DIRECTORY),targetRoot:MODEL_SKILL_ROOT})):await addMaterializedDirectoryFiles({files:n,logicalDirectoryPath:`.`,sourceDirectoryPath:t,targetRoot:WORKSPACE_ROOT}),n.sort((e,t)=>e.path.localeCompare(t.path)),n}async function addMaterializedDirectoryFiles(i){let a=await readdir(i.sourceDirectoryPath,{withFileTypes:!0});for(let r of a){if(!r.isDirectory()&&!r.isFile())continue;let a=join(i.sourceDirectoryPath,r.name),o=posix.join(i.logicalDirectoryPath,r.name);if(r.isDirectory()){await addMaterializedDirectoryFiles({files:i.files,logicalDirectoryPath:o,sourceDirectoryPath:a,targetRoot:i.targetRoot});continue}i.files.push({content:await readFile(a),path:posix.join(i.targetRoot,o)})}}export{materializeWorkspaceDirectory};
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.20.0`,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){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).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{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.21.0`,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){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).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,7 +1,7 @@
1
1
  export declare const WEB_APP_TEMPLATE_FILES: {
2
2
  readonly "agent/channels/eve.ts": 'import { eveChannel } from "eve/channels/eve";\nimport { localDev, placeholderAuth, vercelOidc } from "eve/channels/auth";\n\nexport default eveChannel({\n auth: [\n // Lets the eve TUI and your Vercel deployments reach the deployed agent.\n vercelOidc(),\n // Open on localhost for `eve dev` and the REPL; ignored in production.\n localDev(),\n // This placeholder will not allow browser requests in production.\n // Replace it with your app\'s auth provider, like Auth.js or Clerk,\n // or use none() for a public demo.\n placeholderAuth(),\n ],\n});\n';
3
- readonly "app/_components/agent-chat.tsx": '"use client";\n\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon } from "lucide-react";\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n} from "@/components/ai-elements/conversation";\nimport {\n PromptInput,\n type PromptInputMessage,\n PromptInputSubmit,\n PromptInputTextarea,\n} from "@/components/ai-elements/prompt-input";\nimport { cn } from "@/lib/utils";\nimport { AgentMessage } from "./agent-message";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\ntype AgentStatus = ReturnType<typeof useEveAgent>["status"];\n\nexport function AgentChat() {\n const agent = useEveAgent();\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isEmpty = agent.data.messages.length === 0;\n\n const handleSubmit = async (message: PromptInputMessage) => {\n const text = message.text.trim();\n if (!text || isBusy) return;\n\n await agent.send({ message: text });\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea placeholder="Send a message…" />\n <PromptInputSubmit onStop={agent.stop} status={agent.status} />\n </PromptInput>\n );\n\n return (\n <main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">\n {isEmpty ? null : (\n <header className="flex h-14 shrink-0 items-center justify-center gap-3 pl-4 pr-2">\n <span className="flex min-w-0 items-center gap-2">\n <span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>\n <StatusDot status={agent.status} />\n </span>\n </header>\n )}\n\n {agent.error ? (\n <div className="mx-auto w-full max-w-3xl shrink-0 px-4 pt-2 sm:px-6">\n <div className="flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm">\n <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />\n <div>\n <p className="font-medium">Request failed</p>\n <p className="mt-0.5 text-muted-foreground">{agent.error.message}</p>\n </div>\n </div>\n </div>\n ) : null}\n\n {isEmpty ? null : (\n <Conversation className="min-h-0 flex-1">\n <ConversationContent className="mx-auto w-full max-w-3xl gap-6 px-4 py-6 sm:px-6">\n {agent.data.messages.map((message, index) => (\n <AgentMessage\n canRespond={!isBusy}\n isStreaming={\n agent.status === "streaming" && index === agent.data.messages.length - 1\n }\n key={message.id}\n message={message}\n onInputResponses={(inputResponses) => agent.send({ inputResponses })}\n />\n ))}\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n )}\n\n <div\n className={cn(\n "mx-auto w-full px-4 sm:px-6",\n isEmpty\n ? "flex max-w-xl flex-1 flex-col items-center justify-center gap-8 pb-[10vh]"\n : "max-w-3xl shrink-0 pb-6",\n )}\n >\n {isEmpty ? (\n <div className="flex flex-col items-center gap-3 text-center">\n <h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>\n </div>\n ) : null}\n <div className="w-full">{composer}</div>\n </div>\n </main>\n );\n}\n\nfunction StatusDot({ status }: { readonly status: AgentStatus }) {\n const isLive = status === "submitted" || status === "streaming";\n const tone =\n status === "error"\n ? "bg-destructive"\n : isLive\n ? "bg-emerald-500"\n : status === "ready"\n ? "bg-muted-foreground"\n : "bg-muted-foreground/50";\n\n return (\n <span className="relative flex size-1">\n {isLive ? (\n <span\n className={cn(\n "absolute inline-flex size-full animate-ping rounded-full opacity-75",\n tone,\n )}\n />\n ) : null}\n <span className={cn("relative inline-flex size-1 rounded-full transition-colors", tone)} />\n </span>\n );\n}\n';
4
- readonly "app/_components/agent-message.tsx": '"use client";\n\nimport type {\n EveAuthorizationPart,\n EveDynamicToolPart,\n EveMessage,\n EveMessagePart,\n} from "eve/react";\nimport { CheckCircleIcon, ExternalLinkIcon, KeyRoundIcon, XCircleIcon } from "lucide-react";\nimport { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";\nimport { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";\nimport {\n Tool,\n ToolContent,\n ToolHeader,\n ToolInput,\n ToolOutput,\n} from "@/components/ai-elements/tool";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\n\nexport type AgentInputResponse = {\n readonly optionId?: string;\n readonly requestId: string;\n readonly text?: string;\n};\n\nexport function AgentMessage({\n canRespond,\n isStreaming,\n message,\n onInputResponses,\n}: {\n readonly canRespond: boolean;\n readonly isStreaming: boolean;\n readonly message: EveMessage;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n const lastTextIndex = message.parts.reduce(\n (last, part, index) => (part.type === "text" ? index : last),\n -1,\n );\n\n return (\n <Message\n data-optimistic={message.metadata?.optimistic ? "true" : undefined}\n from={message.role}\n >\n <MessageContent>\n {message.parts.map((part, index) => (\n <AgentMessagePart\n canRespond={canRespond}\n key={partKey(part, index)}\n onInputResponses={onInputResponses}\n part={part}\n showCaret={isStreaming && message.role === "assistant" && index === lastTextIndex}\n />\n ))}\n </MessageContent>\n </Message>\n );\n}\n\nfunction AgentMessagePart({\n canRespond,\n onInputResponses,\n part,\n showCaret,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveMessagePart;\n readonly showCaret: boolean;\n}) {\n switch (part.type) {\n case "step-start":\n return null;\n case "text":\n return (\n <MessageResponse caret="block" isAnimating={showCaret}>\n {part.text}\n </MessageResponse>\n );\n case "reasoning":\n return (\n <Reasoning defaultOpen isStreaming={part.state === "streaming"}>\n <ReasoningTrigger />\n <ReasoningContent>{part.text}</ReasoningContent>\n </Reasoning>\n );\n case "authorization":\n return <AuthorizationPrompt part={part} />;\n case "dynamic-tool":\n return (\n <Tool\n defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}\n >\n <ToolHeader\n state={part.state}\n title={part.toolName}\n toolName={part.toolName}\n type="dynamic-tool"\n />\n <ToolContent>\n <ToolInput input={part.input} />\n <InputRequestActions\n canRespond={canRespond}\n part={part}\n onInputResponses={onInputResponses}\n />\n <ToolOutput errorText={part.errorText} output={part.output} />\n </ToolContent>\n </Tool>\n );\n }\n}\n\nfunction AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {\n const isAuthorized = part.state === "completed" && part.outcome === "authorized";\n const isCompleted = part.state === "completed";\n const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;\n const instructions = part.authorization?.instructions;\n const shouldShowInstructions = instructions !== undefined && instructions !== part.description;\n\n return (\n <div\n className={cn(\n "space-y-3 rounded-md border p-3",\n isAuthorized\n ? "border-emerald-500/30 bg-emerald-500/5"\n : isCompleted\n ? "border-destructive/30 bg-destructive/5"\n : "border-blue-500/30 bg-blue-500/5",\n )}\n >\n <div className="flex items-start gap-3">\n <span\n className={cn(\n "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",\n isAuthorized\n ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"\n : isCompleted\n ? "bg-destructive/10 text-destructive"\n : "bg-blue-500/10 text-blue-700 dark:text-blue-300",\n )}\n >\n <Icon className="size-4" />\n </span>\n <div className="min-w-0 flex-1 space-y-2">\n <p className="font-medium text-sm">{authorizationTitle(part)}</p>\n <p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>\n {shouldShowInstructions ? (\n <p className="text-muted-foreground text-sm">{instructions}</p>\n ) : null}\n {part.state === "required" && part.authorization?.userCode ? (\n <div className="flex flex-wrap items-center gap-2 text-sm">\n <span className="text-muted-foreground">Code</span>\n <code className="rounded-md bg-background px-2 py-1 font-mono">\n {part.authorization.userCode}\n </code>\n </div>\n ) : null}\n {part.state === "required" && part.authorization?.url ? (\n <Button asChild size="sm">\n <a href={part.authorization.url} rel="noreferrer" target="_blank">\n <ExternalLinkIcon className="size-4" />\n Sign in with {part.displayName}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nfunction authorizationTitle(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return `Connect ${part.displayName}`;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected`;\n }\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}`;\n}\n\nfunction authorizationDescription(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return part.description;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected.`;\n }\n const tail = part.reason !== undefined ? ` (${part.reason})` : "";\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}${tail}.`;\n}\n\nfunction formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {\n switch (outcome) {\n case "authorized":\n return "authorized";\n case "declined":\n return "declined";\n case "failed":\n return "failed";\n case "timed-out":\n return "timed out";\n }\n}\n\nfunction InputRequestActions({\n canRespond,\n onInputResponses,\n part,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveDynamicToolPart;\n}) {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (!inputRequest) {\n return null;\n }\n\n const inputResponse = part.toolMetadata?.eve?.inputResponse;\n const selectedOption = inputRequest.options?.find(\n (option) => option.id === inputResponse?.optionId,\n );\n\n return (\n <div className="space-y-3 rounded-md border border-yellow-500/30 bg-yellow-500/5 p-3">\n <p className="text-muted-foreground text-sm">{inputRequest.prompt}</p>\n {inputResponse ? (\n <p className="font-medium text-sm">\n Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}\n </p>\n ) : (\n <div className="flex flex-wrap gap-2">\n {inputRequest.options?.map((option) => (\n <Button\n disabled={!canRespond}\n key={option.id}\n onClick={() => {\n void onInputResponses([\n {\n optionId: option.id,\n requestId: inputRequest.requestId,\n },\n ]);\n }}\n size="sm"\n type="button"\n variant={option.style === "danger" ? "destructive" : "default"}\n >\n {option.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction partKey(part: EveMessagePart, index: number): string {\n switch (part.type) {\n case "authorization":\n return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;\n case "dynamic-tool":\n return part.toolCallId;\n default:\n return `${part.type}:${index}`;\n }\n}\n';
3
+ readonly "app/_components/agent-chat.tsx": '"use client";\n\nimport type { UserContent } from "ai";\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon } from "lucide-react";\nimport {\n Conversation,\n ConversationContent,\n ConversationScrollButton,\n} from "@/components/ai-elements/conversation";\nimport {\n PromptInput,\n type PromptInputMessage,\n PromptInputSubmit,\n PromptInputTextarea,\n} from "@/components/ai-elements/prompt-input";\nimport { cn } from "@/lib/utils";\nimport { AgentMessage } from "./agent-message";\n\nconst AGENT_NAME = "__EVE_INIT_APP_NAME__";\n\ntype AgentStatus = ReturnType<typeof useEveAgent>["status"];\n\nexport function AgentChat() {\n const agent = useEveAgent();\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isEmpty = agent.data.messages.length === 0;\n\n const handleSubmit = async (message: PromptInputMessage) => {\n const text = message.text.trim();\n if ((text.length === 0 && message.files.length === 0) || isBusy) return;\n\n if (message.files.length === 0) {\n await agent.send({ message: text });\n return;\n }\n\n const parts: UserContent = [];\n if (text.length > 0) {\n parts.push({ text, type: "text" });\n }\n for (const file of message.files) {\n parts.push({\n data: file.url,\n filename: file.filename,\n mediaType: file.mediaType,\n type: "file",\n });\n }\n\n await agent.send({ message: parts });\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea placeholder="Send a message…" />\n <PromptInputSubmit onStop={agent.stop} status={agent.status} />\n </PromptInput>\n );\n\n return (\n <main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">\n {isEmpty ? null : (\n <header className="flex h-14 shrink-0 items-center justify-center gap-3 pl-4 pr-2">\n <span className="flex min-w-0 items-center gap-2">\n <span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>\n <StatusDot status={agent.status} />\n </span>\n </header>\n )}\n\n {agent.error ? (\n <div className="mx-auto w-full max-w-3xl shrink-0 px-4 pt-2 sm:px-6">\n <div className="flex items-start gap-3 rounded-lg border border-destructive/30 bg-destructive/5 px-3 py-2.5 text-sm">\n <AlertCircleIcon className="mt-0.5 size-4 shrink-0 text-destructive" />\n <div>\n <p className="font-medium">Request failed</p>\n <p className="mt-0.5 text-muted-foreground">{agent.error.message}</p>\n </div>\n </div>\n </div>\n ) : null}\n\n {isEmpty ? null : (\n <Conversation className="min-h-0 flex-1">\n <ConversationContent className="mx-auto w-full max-w-3xl gap-6 px-4 py-6 sm:px-6">\n {agent.data.messages.map((message, index) => (\n <AgentMessage\n canRespond={!isBusy}\n isStreaming={\n agent.status === "streaming" && index === agent.data.messages.length - 1\n }\n key={message.id}\n message={message}\n onInputResponses={(inputResponses) => agent.send({ inputResponses })}\n />\n ))}\n </ConversationContent>\n <ConversationScrollButton />\n </Conversation>\n )}\n\n <div\n className={cn(\n "mx-auto w-full px-4 sm:px-6",\n isEmpty\n ? "flex max-w-xl flex-1 flex-col items-center justify-center gap-8 pb-[10vh]"\n : "max-w-3xl shrink-0 pb-6",\n )}\n >\n {isEmpty ? (\n <div className="flex flex-col items-center gap-3 text-center">\n <h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>\n </div>\n ) : null}\n <div className="w-full">{composer}</div>\n </div>\n </main>\n );\n}\n\nfunction StatusDot({ status }: { readonly status: AgentStatus }) {\n const isLive = status === "submitted" || status === "streaming";\n const tone =\n status === "error"\n ? "bg-destructive"\n : isLive\n ? "bg-emerald-500"\n : status === "ready"\n ? "bg-muted-foreground"\n : "bg-muted-foreground/50";\n\n return (\n <span className="relative flex size-1">\n {isLive ? (\n <span\n className={cn(\n "absolute inline-flex size-full animate-ping rounded-full opacity-75",\n tone,\n )}\n />\n ) : null}\n <span className={cn("relative inline-flex size-1 rounded-full transition-colors", tone)} />\n </span>\n );\n}\n';
4
+ readonly "app/_components/agent-message.tsx": '"use client";\n\nimport type {\n EveAuthorizationPart,\n EveDynamicToolPart,\n EveMessage,\n EveMessagePart,\n} from "eve/react";\nimport {\n CheckCircleIcon,\n ExternalLinkIcon,\n FileIcon,\n ImageIcon,\n KeyRoundIcon,\n XCircleIcon,\n} from "lucide-react";\nimport { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";\nimport { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";\nimport {\n Tool,\n ToolContent,\n ToolHeader,\n ToolInput,\n ToolOutput,\n} from "@/components/ai-elements/tool";\nimport { Button } from "@/components/ui/button";\nimport { cn } from "@/lib/utils";\n\nexport type AgentInputResponse = {\n readonly optionId?: string;\n readonly requestId: string;\n readonly text?: string;\n};\n\ntype EveFilePart = Extract<EveMessagePart, { type: "file" }>;\n\nexport function AgentMessage({\n canRespond,\n isStreaming,\n message,\n onInputResponses,\n}: {\n readonly canRespond: boolean;\n readonly isStreaming: boolean;\n readonly message: EveMessage;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n}) {\n const lastTextIndex = message.parts.reduce(\n (last, part, index) => (part.type === "text" ? index : last),\n -1,\n );\n\n return (\n <Message\n data-optimistic={message.metadata?.optimistic ? "true" : undefined}\n from={message.role}\n >\n <MessageContent>\n {message.parts.map((part, index) => (\n <AgentMessagePart\n canRespond={canRespond}\n key={partKey(part, index)}\n onInputResponses={onInputResponses}\n part={part}\n showCaret={isStreaming && message.role === "assistant" && index === lastTextIndex}\n />\n ))}\n </MessageContent>\n </Message>\n );\n}\n\nfunction AgentMessagePart({\n canRespond,\n onInputResponses,\n part,\n showCaret,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveMessagePart;\n readonly showCaret: boolean;\n}) {\n switch (part.type) {\n case "step-start":\n return null;\n case "text":\n return (\n <MessageResponse caret="block" isAnimating={showCaret}>\n {part.text}\n </MessageResponse>\n );\n case "reasoning":\n return (\n <Reasoning defaultOpen isStreaming={part.state === "streaming"}>\n <ReasoningTrigger />\n <ReasoningContent>{part.text}</ReasoningContent>\n </Reasoning>\n );\n case "file":\n return <AttachmentPart part={part} />;\n case "authorization":\n return <AuthorizationPrompt part={part} />;\n case "dynamic-tool":\n return (\n <Tool\n defaultOpen={part.state === "approval-requested" || part.state === "approval-responded"}\n >\n <ToolHeader\n state={part.state}\n title={part.toolName}\n toolName={part.toolName}\n type="dynamic-tool"\n />\n <ToolContent>\n <ToolInput input={part.input} />\n <InputRequestActions\n canRespond={canRespond}\n part={part}\n onInputResponses={onInputResponses}\n />\n <ToolOutput errorText={part.errorText} output={part.output} />\n </ToolContent>\n </Tool>\n );\n }\n}\n\nfunction AttachmentPart({ part }: { readonly part: EveFilePart }) {\n const label = part.filename ?? "Attachment";\n const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");\n const isImage = part.mediaType.startsWith("image/") && part.url !== undefined;\n const Icon = isImage ? ImageIcon : FileIcon;\n const body = (\n <span className="flex max-w-sm items-center gap-3 rounded-md border bg-background/60 p-2 text-sm">\n {isImage ? (\n <img alt={label} className="size-12 shrink-0 rounded-sm object-cover" src={part.url} />\n ) : (\n <span className="flex size-10 shrink-0 items-center justify-center rounded-sm bg-muted text-muted-foreground">\n <Icon className="size-4" />\n </span>\n )}\n <span className="min-w-0 flex-1">\n <span className="block truncate font-medium">{label}</span>\n {detail ? <span className="block truncate text-muted-foreground">{detail}</span> : null}\n </span>\n {part.url ? <ExternalLinkIcon className="size-4 shrink-0 text-muted-foreground" /> : null}\n </span>\n );\n\n return part.url ? (\n <a href={part.url} rel="noreferrer" target="_blank">\n {body}\n </a>\n ) : (\n body\n );\n}\n\nfunction AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {\n const isAuthorized = part.state === "completed" && part.outcome === "authorized";\n const isCompleted = part.state === "completed";\n const Icon = isAuthorized ? CheckCircleIcon : isCompleted ? XCircleIcon : KeyRoundIcon;\n const instructions = part.authorization?.instructions;\n const shouldShowInstructions = instructions !== undefined && instructions !== part.description;\n\n return (\n <div\n className={cn(\n "space-y-3 rounded-md border p-3",\n isAuthorized\n ? "border-emerald-500/30 bg-emerald-500/5"\n : isCompleted\n ? "border-destructive/30 bg-destructive/5"\n : "border-blue-500/30 bg-blue-500/5",\n )}\n >\n <div className="flex items-start gap-3">\n <span\n className={cn(\n "mt-0.5 flex size-8 shrink-0 items-center justify-center rounded-full",\n isAuthorized\n ? "bg-emerald-500/10 text-emerald-700 dark:text-emerald-300"\n : isCompleted\n ? "bg-destructive/10 text-destructive"\n : "bg-blue-500/10 text-blue-700 dark:text-blue-300",\n )}\n >\n <Icon className="size-4" />\n </span>\n <div className="min-w-0 flex-1 space-y-2">\n <p className="font-medium text-sm">{authorizationTitle(part)}</p>\n <p className="text-muted-foreground text-sm">{authorizationDescription(part)}</p>\n {shouldShowInstructions ? (\n <p className="text-muted-foreground text-sm">{instructions}</p>\n ) : null}\n {part.state === "required" && part.authorization?.userCode ? (\n <div className="flex flex-wrap items-center gap-2 text-sm">\n <span className="text-muted-foreground">Code</span>\n <code className="rounded-md bg-background px-2 py-1 font-mono">\n {part.authorization.userCode}\n </code>\n </div>\n ) : null}\n {part.state === "required" && part.authorization?.url ? (\n <Button asChild size="sm">\n <a href={part.authorization.url} rel="noreferrer" target="_blank">\n <ExternalLinkIcon className="size-4" />\n Sign in with {part.displayName}\n </a>\n </Button>\n ) : null}\n </div>\n </div>\n </div>\n );\n}\n\nfunction authorizationTitle(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return `Connect ${part.displayName}`;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected`;\n }\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}`;\n}\n\nfunction authorizationDescription(part: EveAuthorizationPart): string {\n if (part.state === "required") {\n return part.description;\n }\n if (part.outcome === "authorized") {\n return `${part.displayName} connected.`;\n }\n const tail = part.reason !== undefined ? ` (${part.reason})` : "";\n return `${part.displayName} authorization ${formatAuthorizationOutcome(part.outcome)}${tail}.`;\n}\n\nfunction formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["outcome"]>): string {\n switch (outcome) {\n case "authorized":\n return "authorized";\n case "declined":\n return "declined";\n case "failed":\n return "failed";\n case "timed-out":\n return "timed out";\n }\n}\n\nfunction formatBytes(size: number | undefined): string | undefined {\n if (size === undefined) {\n return undefined;\n }\n if (size < 1024) {\n return `${size} B`;\n }\n if (size < 1024 * 1024) {\n return `${(size / 1024).toFixed(1)} KB`;\n }\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n}\n\nfunction InputRequestActions({\n canRespond,\n onInputResponses,\n part,\n}: {\n readonly canRespond: boolean;\n readonly onInputResponses: (responses: readonly AgentInputResponse[]) => void | Promise<void>;\n readonly part: EveDynamicToolPart;\n}) {\n const inputRequest = part.toolMetadata?.eve?.inputRequest;\n if (!inputRequest) {\n return null;\n }\n\n const inputResponse = part.toolMetadata?.eve?.inputResponse;\n const selectedOption = inputRequest.options?.find(\n (option) => option.id === inputResponse?.optionId,\n );\n\n return (\n <div className="space-y-3 rounded-md border border-yellow-500/30 bg-yellow-500/5 p-3">\n <p className="text-muted-foreground text-sm">{inputRequest.prompt}</p>\n {inputResponse ? (\n <p className="font-medium text-sm">\n Responded: {selectedOption?.label ?? inputResponse.text ?? inputResponse.optionId}\n </p>\n ) : (\n <div className="flex flex-wrap gap-2">\n {inputRequest.options?.map((option) => (\n <Button\n disabled={!canRespond}\n key={option.id}\n onClick={() => {\n void onInputResponses([\n {\n optionId: option.id,\n requestId: inputRequest.requestId,\n },\n ]);\n }}\n size="sm"\n type="button"\n variant={option.style === "danger" ? "destructive" : "default"}\n >\n {option.label}\n </Button>\n ))}\n </div>\n )}\n </div>\n );\n}\n\nfunction partKey(part: EveMessagePart, index: number): string {\n switch (part.type) {\n case "authorization":\n return `authorization:${part.turnId}:${part.stepIndex}:${part.name}`;\n case "dynamic-tool":\n return part.toolCallId;\n default:\n return `${part.type}:${index}`;\n }\n}\n';
5
5
  readonly "app/globals.css": '@import "tailwindcss";\n@source "../node_modules/streamdown/dist/*.js";\n\n@theme inline {\n --color-background: var(--background);\n --color-foreground: var(--foreground);\n --color-card: var(--card);\n --color-card-foreground: var(--card-foreground);\n --color-popover: var(--popover);\n --color-popover-foreground: var(--popover-foreground);\n --color-primary: var(--primary);\n --color-primary-foreground: var(--primary-foreground);\n --color-secondary: var(--secondary);\n --color-secondary-foreground: var(--secondary-foreground);\n --color-muted: var(--muted);\n --color-muted-foreground: var(--muted-foreground);\n --color-accent: var(--accent);\n --color-accent-foreground: var(--accent-foreground);\n --color-destructive: var(--destructive);\n --color-border: var(--border);\n --color-input: var(--input);\n --color-ring: var(--ring);\n --radius-sm: calc(var(--radius) - 4px);\n --radius-md: calc(var(--radius) - 2px);\n --radius-lg: var(--radius);\n --radius-xl: calc(var(--radius) + 4px);\n --font-sans: "Geist", "Geist Fallback", ui-sans-serif, system-ui, sans-serif;\n --font-mono: "Geist Mono", "Geist Mono Fallback", ui-monospace, monospace;\n}\n\n:root {\n color-scheme: light;\n /* Soft neutral page with white elevated surfaces so cards/composer pop. */\n --background: oklch(0.971 0 0);\n --foreground: oklch(0.16 0 0);\n --card: oklch(1 0 0);\n --card-foreground: oklch(0.16 0 0);\n --popover: oklch(1 0 0);\n --popover-foreground: oklch(0.16 0 0);\n --primary: oklch(0.19 0 0);\n --primary-foreground: oklch(0.985 0 0);\n --secondary: oklch(0.94 0 0);\n --secondary-foreground: oklch(0.19 0 0);\n --muted: oklch(0.94 0 0);\n --muted-foreground: oklch(0.6 0 0);\n --accent: oklch(0.94 0 0);\n --accent-foreground: oklch(0.19 0 0);\n --destructive: oklch(0.577 0.245 27.325);\n --border: oklch(0.916 0 0);\n --input: oklch(0.916 0 0);\n --ring: oklch(0.708 0 0);\n --radius: 0.625rem;\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n color-scheme: dark;\n --background: oklch(0.145 0 0);\n --foreground: oklch(0.985 0 0);\n --card: oklch(0.205 0 0);\n --card-foreground: oklch(0.985 0 0);\n --popover: oklch(0.205 0 0);\n --popover-foreground: oklch(0.985 0 0);\n --primary: oklch(0.922 0 0);\n --primary-foreground: oklch(0.205 0 0);\n --secondary: oklch(0.269 0 0);\n --secondary-foreground: oklch(0.985 0 0);\n --muted: oklch(0.269 0 0);\n --muted-foreground: oklch(0.708 0 0);\n --accent: oklch(0.269 0 0);\n --accent-foreground: oklch(0.985 0 0);\n --destructive: oklch(0.704 0.191 22.216);\n --border: oklch(1 0 0 / 10%);\n --input: oklch(1 0 0 / 15%);\n --ring: oklch(0.556 0 0);\n }\n}\n\n* {\n border-color: var(--border);\n}\n\nhtml {\n height: 100%;\n}\n\nbody {\n min-height: 100%;\n margin: 0;\n background: var(--background);\n font-family: var(--font-sans);\n}\n\nbutton,\ninput,\ntextarea {\n font: inherit;\n}\n';
6
6
  readonly "app/layout.tsx": 'import type { Metadata } from "next";\nimport { Geist, Geist_Mono } from "next/font/google";\nimport type { ReactNode } from "react";\nimport { TooltipProvider } from "@/components/ui/tooltip";\nimport { cn } from "@/lib/utils";\nimport "./globals.css";\n\nconst sans = Geist({\n variable: "--font-sans",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nconst mono = Geist_Mono({\n variable: "--font-mono",\n subsets: ["latin"],\n weight: "variable",\n display: "swap",\n});\n\nexport const metadata: Metadata = {\n title: "__EVE_INIT_APP_NAME__",\n description: "A Next.js starter for eve agents with AI Elements.",\n};\n\nexport default function RootLayout({ children }: { readonly children: ReactNode }) {\n return (\n <html className={cn(sans.variable, mono.variable)} lang="en">\n <body>\n <TooltipProvider>{children}</TooltipProvider>\n </body>\n </html>\n );\n}\n';
7
7
  readonly "app/page.tsx": 'import { AgentChat } from "@/app/_components/agent-chat";\n\nexport default function Page() {\n return <AgentChat />;\n}\n';
@@ -15,6 +15,7 @@ export default eveChannel({
15
15
  });
16
16
  `,"app/_components/agent-chat.tsx":`"use client";
17
17
 
18
+ import type { UserContent } from "ai";
18
19
  import { useEveAgent } from "eve/react";
19
20
  import { AlertCircleIcon } from "lucide-react";
20
21
  import {
@@ -42,9 +43,27 @@ export function AgentChat() {
42
43
 
43
44
  const handleSubmit = async (message: PromptInputMessage) => {
44
45
  const text = message.text.trim();
45
- if (!text || isBusy) return;
46
+ if ((text.length === 0 && message.files.length === 0) || isBusy) return;
46
47
 
47
- await agent.send({ message: text });
48
+ if (message.files.length === 0) {
49
+ await agent.send({ message: text });
50
+ return;
51
+ }
52
+
53
+ const parts: UserContent = [];
54
+ if (text.length > 0) {
55
+ parts.push({ text, type: "text" });
56
+ }
57
+ for (const file of message.files) {
58
+ parts.push({
59
+ data: file.url,
60
+ filename: file.filename,
61
+ mediaType: file.mediaType,
62
+ type: "file",
63
+ });
64
+ }
65
+
66
+ await agent.send({ message: parts });
48
67
  };
49
68
 
50
69
  const composer = (
@@ -148,7 +167,14 @@ import type {
148
167
  EveMessage,
149
168
  EveMessagePart,
150
169
  } from "eve/react";
151
- import { CheckCircleIcon, ExternalLinkIcon, KeyRoundIcon, XCircleIcon } from "lucide-react";
170
+ import {
171
+ CheckCircleIcon,
172
+ ExternalLinkIcon,
173
+ FileIcon,
174
+ ImageIcon,
175
+ KeyRoundIcon,
176
+ XCircleIcon,
177
+ } from "lucide-react";
152
178
  import { Message, MessageContent, MessageResponse } from "@/components/ai-elements/message";
153
179
  import { Reasoning, ReasoningContent, ReasoningTrigger } from "@/components/ai-elements/reasoning";
154
180
  import {
@@ -167,6 +193,8 @@ export type AgentInputResponse = {
167
193
  readonly text?: string;
168
194
  };
169
195
 
196
+ type EveFilePart = Extract<EveMessagePart, { type: "file" }>;
197
+
170
198
  export function AgentMessage({
171
199
  canRespond,
172
200
  isStreaming,
@@ -230,6 +258,8 @@ function AgentMessagePart({
230
258
  <ReasoningContent>{part.text}</ReasoningContent>
231
259
  </Reasoning>
232
260
  );
261
+ case "file":
262
+ return <AttachmentPart part={part} />;
233
263
  case "authorization":
234
264
  return <AuthorizationPrompt part={part} />;
235
265
  case "dynamic-tool":
@@ -257,6 +287,37 @@ function AgentMessagePart({
257
287
  }
258
288
  }
259
289
 
290
+ function AttachmentPart({ part }: { readonly part: EveFilePart }) {
291
+ const label = part.filename ?? "Attachment";
292
+ const detail = [part.mediaType, formatBytes(part.size)].filter(Boolean).join(" - ");
293
+ const isImage = part.mediaType.startsWith("image/") && part.url !== undefined;
294
+ const Icon = isImage ? ImageIcon : FileIcon;
295
+ const body = (
296
+ <span className="flex max-w-sm items-center gap-3 rounded-md border bg-background/60 p-2 text-sm">
297
+ {isImage ? (
298
+ <img alt={label} className="size-12 shrink-0 rounded-sm object-cover" src={part.url} />
299
+ ) : (
300
+ <span className="flex size-10 shrink-0 items-center justify-center rounded-sm bg-muted text-muted-foreground">
301
+ <Icon className="size-4" />
302
+ </span>
303
+ )}
304
+ <span className="min-w-0 flex-1">
305
+ <span className="block truncate font-medium">{label}</span>
306
+ {detail ? <span className="block truncate text-muted-foreground">{detail}</span> : null}
307
+ </span>
308
+ {part.url ? <ExternalLinkIcon className="size-4 shrink-0 text-muted-foreground" /> : null}
309
+ </span>
310
+ );
311
+
312
+ return part.url ? (
313
+ <a href={part.url} rel="noreferrer" target="_blank">
314
+ {body}
315
+ </a>
316
+ ) : (
317
+ body
318
+ );
319
+ }
320
+
260
321
  function AuthorizationPrompt({ part }: { readonly part: EveAuthorizationPart }) {
261
322
  const isAuthorized = part.state === "completed" && part.outcome === "authorized";
262
323
  const isCompleted = part.state === "completed";
@@ -350,6 +411,19 @@ function formatAuthorizationOutcome(outcome: NonNullable<EveAuthorizationPart["o
350
411
  }
351
412
  }
352
413
 
414
+ function formatBytes(size: number | undefined): string | undefined {
415
+ if (size === undefined) {
416
+ return undefined;
417
+ }
418
+ if (size < 1024) {
419
+ return \`\${size} B\`;
420
+ }
421
+ if (size < 1024 * 1024) {
422
+ return \`\${(size / 1024).toFixed(1)} KB\`;
423
+ }
424
+ return \`\${(size / (1024 * 1024)).toFixed(1)} MB\`;
425
+ }
426
+
353
427
  function InputRequestActions({
354
428
  canRespond,
355
429
  onInputResponses,
@@ -103,9 +103,28 @@ export interface AgentLimitsDefinition {
103
103
  * Root sessions are depth 0. A `maxSubagentDepth` of 3 allows child sessions at
104
104
  * depths 1, 2, and 3; sessions already at depth 3 cannot delegate again.
105
105
  *
106
+ * Delegated subagent sessions resolve this against the cap inherited from
107
+ * the delegating parent; the tighter value wins.
108
+ *
106
109
  * @default 3
107
110
  */
108
111
  readonly maxSubagentDepth?: number;
112
+ /**
113
+ * Maximum number of subagent calls one `Workflow` tool invocation may
114
+ * dispatch.
115
+ *
116
+ * Applies to the opt-in `Workflow` orchestration tool: a single
117
+ * model-authored workflow program may spawn at most this many subagent or
118
+ * remote-agent calls, counted across the whole program (sequential and
119
+ * parallel calls alike). Calls beyond the limit fail with an error result
120
+ * instead of starting a child session.
121
+ *
122
+ * Delegated subagent sessions resolve this against the cap inherited from
123
+ * the delegating parent; the tighter value wins.
124
+ *
125
+ * @default 100
126
+ */
127
+ readonly maxSubagents?: number;
109
128
  /**
110
129
  * Maximum provider-reported input tokens accumulated by one durable session.
111
130
  *
@@ -113,17 +132,26 @@ export interface AgentLimitsDefinition {
113
132
  * the limit is allowed to finish because providers only report exact usage
114
133
  * after the call completes; later model calls in the same session are blocked.
115
134
  *
116
- * @default 40_000_000 for root sessions; 5_000_000 for delegated subagent sessions
135
+ * `false` disables the limit: the session is uncapped.
136
+ *
137
+ * Delegated subagent sessions default to the delegating parent's remaining
138
+ * quota at dispatch time, and the parent's remaining quota always caps an
139
+ * authored child limit — a child can never outspend its parent's budget.
140
+ *
141
+ * @default 40_000_000 for root sessions; the parent's remaining quota for delegated subagent sessions
117
142
  */
118
- readonly maxInputTokensPerSession?: number;
143
+ readonly maxInputTokensPerSession?: number | false;
119
144
  /**
120
145
  * Maximum provider-reported output tokens accumulated by one durable session.
121
146
  *
122
147
  * eve checks this before starting each model call. The model call that crosses
123
148
  * the limit is allowed to finish because providers only report exact usage
124
149
  * after the call completes; later model calls in the same session are blocked.
150
+ *
151
+ * `false` disables the limit. Unset by default; delegated subagent sessions
152
+ * inherit the parent's remaining output quota when the parent has one.
125
153
  */
126
- readonly maxOutputTokensPerSession?: number;
154
+ readonly maxOutputTokensPerSession?: number | false;
127
155
  }
128
156
  /**
129
157
  * Experimental, opt-in agent capabilities authored in `agent.ts`.
@@ -30,7 +30,7 @@ export declare function writeSkillPackageDirectory(input: {
30
30
  }): Promise<void>;
31
31
  /**
32
32
  * Writes a normalized package into the live sandbox under
33
- * `/workspace/skills/<name>/`.
33
+ * the sandbox skill root.
34
34
  */
35
35
  export declare function writeSkillPackageToSandbox(input: {
36
36
  readonly sandbox: SandboxSession;
@@ -45,6 +45,6 @@ export declare function removeSkillPackageFromSandbox(input: {
45
45
  }): Promise<void>;
46
46
  /**
47
47
  * Validates a runtime-contributed skill name before it becomes one path
48
- * segment under `/workspace/skills`.
48
+ * segment under the sandbox skill root.
49
49
  */
50
50
  export declare function assertSafeSkillPackageName(name: string): void;
@@ -1 +1 @@
1
- import{dirname,join}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{Buffer}from"node:buffer";const WORKSPACE_ROOT=`/workspace`;function normalizeSkillPackage(e){assertSafeSkillPackageName(e.name);let t=[{content:Buffer.from(e.markdown,`utf8`),relativePath:`SKILL.md`}];for(let[n,r]of Object.entries(e.files??{}))assertSafeSkillPackageFilePath(n),t.push({content:contentToBuffer(r),relativePath:n});return t.sort((e,t)=>comparePaths(e.relativePath,t.relativePath)),{description:e.description,files:t,license:e.license,markdown:e.markdown,metadata:e.metadata===void 0?void 0:{...e.metadata},name:e.name}}async function writeSkillPackageDirectory(i){for(let a of i.skill.files){let o=join(i.rootPath,`skills`,i.skill.name,a.relativePath);await mkdir(dirname(o),{recursive:!0}),await writeFile(o,a.content)}}async function writeSkillPackageToSandbox(e){for(let t of e.skill.files)await e.sandbox.writeBinaryFile({content:t.content,path:`${WORKSPACE_ROOT}/skills/${e.skill.name}/${t.relativePath}`})}async function removeSkillPackageFromSandbox(e){assertSafeSkillPackageName(e.name),await e.sandbox.removePath({force:!0,path:`${WORKSPACE_ROOT}/skills/${e.name}`,recursive:!0})}function assertSafeSkillPackageName(e){if(e.length===0||e.startsWith(`.`)||e.includes(`/`)||e.includes(`\\`)||e.includes(`..`)||!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(e)||/^[A-Za-z]:/.test(e))throw Error(`Expected skill name to be a non-empty shell-safe path segment starting with an alphanumeric character and containing only alphanumerics, ".", "_", or "-".`)}function assertSafeSkillPackageFilePath(e){if(e===`SKILL.md`)throw Error(`Skill package files must not include "SKILL.md"; eve generates it.`);if(e.length===0||e.startsWith(`/`)||e.includes(`\\`)||/^[A-Za-z]:/.test(e)||e.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw Error(`Expected skill package file paths to be relative POSIX paths.`)}function contentToBuffer(e){return typeof e==`string`?Buffer.from(e,`utf8`):Buffer.from(e)}function comparePaths(e,t){return e<t?-1:+(e>t)}export{assertSafeSkillPackageName,normalizeSkillPackage,removeSkillPackageFromSandbox,writeSkillPackageDirectory,writeSkillPackageToSandbox};
1
+ import{dirname,join}from"node:path";import{mkdir,writeFile}from"node:fs/promises";import{resolveSandboxSkillRoot,resolveSandboxSkillWritePath}from"#shared/skill-paths.js";import{Buffer}from"node:buffer";function normalizeSkillPackage(e){assertSafeSkillPackageName(e.name);let t=[{content:Buffer.from(e.markdown,`utf8`),relativePath:`SKILL.md`}];for(let[n,r]of Object.entries(e.files??{}))assertSafeSkillPackageFilePath(n),t.push({content:contentToBuffer(r),relativePath:n});return t.sort((e,t)=>comparePaths(e.relativePath,t.relativePath)),{description:e.description,files:t,license:e.license,markdown:e.markdown,metadata:e.metadata===void 0?void 0:{...e.metadata},name:e.name}}async function writeSkillPackageDirectory(i){for(let a of i.skill.files){let o=join(i.rootPath,`skills`,i.skill.name,a.relativePath);await mkdir(dirname(o),{recursive:!0}),await writeFile(o,a.content)}}async function writeSkillPackageToSandbox(e){for(let t of e.skill.files)await e.sandbox.writeBinaryFile({content:t.content,path:await resolveSandboxSkillWritePath({name:e.skill.name,relativePath:t.relativePath,sandbox:e.sandbox})})}async function removeSkillPackageFromSandbox(e){assertSafeSkillPackageName(e.name);let t=await resolveSandboxSkillRoot({sandbox:e.sandbox});await e.sandbox.removePath({force:!0,path:`${t}/${e.name}`,recursive:!0})}function assertSafeSkillPackageName(e){if(e.length===0||e.startsWith(`.`)||e.includes(`/`)||e.includes(`\\`)||e.includes(`..`)||!/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(e)||/^[A-Za-z]:/.test(e))throw Error(`Expected skill name to be a non-empty shell-safe path segment starting with an alphanumeric character and containing only alphanumerics, ".", "_", or "-".`)}function assertSafeSkillPackageFilePath(e){if(e===`SKILL.md`)throw Error(`Skill package files must not include "SKILL.md"; eve generates it.`);if(e.length===0||e.startsWith(`/`)||e.includes(`\\`)||/^[A-Za-z]:/.test(e)||e.split(`/`).some(e=>e.length===0||e===`.`||e===`..`))throw Error(`Expected skill package file paths to be relative POSIX paths.`)}function contentToBuffer(e){return typeof e==`string`?Buffer.from(e,`utf8`):Buffer.from(e)}function comparePaths(e,t){return e<t?-1:+(e>t)}export{assertSafeSkillPackageName,normalizeSkillPackage,removeSkillPackageFromSandbox,writeSkillPackageDirectory,writeSkillPackageToSandbox};
@@ -0,0 +1,28 @@
1
+ import type { SandboxSession } from "#shared/sandbox-session.js";
2
+ export declare const MODEL_SKILL_ROOT = "$HOME/.agents/skills";
3
+ export declare const FALLBACK_SKILL_ROOT = "/workspace/skills";
4
+ export declare function formatSkillModelPath(input: {
5
+ readonly name: string;
6
+ readonly relativePath: string;
7
+ }): string;
8
+ export declare function formatFallbackSkillPath(input: {
9
+ readonly name: string;
10
+ readonly relativePath: string;
11
+ }): string;
12
+ export declare function resolveSandboxSkillRoot(input: {
13
+ readonly sandbox: SandboxSession;
14
+ }): Promise<string>;
15
+ export declare function resolveSandboxSkillReadPaths(input: {
16
+ readonly name: string;
17
+ readonly relativePath: string;
18
+ readonly sandbox: SandboxSession;
19
+ }): Promise<readonly string[]>;
20
+ export declare function resolveSandboxSkillWritePath(input: {
21
+ readonly name: string;
22
+ readonly relativePath: string;
23
+ readonly sandbox: SandboxSession;
24
+ }): Promise<string>;
25
+ export declare function resolveSandboxSeedFilePath(input: {
26
+ readonly path: string;
27
+ readonly sandbox: SandboxSession;
28
+ }): Promise<string>;
@@ -0,0 +1,2 @@
1
+ const MODEL_SKILL_ROOT=`$HOME/.agents/skills`,FALLBACK_SKILL_ROOT=`/workspace/skills`,skillRootCache=new WeakMap;function formatSkillModelPath(t){return formatSkillPath({name:t.name,relativePath:t.relativePath,root:MODEL_SKILL_ROOT})}function formatFallbackSkillPath(e){return formatSkillPath({name:e.name,relativePath:e.relativePath,root:FALLBACK_SKILL_ROOT})}async function resolveSandboxSkillRoot(e){let t=skillRootCache.get(e.sandbox);if(t!==void 0)return await t;let r=probeSandboxSkillRoot(e.sandbox);return skillRootCache.set(e.sandbox,r),await r}async function resolveSandboxSkillReadPaths(e){return[formatSkillPath({name:e.name,relativePath:e.relativePath,root:await resolveSandboxSkillRoot({sandbox:e.sandbox})})]}async function resolveSandboxSkillWritePath(e){return formatSkillPath({name:e.name,relativePath:e.relativePath,root:await resolveSandboxSkillRoot({sandbox:e.sandbox})})}async function resolveSandboxSeedFilePath(e){return e.path.startsWith(`$HOME/.agents/skills/`)?`${await resolveSandboxSkillRoot({sandbox:e.sandbox})}${e.path.slice(20)}`:e.path}function formatSkillPath(e){return`${e.root}/${e.name}/${e.relativePath}`}async function probeSandboxSkillRoot(e){try{let n=await e.run({command:`printf '%s\\n' "$HOME"`});if(n.exitCode!==0)return FALLBACK_SKILL_ROOT;let r=n.stdout.trim();return isUsableSandboxHome(r)?joinHomeSkillRoot(r):FALLBACK_SKILL_ROOT}catch{return FALLBACK_SKILL_ROOT}}function isUsableSandboxHome(e){return e.length>0&&e.startsWith(`/`)&&!e.includes(`\0`)&&!e.includes(`
2
+ `)&&!e.includes(`\r`)}function joinHomeSkillRoot(e){return`${e===`/`?``:e.replace(/\/+$/,``)}/.agents/skills`}export{FALLBACK_SKILL_ROOT,MODEL_SKILL_ROOT,formatFallbackSkillPath,formatSkillModelPath,resolveSandboxSeedFilePath,resolveSandboxSkillReadPaths,resolveSandboxSkillRoot,resolveSandboxSkillWritePath};
@@ -0,0 +1,22 @@
1
+ import { z } from "#compiled/zod/index.js";
2
+ /**
3
+ * Provider-reported token usage totals.
4
+ *
5
+ * The single usage shape across eve: harness accumulation
6
+ * (`turn-tag-state`), delegated subagent results, remote session
7
+ * callbacks, and usage spans all carry this type.
8
+ */
9
+ export type TokenUsage = z.infer<typeof tokenUsageSchema>;
10
+ /**
11
+ * Zod schema for {@link TokenUsage}.
12
+ *
13
+ * Validates the `usage` field of remote session callbacks, which may come
14
+ * from a callee on a different eve version — unknown keys are stripped
15
+ * rather than rejected so a newer sender never voids the whole payload.
16
+ */
17
+ export declare const tokenUsageSchema: z.ZodObject<{
18
+ cacheReadTokens: z.ZodNumber;
19
+ cacheWriteTokens: z.ZodNumber;
20
+ inputTokens: z.ZodNumber;
21
+ outputTokens: z.ZodNumber;
22
+ }, z.core.$strip>;
@@ -0,0 +1 @@
1
+ import{z}from"#compiled/zod/index.js";const tokenUsageSchema=z.object({cacheReadTokens:z.number().int().nonnegative(),cacheWriteTokens:z.number().int().nonnegative(),inputTokens:z.number().int().nonnegative(),outputTokens:z.number().int().nonnegative()});export{tokenUsageSchema};
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-Bh1NmXO9.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-CxcKypLZ.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-Bh1NmXO9.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-CxcKypLZ.js";
2
2
 
3
3
  export { useEveAgent };
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-Dvy_Wjvq.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-CM24ZUEI.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-Dvy_Wjvq.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-CM24ZUEI.js";
2
2
 
3
3
  export { useEveAgent };
@@ -93,13 +93,30 @@ export default defineAgent({
93
93
 
94
94
  Input and output budgets are checked independently. The model call that crosses
95
95
  either limit is allowed to finish because providers only report exact token
96
- usage after a call completes. Follow-up model calls in the same session fail
97
- with `SESSION_TOKEN_LIMIT_REACHED`.
98
-
99
- When `maxInputTokensPerSession` is omitted, eve applies a default input budget:
100
- `40_000_000` provider-reported input tokens for root sessions and `5_000_000`
101
- for delegated subagent sessions. `maxOutputTokensPerSession` is unset unless
102
- configured.
96
+ usage after a call completes. Before the next model call, eve pauses the
97
+ session and sends a deterministic continuation prompt with two options:
98
+ **Continue** grants a fresh budget window of the configured size (both input
99
+ and output windows reset together), and **Stop** ends the session gracefully
100
+ (`session.completed`) declining is a user decision, not an error. A reply
101
+ that answers neither option re-raises the prompt; the reply stays in history
102
+ and is processed once the budget is granted.
103
+
104
+ Sessions that cannot reach a human — task-mode runs such as schedules and
105
+ subagents without input proxying — skip the prompt and fail the next model
106
+ call with `SESSION_TOKEN_LIMIT_REACHED`.
107
+
108
+ When `maxInputTokensPerSession` is omitted, root sessions apply a default
109
+ input budget of `40_000_000` provider-reported input tokens.
110
+ `maxOutputTokensPerSession` is unset unless configured. Setting either limit
111
+ to `false` uncaps that axis — the session never stops on it.
112
+
113
+ Delegated subagent sessions have no fixed default. Each child receives a
114
+ share of the delegating parent's remaining quota at dispatch time — the
115
+ remainder (limit minus accumulated usage) split evenly across the batch's
116
+ local subagent calls — and a completed child's usage counts against the
117
+ parent's quota, so a delegation tree can never outspend the budget configured
118
+ at its root. An authored child limit applies only when it is tighter than the
119
+ parent's grant; an uncapped parent delegates uncapped children.
103
120
 
104
121
  ## Workflow world
105
122
 
@@ -142,14 +159,14 @@ installed package must stay external in hosted output, list it in
142
159
 
143
160
  `defineAgent` takes a few more fields, all optional. For the exported types, see the [TypeScript API](./reference/typescript-api).
144
161
 
145
- | Field | Type | Default | Description |
146
- | -------------- | --------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
147
- | `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
148
- | `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
149
- | `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. `maxSubagentDepth` defaults to `3`; `maxInputTokensPerSession` defaults to `40_000_000` for root sessions and `5_000_000` for delegated subagent sessions; `maxOutputTokensPerSession` is unset unless configured. |
150
- | `experimental` | `{ workflow?: { world?: string } }` | unset | Opt-in settings that can change or disappear in any release. Treat them as unstable. `workflow.world` selects the Workflow world package backing session state, queues, hooks, and streams on the root agent. |
151
- | `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for task-mode runs (a subagent, schedule, or remote job). Interactive conversation turns ignore it unless the client supplies a per-message schema. |
152
- | `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
162
+ | Field | Type | Default | Description |
163
+ | -------------- | --------------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
164
+ | `reasoning` | `AgentReasoningDefinition` | provider default | Provider-agnostic reasoning effort forwarded to the agent's turn model calls. |
165
+ | `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
166
+ | `limits` | `AgentLimitsDefinition` | field-specific | Framework-owned runtime limits. `maxSubagentDepth` defaults to `3`; `maxInputTokensPerSession` defaults to `40_000_000` for root sessions, and delegated subagent sessions inherit the parent's remaining quota; `maxOutputTokensPerSession` is unset unless configured; `false` uncaps a session token limit. |
167
+ | `experimental` | `{ workflow?: { world?: string } }` | unset | Opt-in settings that can change or disappear in any release. Treat them as unstable. `workflow.world` selects the Workflow world package backing session state, queues, hooks, and streams on the root agent. |
168
+ | `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for task-mode runs (a subagent, schedule, or remote job). Interactive conversation turns ignore it unless the client supplies a per-message schema. |
169
+ | `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
153
170
 
154
171
  `externalDependencies` is a packaging control only. It keeps selected packages as runtime dependencies in the hosted output; it does not authorize, configure, or review any third-party service those packages may call.
155
172