eve 0.37.1 → 0.38.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 (215) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/src/chunks/{use-eve-agent-DbKUBhl-.js → use-eve-agent-BbSsu99c.js} +70 -31
  3. package/dist/src/chunks/{use-eve-agent-Bi5fRxcZ.js → use-eve-agent-Dt8Y5QtW.js} +69 -30
  4. package/dist/src/cli/acp/command.d.ts +2 -1
  5. package/dist/src/cli/acp/command.js +2 -2
  6. package/dist/src/cli/application-command.d.ts +8 -0
  7. package/dist/src/cli/application-command.js +1 -0
  8. package/dist/src/cli/application-root.d.ts +8 -0
  9. package/dist/src/cli/application-root.js +1 -0
  10. package/dist/src/cli/commands/build.d.ts +2 -1
  11. package/dist/src/cli/commands/build.js +1 -1
  12. package/dist/src/cli/commands/init-repl.js +1 -1
  13. package/dist/src/cli/commands/register-integration-commands.d.ts +2 -1
  14. package/dist/src/cli/commands/register-integration-commands.js +1 -1
  15. package/dist/src/cli/commands/register-project-commands.d.ts +2 -1
  16. package/dist/src/cli/commands/register-project-commands.js +1 -1
  17. package/dist/src/cli/commands/register-registry-commands.d.ts +2 -1
  18. package/dist/src/cli/commands/register-registry-commands.js +4 -1
  19. package/dist/src/cli/commands/registry-recovery.d.ts +14 -0
  20. package/dist/src/cli/commands/registry-recovery.js +1 -0
  21. package/dist/src/cli/commands/registry.d.ts +2 -5
  22. package/dist/src/cli/commands/registry.js +1 -1
  23. package/dist/src/cli/dev/diagnostic-dump.js +1 -1
  24. package/dist/src/cli/dev/environment.js +1 -1
  25. package/dist/src/cli/invoke/command.d.ts +3 -2
  26. package/dist/src/cli/invoke/command.js +1 -1
  27. package/dist/src/cli/run.d.ts +3 -2
  28. package/dist/src/cli/run.js +3 -3
  29. package/dist/src/client/eve-agent-store.d.ts +15 -3
  30. package/dist/src/client/eve-agent-store.js +2 -2
  31. package/dist/src/client/message-response.d.ts +10 -2
  32. package/dist/src/client/message-response.js +1 -1
  33. package/dist/src/client/session.js +1 -1
  34. package/dist/src/compiled/.vendor-stamp.json +4 -1
  35. package/dist/src/compiled/@ai-sdk/otel/index.js +3 -3
  36. package/dist/src/compiled/@chat-adapter/slack/index.js +25 -25
  37. package/dist/src/compiled/@opentelemetry/api/index.js +1 -1
  38. package/dist/src/compiled/@opentelemetry/otlp-transformer/index.js +1 -1
  39. package/dist/src/compiled/@photon-ai/chat-adapter-imessage/index.js +61 -61
  40. package/dist/src/compiled/@vercel/oidc/index.js +14 -14
  41. package/dist/src/compiled/@vercel/otel/index.js +1 -1
  42. package/dist/src/compiled/@vercel/sandbox/index.js +1 -1
  43. package/dist/src/compiled/@workflow/core/index.js +1 -1
  44. package/dist/src/compiled/@workflow/core/private.js +1 -1
  45. package/dist/src/compiled/@workflow/core/runtime.js +2 -2
  46. package/dist/src/compiled/@workflow/core/workflow.js +1 -1
  47. package/dist/src/compiled/@workflow/errors/index.js +1 -1
  48. package/dist/src/compiled/@workflow/world-local/index.js +5 -5
  49. package/dist/src/compiled/@workflow/world-vercel/index.js +13 -13
  50. package/dist/src/compiled/_chunks/workflow/{attribute-changes-BoH7JsWp.js → attribute-changes-DZtQkszH.js} +1 -1
  51. package/dist/src/compiled/_chunks/workflow/chunk-5MU5Z6L3-B_3nkJFi.js +1 -0
  52. package/dist/src/compiled/_chunks/workflow/{chunk-NWCAEW5Y-Oxw40oRR.js → chunk-NWCAEW5Y-BgbcH0OK.js} +1 -1
  53. package/dist/src/compiled/_chunks/workflow/{dist-DlFv0aHY.js → dist-CPlyFOVo.js} +1 -1
  54. package/dist/src/compiled/_chunks/workflow/{dist-tJoQXAF6.js → dist-DpYyXbJv.js} +1 -1
  55. package/dist/src/compiled/_chunks/workflow/{dist-CRTn4Sg8.js → dist-xQXN70ED.js} +1 -1
  56. package/dist/src/compiled/_chunks/workflow/esm-seIr7a6j.js +1 -0
  57. package/dist/src/compiled/_chunks/workflow/{frames-CTpeJYEQ.js → frames-BBs-9k1d.js} +2 -2
  58. package/dist/src/compiled/_chunks/workflow/{functions-CeeNvKsq.js → functions-DAYiHNti.js} +1 -1
  59. package/dist/src/compiled/_chunks/workflow/{getMachineId-bsd-WEBNKY2R-CEYkx6Nv.js → getMachineId-bsd-WEBNKY2R-BTaxrQ52.js} +1 -1
  60. package/dist/src/compiled/_chunks/workflow/{getMachineId-darwin-LT47KAXP-DPwWlhif.js → getMachineId-darwin-LT47KAXP-DhYmwE_R.js} +1 -1
  61. package/dist/src/compiled/_chunks/workflow/{getMachineId-linux-LTVQO6VW-DAFXHwZp.js → getMachineId-linux-LTVQO6VW-Dru_L5ru.js} +1 -1
  62. package/dist/src/compiled/_chunks/workflow/{getMachineId-unsupported-UKWBA27G-BZKOI8mG.js → getMachineId-unsupported-UKWBA27G-DGfoqVW1.js} +1 -1
  63. package/dist/src/compiled/_chunks/workflow/{getMachineId-win-NLJKOPY6-r7_CJB5o.js → getMachineId-win-NLJKOPY6-CLM98q4X.js} +1 -1
  64. package/dist/src/compiled/_chunks/workflow/{private-tvMBynnC.js → private-UQtz8ZcW.js} +1 -1
  65. package/dist/src/compiled/_chunks/workflow/{resume-hook-BPQHjeY5.js → resume-hook-CYtSorp6.js} +1 -1
  66. package/dist/src/compiled/_chunks/workflow/{rolldown-runtime-DaDcL9Zw.js → rolldown-runtime-8V8biNmG.js} +1 -1
  67. package/dist/src/compiled/_chunks/workflow/{run-DQ5dOyjm.js → run-Cjo0A3NO.js} +1 -1
  68. package/dist/src/compiled/_chunks/workflow/{signal-exit-C8vsI6zj.js → signal-exit-o3IPQwwv.js} +1 -1
  69. package/dist/src/compiled/_chunks/workflow/sleep-C1P0OWBm.js +1 -0
  70. package/dist/src/compiled/_chunks/workflow/{token-DHD-q-fS.js → token-DGzfw-Vb.js} +1 -1
  71. package/dist/src/compiled/_chunks/workflow/{token-DtCUEpJs.js → token-DNbxVpeq.js} +1 -1
  72. package/dist/src/compiled/_chunks/workflow/token-util-BneBe0g5.js +27 -0
  73. package/dist/src/compiled/_chunks/workflow/{token-util-Ldar52H7.js → token-util-DjMgNdXS.js} +1 -1
  74. package/dist/src/compiled/_chunks/workflow/{undici-CUIybhQ2.js → undici-BBG5cZTy.js} +1 -1
  75. package/dist/src/compiled/_chunks/workflow/{wait-until-DK2lnH6U.js → wait-until-CT1ve8qB.js} +3 -3
  76. package/dist/src/compiled/_chunks/workflow/{wrapper-CMGju7QA.js → wrapper-CQNxP9mU.js} +3 -3
  77. package/dist/src/compiled/_chunks/workflow/{ws-transport-Csi6Cydc.js → ws-transport-beXxD0s_.js} +1 -1
  78. package/dist/src/compiled/env-runner/node-worker.js +1 -1
  79. package/dist/src/compiled/jose/index.js +1 -1
  80. package/dist/src/compiled/shadcn-registry/index.js +403 -403
  81. package/dist/src/compiler/artifacts.js +1 -1
  82. package/dist/src/compiler/compile-agent.js +2 -2
  83. package/dist/src/compiler/extension-compatibility.d.ts +10 -0
  84. package/dist/src/compiler/extension-compatibility.js +1 -1
  85. package/dist/src/compiler/normalize-extension.d.ts +8 -5
  86. package/dist/src/compiler/normalize-extension.js +1 -1
  87. package/dist/src/compiler/normalize-manifest.js +1 -1
  88. package/dist/src/discover/discover-agent.js +1 -1
  89. package/dist/src/discover/extensions.d.ts +0 -6
  90. package/dist/src/discover/extensions.js +1 -1
  91. package/dist/src/evals/cli/eval.d.ts +1 -1
  92. package/dist/src/evals/cli/eval.js +1 -1
  93. package/dist/src/execution/sandbox/bindings/docker-templates.js +1 -1
  94. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  95. package/dist/src/execution/sandbox/bindings/microsandbox-templates.js +1 -1
  96. package/dist/src/execution/sandbox/prewarm.js +1 -1
  97. package/dist/src/harness/instrumentation/providers.js +1 -1
  98. package/dist/src/harness/instrumentation/runtime-context.d.ts +2 -0
  99. package/dist/src/harness/instrumentation/runtime-context.js +1 -1
  100. package/dist/src/harness/instrumentation/runtime.d.ts +3 -1
  101. package/dist/src/harness/tool-loop.js +1 -1
  102. package/dist/src/internal/application/cache-metadata.js +1 -1
  103. package/dist/src/internal/application/compiled-artifacts.js +2 -2
  104. package/dist/src/internal/application/optional-package-install.js +1 -1
  105. package/dist/src/internal/application/output-publication-lock.js +1 -1
  106. package/dist/src/internal/application/package.js +1 -1
  107. package/dist/src/internal/application/paths.js +1 -1
  108. package/dist/src/internal/application/tsconfig-dependencies.js +1 -1
  109. package/dist/src/internal/authored-module-evaluation-error.js +4 -4
  110. package/dist/src/internal/authored-module-loader.js +3 -3
  111. package/dist/src/internal/authored-package-boundary.js +1 -1
  112. package/dist/src/internal/authored-relative-extension-resolver.js +1 -1
  113. package/dist/src/internal/bundler/extension-scope-plugin.js +1 -1
  114. package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
  115. package/dist/src/internal/instrumentation-layout.js +1 -1
  116. package/dist/src/internal/materialized-authored-modules.js +1 -1
  117. package/dist/src/internal/nitro/dev-runtime-artifacts-retention.js +1 -1
  118. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  119. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  120. package/dist/src/internal/nitro/dev-runtime-source-snapshot-local-roots.js +1 -1
  121. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  122. package/dist/src/internal/nitro/host/application-route-registry.d.ts +88 -0
  123. package/dist/src/internal/nitro/host/application-route-registry.js +1 -0
  124. package/dist/src/internal/nitro/host/build-application.js +1 -1
  125. package/dist/src/internal/nitro/host/build-extension.js +1 -1
  126. package/dist/src/internal/nitro/host/build-vercel-agent-summary.js +1 -1
  127. package/dist/src/internal/nitro/host/channel-routes.d.ts +4 -11
  128. package/dist/src/internal/nitro/host/channel-routes.js +3 -3
  129. package/dist/src/internal/nitro/host/configure-nitro-routes.js +3 -3
  130. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  131. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  132. package/dist/src/internal/nitro/host/dev-runner.js +1 -1
  133. package/dist/src/internal/nitro/host/dev-workspace-extensions.js +1 -1
  134. package/dist/src/internal/nitro/host/extension-capability-requirements.js +1 -1
  135. package/dist/src/internal/nitro/host/local-tracing-runtime-plugin.js +1 -1
  136. package/dist/src/internal/nitro/host/nitro-bundler-config.js +1 -1
  137. package/dist/src/internal/nitro/host/start-development-server.js +2 -2
  138. package/dist/src/internal/nitro/host/start-production-server.js +2 -2
  139. package/dist/src/internal/nitro/host/vercel-build-output-config.js +1 -1
  140. package/dist/src/internal/process/pnpm.js +1 -1
  141. package/dist/src/internal/workflow/development-world-client.js +1 -1
  142. package/dist/src/internal/workflow/development-world-server.js +1 -1
  143. package/dist/src/internal/workflow-bundle/builder-support.d.ts +12 -8
  144. package/dist/src/internal/workflow-bundle/builder-support.js +8 -7
  145. package/dist/src/internal/workflow-bundle/builder.d.ts +1 -1
  146. package/dist/src/internal/workflow-bundle/builder.js +2 -3
  147. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  148. package/dist/src/public/channels/discord/discordChannel.d.ts +2 -0
  149. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  150. package/dist/src/public/channels/eve.d.ts +2 -0
  151. package/dist/src/public/channels/eve.js +1 -1
  152. package/dist/src/public/channels/github/dispatch.js +1 -1
  153. package/dist/src/public/channels/github/githubChannel.d.ts +2 -0
  154. package/dist/src/public/channels/linear/linearChannel.d.ts +2 -0
  155. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  156. package/dist/src/public/channels/photon/photonIMessageChannel.d.ts +2 -0
  157. package/dist/src/public/channels/photon/photonIMessageChannel.js +1 -1
  158. package/dist/src/public/channels/slack/slackChannel.d.ts +3 -1
  159. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  160. package/dist/src/public/channels/teams/teamsChannel.d.ts +2 -0
  161. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  162. package/dist/src/public/channels/telegram/telegramChannel.d.ts +2 -0
  163. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  164. package/dist/src/public/channels/twilio/twilioChannel.d.ts +2 -0
  165. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  166. package/dist/src/public/instrumentation/index.d.ts +9 -3
  167. package/dist/src/public/next/server.js +1 -1
  168. package/dist/src/public/nuxt/dev-server.js +1 -1
  169. package/dist/src/public/sveltekit/dev-server.js +1 -1
  170. package/dist/src/react/use-eve-agent.d.ts +4 -4
  171. package/dist/src/react/use-eve-agent.js +1 -1
  172. package/dist/src/services/inspect-application.js +1 -1
  173. package/dist/src/setup/primitives/pm/pnpm.js +2 -2
  174. package/dist/src/setup/primitives/run-vercel.js +1 -1
  175. package/dist/src/setup/scaffold/create/extension.js +1 -1
  176. package/dist/src/setup/scaffold/create/project.js +1 -1
  177. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  178. package/dist/src/setup/scaffold/create/web-template.js +8 -86
  179. package/dist/src/setup/scaffold/version-tokens.js +1 -1
  180. package/dist/src/setup/scaffold/workspace-root.js +1 -1
  181. package/dist/src/svelte/index.js +1 -1
  182. package/dist/src/svelte/use-eve-agent.d.ts +3 -3
  183. package/dist/src/svelte/use-eve-agent.js +1 -1
  184. package/dist/src/tracing/install-instrumentation-runtime.d.ts +2 -1
  185. package/dist/src/tracing/install-instrumentation-runtime.js +1 -1
  186. package/dist/src/tracing/otel-declaration.d.ts +32 -3
  187. package/dist/src/tracing/otel-declaration.js +1 -1
  188. package/dist/src/tracing/otel-registration.js +1 -1
  189. package/dist/src/vue/index.js +1 -1
  190. package/dist/src/vue/use-eve-agent.d.ts +3 -3
  191. package/dist/src/vue/use-eve-agent.js +1 -1
  192. package/docs/channels/custom.mdx +1 -1
  193. package/docs/channels/discord.mdx +1 -1
  194. package/docs/channels/eve.mdx +1 -2
  195. package/docs/channels/github.mdx +1 -1
  196. package/docs/channels/linear.mdx +1 -1
  197. package/docs/channels/overview.mdx +1 -1
  198. package/docs/channels/photon.mdx +1 -1
  199. package/docs/channels/slack.mdx +1 -1
  200. package/docs/channels/teams.mdx +1 -1
  201. package/docs/channels/telegram.mdx +1 -1
  202. package/docs/channels/twilio.mdx +1 -1
  203. package/docs/extensions.md +10 -6
  204. package/docs/guides/client/streaming.mdx +6 -5
  205. package/docs/guides/frontend/overview.mdx +10 -8
  206. package/docs/guides/frontend/use-eve-agent-svelte.mdx +10 -10
  207. package/docs/guides/frontend/use-eve-agent-vue.mdx +10 -10
  208. package/docs/install-integrations.mdx +4 -0
  209. package/docs/reference/cli.md +1 -1
  210. package/docs/schedules.mdx +2 -2
  211. package/package.json +1 -1
  212. package/dist/src/compiled/_chunks/workflow/chunk-5MU5Z6L3-CaJgXkVg.js +0 -1
  213. package/dist/src/compiled/_chunks/workflow/sleep-CzdoBiqy.js +0 -1
  214. package/dist/src/compiled/_chunks/workflow/src-Cj3P1ChQ.js +0 -1
  215. package/dist/src/compiled/_chunks/workflow/token-util-DNwIAn_u.js +0 -27
@@ -1,6 +1,6 @@
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 type { UserContent } from "ai";\nimport { Client, type MessageStreamEvent } from "eve/client";\nimport { useEveAgent } from "eve/react";\nimport { AlertCircleIcon } from "lucide-react";\nimport { useCallback, useRef, useState } from "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"];\ntype CancellationState = "idle" | "requested" | "cancelling";\n\ntype Cancellation = {\n requested: boolean;\n sentTurnId?: string;\n turnId?: string;\n};\n\nexport function AgentChat() {\n const [client] = useState(() => new Client({ host: "" }));\n const sessionIdRef = useRef<string | undefined>(undefined);\n const cancellationRef = useRef<Cancellation>({ requested: false });\n const [cancellationError, setCancellationError] = useState<string>();\n const [cancellationState, setCancellationState] = useState<CancellationState>("idle");\n\n const cancelTurn = useCallback(\n (turnId: string) => {\n const cancellation = cancellationRef.current;\n if (!cancellation.requested || cancellation.sentTurnId === turnId) {\n return;\n }\n\n cancellation.sentTurnId = turnId;\n setCancellationState("cancelling");\n\n const sessionId = sessionIdRef.current;\n if (sessionId === undefined) {\n return;\n }\n\n void client.sessions\n .attach(sessionId)\n .cancel({ turnId })\n .catch((error: unknown) => {\n if (cancellationRef.current !== cancellation) {\n return;\n }\n\n cancellation.requested = false;\n cancellation.sentTurnId = undefined;\n setCancellationError(toErrorMessage(error));\n setCancellationState("idle");\n });\n },\n [client],\n );\n\n const handleEvent = useCallback(\n (event: MessageStreamEvent) => {\n if (event.type !== "turn.started") {\n return;\n }\n\n const cancellation = cancellationRef.current;\n cancellation.turnId = event.data.turnId;\n cancelTurn(event.data.turnId);\n },\n [cancelTurn],\n );\n\n const agent = useEveAgent({\n onEvent: handleEvent,\n onSessionChange(session) {\n sessionIdRef.current = session?.sessionId;\n },\n });\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isEmpty = agent.data.messages.length === 0;\n const errorMessage = cancellationError ?? agent.error?.message;\n const submitStatus = isBusy && cancellationState !== "idle" ? "submitted" : agent.status;\n\n const prepareTurn = () => {\n cancellationRef.current = { requested: false };\n setCancellationError(undefined);\n setCancellationState("idle");\n };\n\n const requestCancellation = () => {\n if (!isBusy || cancellationState !== "idle") {\n return;\n }\n\n const cancellation = cancellationRef.current;\n cancellation.requested = true;\n setCancellationError(undefined);\n setCancellationState("requested");\n\n if (cancellation.turnId !== undefined) {\n cancelTurn(cancellation.turnId);\n }\n };\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 prepareTurn();\n\n if (message.files.length === 0) {\n await agent.send(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(parts);\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea placeholder="Send a message…" />\n <PromptInputSubmit onStop={requestCancellation} status={submitStatus} />\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 {errorMessage ? (\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">{errorMessage}</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) => {\n prepareTurn();\n return agent.respond(inputResponses);\n }}\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 toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : "Unable to cancel the response.";\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';
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 { useState } from "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 [cancellationError, setCancellationError] = useState<string>();\n const agent = useEveAgent();\n const isBusy = agent.status === "submitted" || agent.status === "streaming";\n const isEmpty = agent.data.messages.length === 0;\n const errorMessage = cancellationError ?? agent.error?.message;\n\n const requestCancellation = () => {\n setCancellationError(undefined);\n void agent.cancel().catch((error: unknown) => {\n setCancellationError(toErrorMessage(error));\n });\n };\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 setCancellationError(undefined);\n\n if (message.files.length === 0) {\n await agent.send(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(parts);\n };\n\n const composer = (\n <PromptInput onSubmit={handleSubmit}>\n <PromptInputTextarea placeholder="Send a message…" />\n <PromptInputSubmit onStop={requestCancellation} 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 {errorMessage ? (\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">{errorMessage}</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) => {\n setCancellationError(undefined);\n return agent.respond(inputResponses);\n }}\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 toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : "Unable to cancel the response.";\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
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';
@@ -16,10 +16,9 @@ export default eveChannel({
16
16
  `,"app/_components/agent-chat.tsx":`"use client";
17
17
 
18
18
  import type { UserContent } from "ai";
19
- import { Client, type MessageStreamEvent } from "eve/client";
20
19
  import { useEveAgent } from "eve/react";
21
20
  import { AlertCircleIcon } from "lucide-react";
22
- import { useCallback, useRef, useState } from "react";
21
+ import { useState } from "react";
23
22
  import {
24
23
  Conversation,
25
24
  ConversationContent,
@@ -37,103 +36,26 @@ import { AgentMessage } from "./agent-message";
37
36
  const AGENT_NAME = "__EVE_INIT_APP_NAME__";
38
37
 
39
38
  type AgentStatus = ReturnType<typeof useEveAgent>["status"];
40
- type CancellationState = "idle" | "requested" | "cancelling";
41
-
42
- type Cancellation = {
43
- requested: boolean;
44
- sentTurnId?: string;
45
- turnId?: string;
46
- };
47
39
 
48
40
  export function AgentChat() {
49
- const [client] = useState(() => new Client({ host: "" }));
50
- const sessionIdRef = useRef<string | undefined>(undefined);
51
- const cancellationRef = useRef<Cancellation>({ requested: false });
52
41
  const [cancellationError, setCancellationError] = useState<string>();
53
- const [cancellationState, setCancellationState] = useState<CancellationState>("idle");
54
-
55
- const cancelTurn = useCallback(
56
- (turnId: string) => {
57
- const cancellation = cancellationRef.current;
58
- if (!cancellation.requested || cancellation.sentTurnId === turnId) {
59
- return;
60
- }
61
-
62
- cancellation.sentTurnId = turnId;
63
- setCancellationState("cancelling");
64
-
65
- const sessionId = sessionIdRef.current;
66
- if (sessionId === undefined) {
67
- return;
68
- }
69
-
70
- void client.sessions
71
- .attach(sessionId)
72
- .cancel({ turnId })
73
- .catch((error: unknown) => {
74
- if (cancellationRef.current !== cancellation) {
75
- return;
76
- }
77
-
78
- cancellation.requested = false;
79
- cancellation.sentTurnId = undefined;
80
- setCancellationError(toErrorMessage(error));
81
- setCancellationState("idle");
82
- });
83
- },
84
- [client],
85
- );
86
-
87
- const handleEvent = useCallback(
88
- (event: MessageStreamEvent) => {
89
- if (event.type !== "turn.started") {
90
- return;
91
- }
92
-
93
- const cancellation = cancellationRef.current;
94
- cancellation.turnId = event.data.turnId;
95
- cancelTurn(event.data.turnId);
96
- },
97
- [cancelTurn],
98
- );
99
-
100
- const agent = useEveAgent({
101
- onEvent: handleEvent,
102
- onSessionChange(session) {
103
- sessionIdRef.current = session?.sessionId;
104
- },
105
- });
42
+ const agent = useEveAgent();
106
43
  const isBusy = agent.status === "submitted" || agent.status === "streaming";
107
44
  const isEmpty = agent.data.messages.length === 0;
108
45
  const errorMessage = cancellationError ?? agent.error?.message;
109
- const submitStatus = isBusy && cancellationState !== "idle" ? "submitted" : agent.status;
110
-
111
- const prepareTurn = () => {
112
- cancellationRef.current = { requested: false };
113
- setCancellationError(undefined);
114
- setCancellationState("idle");
115
- };
116
46
 
117
47
  const requestCancellation = () => {
118
- if (!isBusy || cancellationState !== "idle") {
119
- return;
120
- }
121
-
122
- const cancellation = cancellationRef.current;
123
- cancellation.requested = true;
124
48
  setCancellationError(undefined);
125
- setCancellationState("requested");
126
-
127
- if (cancellation.turnId !== undefined) {
128
- cancelTurn(cancellation.turnId);
129
- }
49
+ void agent.cancel().catch((error: unknown) => {
50
+ setCancellationError(toErrorMessage(error));
51
+ });
130
52
  };
131
53
 
132
54
  const handleSubmit = async (message: PromptInputMessage) => {
133
55
  const text = message.text.trim();
134
56
  if ((text.length === 0 && message.files.length === 0) || isBusy) return;
135
57
 
136
- prepareTurn();
58
+ setCancellationError(undefined);
137
59
 
138
60
  if (message.files.length === 0) {
139
61
  await agent.send(text);
@@ -159,7 +81,7 @@ export function AgentChat() {
159
81
  const composer = (
160
82
  <PromptInput onSubmit={handleSubmit}>
161
83
  <PromptInputTextarea placeholder="Send a message…" />
162
- <PromptInputSubmit onStop={requestCancellation} status={submitStatus} />
84
+ <PromptInputSubmit onStop={requestCancellation} status={agent.status} />
163
85
  </PromptInput>
164
86
  );
165
87
 
@@ -198,7 +120,7 @@ export function AgentChat() {
198
120
  key={message.id}
199
121
  message={message}
200
122
  onInputResponses={(inputResponses) => {
201
- prepareTurn();
123
+ setCancellationError(undefined);
202
124
  return agent.respond(inputResponses);
203
125
  }}
204
126
  />
@@ -1 +1 @@
1
- import{existsSync,readFileSync,realpathSync}from"node:fs";import{dirname,join}from"node:path";import{fileURLToPath}from"node:url";function versionToken(e){return`__${e}_VERSION__`}function bareToken(e){return`__${e}__`}const NODE_ENGINE_TOKEN=bareToken(`NODE_ENGINE`),TOKEN_SOURCES={[versionToken(`EVE_PACKAGE`)]:{kind:`eve-version`},[versionToken(`EVE_PACKAGE_DEPENDENCY`)]:{kind:`eve-version`},[NODE_ENGINE_TOKEN]:{kind:`eve-node-engine`},[versionToken(`AI_SDK`)]:{kind:`catalog`,packageName:`ai`},[versionToken(`VERCEL_CONNECT`)]:{kind:`catalog`,packageName:`@vercel/connect`},[versionToken(`NEXT`)]:{kind:`catalog`,packageName:`next`},[versionToken(`REACT`)]:{kind:`catalog`,packageName:`react`},[versionToken(`REACT_DOM`)]:{kind:`catalog`,packageName:`react-dom`},[versionToken(`STREAMDOWN`)]:{kind:`catalog`,packageName:`streamdown`},[versionToken(`ZOD`)]:{kind:`catalog`,packageName:`zod`},[versionToken(`TYPESCRIPT`)]:{kind:`catalog`,packageName:`typescript`},[versionToken(`TYPES_REACT`)]:{kind:`catalog`,packageName:`@types/react`},[versionToken(`TYPES_REACT_DOM`)]:{kind:`catalog`,packageName:`@types/react-dom`}},resolvedTokens=new Map;function findEvePackageRoot(){let o=dirname(realpathSync(fileURLToPath(import.meta.url)));for(;;){let n=join(o,`package.json`);if(existsSync(n)&&JSON.parse(readFileSync(n,`utf8`)).name===`eve`)return o;let a=dirname(o);if(a===o)return;o=a}}function findWorkspaceManifest(t){let n=t;for(;;){let t=join(n,`pnpm-workspace.yaml`);if(existsSync(t))return t;let a=dirname(n);if(a===n)return;n=a}}function readCatalogVersion(e,n){let r=readFileSync(e,`utf8`).split(/\r?\n/),i=!1;for(let e of r){if(/^catalog:\s*$/.test(e)){i=!0;continue}if(!i)continue;if(/^\S/.test(e))break;let t=e.match(/^\s+(?:"([^"]+)"|([\w@/.-]+)):\s*"([^"]+)"/);if(t&&(t[1]??t[2])===n)return t[3]}}function resolveTokenFromDevTree(n){let r=TOKEN_SOURCES[n];if(r!==void 0)try{let n=findEvePackageRoot();if(n===void 0||!existsSync(join(n,`scripts/stamp-version-tokens.mjs`)))return;if(r.kind===`eve-version`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`));return typeof e.version==`string`?e.version:void 0}if(r.kind===`eve-node-engine`){let e=JSON.parse(readFileSync(join(n,`package.json`),`utf8`)).engines?.node;return typeof e==`string`?e:void 0}let a=findWorkspaceManifest(n);return a===void 0?void 0:readCatalogVersion(a,r.packageName)}catch{return}}function resolveVersionToken(e,t){if(!t.startsWith(`__`))return t;let n=resolvedTokens.get(t);if(n!==void 0)return n;let r=resolveTokenFromDevTree(t);if(r===void 0)throw Error(`Scaffold received unstamped version token (${e}=${t}). Build eve before using its dist entrypoint.`);return resolvedTokens.set(t,r),r}export{resolveVersionToken};
1
+ import{dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{fileURLToPath}from"node:url";function versionToken(e){return`__${e}_VERSION__`}function bareToken(e){return`__${e}__`}const NODE_ENGINE_TOKEN=bareToken(`NODE_ENGINE`),TOKEN_SOURCES={[versionToken(`EVE_PACKAGE`)]:{kind:`eve-version`},[versionToken(`EVE_PACKAGE_DEPENDENCY`)]:{kind:`eve-version`},[NODE_ENGINE_TOKEN]:{kind:`eve-node-engine`},[versionToken(`AI_SDK`)]:{kind:`catalog`,packageName:`ai`},[versionToken(`VERCEL_CONNECT`)]:{kind:`catalog`,packageName:`@vercel/connect`},[versionToken(`NEXT`)]:{kind:`catalog`,packageName:`next`},[versionToken(`REACT`)]:{kind:`catalog`,packageName:`react`},[versionToken(`REACT_DOM`)]:{kind:`catalog`,packageName:`react-dom`},[versionToken(`STREAMDOWN`)]:{kind:`catalog`,packageName:`streamdown`},[versionToken(`ZOD`)]:{kind:`catalog`,packageName:`zod`},[versionToken(`TYPESCRIPT`)]:{kind:`catalog`,packageName:`typescript`},[versionToken(`TYPES_REACT`)]:{kind:`catalog`,packageName:`@types/react`},[versionToken(`TYPES_REACT_DOM`)]:{kind:`catalog`,packageName:`@types/react-dom`}},resolvedTokens=new Map;function findEvePackageRoot(){let o=dirname(realpathSync(fileURLToPath(import.meta.url)));for(;;){let i=join(o,`package.json`);if(existsSync(i)&&JSON.parse(readFileSync(i,`utf8`)).name===`eve`)return o;let a=dirname(o);if(a===o)return;o=a}}function findWorkspaceManifest(r){let i=r;for(;;){let r=join(i,`pnpm-workspace.yaml`);if(existsSync(r))return r;let a=dirname(i);if(a===i)return;i=a}}function readCatalogVersion(e,t){let n=readFileSync(e,`utf8`).split(/\r?\n/),i=!1;for(let e of n){if(/^catalog:\s*$/.test(e)){i=!0;continue}if(!i)continue;if(/^\S/.test(e))break;let n=e.match(/^\s+(?:"([^"]+)"|([\w@/.-]+)):\s*"([^"]+)"/);if(n&&(n[1]??n[2])===t)return n[3]}}function resolveTokenFromDevTree(e){let i=TOKEN_SOURCES[e];if(i!==void 0)try{let e=findEvePackageRoot();if(e===void 0||!existsSync(join(e,`scripts/stamp-version-tokens.mjs`)))return;if(i.kind===`eve-version`){let n=JSON.parse(readFileSync(join(e,`package.json`),`utf8`));return typeof n.version==`string`?n.version:void 0}if(i.kind===`eve-node-engine`){let n=JSON.parse(readFileSync(join(e,`package.json`),`utf8`)).engines?.node;return typeof n==`string`?n:void 0}let a=findWorkspaceManifest(e);return a===void 0?void 0:readCatalogVersion(a,i.packageName)}catch{return}}function resolveVersionToken(e,t){if(!t.startsWith(`__`))return t;let n=resolvedTokens.get(t);if(n!==void 0)return n;let r=resolveTokenFromDevTree(t);if(r===void 0)throw Error(`Scaffold received unstamped version token (${e}=${t}). Build eve before using its dist entrypoint.`);return resolvedTokens.set(t,r),r}export{resolveVersionToken};
@@ -1 +1 @@
1
- import{isPathInside,workspacePatternForProject,workspacePatternsClaimProject}from"./workspace-glob.js";import{ensurePnpmWorkspaceIncludesProject,findAncestorPnpmWorkspaceRoot}from"../primitives/pm/pnpm.js";import{getPackageManagerStrategy}from"../primitives/pm/index.js";import{patchPackageJson}from"./update/package-json.js";import{readFile,writeFile}from"node:fs/promises";import{existsSync,readFileSync}from"node:fs";import{dirname,join,resolve}from"node:path";function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function packageJsonWorkspacePatterns(e){let t=e.workspaces;return Array.isArray(t)?t.filter(e=>typeof e==`string`):!isJsonObject(t)||!Array.isArray(t.packages)?[]:t.packages.filter(e=>typeof e==`string`)}function readPackageJsonWorkspacePatterns(e){let t=JSON.parse(readFileSync(e,`utf8`));if(!isJsonObject(t))return;let n=packageJsonWorkspacePatterns(t);return n.length===0?void 0:n}function findAncestorPackageJsonWorkspaceRoot(e){let t=dirname(resolve(e));for(;;){let e=join(t,`package.json`);if(existsSync(e))try{if(readPackageJsonWorkspacePatterns(e)!==void 0)return t}catch{}let n=dirname(t);if(n===t)return;t=n}}function findClaimingPackageJsonWorkspaceRoot(e){let t=findAncestorPackageJsonWorkspaceRoot(e);if(t===void 0)return;let r;try{r=readPackageJsonWorkspacePatterns(join(t,`package.json`))}catch{return}return r!==void 0&&workspacePatternsClaimProject(r,t,e)?t:void 0}function findPackageManagerWorkspaceRoot(e,t){switch(e){case`pnpm`:return findAncestorPnpmWorkspaceRoot(t);case`bun`:case`npm`:case`yarn`:return findAncestorPackageJsonWorkspaceRoot(t)}}function isPackageManagerWorkspaceMember(e,t){let n=findPackageManagerWorkspaceRoot(e,t);return n!==void 0&&resolve(n)!==resolve(t)}function workspaceRootPackageJsonPath(e,t){let n=findPackageManagerWorkspaceRoot(e,t);return n===void 0?void 0:join(n,`package.json`)}async function ensurePackageJsonWorkspaceIncludesProject(e){let n=findAncestorPackageJsonWorkspaceRoot(e);if(n===void 0||resolve(n)===resolve(e)||findClaimingPackageJsonWorkspaceRoot(e)===n)return;let r=join(n,`package.json`),i=JSON.parse(await readFile(r,`utf8`)),a=workspacePatternForProject(n,e);if(Array.isArray(i.workspaces))i.workspaces=[...i.workspaces,a];else if(isJsonObject(i.workspaces)&&Array.isArray(i.workspaces.packages))i.workspaces={...i.workspaces,packages:[...i.workspaces.packages,a]};else return;return await writeFile(r,`${JSON.stringify(i,null,2)}\n`,`utf8`),r}async function ensurePackageManagerWorkspaceIncludesProject(e,t){switch(e){case`pnpm`:{let e=findAncestorPnpmWorkspaceRoot(t);return e===void 0?void 0:await ensurePnpmWorkspaceIncludesProject(t)===`written`?join(e,`pnpm-workspace.yaml`):void 0}case`bun`:case`npm`:case`yarn`:return ensurePackageJsonWorkspaceIncludesProject(t)}}function packageManagerRootOnlyPackageJsonPatch(e,t){let n={};if(t.nodeEngineRequirement!==void 0&&(n.nodeEngineRequirement=t.nodeEngineRequirement),t.aiPackageVersion!==void 0)switch(e){case`bun`:case`npm`:n.overrides={ai:t.aiPackageVersion};break;case`yarn`:n.resolutions={ai:t.aiPackageVersion};break;case`pnpm`:break}return n}async function patchWorkspaceRootPackageJson(e,t,n){if(!isPackageManagerWorkspaceMember(e,t))return{changed:!1};let r=workspaceRootPackageJsonPath(e,t);if(r===void 0||!existsSync(r))return{changed:!1};let i=await patchPackageJson(r,packageManagerRootOnlyPackageJsonPatch(e,n));return i.changed&&await n.onWorkspaceRootMutation?.({kind:`package-json`,nodeEngineOverride:i.nodeEngineOverride,path:r}),{...i,path:r}}async function applyPackageManagerWorkspaceConfiguration(t){let n=resolve(t.workspaceProbeRoot??t.projectRoot),r=t.packageManager===`pnpm`?void 0:await ensurePackageManagerWorkspaceIncludesProject(t.packageManager,n),i=await getPackageManagerStrategy(t.packageManager).applyProjectConfiguration(t.projectRoot,{workspaceProbeRoot:n}),o=[...r===void 0?[]:[r],...i.filesWritten],s=[...i.filesSkipped];for(let n of o)isPathInside(t.projectRoot,n)||await t.onWorkspaceRootMutation?.({kind:`workspace-config`,path:n});return{filesSkipped:s,filesWritten:o}}export{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson};
1
+ import{isPathInside,workspacePatternForProject,workspacePatternsClaimProject}from"./workspace-glob.js";import{ensurePnpmWorkspaceIncludesProject,findAncestorPnpmWorkspaceRoot}from"../primitives/pm/pnpm.js";import{getPackageManagerStrategy}from"../primitives/pm/index.js";import{patchPackageJson}from"./update/package-json.js";import{readFile,writeFile}from"node:fs/promises";import{dirname,join,resolve}from"node:path";import{existsSync,readFileSync}from"node:fs";function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function packageJsonWorkspacePatterns(e){let t=e.workspaces;return Array.isArray(t)?t.filter(e=>typeof e==`string`):!isJsonObject(t)||!Array.isArray(t.packages)?[]:t.packages.filter(e=>typeof e==`string`)}function readPackageJsonWorkspacePatterns(e){let t=JSON.parse(readFileSync(e,`utf8`));if(!isJsonObject(t))return;let n=packageJsonWorkspacePatterns(t);return n.length===0?void 0:n}function findAncestorPackageJsonWorkspaceRoot(e){let t=dirname(resolve(e));for(;;){let e=join(t,`package.json`);if(existsSync(e))try{if(readPackageJsonWorkspacePatterns(e)!==void 0)return t}catch{}let n=dirname(t);if(n===t)return;t=n}}function findClaimingPackageJsonWorkspaceRoot(e){let t=findAncestorPackageJsonWorkspaceRoot(e);if(t===void 0)return;let r;try{r=readPackageJsonWorkspacePatterns(join(t,`package.json`))}catch{return}return r!==void 0&&workspacePatternsClaimProject(r,t,e)?t:void 0}function findPackageManagerWorkspaceRoot(e,t){switch(e){case`pnpm`:return findAncestorPnpmWorkspaceRoot(t);case`bun`:case`npm`:case`yarn`:return findAncestorPackageJsonWorkspaceRoot(t)}}function isPackageManagerWorkspaceMember(e,t){let n=findPackageManagerWorkspaceRoot(e,t);return n!==void 0&&resolve(n)!==resolve(t)}function workspaceRootPackageJsonPath(e,t){let n=findPackageManagerWorkspaceRoot(e,t);return n===void 0?void 0:join(n,`package.json`)}async function ensurePackageJsonWorkspaceIncludesProject(e){let n=findAncestorPackageJsonWorkspaceRoot(e);if(n===void 0||resolve(n)===resolve(e)||findClaimingPackageJsonWorkspaceRoot(e)===n)return;let r=join(n,`package.json`),i=JSON.parse(await readFile(r,`utf8`)),a=workspacePatternForProject(n,e);if(Array.isArray(i.workspaces))i.workspaces=[...i.workspaces,a];else if(isJsonObject(i.workspaces)&&Array.isArray(i.workspaces.packages))i.workspaces={...i.workspaces,packages:[...i.workspaces.packages,a]};else return;return await writeFile(r,`${JSON.stringify(i,null,2)}\n`,`utf8`),r}async function ensurePackageManagerWorkspaceIncludesProject(e,t){switch(e){case`pnpm`:{let e=findAncestorPnpmWorkspaceRoot(t);return e===void 0?void 0:await ensurePnpmWorkspaceIncludesProject(t)===`written`?join(e,`pnpm-workspace.yaml`):void 0}case`bun`:case`npm`:case`yarn`:return ensurePackageJsonWorkspaceIncludesProject(t)}}function packageManagerRootOnlyPackageJsonPatch(e,t){let n={};if(t.nodeEngineRequirement!==void 0&&(n.nodeEngineRequirement=t.nodeEngineRequirement),t.aiPackageVersion!==void 0)switch(e){case`bun`:case`npm`:n.overrides={ai:t.aiPackageVersion};break;case`yarn`:n.resolutions={ai:t.aiPackageVersion};break;case`pnpm`:break}return n}async function patchWorkspaceRootPackageJson(e,t,n){if(!isPackageManagerWorkspaceMember(e,t))return{changed:!1};let r=workspaceRootPackageJsonPath(e,t);if(r===void 0||!existsSync(r))return{changed:!1};let i=await patchPackageJson(r,packageManagerRootOnlyPackageJsonPatch(e,n));return i.changed&&await n.onWorkspaceRootMutation?.({kind:`package-json`,nodeEngineOverride:i.nodeEngineOverride,path:r}),{...i,path:r}}async function applyPackageManagerWorkspaceConfiguration(t){let n=resolve(t.workspaceProbeRoot??t.projectRoot),r=t.packageManager===`pnpm`?void 0:await ensurePackageManagerWorkspaceIncludesProject(t.packageManager,n),i=await getPackageManagerStrategy(t.packageManager).applyProjectConfiguration(t.projectRoot,{workspaceProbeRoot:n}),o=[...r===void 0?[]:[r],...i.filesWritten],s=[...i.filesSkipped];for(let n of o)isPathInside(t.projectRoot,n)||await t.onWorkspaceRootMutation?.({kind:`workspace-config`,path:n});return{filesSkipped:s,filesWritten:o}}export{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson};
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-DbKUBhl-.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-BbSsu99c.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -3,7 +3,7 @@ import { type EveAgentStoreCallbacks, type EveAgentStoreSnapshot, type EveAgentS
3
3
  import { type EveMessageData } from "#client/message-reducer.js";
4
4
  import type { EveAgentReducer } from "#client/reducer.js";
5
5
  import type { ClientSession } from "#client/session.js";
6
- import type { ClientAuth, HeadersValue, RespondTurnOptions, SendTurnOptions, ClientSessionState } from "#client/types.js";
6
+ import type { CancelSessionResult, ClientAuth, HeadersValue, RespondTurnOptions, SendTurnOptions, ClientSessionState } from "#client/types.js";
7
7
  import type { MessageStreamEvent } from "#protocol/message.js";
8
8
  export type { PrepareSend };
9
9
  /**
@@ -26,6 +26,8 @@ export type UseEveAgentSnapshot<TData> = EveAgentStoreSnapshot<TData>;
26
26
  * new events.
27
27
  */
28
28
  export interface UseEveAgentReturn<TData> {
29
+ /** Request durable cancellation of the active turn while continuing to receive its events. */
30
+ readonly cancel: () => Promise<CancelSessionResult>;
29
31
  /** Projected state built by reducing every stream event through the reducer. */
30
32
  readonly data: TData;
31
33
  /** Last transport-level error, or `undefined` when healthy. */
@@ -42,8 +44,6 @@ export interface UseEveAgentReturn<TData> {
42
44
  readonly session: ClientSessionState | undefined;
43
45
  /** Lifecycle phase: `"ready"` (idle), `"submitted"` (request sent, awaiting first event), `"streaming"` (events arriving), or `"error"`. */
44
46
  readonly status: UseEveAgentStatus;
45
- /** Abort the in-flight request. */
46
- readonly stop: () => void;
47
47
  }
48
48
  /**
49
49
  * Configuration for a Svelte eve agent session.
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-DbKUBhl-.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-BbSsu99c.js";
2
2
 
3
3
  export { useEveAgent };
@@ -1,6 +1,6 @@
1
1
  import { type InstrumentationProviderDefinition } from "#harness/instrumentation/lifecycle.js";
2
2
  import { type InstrumentationRuntime } from "#harness/instrumentation/runtime.js";
3
- import type { CollectedOtel } from "#tracing/otel-declaration.js";
3
+ import type { CollectedOtel, RuntimeContextResolver } from "#tracing/otel-declaration.js";
4
4
  /**
5
5
  * Installs the process instrumentation runtime around a collected pipeline.
6
6
  *
@@ -15,5 +15,6 @@ export declare function installInstrumentationRuntime(input: {
15
15
  readonly collected: CollectedOtel;
16
16
  readonly frameworkVersion: string;
17
17
  readonly providers: readonly InstrumentationProviderDefinition[];
18
+ readonly runtimeContextResolvers?: readonly RuntimeContextResolver[];
18
19
  readonly serviceName: string;
19
20
  }): InstrumentationRuntime;
@@ -1 +1 @@
1
- import{createLogger,formatError}from"#internal/logging.js";import{ContextAgentTraceStateStore}from"#tracing/agent-trace-context-store.js";import{registerInstrumentationRuntime}from"#harness/instrumentation/runtime.js";import{trace}from"#compiled/@opentelemetry/api/index.js";import{createInstrumentationHooks}from"#harness/instrumentation/lifecycle.js";import{hasSessionRelease}from"#tracing/local-traces.js";import{createAgentOtelInstrumentation}from"#tracing/agent-otel-provider.js";import{registerOtelPipeline}from"#tracing/otel-registration.js";const log=createLogger(`tracing.install-instrumentation-runtime`);function installInstrumentationRuntime(e){let t=[],a=[],o,s,c,runInContext=(e,t)=>t();if(e.collected.declared){o=registerOtelPipeline({pipeline:e.collected.pipeline,serviceName:e.serviceName});let r=createAgentOtelInstrumentation({frameworkVersion:e.frameworkVersion,idGenerator:o.idGenerator,recordInputs:e.collected.settings.recordInputs,recordOutputs:e.collected.settings.recordOutputs,stateStore:new ContextAgentTraceStateStore,tracer:trace.getTracer(`eve.agent`,e.frameworkVersion)});t.push({...r.hook,stateNamespace:`internal:otel`}),s=r.prepareSessionTrace,c=r.prepareTurnTrace,runInContext=r.runInContext;let i=e.collected.pipeline.spanProcessors.filter(isSpanProcessor).filter(hasSessionRelease);i.length>0&&a.push(sessionReleaseProvider(i))}let l=[...t,...e.providers,...a],u;return registerInstrumentationRuntime({forceFlush:()=>settleAll([...o===void 0?[]:[o.forceFlush],...l.map(e=>()=>e.flush?.())]),hooks:createInstrumentationHooks({parallel:e.providers,serialAfter:a,serialBefore:t}),otelSettings:e.collected.declared?e.collected.settings:void 0,prepareSessionTrace:s,prepareTurnTrace:c,runInContext,shutdown:()=>(u??=settleAll([...o===void 0?[]:[o.shutdown],...l.map(e=>()=>e.shutdown?.())]),u)})}function isSpanProcessor(e){return e!==`auto`}function sessionReleaseProvider(e){let release=async t=>{await Promise.all(e.map(e=>e.releaseSession(t.sessionId)))};return{events:{"session.completed":release,"session.failed":release},name:`eve.session-release`,stateNamespace:`internal:session-release`}}async function settleAll(e){let n=await Promise.allSettled(e.map(async e=>e()));for(let e of n)e.status===`rejected`&&log.warn(`instrumentation drain failed`,{error:formatError(e.reason)})}export{installInstrumentationRuntime};
1
+ import{createLogger,formatError}from"#internal/logging.js";import{ContextAgentTraceStateStore}from"#tracing/agent-trace-context-store.js";import{registerInstrumentationRuntime}from"#harness/instrumentation/runtime.js";import{trace}from"#compiled/@opentelemetry/api/index.js";import{createInstrumentationHooks}from"#harness/instrumentation/lifecycle.js";import{hasSessionRelease}from"#tracing/local-traces.js";import{createAgentOtelInstrumentation}from"#tracing/agent-otel-provider.js";import{registerOtelPipeline}from"#tracing/otel-registration.js";const log=createLogger(`tracing.install-instrumentation-runtime`);function installInstrumentationRuntime(e){let t=[],a=[],o,s,c,runInContext=(e,t)=>t();if(e.collected.declared){o=registerOtelPipeline({pipeline:e.collected.pipeline,serviceName:e.serviceName});let r=createAgentOtelInstrumentation({frameworkVersion:e.frameworkVersion,idGenerator:o.idGenerator,recordInputs:e.collected.settings.recordInputs,recordOutputs:e.collected.settings.recordOutputs,stateStore:new ContextAgentTraceStateStore,tracer:trace.getTracer(`eve.agent`,e.frameworkVersion)});t.push({...r.hook,stateNamespace:`internal:otel`}),s=r.prepareSessionTrace,c=r.prepareTurnTrace,runInContext=r.runInContext;let i=e.collected.pipeline.spanProcessors.filter(isSpanProcessor).filter(hasSessionRelease);i.length>0&&a.push(sessionReleaseProvider(i))}let l=[...t,...e.providers,...a],u;return registerInstrumentationRuntime({forceFlush:()=>settleAll([...o===void 0?[]:[o.forceFlush],...l.map(e=>()=>e.flush?.())]),hooks:createInstrumentationHooks({parallel:e.providers,serialAfter:a,serialBefore:t}),otelSettings:e.collected.declared?e.collected.settings:void 0,prepareSessionTrace:s,prepareTurnTrace:c,runtimeContextResolvers:e.runtimeContextResolvers,runInContext,shutdown:()=>(u??=settleAll([...o===void 0?[]:[o.shutdown],...l.map(e=>()=>e.shutdown?.())]),u)})}function isSpanProcessor(e){return e!==`auto`}function sessionReleaseProvider(e){let release=async t=>{await Promise.all(e.map(e=>e.releaseSession(t.sessionId)))};return{events:{"session.completed":release,"session.failed":release},name:`eve.session-release`,stateNamespace:`internal:session-release`}}async function settleAll(e){let n=await Promise.allSettled(e.map(async e=>e()));for(let e of n)e.status===`rejected`&&log.warn(`instrumentation drain failed`,{error:formatError(e.reason)})}export{installInstrumentationRuntime};
@@ -1,5 +1,7 @@
1
1
  import type { PropagatorOrName, SamplerOrName, SpanExporter, SpanProcessor, SpanProcessorOrName } from "#compiled/@vercel/otel/index.js";
2
2
  import { type InstrumentationProvider } from "#public/instrumentation/provider.js";
3
+ import type { InstrumentationRuntimeContextInput } from "#public/instrumentation/index.js";
4
+ import type { JsonObject } from "#shared/json.js";
3
5
  import type { ResolvedContentOptions } from "#tracing/content-attributes.js";
4
6
  /**
5
7
  * The process-wide OpenTelemetry settings, declared by `otel()`.
@@ -8,9 +10,11 @@ import type { ResolvedContentOptions } from "#tracing/content-attributes.js";
8
10
  * one tracer provider, so it has one resource, one sampler, and one propagator
9
11
  * set. Destinations are the plural half and live in `otelIntegration()`.
10
12
  *
11
- * `contextManager` and `instrumentations` are deliberately absent: eve's span
12
- * nesting depends on the former, and the latter cannot reach anything eve
13
- * imported before setup ran.
13
+ * `contextManager` is deliberately absent: eve's span nesting depends on it.
14
+ * `instrumentations` is accepted so providers can opt into Node auto-
15
+ * instrumentations (e.g. `@opentelemetry/auto-instrumentations-node`); the
16
+ * packages patch modules eve already imported, so their effects are limited
17
+ * to code loaded after registration.
14
18
  */
15
19
  export interface OtelOptions {
16
20
  /**
@@ -38,6 +42,15 @@ export interface OtelOptions {
38
42
  readonly sampler?: SamplerOrName;
39
43
  /** Composed into one propagator. All inject; the first to extract wins. */
40
44
  readonly propagators?: readonly PropagatorOrName[];
45
+ /**
46
+ * OpenTelemetry `Instrumentation` instances passed through to
47
+ * `registerOTel`. Use them to patch Node.js built-ins (HTTP, DNS, fs, etc.)
48
+ * for automatic spans around outbound work. Disabled by default because eve
49
+ * already imports the model SDK before registration, so patching cannot
50
+ * reach it — but code loaded after registration (tool modules, connection
51
+ * clients) will be instrumented.
52
+ */
53
+ readonly instrumentations?: readonly unknown[];
41
54
  }
42
55
  /**
43
56
  * What one destination records of the conversation itself.
@@ -60,6 +73,17 @@ export interface OtelIntegrationOptions extends ContentOptions {
60
73
  readonly spanProcessors?: readonly SpanProcessor[];
61
74
  /** Wrapped in eve's batching processor and appended after `spanProcessors`. */
62
75
  readonly traceExporter?: SpanExporter;
76
+ /**
77
+ * Contributes runtime context that the AI SDK merges into telemetry spans
78
+ * for each model call. Child spans inherit the values, so a destination can
79
+ * stamp channel or auth identity onto every span in the turn.
80
+ *
81
+ * Synchronous: the harness collects from every destination before the model
82
+ * call, so a return that is not a plain object is dropped (warning-only).
83
+ * Keys beginning with `eve.` are reserved and dropped. Return `undefined`
84
+ * to contribute nothing.
85
+ */
86
+ readonly runtimeContext?: (input: InstrumentationRuntimeContextInput) => JsonObject | undefined;
63
87
  }
64
88
  declare const OTEL_DECLARATION: unique symbol;
65
89
  declare const OTEL_INTEGRATION: unique symbol;
@@ -76,6 +100,7 @@ export interface OtelIntegration extends InstrumentationProvider {
76
100
  readonly [OTEL_INTEGRATION]: true;
77
101
  /** Resolved from `ContentOptions`, so the union does not re-apply defaults. */
78
102
  readonly content: ResolvedContentOptions;
103
+ readonly runtimeContext?: (input: InstrumentationRuntimeContextInput) => JsonObject | undefined;
79
104
  readonly spanProcessors: readonly SpanProcessorOrName[];
80
105
  }
81
106
  /**
@@ -105,6 +130,7 @@ export declare function isOtelDeclaration(value: unknown): value is OtelDeclarat
105
130
  export declare function isOtelIntegration(value: unknown): value is OtelIntegration;
106
131
  /** The one pipeline a process can register. @internal */
107
132
  export interface OtelPipeline {
133
+ readonly instrumentations?: readonly unknown[];
108
134
  readonly propagators?: readonly PropagatorOrName[];
109
135
  readonly resource?: Readonly<Record<string, unknown>>;
110
136
  readonly sampler?: SamplerOrName;
@@ -123,6 +149,8 @@ export interface OtelHarnessSettings {
123
149
  readonly recordOutputs?: boolean;
124
150
  }
125
151
  /** @internal */
152
+ export type RuntimeContextResolver = (input: InstrumentationRuntimeContextInput) => JsonObject | undefined;
153
+ /** @internal */
126
154
  export interface CollectedOtel {
127
155
  /**
128
156
  * Whether anything declared OpenTelemetry. False means eve should leave the
@@ -130,6 +158,7 @@ export interface CollectedOtel {
130
158
  */
131
159
  readonly declared: boolean;
132
160
  readonly pipeline: OtelPipeline;
161
+ readonly runtimeContextResolvers: readonly RuntimeContextResolver[];
133
162
  readonly settings: OtelHarnessSettings;
134
163
  }
135
164
  /**
@@ -1 +1 @@
1
- import{PROVIDER}from"#public/instrumentation/provider.js";import{batchSpanProcessor}from"#tracing/batch-span-processor.js";import{contentFilteringProcessor}from"#tracing/content-span-processor.js";import{vercelRuntimeSpanProcessor}from"#tracing/vercel-runtime-span-exporter.js";const OTEL_DECLARATION=Symbol.for(`eve.instrumentation.otel`),OTEL_INTEGRATION=Symbol.for(`eve.instrumentation.otel-integration`);function otel(t={}){return{[OTEL_DECLARATION]:!0,[PROVIDER]:!0,options:t}}function otelIntegration(r={}){let i={recordInputs:r.recordInputs===!0,recordOutputs:r.recordOutputs===!0},o=r.spanProcessors??[],s=r.traceExporter===void 0?o:[...o,batchSpanProcessor(r.traceExporter)];return{[OTEL_INTEGRATION]:!0,[PROVIDER]:!0,content:i,spanProcessors:i.recordInputs&&i.recordOutputs?s:s.map(e=>contentFilteringProcessor(e,i))}}function agentRunsIntegration(t={}){let i=resolveContentOptions(t);return{[OTEL_INTEGRATION]:!0,[PROVIDER]:!0,content:i,spanProcessors:i.recordInputs&&i.recordOutputs?[`auto`]:[contentFilteringProcessor(vercelRuntimeSpanProcessor(),i)]}}function resolveContentOptions(e){return{recordInputs:e.recordInputs===!0,recordOutputs:e.recordOutputs===!0}}function isOtelDeclaration(e){return typeof e==`object`&&!!e&&e[OTEL_DECLARATION]===!0}function isOtelIntegration(e){return typeof e==`object`&&!!e&&e[OTEL_INTEGRATION]===!0}function collectOtelPipeline(e){let t=[],n,r=!1,i=!1,a=!1;for(let o of e){if(isOtelIntegration(o)){r=!0,i||=o.content.recordInputs,a||=o.content.recordOutputs,t.push(...o.spanProcessors);continue}if(isOtelDeclaration(o)){if(n!==void 0)throw Error("Instrumentation declares `otel()` more than once. One process has one OpenTelemetry tracer provider, so it has one resource, one sampler, and one propagator set — declare them in a single `otel()`.");r=!0,n=o}}let o=n?.options??{};return{declared:r,pipeline:{propagators:o.propagators,resource:o.resource,sampler:o.sampler,spanProcessors:t},settings:{functionId:o.functionId,recordInputs:i,recordOutputs:a,traceChannelRequests:o.traceChannelRequests===!0}}}export{agentRunsIntegration,collectOtelPipeline,isOtelDeclaration,isOtelIntegration,otel,otelIntegration,resolveContentOptions};
1
+ import{PROVIDER}from"#public/instrumentation/provider.js";import{batchSpanProcessor}from"#tracing/batch-span-processor.js";import{contentFilteringProcessor}from"#tracing/content-span-processor.js";import{vercelRuntimeSpanProcessor}from"#tracing/vercel-runtime-span-exporter.js";const OTEL_DECLARATION=Symbol.for(`eve.instrumentation.otel`),OTEL_INTEGRATION=Symbol.for(`eve.instrumentation.otel-integration`);function otel(t={}){return{[OTEL_DECLARATION]:!0,[PROVIDER]:!0,options:t}}function otelIntegration(r={}){let i={recordInputs:r.recordInputs===!0,recordOutputs:r.recordOutputs===!0},o=r.spanProcessors??[],s=r.traceExporter===void 0?o:[...o,batchSpanProcessor(r.traceExporter)];return{[OTEL_INTEGRATION]:!0,[PROVIDER]:!0,content:i,runtimeContext:r.runtimeContext,spanProcessors:i.recordInputs&&i.recordOutputs?s:s.map(e=>contentFilteringProcessor(e,i))}}function agentRunsIntegration(t={}){let i=resolveContentOptions(t);return{[OTEL_INTEGRATION]:!0,[PROVIDER]:!0,content:i,spanProcessors:i.recordInputs&&i.recordOutputs?[`auto`]:[contentFilteringProcessor(vercelRuntimeSpanProcessor(),i)]}}function resolveContentOptions(e){return{recordInputs:e.recordInputs===!0,recordOutputs:e.recordOutputs===!0}}function isOtelDeclaration(e){return typeof e==`object`&&!!e&&e[OTEL_DECLARATION]===!0}function isOtelIntegration(e){return typeof e==`object`&&!!e&&e[OTEL_INTEGRATION]===!0}function collectOtelPipeline(e){let t=[],n=[],r,i=!1,a=!1,o=!1;for(let s of e){if(isOtelIntegration(s)){i=!0,a||=s.content.recordInputs,o||=s.content.recordOutputs,t.push(...s.spanProcessors),s.runtimeContext!==void 0&&n.push(s.runtimeContext);continue}if(isOtelDeclaration(s)){if(r!==void 0)throw Error("Instrumentation declares `otel()` more than once. One process has one OpenTelemetry tracer provider, so it has one resource, one sampler, and one propagator set — declare them in a single `otel()`.");i=!0,r=s}}let s=r?.options??{};return{declared:i,pipeline:{instrumentations:s.instrumentations,propagators:s.propagators,resource:s.resource,sampler:s.sampler,spanProcessors:t},runtimeContextResolvers:n,settings:{functionId:s.functionId,recordInputs:a,recordOutputs:o,traceChannelRequests:s.traceChannelRequests===!0}}}export{agentRunsIntegration,collectOtelPipeline,isOtelDeclaration,isOtelIntegration,otel,otelIntegration,resolveContentOptions};
@@ -1 +1 @@
1
- import{context,propagation,trace}from"#compiled/@opentelemetry/api/index.js";import{registerOTel}from"#compiled/@vercel/otel/index.js";import{AgentSpanIdGenerator}from"#tracing/agent-span-id-generator.js";const REGISTRATION_SPAN_NAME=`eve.otel.registration`,REPLAY_DEDUPLICATION_LIMIT=1e5;var RegistrationMarkerPropagator=class{#e=!1;extract(e){return e}fields(){return[]}inject(){this.#e=!0}isInstalled(){return this.#e=!1,propagation.inject(context.active(),{},{set:()=>{}}),this.#e}},PrivateSpanFilteringProcessor=class{endedSpans=new Set;forwardedSpans=new Set;pendingByParent=new Map;processors;startedSpans=new Set;constructor(e){this.processors=e}async forceFlush(){await Promise.all(this.processors.map(e=>e.forceFlush()))}onEnd(e){if(isRegistrationSpan(e))return;let t=spanIdentity(e);if(t!==void 0){if(this.endedSpans.has(t))return;if(this.endedSpans.size>=REPLAY_DEDUPLICATION_LIMIT){let e=this.endedSpans.values().next().value;e!==void 0&&this.endedSpans.delete(e)}this.endedSpans.add(t)}let n=parentIdentity(e);if(n!==void 0&&this.startedSpans.has(n)&&!this.forwardedSpans.has(n)){let t=this.pendingByParent.get(n)??[];t.push(e),this.pendingByParent.set(n,t);return}this.forward(e,t)}onStart(e,t){if(isRegistrationSpan(e))return;let n=spanIdentity(e);n!==void 0&&addBounded(this.startedSpans,n);for(let n of this.processors)n.onStart(e,t)}async shutdown(){await Promise.all(this.processors.map(e=>e.shutdown()))}forward(e,t){for(let t of this.processors)t.onEnd(e);if(t===void 0)return;addBounded(this.forwardedSpans,t);let n=this.pendingByParent.get(t);if(n!==void 0){this.pendingByParent.delete(t);for(let e of n)this.forward(e,spanIdentity(e))}}};function registerOtelPipeline(e){let{pipeline:t}=e,n=new AgentSpanIdGenerator,i=new RegistrationMarkerPropagator,a={attributes:t.resource,autoDetectResources:!1,idGenerator:n,instrumentations:[],propagators:[...t.propagators??[`none`],i],serviceName:e.serviceName,spanProcessors:t.spanProcessors.map(e=>isSpanProcessor(e)?new PrivateSpanFilteringProcessor([e]):e)};registerOTel(t.sampler===void 0?a:{...a,traceSampler:t.sampler});let o=globalTracerUses(n),s=i.isInstalled();if((!o||!s)&&rollbackRegistration({ownsPropagator:s,ownsTracer:o}),!o)throw Error("eve could not register OpenTelemetry because another runtime already owns the global tracer provider. Remove the other `registerOTel` call, or move its exporters into eve's `otelIntegration({ spanProcessors: [...] })`.");if(!s)throw Error("eve could not register OpenTelemetry because another runtime already owns the global propagator. Remove the other global propagator registration and declare propagators through eve's `otel()` instead.");let c=runtimeTracerProvider();if(typeof c.forceFlush!=`function`||typeof c.shutdown!=`function`)throw rollbackRegistration({ownsPropagator:s,ownsTracer:o}),Error(`The registered OpenTelemetry tracer provider has no lifecycle methods.`);return{forceFlush:()=>c.forceFlush(),idGenerator:n,shutdown:()=>c.shutdown()}}function rollbackRegistration(e){if(e.ownsPropagator&&propagation.disable(),!e.ownsTracer)return;let r=runtimeTracerProvider();if(typeof r.shutdown==`function`)try{r.shutdown().catch(()=>{})}catch{}trace.disable()}function runtimeTracerProvider(){let e=trace.getTracerProvider();return e.getDelegate?.()??e}function globalTracerUses(e){let t=e.allocateSpanId();return e.withSpanId(t,()=>trace.getTracer(`eve.registration`).startSpan(REGISTRATION_SPAN_NAME)).spanContext().spanId===t}function isRegistrationSpan(e){return typeof e==`object`&&!!e&&`name`in e&&e.name===REGISTRATION_SPAN_NAME}function spanIdentity(e){if(typeof e!=`object`||!e||!(`spanContext`in e)||typeof e.spanContext!=`function`)return;let t=e.spanContext();return typeof t.traceId==`string`&&typeof t.spanId==`string`?`${t.traceId}:${t.spanId}`:void 0}function parentIdentity(e){if(typeof e!=`object`||!e||!(`parentSpanContext`in e))return;let t=e.parentSpanContext;return typeof t?.traceId==`string`&&typeof t.spanId==`string`?`${t.traceId}:${t.spanId}`:void 0}function addBounded(e,t){if(e.size>=REPLAY_DEDUPLICATION_LIMIT){let t=e.values().next().value;t!==void 0&&e.delete(t)}e.add(t)}function isSpanProcessor(e){return e!==`auto`}export{registerOtelPipeline};
1
+ import{createRequire}from"node:module";import{context,propagation,trace}from"#compiled/@opentelemetry/api/index.js";import{registerOTel}from"#compiled/@vercel/otel/index.js";import{AgentSpanIdGenerator}from"#tracing/agent-span-id-generator.js";const REGISTRATION_SPAN_NAME=`eve.otel.registration`,REPLAY_DEDUPLICATION_LIMIT=1e5,require=createRequire(import.meta.url);var RegistrationMarkerPropagator=class{#e=!1;extract(e){return e}fields(){return[]}inject(){this.#e=!0}isInstalled(){return this.#e=!1,propagation.inject(context.active(),{},{set:()=>{}}),this.#e}},PrivateSpanFilteringProcessor=class{endedSpans=new Set;forwardedSpans=new Set;pendingByParent=new Map;processors;startedSpans=new Set;constructor(e){this.processors=e}async forceFlush(){await Promise.all(this.processors.map(e=>e.forceFlush()))}onEnd(e){if(isRegistrationSpan(e))return;let t=spanIdentity(e);if(t!==void 0){if(this.endedSpans.has(t))return;if(this.endedSpans.size>=REPLAY_DEDUPLICATION_LIMIT){let e=this.endedSpans.values().next().value;e!==void 0&&this.endedSpans.delete(e)}this.endedSpans.add(t)}let n=parentIdentity(e);if(n!==void 0&&this.startedSpans.has(n)&&!this.forwardedSpans.has(n)){let t=this.pendingByParent.get(n)??[];t.push(e),this.pendingByParent.set(n,t);return}this.forward(e,t)}onStart(e,t){if(isRegistrationSpan(e))return;let n=spanIdentity(e);n!==void 0&&addBounded(this.startedSpans,n);for(let n of this.processors)n.onStart(e,t)}async shutdown(){await Promise.all(this.processors.map(e=>e.shutdown()))}forward(e,t){for(let t of this.processors)t.onEnd(e);if(t===void 0)return;addBounded(this.forwardedSpans,t);let n=this.pendingByParent.get(t);if(n!==void 0){this.pendingByParent.delete(t);for(let e of n)this.forward(e,spanIdentity(e))}}};function registerOtelPipeline(e){let{pipeline:t}=e,n=captureOptionalPeerTracerProxy(),r=new AgentSpanIdGenerator,i=new RegistrationMarkerPropagator,a={attributes:t.resource,autoDetectResources:!1,idGenerator:r,instrumentations:t.instrumentations??[],propagators:[...t.propagators??[`none`],i],serviceName:e.serviceName,spanProcessors:t.spanProcessors.map(e=>isSpanProcessor(e)?new PrivateSpanFilteringProcessor([e]):e)};registerOTel(t.sampler===void 0?a:{...a,traceSampler:t.sampler});let o=globalTracerUses(r),s=i.isInstalled();if((!o||!s)&&rollbackRegistration({ownsPropagator:s,ownsTracer:o}),!o)throw Error("eve could not register OpenTelemetry because another runtime already owns the global tracer provider. Remove the other `registerOTel` call, or move its exporters into eve's `otelIntegration({ spanProcessors: [...] })`.");if(!s)throw Error("eve could not register OpenTelemetry because another runtime already owns the global propagator. Remove the other global propagator registration and declare propagators through eve's `otel()` instead.");let c=runtimeTracerProvider();if(typeof c.forceFlush!=`function`||typeof c.shutdown!=`function`)throw rollbackRegistration({ownsPropagator:s,ownsTracer:o}),Error(`The registered OpenTelemetry tracer provider has no lifecycle methods.`);return n?.setDelegate(c),{forceFlush:()=>c.forceFlush(),idGenerator:r,shutdown:()=>c.shutdown()}}function captureOptionalPeerTracerProxy(){try{let e=require("@opentelemetry/api"),t=e.trace.getTracerProvider();return t instanceof e.ProxyTracerProvider?t:void 0}catch{return}}function rollbackRegistration(e){if(e.ownsPropagator&&propagation.disable(),!e.ownsTracer)return;let t=runtimeTracerProvider();if(typeof t.shutdown==`function`)try{t.shutdown().catch(()=>{})}catch{}trace.disable()}function runtimeTracerProvider(){let e=trace.getTracerProvider();return e.getDelegate?.()??e}function globalTracerUses(e){let t=e.allocateSpanId();return e.withSpanId(t,()=>trace.getTracer(`eve.registration`).startSpan(REGISTRATION_SPAN_NAME)).spanContext().spanId===t}function isRegistrationSpan(e){return typeof e==`object`&&!!e&&`name`in e&&e.name===REGISTRATION_SPAN_NAME}function spanIdentity(e){if(typeof e!=`object`||!e||!(`spanContext`in e)||typeof e.spanContext!=`function`)return;let t=e.spanContext();return typeof t.traceId==`string`&&typeof t.spanId==`string`?`${t.traceId}:${t.spanId}`:void 0}function parentIdentity(e){if(typeof e!=`object`||!e||!(`parentSpanContext`in e))return;let t=e.parentSpanContext;return typeof t?.traceId==`string`&&typeof t.spanId==`string`?`${t.traceId}:${t.spanId}`:void 0}function addBounded(e,t){if(e.size>=REPLAY_DEDUPLICATION_LIMIT){let t=e.values().next().value;t!==void 0&&e.delete(t)}e.add(t)}function isSpanProcessor(e){return e!==`auto`}export{registerOtelPipeline};
@@ -1,3 +1,3 @@
1
- import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-Bi5fRxcZ.js";
1
+ import { n as defaultMessageReducer, t as useEveAgent } from "../chunks/use-eve-agent-Dt8Y5QtW.js";
2
2
 
3
3
  export { defaultMessageReducer, useEveAgent };
@@ -5,7 +5,7 @@ import type { EveAgentReducer } from "#client/reducer.js";
5
5
  import type { ClientSession } from "#client/session.js";
6
6
  import { type EveMessageData } from "#client/message-reducer.js";
7
7
  import type { MessageStreamEvent } from "#protocol/message.js";
8
- import type { ClientAuth, HeadersValue, RespondTurnOptions, SendTurnOptions, ClientSessionState } from "#client/types.js";
8
+ import type { CancelSessionResult, ClientAuth, HeadersValue, RespondTurnOptions, SendTurnOptions, ClientSessionState } from "#client/types.js";
9
9
  export type { PrepareSend };
10
10
  /**
11
11
  * Lifecycle phase of a `useEveAgent` session: `"ready"` (idle), `"submitted"`
@@ -25,6 +25,8 @@ export type UseEveAgentSnapshot<TData> = EveAgentStoreSnapshot<TData>;
25
25
  * Reactive return value from `useEveAgent`.
26
26
  */
27
27
  export interface UseEveAgentReturn<TData> {
28
+ /** Request durable cancellation of the active turn while continuing to receive its events. */
29
+ readonly cancel: () => Promise<CancelSessionResult>;
28
30
  /** Projected state: the reducer folds every stream event into this value. */
29
31
  readonly data: ComputedRef<TData>;
30
32
  /** Last transport-level error, or `undefined` when healthy. */
@@ -41,8 +43,6 @@ export interface UseEveAgentReturn<TData> {
41
43
  readonly session: ComputedRef<ClientSessionState | undefined>;
42
44
  /** Lifecycle phase: `"ready"` (idle), `"submitted"` (request sent, awaiting first event), `"streaming"` (events arriving), or `"error"`. */
43
45
  readonly status: ComputedRef<UseEveAgentStatus>;
44
- /** Abort the in-flight request. */
45
- readonly stop: () => void;
46
46
  }
47
47
  /**
48
48
  * Configuration for creating or binding a Vue eve agent session.
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-Bi5fRxcZ.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-Dt8Y5QtW.js";
2
2
 
3
3
  export { useEveAgent };
@@ -7,7 +7,7 @@ When eve doesn't ship a channel for your surface, you build one. Custom channels
7
7
 
8
8
  ## File location and identity
9
9
 
10
- Custom channels live in `agent/channels/` at the root agent. Local subagents do not declare channels today.
10
+ Custom channels live in `agent/channels/` at the root agent or in an [extension](../extensions) mounted there. Local subagents do not declare channels today.
11
11
 
12
12
  The channel file stem becomes the channel id, so `agent/channels/internal-webhook.ts` is addressed as `internal-webhook`. Export the channel definition as the module's default export.
13
13
 
@@ -56,7 +56,7 @@ Then configure the public `https://…/eve/v1/discord` route as the application'
56
56
 
57
57
  ### Dispatch
58
58
 
59
- `onCommand(ctx, interaction)` decides whether to dispatch and under what `auth`. Return `{ auth }` to proceed or `null` to drop the interaction. By default, auth comes from the invoking user. Event handlers receive `(eventData, channel, ctx)`, with Discord platform handles on `channel.discord`:
59
+ `onCommand(ctx, interaction)` decides whether to dispatch and under what `auth`. Return `{ auth }` to proceed, `null` to drop the interaction, or `title` alongside `auth` to set the title when the dispatch starts a run. By default, auth comes from the invoking user. Event handlers receive `(eventData, channel, ctx)`, with Discord platform handles on `channel.discord`:
60
60
 
61
61
  ```ts
62
62
  import { discordChannel } from "eve/channels/discord";
@@ -160,8 +160,7 @@ export default eveChannel({
160
160
  });
161
161
  ```
162
162
 
163
- `onMessage` must return an auth result. A successful canonical eve HTTP message
164
- always dispatches and therefore always produces or continues a session.
163
+ `onMessage` must return an auth result. Return `title` alongside `auth` to set the title when the dispatch starts a run. A successful canonical eve HTTP message always dispatches and therefore always produces or continues a session.
165
164
 
166
165
  ## Clients
167
166
 
@@ -66,7 +66,7 @@ Point the GitHub App webhook URL at `https://<deployment>/eve/v1/github`. For co
66
66
 
67
67
  ### Dispatch
68
68
 
69
- Inbound hooks return `{ auth }` to dispatch, or `null` to ignore. Use `defaultGitHubAuth(ctx)` to derive auth from the actor.
69
+ Inbound hooks return `{ auth }` to dispatch, or `null` to ignore. Return `title` alongside `auth` to set the title when the dispatch starts a run. Use `defaultGitHubAuth(ctx)` to derive auth from the actor.
70
70
 
71
71
  ```ts
72
72
  import { defaultGitHubAuth, githubChannel } from "eve/channels/github";
@@ -99,7 +99,7 @@ Event handlers receive `channel.linear`, which exposes `createActivity`, `listAc
99
99
 
100
100
  ## Custom hooks
101
101
 
102
- Return `{ auth }` to dispatch, or `null` to acknowledge without waking the agent.
102
+ Return `{ auth }` to dispatch, or `null` to acknowledge without waking the agent. Return `title` alongside `auth` to set the title when the dispatch starts a run.
103
103
 
104
104
  ```ts
105
105
  import { defaultLinearAuth, linearChannel } from "eve/channels/linear";
@@ -36,7 +36,7 @@ Each channel has its own provider terms, data flow, auth model, and user-consent
36
36
 
37
37
  ## Where channels live
38
38
 
39
- Channel files live under `agent/channels/` in the root agent. The file stem is the channel id: `agent/channels/intake.ts` is addressed as `intake`. Export the channel as the module's default export. Local subagents do not declare channels.
39
+ Channel files live under `agent/channels/` in the root agent or come from an [extension](../extensions) mounted there. The file stem is the channel id: `agent/channels/intake.ts` is addressed as `intake`. An extension mount prefixes its contributed channel IDs but does not change their route paths. Local subagents do not declare channels.
40
40
 
41
41
  ```text
42
42
  agent/
@@ -29,7 +29,7 @@ steers its replacement turn.
29
29
 
30
30
  Set `turnPolicy: "queue"` when every response should finish before Photon starts the next message.
31
31
 
32
- Customize inbound dispatch with `onMessage`. Return `null` to ignore a message:
32
+ Customize inbound dispatch with `onMessage`. Return `null` to ignore a message, or return `title` alongside `auth` to set the title when the dispatch starts a run:
33
33
 
34
34
  ```ts
35
35
  export default photonIMessageChannel({
@@ -125,7 +125,7 @@ Check the delivery path in order so you can identify where a Slack event stops:
125
125
 
126
126
  ### Message hooks
127
127
 
128
- Message hooks return `{ auth }` to dispatch, `null` to drop, or `{ auth, context }` to inject background into history.
128
+ Message hooks return `{ auth }` to dispatch, `null` to drop, or `{ auth, context }` to inject background into history. Return `title` alongside `auth` to set the title when the dispatch starts a run. When omitted, the title continues to use the triggering message text.
129
129
 
130
130
  - `onMessage(ctx, message)` handles Slack `message` events. eve drops messages authored by the installed app before this hook runs, preventing self-reply loops. Messages from other bots remain visible; check `message.author?.isBot` when those should also be ignored. `ctx.isBotMentioned()` and `ctx.isSubscribed()` support mention and active-thread policies.
131
131
  - `onAppMention(ctx, message)` handles only `app_mention` and takes precedence over `onMessage`. Its default derives workspace-scoped auth and posts `Thinking…`.
@@ -26,7 +26,7 @@ By default the channel mounts at `POST /eve/v1/teams`. Point your Azure Bot or T
26
26
 
27
27
  ### Dispatch
28
28
 
29
- The default `onMessage` handles two cases: personal-chat messages, and channel or group-chat messages that mention the bot directly. Ambient resource-specific-consent messages are dropped unless you override it. Before dispatch, eve strips the mention, adds a `<teams_context>` block, and scopes channel and group threads by root activity id (`replyToId ?? id`).
29
+ The default `onMessage` handles two cases: personal-chat messages, and channel or group-chat messages that mention the bot directly. Ambient resource-specific-consent messages are dropped unless you override it. Return `title` alongside `auth` to set the title when the dispatch starts a run. Before dispatch, eve strips the mention, adds a `<teams_context>` block, and scopes channel and group threads by root activity id (`replyToId ?? id`).
30
30
 
31
31
  For example, use the contextual `isSubscribed()` helper to continue active threads without requiring another mention:
32
32
 
@@ -39,7 +39,7 @@ In a private chat, text, captions, photos, and documents all go through. Groups
39
39
 
40
40
  Forum topics carry `message_thread_id` in the continuation token, so each topic stays on its own thread.
41
41
 
42
- To customize auth or filtering, override `onMessage`. Group privacy mode itself lives in BotFather, not here.
42
+ To customize auth or filtering, override `onMessage`. Return `title` alongside `auth` to set the title when the dispatch starts a run. Group privacy mode itself lives in BotFather, not here.
43
43
 
44
44
  ### Delivery
45
45
 
@@ -40,7 +40,7 @@ Point your Twilio number's Messaging webhook at `/messages` and Voice webhook at
40
40
  export default twilioChannel({ allowFrom: ["+15551234567", "+15557654321"] });
41
41
  ```
42
42
 
43
- `onText` and `onVoiceTranscription` decide dispatch and `auth`. Return `{ auth }` to proceed, or `null` to drop the message. `onVoice` fires the moment a call comes in. Return `null` to reject it, or return an object to override the spoken prompt, language, `<Say voice>`, and speech-recognition options.
43
+ `onText` and `onVoiceTranscription` decide dispatch and `auth`. Return `{ auth }` to proceed, `null` to drop the message, or `title` alongside `auth` to set the title when the dispatch starts a run. `onVoice` fires the moment a call comes in. Return `null` to reject it, or return an object to override the spoken prompt, language, `<Say voice>`, and speech-recognition options.
44
44
 
45
45
  ```ts
46
46
  export default twilioChannel({