eve 0.29.3 → 0.29.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (326) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/src/acp/adapter.d.ts +43 -0
  3. package/dist/src/acp/adapter.js +1 -0
  4. package/dist/src/acp/line-limit.d.ts +3 -0
  5. package/dist/src/acp/line-limit.js +1 -0
  6. package/dist/src/acp/server.d.ts +24 -0
  7. package/dist/src/acp/server.js +1 -0
  8. package/dist/src/channel/clear-session.d.ts +4 -0
  9. package/dist/src/channel/clear-session.js +1 -0
  10. package/dist/src/channel/compact-session.d.ts +4 -0
  11. package/dist/src/channel/compact-session.js +1 -0
  12. package/dist/src/channel/routes.d.ts +34 -6
  13. package/dist/src/channel/types.d.ts +61 -9
  14. package/dist/src/chunks/{use-eve-agent-DaH3cf8K.js → use-eve-agent-BXMIf5fR.js} +130 -11
  15. package/dist/src/chunks/{use-eve-agent-CyDt3Lny.js → use-eve-agent-k-XHfrJT.js} +130 -11
  16. package/dist/src/cli/acp/command.d.ts +22 -0
  17. package/dist/src/cli/acp/command.js +4 -0
  18. package/dist/src/cli/commands/agent-prompt/build-and-verify.md +4 -0
  19. package/dist/src/cli/commands/extension-init.js +1 -1
  20. package/dist/src/cli/commands/init-git.js +1 -1
  21. package/dist/src/cli/commands/init-repl.js +1 -1
  22. package/dist/src/cli/commands/init.js +1 -1
  23. package/dist/src/cli/commands/logs.js +2 -2
  24. package/dist/src/cli/commands/register-integration-commands.js +1 -1
  25. package/dist/src/cli/commands/register-registry-commands.js +1 -1
  26. package/dist/src/cli/commands/registry-project.js +1 -1
  27. package/dist/src/cli/commands/registry-setup-command.js +1 -1
  28. package/dist/src/cli/commands/registry.d.ts +14 -2
  29. package/dist/src/cli/commands/registry.js +1 -1
  30. package/dist/src/cli/commands/trace.d.ts +2 -2
  31. package/dist/src/cli/dev/command-options.d.ts +22 -0
  32. package/dist/src/cli/dev/command-options.js +1 -0
  33. package/dist/src/cli/dev/diagnostic-dump.js +1 -1
  34. package/dist/src/cli/dev/diagnostic-sink.js +1 -1
  35. package/dist/src/cli/dev/local-server-cleanup.js +1 -1
  36. package/dist/src/cli/dev/local-server-process.js +1 -1
  37. package/dist/src/cli/dev/tui/command-typeahead.js +1 -1
  38. package/dist/src/cli/dev/tui/message-queue.d.ts +9 -13
  39. package/dist/src/cli/dev/tui/message-queue.js +1 -1
  40. package/dist/src/cli/dev/tui/prompt-commands.d.ts +13 -5
  41. package/dist/src/cli/dev/tui/prompt-commands.js +1 -1
  42. package/dist/src/cli/dev/tui/remote-auth.d.ts +6 -3
  43. package/dist/src/cli/dev/tui/remote-connection-probe.js +1 -1
  44. package/dist/src/cli/dev/tui/runner.d.ts +7 -7
  45. package/dist/src/cli/dev/tui/runner.js +1 -1
  46. package/dist/src/cli/dev/tui/stream-format.d.ts +14 -0
  47. package/dist/src/cli/dev/tui/stream-format.js +2 -2
  48. package/dist/src/cli/dev/tui/subagent-pump.d.ts +5 -5
  49. package/dist/src/cli/dev/tui/terminal-background.d.ts +23 -0
  50. package/dist/src/cli/dev/tui/terminal-background.js +1 -0
  51. package/dist/src/cli/dev/tui/terminal-renderer.js +12 -12
  52. package/dist/src/cli/dev/tui/traces/trace-content.d.ts +7 -0
  53. package/dist/src/cli/dev/tui/traces/trace-content.js +2 -2
  54. package/dist/src/cli/dev/tui/traces/trace-conversation.d.ts +10 -5
  55. package/dist/src/cli/dev/tui/traces/trace-conversation.js +1 -1
  56. package/dist/src/cli/dev/tui/traces/trace-store.js +1 -1
  57. package/dist/src/cli/dev/tui/traces/trace-surfaces.d.ts +40 -0
  58. package/dist/src/cli/dev/tui/traces/trace-surfaces.js +1 -0
  59. package/dist/src/cli/dev/tui/traces/trace-view.d.ts +8 -1
  60. package/dist/src/cli/dev/tui/traces/trace-view.js +2 -2
  61. package/dist/src/cli/dev/tui/traces/trace-viewer-session.d.ts +13 -0
  62. package/dist/src/cli/dev/tui/traces/trace-viewer-session.js +1 -1
  63. package/dist/src/cli/dev/tui/traces/trace-viewer-state.js +1 -1
  64. package/dist/src/cli/dev/tui/tui.js +1 -1
  65. package/dist/src/cli/invoke/invoke.js +1 -1
  66. package/dist/src/cli/invoke/result.js +1 -1
  67. package/dist/src/cli/run.d.ts +3 -0
  68. package/dist/src/cli/run.js +3 -3
  69. package/dist/src/cli/ui/terminal-text.d.ts +0 -3
  70. package/dist/src/cli/ui/terminal-text.js +1 -1
  71. package/dist/src/client/agent-info-schema.d.ts +2 -2
  72. package/dist/src/client/agent-info-schema.js +1 -1
  73. package/dist/src/client/index.d.ts +1 -1
  74. package/dist/src/client/open-stream.js +1 -1
  75. package/dist/src/client/session.d.ts +29 -1
  76. package/dist/src/client/session.js +1 -1
  77. package/dist/src/client/types.d.ts +29 -0
  78. package/dist/src/compiled/.vendor-stamp.json +2 -1
  79. package/dist/src/compiled/@agentclientprotocol/sdk/LICENSE +191 -0
  80. package/dist/src/compiled/@agentclientprotocol/sdk/index.d.ts +1835 -0
  81. package/dist/src/compiled/@agentclientprotocol/sdk/index.js +65 -0
  82. package/dist/src/compiled/@agentclientprotocol/sdk/jsonrpc.d.ts +603 -0
  83. package/dist/src/compiled/@agentclientprotocol/sdk/schema/guards.gen.d.ts +199 -0
  84. package/dist/src/compiled/@agentclientprotocol/sdk/schema/index.d.ts +51 -0
  85. package/dist/src/compiled/@agentclientprotocol/sdk/schema/types.gen.d.ts +6118 -0
  86. package/dist/src/compiled/@agentclientprotocol/sdk/stream.d.ts +35 -0
  87. package/dist/src/compiler/artifacts.js +1 -1
  88. package/dist/src/compiler/extension-compatibility.d.ts +8 -8
  89. package/dist/src/compiler/extension-compatibility.js +1 -1
  90. package/dist/src/compiler/manifest.d.ts +11 -22
  91. package/dist/src/compiler/manifest.js +1 -1
  92. package/dist/src/compiler/model-catalog.js +1 -1
  93. package/dist/src/compiler/normalize-agent-config.d.ts +3 -1
  94. package/dist/src/compiler/normalize-agent-config.js +1 -1
  95. package/dist/src/compiler/normalize-manifest.js +1 -1
  96. package/dist/src/compiler/normalize-sandbox.js +1 -1
  97. package/dist/src/compiler/normalize-subagent.d.ts +1 -0
  98. package/dist/src/compiler/normalize-subagent.js +1 -1
  99. package/dist/src/compiler/remote-agent-node.d.ts +3 -0
  100. package/dist/src/compiler/workspace-resources.js +1 -1
  101. package/dist/src/context/dynamic-subagent-lifecycle.d.ts +22 -0
  102. package/dist/src/context/dynamic-subagent-lifecycle.js +1 -0
  103. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  104. package/dist/src/context/keys.d.ts +13 -2
  105. package/dist/src/context/keys.js +1 -1
  106. package/dist/src/context/run-step.js +1 -1
  107. package/dist/src/discover/project-source.js +1 -1
  108. package/dist/src/evals/cli/eval.js +2 -2
  109. package/dist/src/evals/loaders/json.js +1 -1
  110. package/dist/src/evals/loaders/yaml.js +1 -1
  111. package/dist/src/evals/runner/artifacts.js +1 -1
  112. package/dist/src/evals/runner/discover.js +1 -1
  113. package/dist/src/evals/runner/reporters/junit.js +1 -1
  114. package/dist/src/evals/session.js +1 -1
  115. package/dist/src/execution/create-session-step.d.ts +2 -0
  116. package/dist/src/execution/create-session-step.js +1 -1
  117. package/dist/src/execution/delegation-tool.d.ts +3 -0
  118. package/dist/src/execution/delegation-tool.js +1 -0
  119. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  120. package/dist/src/execution/dispatch-workflow-runtime-actions-step.js +1 -1
  121. package/dist/src/execution/effective-agent-config.d.ts +12 -0
  122. package/dist/src/execution/effective-agent-config.js +1 -0
  123. package/dist/src/execution/node-step.d.ts +4 -0
  124. package/dist/src/execution/node-step.js +1 -1
  125. package/dist/src/execution/runtime-context.d.ts +2 -0
  126. package/dist/src/execution/runtime-context.js +1 -1
  127. package/dist/src/execution/sandbox/bindings/docker-cli.js +1 -1
  128. package/dist/src/execution/sandbox/bindings/docker-templates.js +1 -1
  129. package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
  130. package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
  131. package/dist/src/execution/sandbox/bindings/local-backend-utils.js +1 -1
  132. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  133. package/dist/src/execution/sandbox/bindings/microsandbox-metadata.js +1 -1
  134. package/dist/src/execution/sandbox/bindings/microsandbox-platform.js +1 -1
  135. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  136. package/dist/src/execution/sandbox/bindings/microsandbox-templates.js +1 -1
  137. package/dist/src/execution/sandbox/development-cleanup.js +1 -1
  138. package/dist/src/execution/sandbox/template-prewarm-lock.js +1 -1
  139. package/dist/src/execution/session-callback-request.d.ts +5 -0
  140. package/dist/src/execution/session-callback-request.js +1 -0
  141. package/dist/src/execution/session-delivery-hook.d.ts +1 -0
  142. package/dist/src/execution/session-delivery-hook.js +1 -1
  143. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  144. package/dist/src/execution/subagent-event-proxy-step.js +1 -1
  145. package/dist/src/execution/workflow-entry.js +1 -1
  146. package/dist/src/execution/workflow-runtime.d.ts +2 -0
  147. package/dist/src/execution/workflow-runtime.js +1 -1
  148. package/dist/src/execution/workflow-steps.js +1 -1
  149. package/dist/src/harness/agent-handles.d.ts +238 -0
  150. package/dist/src/harness/agent-handles.js +2 -0
  151. package/dist/src/harness/attachment-staging.js +1 -1
  152. package/dist/src/harness/compaction.d.ts +1 -1
  153. package/dist/src/harness/compaction.js +1 -1
  154. package/dist/src/harness/tool-loop.js +2 -2
  155. package/dist/src/harness/types.d.ts +16 -0
  156. package/dist/src/internal/application/build-profile.js +1 -1
  157. package/dist/src/internal/application/build-workspace.js +1 -1
  158. package/dist/src/internal/application/cache-metadata.js +1 -1
  159. package/dist/src/internal/application/compiled-artifacts.js +8 -8
  160. package/dist/src/internal/application/optional-package-install.js +2 -2
  161. package/dist/src/internal/application/output-publication-artifacts.js +1 -1
  162. package/dist/src/internal/application/output-publication-journal.js +1 -1
  163. package/dist/src/internal/application/output-publication-lock.js +1 -1
  164. package/dist/src/internal/application/output-publication.js +1 -1
  165. package/dist/src/internal/application/package.js +1 -1
  166. package/dist/src/internal/application/paths.js +1 -1
  167. package/dist/src/internal/application/production-compiler-artifacts.js +1 -1
  168. package/dist/src/internal/application/tsconfig-dependencies.js +1 -1
  169. package/dist/src/internal/authored-asset-import-plugin.js +1 -1
  170. package/dist/src/internal/authored-definition/core.js +1 -1
  171. package/dist/src/internal/authored-module-loader.js +3 -3
  172. package/dist/src/internal/authored-package-tsconfig-paths.js +1 -1
  173. package/dist/src/internal/materialized-authored-modules.js +1 -1
  174. package/dist/src/internal/nitro/dev-runtime-artifacts-retention.js +1 -1
  175. package/dist/src/internal/nitro/dev-runtime-artifacts.js +1 -1
  176. package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
  177. package/dist/src/internal/nitro/dev-runtime-source-snapshot.js +1 -1
  178. package/dist/src/internal/nitro/host/build-application.js +1 -1
  179. package/dist/src/internal/nitro/host/build-extension.js +1 -1
  180. package/dist/src/internal/nitro/host/build-vercel-agent-summary.js +1 -1
  181. package/dist/src/internal/nitro/host/configure-nitro-routes.js +3 -3
  182. package/dist/src/internal/nitro/host/copy-host-middleware.js +1 -1
  183. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  184. package/dist/src/internal/nitro/host/cron-handler-route.js +1 -1
  185. package/dist/src/internal/nitro/host/dev-authored-rebuild-coordinator.js +1 -1
  186. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  187. package/dist/src/internal/nitro/host/dev-host-fingerprint.js +1 -1
  188. package/dist/src/internal/nitro/host/dev-host-workspace.js +1 -1
  189. package/dist/src/internal/nitro/host/dev-server-http.js +1 -1
  190. package/dist/src/internal/nitro/host/dev-server-state.js +1 -1
  191. package/dist/src/internal/nitro/host/dev-workspace-extensions.js +1 -1
  192. package/dist/src/internal/nitro/host/extension-build-config.js +1 -1
  193. package/dist/src/internal/nitro/host/extension-declarations.js +2 -2
  194. package/dist/src/internal/nitro/host/extension-distribution.js +3 -3
  195. package/dist/src/internal/nitro/host/extension-state-usage.js +1 -1
  196. package/dist/src/internal/nitro/host/normalize-vercel-service-crons.js +1 -1
  197. package/dist/src/internal/nitro/host/start-development-server.js +2 -2
  198. package/dist/src/internal/nitro/host/start-production-server.js +2 -2
  199. package/dist/src/internal/nitro/host/types.d.ts +2 -0
  200. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
  201. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +1 -1
  202. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  203. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  204. package/dist/src/internal/vercel/project-link.js +1 -1
  205. package/dist/src/internal/vercel-agent-summary.d.ts +1 -1
  206. package/dist/src/internal/workflow/development-world-client.js +1 -1
  207. package/dist/src/internal/workflow-bundle/builder-support.js +6 -6
  208. package/dist/src/internal/workflow-bundle/builder.js +3 -3
  209. package/dist/src/internal/workflow-bundle/nitro-step-entry.js +2 -2
  210. package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
  211. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  212. package/dist/src/protocol/clear-session.d.ts +14 -0
  213. package/dist/src/protocol/clear-session.js +1 -0
  214. package/dist/src/protocol/compact-session.d.ts +14 -0
  215. package/dist/src/protocol/compact-session.js +1 -0
  216. package/dist/src/protocol/message.d.ts +19 -1
  217. package/dist/src/protocol/message.js +1 -1
  218. package/dist/src/protocol/routes.d.ts +10 -0
  219. package/dist/src/protocol/routes.js +1 -1
  220. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  221. package/dist/src/public/channels/discord/verify.js +1 -1
  222. package/dist/src/public/channels/eve.js +1 -1
  223. package/dist/src/public/channels/github/auth.js +2 -2
  224. package/dist/src/public/channels/github/githubChannel.js +1 -1
  225. package/dist/src/public/channels/github/verify.js +1 -1
  226. package/dist/src/public/channels/index.d.ts +1 -1
  227. package/dist/src/public/channels/linear/inbound.js +2 -2
  228. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  229. package/dist/src/public/channels/linear/verify.js +1 -1
  230. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  231. package/dist/src/public/channels/telegram/verify.js +1 -1
  232. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  233. package/dist/src/public/definitions/agent.d.ts +32 -1
  234. package/dist/src/public/definitions/agent.js +1 -1
  235. package/dist/src/public/definitions/channel.d.ts +5 -2
  236. package/dist/src/public/definitions/channel.js +1 -1
  237. package/dist/src/public/definitions/hook.d.ts +1 -0
  238. package/dist/src/public/definitions/tool.d.ts +4 -1
  239. package/dist/src/public/index.d.ts +1 -2
  240. package/dist/src/public/index.js +1 -1
  241. package/dist/src/public/models/openai/chatgpt/auth.js +1 -1
  242. package/dist/src/public/next/server.js +2 -2
  243. package/dist/src/public/next/vercel-output-config.js +1 -1
  244. package/dist/src/public/nuxt/dev-server.js +1 -1
  245. package/dist/src/public/nuxt/vercel-services.js +1 -1
  246. package/dist/src/public/sveltekit/dev-server.js +1 -1
  247. package/dist/src/public/sveltekit/vercel-json.js +1 -1
  248. package/dist/src/runtime/framework-tools/connection-search-dynamic.d.ts +2 -18
  249. package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
  250. package/dist/src/runtime/framework-tools/file-state.js +1 -1
  251. package/dist/src/runtime/framework-tools/index.d.ts +7 -2
  252. package/dist/src/runtime/framework-tools/index.js +1 -1
  253. package/dist/src/runtime/resolve-agent-graph.js +1 -1
  254. package/dist/src/runtime/resolve-agent.js +1 -1
  255. package/dist/src/runtime/resolve-dynamic-subagent.d.ts +12 -0
  256. package/dist/src/runtime/resolve-dynamic-subagent.js +1 -0
  257. package/dist/src/runtime/resolve-dynamic-tool.d.ts +15 -0
  258. package/dist/src/runtime/resolve-dynamic-tool.js +1 -1
  259. package/dist/src/runtime/sandbox/keys.js +1 -1
  260. package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +22 -0
  261. package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -0
  262. package/dist/src/runtime/subagents/registry.d.ts +10 -2
  263. package/dist/src/runtime/subagents/registry.js +1 -1
  264. package/dist/src/runtime/types.d.ts +11 -2
  265. package/dist/src/runtime/workspace/seed-files.js +1 -1
  266. package/dist/src/setup/boxes/detect-ai-gateway.js +1 -1
  267. package/dist/src/setup/flows/registry.js +1 -1
  268. package/dist/src/setup/index.d.ts +1 -0
  269. package/dist/src/setup/index.js +1 -1
  270. package/dist/src/setup/integrations/discord/api.d.ts +15 -0
  271. package/dist/src/setup/integrations/discord/api.js +1 -0
  272. package/dist/src/setup/integrations/discord/connect.d.ts +24 -0
  273. package/dist/src/setup/integrations/discord/connect.js +1 -0
  274. package/dist/src/setup/integrations/discord/setup.d.ts +19 -0
  275. package/dist/src/setup/integrations/discord/setup.js +8 -0
  276. package/dist/src/setup/integrations/registry.js +1 -1
  277. package/dist/src/setup/package-manager.js +1 -1
  278. package/dist/src/setup/primitives/pm/pnpm.js +3 -3
  279. package/dist/src/setup/project-resolution.js +1 -1
  280. package/dist/src/setup/prompter.js +1 -1
  281. package/dist/src/setup/registry-setup-client.d.ts +6 -2
  282. package/dist/src/setup/registry-setup-client.js +1 -1
  283. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  284. package/dist/src/setup/scaffold/create/extension.js +1 -1
  285. package/dist/src/setup/scaffold/create/project.js +2 -9
  286. package/dist/src/setup/scaffold/files.js +1 -1
  287. package/dist/src/setup/scaffold/update/channels.js +2 -2
  288. package/dist/src/setup/scaffold/update/connections.js +1 -1
  289. package/dist/src/setup/scaffold/workspace-root.js +1 -1
  290. package/dist/src/setup/slack-connect-lifecycle.js +1 -1
  291. package/dist/src/setup/vercel-project-framework.js +1 -1
  292. package/dist/src/shared/agent-definition.d.ts +7 -0
  293. package/dist/src/shared/agent-turn-outcome.d.ts +47 -0
  294. package/dist/src/shared/agent-turn-outcome.js +1 -0
  295. package/dist/src/shared/dynamic-tool-definition.d.ts +1 -5
  296. package/dist/src/shared/dynamic-tool-definition.js +1 -1
  297. package/dist/src/shared/guards.d.ts +2 -0
  298. package/dist/src/shared/guards.js +1 -1
  299. package/dist/src/shared/skill-package.js +1 -1
  300. package/dist/src/shared/skill-paths.d.ts +4 -4
  301. package/dist/src/shared/skill-paths.js +2 -2
  302. package/dist/src/shared/vercel-output-directory.js +1 -1
  303. package/dist/src/source-change/static-source-change.js +1 -1
  304. package/dist/src/svelte/index.js +1 -1
  305. package/dist/src/svelte/use-eve-agent.js +1 -1
  306. package/dist/src/tracing/local-instrumentation-runtime.js +1 -1
  307. package/dist/src/tracing/local-trace-reader.d.ts +22 -5
  308. package/dist/src/tracing/local-trace-reader.js +1 -1
  309. package/dist/src/tracing/local-trace-retention.js +1 -1
  310. package/dist/src/tracing/local-trace-span-processor.js +1 -1
  311. package/dist/src/vue/index.js +1 -1
  312. package/dist/src/vue/use-eve-agent.js +1 -1
  313. package/docs/channels/custom.mdx +41 -1
  314. package/docs/channels/discord.mdx +30 -14
  315. package/docs/channels/eve.mdx +26 -1
  316. package/docs/concepts/default-harness.md +4 -0
  317. package/docs/guides/acp.md +91 -0
  318. package/docs/guides/client/streaming.mdx +38 -0
  319. package/docs/guides/dev-tui.md +10 -7
  320. package/docs/guides/dynamic-capabilities.md +49 -6
  321. package/docs/guides/meta.json +1 -0
  322. package/docs/reference/cli.md +3 -0
  323. package/docs/reference/project-layout.md +1 -1
  324. package/docs/reference/typescript-api.md +48 -48
  325. package/docs/subagents.mdx +32 -2
  326. package/package.json +3 -2
@@ -0,0 +1,14 @@
1
+ import { z } from "#compiled/zod/index.js";
2
+ /** Outcome of queueing a manual context clear. */
3
+ export type ClearStatus = "accepted" | "no_active_session";
4
+ /** Successful response returned by the standard session-clear route. */
5
+ export type ClearResponse = {
6
+ readonly ok: true;
7
+ readonly sessionId: string;
8
+ readonly status: "accepted";
9
+ } | {
10
+ readonly ok: true;
11
+ readonly status: "no_active_session";
12
+ };
13
+ /** Validates successful responses from the standard session-clear route. */
14
+ export declare const ClearResponseSchema: z.ZodType<ClearResponse>;
@@ -0,0 +1 @@
1
+ import{z}from"#compiled/zod/index.js";const ClearResponseSchema=z.discriminatedUnion(`status`,[z.object({ok:z.literal(!0),sessionId:z.string().min(1),status:z.literal(`accepted`)}),z.object({ok:z.literal(!0),status:z.literal(`no_active_session`)})]);export{ClearResponseSchema};
@@ -0,0 +1,14 @@
1
+ import { z } from "#compiled/zod/index.js";
2
+ /** Outcome of queueing manual context compaction. */
3
+ export type CompactStatus = "accepted" | "no_active_session";
4
+ /** Successful response returned by the standard session-compaction route. */
5
+ export type CompactResponse = {
6
+ readonly ok: true;
7
+ readonly sessionId: string;
8
+ readonly status: "accepted";
9
+ } | {
10
+ readonly ok: true;
11
+ readonly status: "no_active_session";
12
+ };
13
+ /** Validates successful responses from the standard session-compaction route. */
14
+ export declare const CompactResponseSchema: z.ZodType<CompactResponse>;
@@ -0,0 +1 @@
1
+ import{z}from"#compiled/zod/index.js";const CompactResponseSchema=z.discriminatedUnion(`status`,[z.object({ok:z.literal(!0),sessionId:z.string().min(1),status:z.literal(`accepted`)}),z.object({ok:z.literal(!0),status:z.literal(`no_active_session`)})]);export{CompactResponseSchema};
@@ -421,6 +421,18 @@ export interface TurnCancelledStreamEvent {
421
421
  };
422
422
  type: "turn.cancelled";
423
423
  }
424
+ /**
425
+ * Stream event emitted after the durable model-message history is cleared.
426
+ * The session itself and its non-message state remain active.
427
+ */
428
+ export interface ContextClearedStreamEvent {
429
+ data: {
430
+ sequence: number;
431
+ sessionId: string;
432
+ turnId: string;
433
+ };
434
+ type: "context.cleared";
435
+ }
424
436
  /**
425
437
  * Stream event emitted when the workflow decides to compact the current
426
438
  * visible session history before the next model fragment runs.
@@ -534,7 +546,7 @@ export interface SessionCompletedStreamEvent {
534
546
  * Internal emitters use this type while constructing events. Public stream
535
547
  * consumers receive {@link MessageStreamEvent}.
536
548
  */
537
- export type UnstampedMessageStreamEvent = CompactionCompletedStreamEvent | CompactionRequestedStreamEvent | AuthorizationCompletedStreamEvent | AuthorizationRequiredStreamEvent | MessageAppendedStreamEvent | MessageCompletedStreamEvent | MessageReceivedStreamEvent | ReasoningAppendedStreamEvent | SessionCompletedStreamEvent | SessionFailedStreamEvent | SessionStartedStreamEvent | SessionWaitingStreamEvent | ResultCompletedStreamEvent | SubagentCalledStreamEvent | SubagentChildEventStreamEvent | SubagentCompletedStreamEvent | SubagentStartedStreamEvent | ActionsRequestedStreamEvent | InputRequestedStreamEvent | ActionResultStreamEvent | ReasoningCompletedStreamEvent | StepCompletedStreamEvent | StepFailedStreamEvent | StepStartedStreamEvent | TurnCancelledStreamEvent | TurnCompletedStreamEvent | TurnFailedStreamEvent | TurnStartedStreamEvent;
549
+ export type UnstampedMessageStreamEvent = ContextClearedStreamEvent | CompactionCompletedStreamEvent | CompactionRequestedStreamEvent | AuthorizationCompletedStreamEvent | AuthorizationRequiredStreamEvent | MessageAppendedStreamEvent | MessageCompletedStreamEvent | MessageReceivedStreamEvent | ReasoningAppendedStreamEvent | SessionCompletedStreamEvent | SessionFailedStreamEvent | SessionStartedStreamEvent | SessionWaitingStreamEvent | ResultCompletedStreamEvent | SubagentCalledStreamEvent | SubagentChildEventStreamEvent | SubagentCompletedStreamEvent | SubagentStartedStreamEvent | ActionsRequestedStreamEvent | InputRequestedStreamEvent | ActionResultStreamEvent | ReasoningCompletedStreamEvent | StepCompletedStreamEvent | StepFailedStreamEvent | StepStartedStreamEvent | TurnCancelledStreamEvent | TurnCompletedStreamEvent | TurnFailedStreamEvent | TurnStartedStreamEvent;
538
550
  /**
539
551
  * Stream events that represent an unrecovered turn/session failure.
540
552
  */
@@ -777,6 +789,12 @@ export declare function createTurnCancelledEvent(input: {
777
789
  readonly sequence: number;
778
790
  readonly turnId: string;
779
791
  }): TurnCancelledStreamEvent;
792
+ /** Creates the `context.cleared` event for one manual history clear. */
793
+ export declare function createContextClearedEvent(input: {
794
+ readonly sequence: number;
795
+ readonly sessionId: string;
796
+ readonly turnId: string;
797
+ }): ContextClearedStreamEvent;
780
798
  /**
781
799
  * Creates the `compaction.requested` event for one runtime compaction pass.
782
800
  */
@@ -1,2 +1,2 @@
1
1
  import{toChannelLocalContinuationToken}from"#shared/continuation-token.js";import{deserializeUrlFilePart,hasInternalRefScheme,isSerializedUrlFilePart}from"#internal/attachments/url-refs.js";import{decodeSandboxRef,isSandboxRefUrl}from"#internal/attachments/sandbox-refs.js";import{createEventId}from"#protocol/event-id.js";const EVE_SESSION_ID_HEADER=`x-eve-session-id`,EVE_STREAM_FORMAT_HEADER=`x-eve-stream-format`,EVE_STREAM_TAIL_INDEX_HEADER=`x-eve-stream-tail-index`,EVE_STREAM_VERSION_HEADER=`x-eve-stream-version`,EVE_MESSAGE_STREAM_CONTENT_TYPE=`application/x-ndjson; charset=utf-8`,EVE_MESSAGE_STREAM_FORMAT=`ndjson`,EVE_MESSAGE_STREAM_VERSION=`20`,textEncoder=new TextEncoder;function isCurrentTurnBoundaryEvent(e){return e.type===`session.completed`||e.type===`session.failed`||e.type===`session.waiting`}function isTurnFailureEvent(e){return e.type===`session.failed`||e.type===`step.failed`||e.type===`turn.failed`}function createSessionStartedEvent(e){let t={};return e?.invocation!==void 0&&(t.invocation=e.invocation),e?.runtime!==void 0&&(t.runtime=e.runtime),{data:t,type:`session.started`}}function createTurnStartedEvent(e){return{data:{sequence:e.sequence,turnId:e.turnId},type:`turn.started`}}function createMessageReceivedEvent(e){return{data:{message:summarizeUserContent(e.message),parts:projectUserContentParts(e.message),sequence:e.sequence,turnId:e.turnId},type:`message.received`}}function summarizeUserContent(e){if(typeof e==`string`)return e;let t=[];for(let n of e)if(n.type===`text`)t.push(n.text);else if(n.type===`file`){let e=n.filename??n.mediaType;t.push(`[file: ${e} (${n.mediaType})]`)}else n.type===`image`&&t.push(`[image: ${n.mediaType??`image`}]`);return t.join(`
2
- `)}function projectUserContentParts(e){if(typeof e==`string`)return[{text:e,type:`text`}];let t=[];for(let n of e)n.type===`text`?t.push({text:n.text,type:`text`}):n.type===`file`?t.push(projectFileLikePart(n.data,n.mediaType,n.filename)):n.type===`image`&&t.push(projectFileLikePart(n.image,n.mediaType??`application/octet-stream`,void 0));return t}function projectFileLikePart(e,t,n){if(isSandboxRefUrl(e)){let t=decodeSandboxRef(e);return createProjectedFilePart({filename:basenameOf(n??t.path),mediaType:t.mediaType,size:t.size})}let r=projectTaggedFileData(e,t,n);if(r!==void 0)return r;let i=byteLengthOf(e);return createProjectedFilePart(i===void 0?{filename:n,mediaType:t,...clientUrlFragment(e)}:{filename:n,mediaType:t,size:i})}function projectTaggedFileData(e,t,n){if(isTaggedFileData(e))switch(e.type){case`data`:{let r=byteLengthOf(e.data);return createProjectedFilePart(r===void 0?{filename:n,mediaType:t}:{filename:n,mediaType:t,size:r})}case`reference`:case`text`:return createProjectedFilePart({filename:n,mediaType:t});case`url`:return createProjectedFilePart({filename:n,mediaType:t,...clientUrlFragment(e.url)})}}function createProjectedFilePart(e){let t={mediaType:e.mediaType,type:`file`};return e.filename!==void 0&&(t.filename=e.filename),e.size!==void 0&&(t.size=e.size),e.url!==void 0&&(t.url=e.url),t}function isTaggedFileData(e){if(typeof e!=`object`||!e)return!1;let t=e.type;return t===`data`||t===`reference`||t===`text`||t===`url`}function byteLengthOf(e){if(e instanceof Uint8Array||e instanceof ArrayBuffer)return e.byteLength}function clientUrlFragment(e){if(isSerializedUrlFilePart(e))try{let n=deserializeUrlFilePart(e);return isClientResolvableUrl(n)?{url:n.href}:{}}catch{return{}}if(e instanceof URL)return isClientResolvableUrl(e)?{url:e.href}:{};if(typeof e!=`string`||hasInternalRefScheme(e))return{};if(e.startsWith(`data:`))return{url:e};try{let t=new URL(e);return isClientResolvableUrl(t)?{url:t.href}:{}}catch{return{}}}function isClientResolvableUrl(e){return e.protocol===`http:`||e.protocol===`https:`||e.protocol===`data:`}function basenameOf(e){let t=e.replaceAll(`\\`,`/`),n=t.slice(t.lastIndexOf(`/`)+1);return n.length>0?n:e}function createActionsRequestedEvent(e){return{data:{actions:e.actions,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`actions.requested`}}function createAuthorizationRequiredEvent(e){let t={description:e.description,name:e.name,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.authorization!==void 0&&(t.authorization=e.authorization),e.webhookUrl!==void 0&&(t.webhookUrl=e.webhookUrl),{data:t,type:`authorization.required`}}function createAuthorizationCompletedEvent(e){let t={name:e.name,outcome:e.outcome,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.authorization!==void 0&&(t.authorization=e.authorization),e.reason!==void 0&&(t.reason=e.reason),{data:t,type:`authorization.completed`}}function createInputRequestedEvent(e){return{data:{requests:e.requests,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`input.requested`}}function createActionResultEvent(e){let t=e.rejected===!0?{error:buildActionResultError(e.result),status:`rejected`}:normalizeActionResultOutcome(e.result);return{data:{error:t.error,result:e.result,sequence:e.sequence,stepIndex:e.stepIndex,status:t.status,turnId:e.turnId},type:`action.result`}}function createSubagentCalledEvent(e){return{data:{callId:e.callId,childSessionId:e.childSessionId,sessionId:e.sessionId,sequence:e.sequence,name:e.name,remote:e.remote,toolName:e.toolName,turnId:e.turnId,workflowId:e.workflowId},type:`subagent.called`}}function createMessageAppendedEvent(e){return{data:{messageDelta:e.messageDelta,messageSoFar:e.messageSoFar,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`message.appended`}}function createReasoningAppendedEvent(e){return{data:{reasoningDelta:e.reasoningDelta,reasoningSoFar:e.reasoningSoFar,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`reasoning.appended`}}function createMessageCompletedEvent(e){return{data:{finishReason:e.finishReason??`stop`,message:e.message,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`message.completed`}}function createReasoningCompletedEvent(e){return{data:{reasoning:e.reasoning,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`reasoning.completed`}}function createResultCompletedEvent(e){return{data:{result:e.result,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`result.completed`}}function createStepStartedEvent(e){return{data:{sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`step.started`}}function createStepCompletedEvent(e){let t={finishReason:e.finishReason,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.usage!==void 0&&(t.usage=e.usage),e.providerMetadata!==void 0&&(t.providerMetadata=e.providerMetadata),{data:t,type:`step.completed`}}function createStepFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`step.failed`}}function createTurnCompletedEvent(e){return{data:{sequence:e.sequence,turnId:e.turnId},type:`turn.completed`}}function createTurnFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sequence:e.sequence,turnId:e.turnId},type:`turn.failed`}}function createTurnCancelledEvent(e){return{data:{sequence:e.sequence,turnId:e.turnId},type:`turn.cancelled`}}function createCompactionRequestedEvent(e){return{data:{modelId:e.modelId,sequence:e.sequence,sessionId:e.sessionId,turnId:e.turnId,usageInputTokens:e.usageInputTokens??null},type:`compaction.requested`}}function createCompactionCompletedEvent(e){return{data:{modelId:e.modelId,sequence:e.sequence,sessionId:e.sessionId,turnId:e.turnId},type:`compaction.completed`}}function createSessionWaitingEvent(t){return{data:{continuationToken:toChannelLocalContinuationToken(t),wait:`next-user-message`},type:`session.waiting`}}function createSessionFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sessionId:e.sessionId},type:`session.failed`}}function createSessionCompletedEvent(){return{type:`session.completed`}}function stampMessageStreamEvent(e){return{...e,meta:{at:new Date().toISOString(),id:createEventId()}}}function encodeMessageStreamEvent(e){return textEncoder.encode(`${JSON.stringify(e)}\n`)}function normalizeActionResultOutcome(e){if(e.isError===!0)return{error:buildActionResultError(e),status:`failed`};let t=readActionResultOutputError(e.output);return t===void 0?{status:`completed`}:{error:t,status:`failed`}}function buildActionResultError(e){let t=readActionResultOutputError(e.output);return t===void 0?{code:`ACTION_RESULT_FAILED`,message:formatActionResultOutput(e.output)}:t}function readActionResultOutputError(e){let t=parseActionResultOutputRecord(e);if(t===void 0)return;let n=typeof t.code==`string`&&t.code.length>0?t.code:void 0,r=typeof t.message==`string`&&t.message.length>0?t.message:void 0;if(!(n===void 0||r===void 0))return{code:n,message:r}}function parseActionResultOutputRecord(e){if(typeof e==`object`&&e)return e;if(typeof e!=`string`)return;let t=e.trim();if(t.length!==0)try{let e=JSON.parse(t);if(typeof e==`object`&&e)return e}catch{return}}function formatActionResultOutput(e){if(typeof e==`string`)return e;let t=JSON.stringify(e);return typeof t==`string`&&t.length>0?t:`Action failed.`}export{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER,createActionResultEvent,createActionsRequestedEvent,createAuthorizationCompletedEvent,createAuthorizationRequiredEvent,createCompactionCompletedEvent,createCompactionRequestedEvent,createInputRequestedEvent,createMessageAppendedEvent,createMessageCompletedEvent,createMessageReceivedEvent,createReasoningAppendedEvent,createReasoningCompletedEvent,createResultCompletedEvent,createSessionCompletedEvent,createSessionFailedEvent,createSessionStartedEvent,createSessionWaitingEvent,createStepCompletedEvent,createStepFailedEvent,createStepStartedEvent,createSubagentCalledEvent,createTurnCancelledEvent,createTurnCompletedEvent,createTurnFailedEvent,createTurnStartedEvent,encodeMessageStreamEvent,isCurrentTurnBoundaryEvent,isTurnFailureEvent,stampMessageStreamEvent};
2
+ `)}function projectUserContentParts(e){if(typeof e==`string`)return[{text:e,type:`text`}];let t=[];for(let n of e)n.type===`text`?t.push({text:n.text,type:`text`}):n.type===`file`?t.push(projectFileLikePart(n.data,n.mediaType,n.filename)):n.type===`image`&&t.push(projectFileLikePart(n.image,n.mediaType??`application/octet-stream`,void 0));return t}function projectFileLikePart(e,t,n){if(isSandboxRefUrl(e)){let t=decodeSandboxRef(e);return createProjectedFilePart({filename:basenameOf(n??t.path),mediaType:t.mediaType,size:t.size})}let r=projectTaggedFileData(e,t,n);if(r!==void 0)return r;let i=byteLengthOf(e);return createProjectedFilePart(i===void 0?{filename:n,mediaType:t,...clientUrlFragment(e)}:{filename:n,mediaType:t,size:i})}function projectTaggedFileData(e,t,n){if(isTaggedFileData(e))switch(e.type){case`data`:{let r=byteLengthOf(e.data);return createProjectedFilePart(r===void 0?{filename:n,mediaType:t}:{filename:n,mediaType:t,size:r})}case`reference`:case`text`:return createProjectedFilePart({filename:n,mediaType:t});case`url`:return createProjectedFilePart({filename:n,mediaType:t,...clientUrlFragment(e.url)})}}function createProjectedFilePart(e){let t={mediaType:e.mediaType,type:`file`};return e.filename!==void 0&&(t.filename=e.filename),e.size!==void 0&&(t.size=e.size),e.url!==void 0&&(t.url=e.url),t}function isTaggedFileData(e){if(typeof e!=`object`||!e)return!1;let t=e.type;return t===`data`||t===`reference`||t===`text`||t===`url`}function byteLengthOf(e){if(e instanceof Uint8Array||e instanceof ArrayBuffer)return e.byteLength}function clientUrlFragment(e){if(isSerializedUrlFilePart(e))try{let n=deserializeUrlFilePart(e);return isClientResolvableUrl(n)?{url:n.href}:{}}catch{return{}}if(e instanceof URL)return isClientResolvableUrl(e)?{url:e.href}:{};if(typeof e!=`string`||hasInternalRefScheme(e))return{};if(e.startsWith(`data:`))return{url:e};try{let t=new URL(e);return isClientResolvableUrl(t)?{url:t.href}:{}}catch{return{}}}function isClientResolvableUrl(e){return e.protocol===`http:`||e.protocol===`https:`||e.protocol===`data:`}function basenameOf(e){let t=e.replaceAll(`\\`,`/`),n=t.slice(t.lastIndexOf(`/`)+1);return n.length>0?n:e}function createActionsRequestedEvent(e){return{data:{actions:e.actions,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`actions.requested`}}function createAuthorizationRequiredEvent(e){let t={description:e.description,name:e.name,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.authorization!==void 0&&(t.authorization=e.authorization),e.webhookUrl!==void 0&&(t.webhookUrl=e.webhookUrl),{data:t,type:`authorization.required`}}function createAuthorizationCompletedEvent(e){let t={name:e.name,outcome:e.outcome,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.authorization!==void 0&&(t.authorization=e.authorization),e.reason!==void 0&&(t.reason=e.reason),{data:t,type:`authorization.completed`}}function createInputRequestedEvent(e){return{data:{requests:e.requests,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`input.requested`}}function createActionResultEvent(e){let t=e.rejected===!0?{error:buildActionResultError(e.result),status:`rejected`}:normalizeActionResultOutcome(e.result);return{data:{error:t.error,result:e.result,sequence:e.sequence,stepIndex:e.stepIndex,status:t.status,turnId:e.turnId},type:`action.result`}}function createSubagentCalledEvent(e){return{data:{callId:e.callId,childSessionId:e.childSessionId,sessionId:e.sessionId,sequence:e.sequence,name:e.name,remote:e.remote,toolName:e.toolName,turnId:e.turnId,workflowId:e.workflowId},type:`subagent.called`}}function createMessageAppendedEvent(e){return{data:{messageDelta:e.messageDelta,messageSoFar:e.messageSoFar,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`message.appended`}}function createReasoningAppendedEvent(e){return{data:{reasoningDelta:e.reasoningDelta,reasoningSoFar:e.reasoningSoFar,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`reasoning.appended`}}function createMessageCompletedEvent(e){return{data:{finishReason:e.finishReason??`stop`,message:e.message,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`message.completed`}}function createReasoningCompletedEvent(e){return{data:{reasoning:e.reasoning,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`reasoning.completed`}}function createResultCompletedEvent(e){return{data:{result:e.result,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`result.completed`}}function createStepStartedEvent(e){return{data:{sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`step.started`}}function createStepCompletedEvent(e){let t={finishReason:e.finishReason,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.usage!==void 0&&(t.usage=e.usage),e.providerMetadata!==void 0&&(t.providerMetadata=e.providerMetadata),{data:t,type:`step.completed`}}function createStepFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`step.failed`}}function createTurnCompletedEvent(e){return{data:{sequence:e.sequence,turnId:e.turnId},type:`turn.completed`}}function createTurnFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sequence:e.sequence,turnId:e.turnId},type:`turn.failed`}}function createTurnCancelledEvent(e){return{data:{sequence:e.sequence,turnId:e.turnId},type:`turn.cancelled`}}function createContextClearedEvent(e){return{data:{sequence:e.sequence,sessionId:e.sessionId,turnId:e.turnId},type:`context.cleared`}}function createCompactionRequestedEvent(e){return{data:{modelId:e.modelId,sequence:e.sequence,sessionId:e.sessionId,turnId:e.turnId,usageInputTokens:e.usageInputTokens??null},type:`compaction.requested`}}function createCompactionCompletedEvent(e){return{data:{modelId:e.modelId,sequence:e.sequence,sessionId:e.sessionId,turnId:e.turnId},type:`compaction.completed`}}function createSessionWaitingEvent(t){return{data:{continuationToken:toChannelLocalContinuationToken(t),wait:`next-user-message`},type:`session.waiting`}}function createSessionFailedEvent(e){return{data:{code:e.code,details:e.details,message:e.message,sessionId:e.sessionId},type:`session.failed`}}function createSessionCompletedEvent(){return{type:`session.completed`}}function stampMessageStreamEvent(e){return{...e,meta:{at:new Date().toISOString(),id:createEventId()}}}function encodeMessageStreamEvent(e){return textEncoder.encode(`${JSON.stringify(e)}\n`)}function normalizeActionResultOutcome(e){if(e.isError===!0)return{error:buildActionResultError(e),status:`failed`};let t=readActionResultOutputError(e.output);return t===void 0?{status:`completed`}:{error:t,status:`failed`}}function buildActionResultError(e){let t=readActionResultOutputError(e.output);return t===void 0?{code:`ACTION_RESULT_FAILED`,message:formatActionResultOutput(e.output)}:t}function readActionResultOutputError(e){let t=parseActionResultOutputRecord(e);if(t===void 0)return;let n=typeof t.code==`string`&&t.code.length>0?t.code:void 0,r=typeof t.message==`string`&&t.message.length>0?t.message:void 0;if(!(n===void 0||r===void 0))return{code:n,message:r}}function parseActionResultOutputRecord(e){if(typeof e==`object`&&e)return e;if(typeof e!=`string`)return;let t=e.trim();if(t.length!==0)try{let e=JSON.parse(t);if(typeof e==`object`&&e)return e}catch{return}}function formatActionResultOutput(e){if(typeof e==`string`)return e;let t=JSON.stringify(e);return typeof t==`string`&&t.length>0?t:`Action failed.`}export{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER,createActionResultEvent,createActionsRequestedEvent,createAuthorizationCompletedEvent,createAuthorizationRequiredEvent,createCompactionCompletedEvent,createCompactionRequestedEvent,createContextClearedEvent,createInputRequestedEvent,createMessageAppendedEvent,createMessageCompletedEvent,createMessageReceivedEvent,createReasoningAppendedEvent,createReasoningCompletedEvent,createResultCompletedEvent,createSessionCompletedEvent,createSessionFailedEvent,createSessionStartedEvent,createSessionWaitingEvent,createStepCompletedEvent,createStepFailedEvent,createStepStartedEvent,createSubagentCalledEvent,createTurnCancelledEvent,createTurnCompletedEvent,createTurnFailedEvent,createTurnStartedEvent,encodeMessageStreamEvent,isCurrentTurnBoundaryEvent,isTurnFailureEvent,stampMessageStreamEvent};
@@ -22,6 +22,16 @@ export declare const EVE_CREATE_SESSION_ROUTE_PATH = "/eve/v1/session";
22
22
  * continuation token. The request body supplies the channel-local token.
23
23
  */
24
24
  export declare const EVE_RESET_SESSION_ROUTE_PATH = "/eve/v1/session/reset";
25
+ /**
26
+ * Stable framework-owned route for compacting the session that owns a client
27
+ * continuation token. The request body supplies the channel-local token.
28
+ */
29
+ export declare const EVE_COMPACT_SESSION_ROUTE_PATH = "/eve/v1/session/compact";
30
+ /**
31
+ * Stable framework-owned route for clearing the model history of the session
32
+ * that owns a client continuation token.
33
+ */
34
+ export declare const EVE_CLEAR_SESSION_ROUTE_PATH = "/eve/v1/session/clear";
25
35
  /**
26
36
  * Stable framework-owned route pattern for sending a message to an existing
27
37
  * session.
@@ -1 +1 @@
1
- const EVE_ROUTE_PREFIX=`/eve/v1`,EVE_HEALTH_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/health`,EVE_INFO_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/info`,EVE_CREATE_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session`,EVE_RESET_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session/reset`,EVE_CONTINUE_SESSION_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId`,EVE_MESSAGE_STREAM_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId/stream`,EVE_CANCEL_TURN_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId/cancel`,EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/dev/schedules/:scheduleId`,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/dev/runtime-artifacts`,EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/rebuild`,EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/suspend`,EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/resume`;function createEveDevDispatchSchedulePath(e){return`${EVE_ROUTE_PREFIX}/dev/schedules/${encodeURIComponent(e)}`}const EVE_CONNECTION_CALLBACK_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/connections/:name/callback/:token`,EVE_CALLBACK_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/callback/:token`;function createEveMessageStreamRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createEveContinueSessionRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createEveCancelTurnRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/cancel`}function createEveConnectionCallbackRoutePath(e,t){return`${EVE_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createEveCallbackRoutePath(e){return`${EVE_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{EVE_CALLBACK_ROUTE_PATTERN,EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_CONNECTION_CALLBACK_ROUTE_PATTERN,EVE_CONTINUE_SESSION_ROUTE_PATTERN,EVE_CREATE_SESSION_ROUTE_PATH,EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH,EVE_HEALTH_ROUTE_PATH,EVE_INFO_ROUTE_PATH,EVE_MESSAGE_STREAM_ROUTE_PATTERN,EVE_RESET_SESSION_ROUTE_PATH,EVE_ROUTE_PREFIX,createEveCallbackRoutePath,createEveCancelTurnRoutePath,createEveConnectionCallbackRoutePath,createEveContinueSessionRoutePath,createEveDevDispatchSchedulePath,createEveMessageStreamRoutePath};
1
+ const EVE_ROUTE_PREFIX=`/eve/v1`,EVE_HEALTH_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/health`,EVE_INFO_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/info`,EVE_CREATE_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session`,EVE_RESET_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session/reset`,EVE_COMPACT_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session/compact`,EVE_CLEAR_SESSION_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/session/clear`,EVE_CONTINUE_SESSION_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId`,EVE_MESSAGE_STREAM_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId/stream`,EVE_CANCEL_TURN_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/session/:sessionId/cancel`,EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/dev/schedules/:scheduleId`,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH=`${EVE_ROUTE_PREFIX}/dev/runtime-artifacts`,EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/rebuild`,EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/suspend`,EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH=`${EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH}/resume`;function createEveDevDispatchSchedulePath(e){return`${EVE_ROUTE_PREFIX}/dev/schedules/${encodeURIComponent(e)}`}const EVE_CONNECTION_CALLBACK_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/connections/:name/callback/:token`,EVE_CALLBACK_ROUTE_PATTERN=`${EVE_ROUTE_PREFIX}/callback/:token`;function createEveMessageStreamRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createEveContinueSessionRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createEveCancelTurnRoutePath(e){return`${EVE_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/cancel`}function createEveConnectionCallbackRoutePath(e,t){return`${EVE_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createEveCallbackRoutePath(e){return`${EVE_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{EVE_CALLBACK_ROUTE_PATTERN,EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_CLEAR_SESSION_ROUTE_PATH,EVE_COMPACT_SESSION_ROUTE_PATH,EVE_CONNECTION_CALLBACK_ROUTE_PATTERN,EVE_CONTINUE_SESSION_ROUTE_PATTERN,EVE_CREATE_SESSION_ROUTE_PATH,EVE_DEV_DISPATCH_SCHEDULE_ROUTE_PATTERN,EVE_DEV_RUNTIME_ARTIFACTS_REBUILD_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_RESUME_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_ROUTE_PATH,EVE_DEV_RUNTIME_ARTIFACTS_SUSPEND_ROUTE_PATH,EVE_HEALTH_ROUTE_PATH,EVE_INFO_ROUTE_PATH,EVE_MESSAGE_STREAM_ROUTE_PATTERN,EVE_RESET_SESSION_ROUTE_PATH,EVE_ROUTE_PREFIX,createEveCallbackRoutePath,createEveCancelTurnRoutePath,createEveConnectionCallbackRoutePath,createEveContinueSessionRoutePath,createEveDevDispatchSchedulePath,createEveMessageStreamRoutePath};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,resolveDiscordBotToken,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";const log=createLogger(`discord.channel`);function discordChannel(e={}){let t=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),metadata:e=>({channelId:e.channelId,guildId:e.guildId}),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/eve/v1/discord`,async(r,{send:i,waitUntil:a})=>{let o=await verifyDiscordInbound(r,e.credentials);if(o===null)return new Response(`unauthorized`,{status:401});let s;try{s=parseJsonObject(JSON.parse(o))}catch(e){return log.warn(`inbound Discord body is not valid JSON`,{error:e}),discordJson({content:`invalid request`,ephemeral:!0})}if(s.type===DISCORD_INTERACTION_TYPE.PING)return discordJson({type:DISCORD_INTERACTION_RESPONSE_TYPE.PONG});let c=parseDiscordInteraction(s);return c===null?discordJson({content:`Unsupported Discord interaction.`,ephemeral:!0}):handleInteraction({config:e,interaction:c,onCommand:t,send:i,waitUntil:a})})],async receive(t,{send:n}){let r=t.target,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires target.channelId.`);let a=readString(r.conversationId),o=r.initialMessage;if(o!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(o!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(o);c=t.id,l=t.id.length>0}return n(t.message,{auth:t.auth,continuationToken:discordContinuationToken(i,c),state:{applicationId:null,channelId:i,conversationId:c||null,guildId:null,hasMessageAnchor:l,initialResponseSent:!0,interactionToken:null}})},events:a})}function rebuildDiscordContext(e,t,n){return{discord:buildDiscordHandle({config:n,session:t,state:e}),state:e}}function buildDiscordHandle(e){let n=e.config.api,r=e.state,i=mergeCredentials(e.config.credentials,r);function anchor(t){!t.id||r.hasMessageAnchor||(r.conversationId=t.id,r.hasMessageAnchor=!0,r.channelId&&e.session?.setContinuationToken(discordContinuationToken(r.channelId,t.id)))}async function sendViaChannel(e){let t=r.channelId??``;if(!t)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,channelId:t});return anchor(a),a}async function editOriginal(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return r.initialResponseSent=!0,anchor(a),a}async function followup(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for followup message.`);let a=await createDiscordFollowupMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return anchor(a),a}async function startTyping(){let e=r.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:n?.apiBaseUrl,credentials:i,fetch:n?.fetch,channelId:e})}catch(n){logError(log,`Discord typing indicator failed — swallowed`,n,{channelId:e})}}return{applicationId:r.applicationId??void 0,channelId:r.channelId??``,conversationId:r.conversationId??``,guildId:r.guildId??void 0,interactionToken:r.interactionToken??void 0,request(e,t,r){return callDiscordApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:r?.botAuth===!0?i.botToken:void 0,fetch:n?.fetch,method:r?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),n;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:r});n===void 0&&(n=t)}return n??{id:``,raw:null}},editOriginalResponse:editOriginal,followup,sendChannelMessage:sendViaChannel,startTyping}}async function postOne(e){if(e.state.interactionToken&&e.state.applicationId)try{return e.state.initialResponseSent?await e.followup(e.body):await e.editOriginal(e.body)}catch(e){log.warn(`Discord interaction-token delivery failed, falling back to channel message`,{error:e})}return e.sendViaChannel(e.body)}async function handleInteraction(e){return e.interaction.type===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?handleCommandInteraction({config:e.config,interaction:e.interaction,onCommand:e.onCommand,send:e.send,waitUntil:e.waitUntil}):e.interaction.type===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?handleComponentInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil}):handleModalSubmitInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil})}async function handleCommandInteraction(e){let t=stateFromInteraction(e.interaction,{conversationId:e.interaction.id,hasMessageAnchor:!1,initialResponseSent:!1}),n={discord:buildDiscordHandle({config:e.config,state:t})},r;try{r=await e.onCommand(n,e.interaction)}catch(e){return log.error(`command handler failed`,{error:e}),discordJson({content:`The Discord command handler failed.`,ephemeral:!0})}return r==null?discordJson({content:`Command ignored.`,ephemeral:!0}):(e.waitUntil(dispatchCommand({interaction:e.interaction,result:r,send:e.send,state:t})),discordDeferredJson(r.ephemeral===!0))}function handleComponentInteraction(e){if(isDiscordFreeformComponent(e.interaction.customId)){let t=readMessageContent(e.interaction.raw);return discordJsonBody(buildFreeformModalResponse({customId:e.interaction.customId,prompt:t}))}let t=deriveComponentInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId,inputResponses:t,interaction:e.interaction,send:e.send})),discordJsonBody({type:DISCORD_INTERACTION_RESPONSE_TYPE.DEFERRED_UPDATE_MESSAGE})}function handleModalSubmitInteraction(e){let t=deriveModalInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId??e.interaction.id,inputResponses:t,interaction:e.interaction,send:e.send})),discordJson({content:`Answer received.`,ephemeral:!0})}async function dispatchCommand(e){let t=commandInteractionMessage(e.interaction),n=formatDiscordContextBlock({channelId:e.interaction.channelId,commandName:e.interaction.commandName,guildId:e.interaction.guildId,interactionId:e.interaction.id,userId:e.interaction.user.id,username:e.interaction.user.username}),r=e.result.context??[];try{await e.send({message:t,context:[n,...r]},{auth:e.result.auth,continuationToken:discordContinuationToken(e.interaction.channelId,e.interaction.id),state:e.state})}catch(e){log.error(`command delivery failed`,{error:e})}}async function dispatchInputResponses(e){try{await e.send({inputResponses:e.inputResponses},{auth:null,continuationToken:discordContinuationToken(e.interaction.channelId,e.conversationId),state:stateFromInteraction(e.interaction,{conversationId:e.conversationId,hasMessageAnchor:!0,initialResponseSent:!0})})}catch(e){log.error(`interaction response delivery failed`,{error:e})}}function stateFromInteraction(e,t){return{applicationId:e.applicationId,channelId:e.channelId,conversationId:t.conversationId,guildId:e.guildId??null,hasMessageAnchor:t.hasMessageAnchor,initialResponseSent:t.initialResponseSent,interactionToken:e.token}}function initialDiscordState(){return{applicationId:null,channelId:null,conversationId:null,guildId:null,hasMessageAnchor:!1,initialResponseSent:!1,interactionToken:null}}function mergeCredentials(e,t){return{applicationId:t.applicationId??e?.applicationId,botToken:e?.botToken??(()=>resolveDiscordBotToken()),publicKey:e?.publicKey,webhookVerifier:e?.webhookVerifier}}function normalizePostInput(e){return typeof e==`string`?{content:e}:e}function expandPostBodies(e){return typeof e.content==`string`?splitDiscordMessageContent(e.content).map((t,n)=>n===0?{...e,content:t}:{allowed_mentions:e.allowed_mentions,content:t}):[e]}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{discordChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,resolveDiscordBotToken,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";const log=createLogger(`discord.channel`);function discordChannel(e={}){let t=e.onCommand??defaultOnCommand,o={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),metadata:e=>({channelId:e.channelId,guildId:e.guildId}),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/eve/v1/discord`,async(n,{send:i,waitUntil:a})=>{let o=await verifyDiscordInbound(n,e.credentials);if(o===null)return new Response(`unauthorized`,{status:401});let s;try{s=parseJsonObject(JSON.parse(o))}catch(e){return log.warn(`inbound Discord body is not valid JSON`,{error:e}),discordJson({content:`invalid request`,ephemeral:!0})}if(s.type===DISCORD_INTERACTION_TYPE.PING)return discordJson({type:DISCORD_INTERACTION_RESPONSE_TYPE.PONG});let c=parseDiscordInteraction(s);return c===null?discordJson({content:`Unsupported Discord interaction.`,ephemeral:!0}):handleInteraction({config:e,interaction:c,onCommand:t,send:i,waitUntil:a})})],async receive(t,{send:r}){let i=t.target,a=readNonEmptyString(i.channelId);if(!a)throw Error(`discordChannel().receive requires target.channelId.`);let o=readNonEmptyString(i.conversationId),s=i.initialMessage;if(s!==void 0&&o!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let l=o??``,u=o!==void 0;if(s!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:a}}).sendChannelMessage(s);l=t.id,u=t.id.length>0}return r(t.message,{auth:t.auth,continuationToken:discordContinuationToken(a,l),state:{applicationId:null,channelId:a,conversationId:l||null,guildId:null,hasMessageAnchor:u,initialResponseSent:!0,interactionToken:null}})},events:o})}function rebuildDiscordContext(e,t,n){return{discord:buildDiscordHandle({config:n,session:t,state:e}),state:e}}function buildDiscordHandle(e){let n=e.config.api,r=e.state,i=mergeCredentials(e.config.credentials,r);function anchor(t){!t.id||r.hasMessageAnchor||(r.conversationId=t.id,r.hasMessageAnchor=!0,r.channelId&&e.session?.setContinuationToken(discordContinuationToken(r.channelId,t.id)))}async function sendViaChannel(e){let t=r.channelId??``;if(!t)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,channelId:t});return anchor(a),a}async function editOriginal(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return r.initialResponseSent=!0,anchor(a),a}async function followup(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for followup message.`);let a=await createDiscordFollowupMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return anchor(a),a}async function startTyping(){let e=r.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:n?.apiBaseUrl,credentials:i,fetch:n?.fetch,channelId:e})}catch(n){logError(log,`Discord typing indicator failed — swallowed`,n,{channelId:e})}}return{applicationId:r.applicationId??void 0,channelId:r.channelId??``,conversationId:r.conversationId??``,guildId:r.guildId??void 0,interactionToken:r.interactionToken??void 0,request(e,t,r){return callDiscordApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:r?.botAuth===!0?i.botToken:void 0,fetch:n?.fetch,method:r?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),n;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:r});n===void 0&&(n=t)}return n??{id:``,raw:null}},editOriginalResponse:editOriginal,followup,sendChannelMessage:sendViaChannel,startTyping}}async function postOne(e){if(e.state.interactionToken&&e.state.applicationId)try{return e.state.initialResponseSent?await e.followup(e.body):await e.editOriginal(e.body)}catch(e){log.warn(`Discord interaction-token delivery failed, falling back to channel message`,{error:e})}return e.sendViaChannel(e.body)}async function handleInteraction(e){return e.interaction.type===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?handleCommandInteraction({config:e.config,interaction:e.interaction,onCommand:e.onCommand,send:e.send,waitUntil:e.waitUntil}):e.interaction.type===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?handleComponentInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil}):handleModalSubmitInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil})}async function handleCommandInteraction(e){let t=stateFromInteraction(e.interaction,{conversationId:e.interaction.id,hasMessageAnchor:!1,initialResponseSent:!1}),n={discord:buildDiscordHandle({config:e.config,state:t})},r;try{r=await e.onCommand(n,e.interaction)}catch(e){return log.error(`command handler failed`,{error:e}),discordJson({content:`The Discord command handler failed.`,ephemeral:!0})}return r==null?discordJson({content:`Command ignored.`,ephemeral:!0}):(e.waitUntil(dispatchCommand({interaction:e.interaction,result:r,send:e.send,state:t})),discordDeferredJson(r.ephemeral===!0))}function handleComponentInteraction(e){if(isDiscordFreeformComponent(e.interaction.customId)){let t=readMessageContent(e.interaction.raw);return discordJsonBody(buildFreeformModalResponse({customId:e.interaction.customId,prompt:t}))}let t=deriveComponentInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId,inputResponses:t,interaction:e.interaction,send:e.send})),discordJsonBody({type:DISCORD_INTERACTION_RESPONSE_TYPE.DEFERRED_UPDATE_MESSAGE})}function handleModalSubmitInteraction(e){let t=deriveModalInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId??e.interaction.id,inputResponses:t,interaction:e.interaction,send:e.send})),discordJson({content:`Answer received.`,ephemeral:!0})}async function dispatchCommand(e){let t=commandInteractionMessage(e.interaction),n=formatDiscordContextBlock({channelId:e.interaction.channelId,commandName:e.interaction.commandName,guildId:e.interaction.guildId,interactionId:e.interaction.id,userId:e.interaction.user.id,username:e.interaction.user.username}),r=e.result.context??[];try{await e.send({message:t,context:[n,...r]},{auth:e.result.auth,continuationToken:discordContinuationToken(e.interaction.channelId,e.interaction.id),state:e.state})}catch(e){log.error(`command delivery failed`,{error:e})}}async function dispatchInputResponses(e){try{await e.send({inputResponses:e.inputResponses},{auth:null,continuationToken:discordContinuationToken(e.interaction.channelId,e.conversationId),state:stateFromInteraction(e.interaction,{conversationId:e.conversationId,hasMessageAnchor:!0,initialResponseSent:!0})})}catch(e){log.error(`interaction response delivery failed`,{error:e})}}function stateFromInteraction(e,t){return{applicationId:e.applicationId,channelId:e.channelId,conversationId:t.conversationId,guildId:e.guildId??null,hasMessageAnchor:t.hasMessageAnchor,initialResponseSent:t.initialResponseSent,interactionToken:e.token}}function initialDiscordState(){return{applicationId:null,channelId:null,conversationId:null,guildId:null,hasMessageAnchor:!1,initialResponseSent:!1,interactionToken:null}}function mergeCredentials(e,t){return{applicationId:t.applicationId??e?.applicationId,botToken:e?.botToken??(()=>resolveDiscordBotToken()),publicKey:e?.publicKey,webhookVerifier:e?.webhookVerifier}}function normalizePostInput(e){return typeof e==`string`?{content:e}:e}function expandPostBodies(e){return typeof e.content==`string`?splitDiscordMessageContent(e.content).map((t,n)=>n===0?{...e,content:t}:{allowed_mentions:e.allowed_mentions,content:t}):[e]}export{discordChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{createPublicKey,verify}from"node:crypto";const log=createLogger(`discord.verify`),ED25519_SPKI_PREFIX=Buffer.from(`302a300506032b6570032100`,`hex`);async function resolveDiscordPublicKey(e){let t=e??process.env.DISCORD_PUBLIC_KEY;if(!t)throw Error(`DISCORD_PUBLIC_KEY is required.`);return typeof t==`function`?await t():t}async function verifyDiscordRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`discordChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveDiscordPublicKey(t.publicKey),i=e.headers.get(`x-signature-ed25519`)??``,a=e.headers.get(`x-signature-timestamp`)??``;if(!i||!a)throw Error(`discordChannel: inbound request missing Discord signature headers.`);let o=Number(a);if(!Number.isFinite(o))throw Error(`discordChannel: inbound request has malformed timestamp.`);let s=t.maxSkewSeconds??300,c=Math.floor(Date.now()/1e3);if(Math.abs(c-o)>s)throw Error(`discordChannel: inbound request timestamp outside allowed skew.`);if(!verifyDiscordSignature({body:n,publicKey:r,signature:i,timestamp:a}))throw Error(`discordChannel: inbound request signature mismatch.`);return n}function verifyDiscordSignature(e){try{let r=Buffer.from(e.publicKey,`hex`),a=Buffer.from(e.signature,`hex`);if(r.length!==32||a.length!==64)return!1;let o=createPublicKey({format:`der`,key:Buffer.concat([ED25519_SPKI_PREFIX,r]),type:`spki`});return verify(null,Buffer.from(`${e.timestamp}${e.body}`),o,a)}catch(e){return log.debug(`Discord signature verification threw`,{error:e}),!1}}export{resolveDiscordPublicKey,verifyDiscordRequest,verifyDiscordSignature};
1
+ import{createPublicKey,verify}from"node:crypto";import{createLogger}from"#internal/logging.js";const log=createLogger(`discord.verify`),ED25519_SPKI_PREFIX=Buffer.from(`302a300506032b6570032100`,`hex`);async function resolveDiscordPublicKey(e){let t=e??process.env.DISCORD_PUBLIC_KEY;if(!t)throw Error(`DISCORD_PUBLIC_KEY is required.`);return typeof t==`function`?await t():t}async function verifyDiscordRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`discordChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveDiscordPublicKey(t.publicKey),i=e.headers.get(`x-signature-ed25519`)??``,a=e.headers.get(`x-signature-timestamp`)??``;if(!i||!a)throw Error(`discordChannel: inbound request missing Discord signature headers.`);let o=Number(a);if(!Number.isFinite(o))throw Error(`discordChannel: inbound request has malformed timestamp.`);let s=t.maxSkewSeconds??300,c=Math.floor(Date.now()/1e3);if(Math.abs(c-o)>s)throw Error(`discordChannel: inbound request timestamp outside allowed skew.`);if(!verifyDiscordSignature({body:n,publicKey:r,signature:i,timestamp:a}))throw Error(`discordChannel: inbound request signature mismatch.`);return n}function verifyDiscordSignature(n){try{let r=Buffer.from(n.publicKey,`hex`),a=Buffer.from(n.signature,`hex`);if(r.length!==32||a.length!==64)return!1;let o=createPublicKey({format:`der`,key:Buffer.concat([ED25519_SPKI_PREFIX,r]),type:`spki`});return verify(null,Buffer.from(`${n.timestamp}${n.body}`),o,a)}catch(e){return log.debug(`Discord signature verification threw`,{error:e}),!1}}export{resolveDiscordPublicKey,verifyDiscordRequest,verifyDiscordSignature};
@@ -1,3 +1,3 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_INFO_ROUTE_PATH,EVE_RESET_SESSION_ROUTE_PATH}from"#protocol/routes.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{readAgentInfoRouteResponse,readRouteAgent}from"#internal/nitro/routes/channel-route-context.js";import{resolveForwardedPrincipal}from"#channel/forwarded-principal.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`eve.channel`);function defaultEveAuth(e){return e.eve.caller}function eveChannel(e){let n=mergeUploadPolicy(e.uploadPolicy);return defineChannel({cors:normalizeEveCors(e.cors),routes:[GET(EVE_INFO_ROUTE_PATH,async(t,n)=>{let r=await routeAuth(t,e.auth);if(r instanceof Response)return r;let i=readAgentInfoRouteResponse(n);return i===void 0?Response.json({error:`Agent info route requires internal channel dispatch context.`,ok:!1},{status:500}):await i()}),POST(`/eve/v1/session`,async(t,{send:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=i,o;try{o=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof o!=`object`||!o)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let s=await resolveForwardedPrincipal({trustedForwarders:e.trustedForwarders,forwarder:a,payload:o});if(s instanceof Response)return s;let c=parseCreateBody(o);if(c instanceof Response)return c;let l=checkUploadPolicy(c,n);if(l!==null)return l;let u=await resolveOnMessage({auth:s.auth,config:e,message:c.message,request:t});if(u instanceof Response)return u;if(!u.dispatch)return droppedMessageResponse();let d=`eve:${crypto.randomUUID()}`,f=mergeContext(c.context,u.context),p={auth:u.auth,callback:c.callback,continuationToken:d,mode:c.mode};s.accepted&&(p.initiatorAuth=s.initiatorAuth);let m=await r(createSendPayload(c,f),p);return Response.json({continuationToken:m.continuationToken,ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:202})}),POST(EVE_RESET_SESSION_ROUTE_PATH,async(n,{reset:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=await parseResetSessionBody(n);if(a instanceof Response)return a;let o;try{o=await r({continuationToken:a.continuationToken,reason:`Client requested session reset`})}catch(e){let n=logError(log,`session-reset request failed`,e);return Response.json({error:`Failed to reset the session.`,errorId:n,ok:!1},{status:500})}let s=o.status===`reset`?{ok:!0,previousSessionId:o.previousSessionId,status:`reset`}:{ok:!0,status:`no_active_session`};return Response.json(s,{headers:{"cache-control":`no-store`}})}),POST(`/eve/v1/session/:sessionId`,async(t,{send:r,getSession:i,params:a})=>{let o=await routeAuth(t,e.auth);if(o instanceof Response)return o;let s=o,c=a.sessionId;if(!c)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(c)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let l;try{l=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof l!=`object`||!l)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let u=parseContinueBody(l);if(u instanceof Response)return u;let d=checkUploadPolicy(u,n);if(d!==null)return d;let f=u.context,p=s;if(u.message!==void 0){let n=await resolveOnMessage({auth:s,config:e,message:u.message,request:t,sessionId:c});if(n instanceof Response)return n;if(!n.dispatch)return droppedMessageResponse();f=mergeContext(u.context,n.context),p=n.auth}let m=await r({inputResponses:u.inputResponses,message:u.message,context:f,outputSchema:u.outputSchema},{auth:p,continuationToken:u.continuationToken});return Response.json({ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:200})}),POST(EVE_CANCEL_TURN_ROUTE_PATTERN,async(n,r)=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=r.params.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=await parseCancelTurnBody(n);if(o instanceof Response)return o;let s;try{let e=readRouteAgent(r);if(e===void 0)throw Error(`Missing route agent.`);s=await e.cancelTurn({sessionId:a,turnId:o.turnId})}catch(e){let n=logError(log,`cancel-turn request failed`,e,{sessionId:a});return Response.json({error:`Failed to cancel the turn.`,errorId:n,ok:!1},{status:500})}return Response.json({ok:!0,sessionId:a,status:s.status},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:a},status:202})}),GET(`/eve/v1/session/:sessionId/stream`,async(t,{getSession:n,params:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=r.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let f=parseStartIndex(t);if(f instanceof Response)return f;let p=parseIncludeTailIndex(t);try{let e=n(a),t=p?await e.getStreamTailIndex():void 0,r=serializeAsNdjson(await e.getEventStream({startIndex:f}));return new Response(r,{headers:{"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:a,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,...t===void 0?{}:{[EVE_STREAM_TAIL_INDEX_HEADER]:String(t)},[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}function normalizeEveCors(e){if(e===void 0||e===!1)return!1;if(e===!0)return!0;let t={};return e.origin!==void 0&&(t.origin=normalizeEveCorsOrigin(e.origin)),e.methods!==void 0&&(t.methods=e.methods),e.allowedHeaders!==void 0&&(t.allowHeaders=e.allowedHeaders),e.exposedHeaders!==void 0&&(t.exposeHeaders=e.exposedHeaders),e.credentials!==void 0&&(t.credentials=e.credentials),e.maxAge!==void 0&&(t.maxAge=e.maxAge),e.preflightStatus!==void 0&&(t.preflight={statusCode:e.preflightStatus}),t}function normalizeEveCorsOrigin(e){return e===`*`||e===`null`?e:typeof e==`string`?[e]:e}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({eve:e.sessionId===void 0?{caller:e.auth,request:e.request}:{caller:e.auth,request:e.request,sessionId:e.sessionId}},e.message)}catch(n){let r=logError(log,`onMessage handler failed`,n,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:r,ok:!1},{status:500})}return r==null?{dispatch:!1}:r.context===void 0?{auth:r.auth,dispatch:!0}:{auth:r.auth,context:r.context,dispatch:!0}}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}function droppedMessageResponse(){return new Response(null,{headers:{"cache-control":`no-store`},status:204})}function parseCreateBody(e){let t=parseMessageField(e.message);if(t instanceof Response)return t;let n=parseClientContextField(e.clientContext);if(n instanceof Response)return n;let r=parseCallbackField(e.callback);if(r instanceof Response)return r;let i=parseModeField(e.mode);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,context:n,outputSchema:a}}function parseContinueBody(e){if(e.forwardedPrincipal!==void 0)return Response.json({error:`A forwarded principal is only accepted on session creation.`,ok:!1},{status:400});let t=typeof e.continuationToken==`string`&&e.continuationToken.length>0?e.continuationToken:void 0;if(t===void 0)return Response.json({error:`Missing or empty 'continuationToken' field.`,ok:!1},{status:400});let n=parseMessageField(e.message);if(n instanceof Response)return n;let r=parseInputResponses(e.inputResponses);if(r instanceof Response)return r;let i=parseClientContextField(e.clientContext);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:n===void 0&&r===void 0?Response.json({error:`Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.`,ok:!1},{status:400}):{message:n,continuationToken:t,inputResponses:r,context:i,outputSchema:a}}async function parseResetSessionBody(e){let t;try{t=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof t!=`object`||!t||Array.isArray(t))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let n=t.continuationToken;return typeof n!=`string`||n.length===0?Response.json({error:`Expected 'continuationToken' to be a non-empty string.`,ok:!1},{status:400}):{continuationToken:n}}async function parseCancelTurnBody(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof n!=`object`||!n||Array.isArray(n))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let r=n.turnId;return r===void 0?{}:typeof r!=`string`||r.length===0?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):{turnId:r}}function createSendPayload(e,t=e.context){if(t===void 0&&e.outputSchema===void 0)return e.message;let n={message:e.message};return t!==void 0&&(n.context=t),e.outputSchema!==void 0&&(n.outputSchema=e.outputSchema),n}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseModeField(e){if(e!==void 0)return e===`conversation`||e===`task`?e:Response.json({error:`Expected 'mode' to be either 'conversation' or 'task'.`,ok:!1},{status:400})}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function mergeContext(e,t){return e===void 0?t:t===void 0?e:[...e,...t]}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?[toClientContextMessage(e)]:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e.map(e=>toClientContextMessage(e)):Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{let t=parseJsonObject(e);return[toClientContextMessage(JSON.stringify(t))]}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function toClientContextMessage(e){return`Client context:
1
+ import{createLogger,logError}from"#internal/logging.js";import{hasInternalRefScheme}from"#internal/attachments/url-refs.js";import{EVE_CANCEL_TURN_ROUTE_PATTERN,EVE_CLEAR_SESSION_ROUTE_PATH,EVE_COMPACT_SESSION_ROUTE_PATH,EVE_INFO_ROUTE_PATH,EVE_RESET_SESSION_ROUTE_PATH}from"#protocol/routes.js";import{EVE_MESSAGE_STREAM_CONTENT_TYPE,EVE_MESSAGE_STREAM_FORMAT,EVE_MESSAGE_STREAM_VERSION,EVE_SESSION_ID_HEADER,EVE_STREAM_FORMAT_HEADER,EVE_STREAM_TAIL_INDEX_HEADER,EVE_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{readAgentInfoRouteResponse,readRouteAgent}from"#internal/nitro/routes/channel-route-context.js";import{resolveForwardedPrincipal}from"#channel/forwarded-principal.js";import{routeAuth}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`eve.channel`);function defaultEveAuth(e){return e.eve.caller}function eveChannel(e){let n=mergeUploadPolicy(e.uploadPolicy);return defineChannel({cors:normalizeEveCors(e.cors),routes:[GET(EVE_INFO_ROUTE_PATH,async(t,n)=>{let r=await routeAuth(t,e.auth);if(r instanceof Response)return r;let i=readAgentInfoRouteResponse(n);return i===void 0?Response.json({error:`Agent info route requires internal channel dispatch context.`,ok:!1},{status:500}):await i()}),POST(`/eve/v1/session`,async(t,{send:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=i,o;try{o=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof o!=`object`||!o)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let s=await resolveForwardedPrincipal({trustedForwarders:e.trustedForwarders,forwarder:a,payload:o});if(s instanceof Response)return s;let c=parseCreateBody(o);if(c instanceof Response)return c;let l=checkUploadPolicy(c,n);if(l!==null)return l;let u=await resolveOnMessage({auth:s.auth,config:e,message:c.message,request:t});if(u instanceof Response)return u;if(!u.dispatch)return droppedMessageResponse();let d=`eve:${crypto.randomUUID()}`,f=mergeContext(c.context,u.context),p={auth:u.auth,callback:c.callback,continuationToken:d,mode:c.mode};s.accepted&&(p.initiatorAuth=s.initiatorAuth);let m=await r(createSendPayload(c,f),p);return Response.json({continuationToken:m.continuationToken,ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:202})}),POST(EVE_RESET_SESSION_ROUTE_PATH,async(n,{reset:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=await parseContinuationTokenBody(n);if(a instanceof Response)return a;let o;try{o=await r({continuationToken:a.continuationToken,reason:`Client requested session reset`})}catch(e){let n=logError(log,`session-reset request failed`,e);return Response.json({error:`Failed to reset the session.`,errorId:n,ok:!1},{status:500})}let s=o.status===`reset`?{ok:!0,previousSessionId:o.previousSessionId,status:`reset`}:{ok:!0,status:`no_active_session`};return Response.json(s,{headers:{"cache-control":`no-store`}})}),POST(EVE_CLEAR_SESSION_ROUTE_PATH,async(n,{clear:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=await parseContinuationTokenBody(n);if(a instanceof Response)return a;let o;try{o=await r({continuationToken:a.continuationToken})}catch(e){let n=logError(log,`session-clear request failed`,e);return Response.json({error:`Failed to clear the session context.`,errorId:n,ok:!1},{status:500})}let s=o.status===`accepted`?{ok:!0,sessionId:o.sessionId,status:`accepted`}:{ok:!0,status:`no_active_session`};return Response.json(s,{headers:{"cache-control":`no-store`},status:o.status===`accepted`?202:200})}),POST(EVE_COMPACT_SESSION_ROUTE_PATH,async(n,{compact:r})=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=await parseContinuationTokenBody(n);if(a instanceof Response)return a;let o;try{o=await r({continuationToken:a.continuationToken})}catch(e){let n=logError(log,`session-compaction request failed`,e);return Response.json({error:`Failed to compact the session.`,errorId:n,ok:!1},{status:500})}let s=o.status===`accepted`?{ok:!0,sessionId:o.sessionId,status:`accepted`}:{ok:!0,status:`no_active_session`};return Response.json(s,{headers:{"cache-control":`no-store`},status:o.status===`accepted`?202:200})}),POST(`/eve/v1/session/:sessionId`,async(t,{send:r,getSession:i,params:a})=>{let o=await routeAuth(t,e.auth);if(o instanceof Response)return o;let s=o,c=a.sessionId;if(!c)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{i(c)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let l;try{l=await t.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof l!=`object`||!l)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let u=parseContinueBody(l);if(u instanceof Response)return u;let d=checkUploadPolicy(u,n);if(d!==null)return d;let f=u.context,p=s;if(u.message!==void 0){let n=await resolveOnMessage({auth:s,config:e,message:u.message,request:t,sessionId:c});if(n instanceof Response)return n;if(!n.dispatch)return droppedMessageResponse();f=mergeContext(u.context,n.context),p=n.auth}let m=await r({inputResponses:u.inputResponses,message:u.message,context:f,outputSchema:u.outputSchema},{auth:p,continuationToken:u.continuationToken});return Response.json({ok:!0,sessionId:m.id},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:m.id},status:200})}),POST(EVE_CANCEL_TURN_ROUTE_PATTERN,async(n,r)=>{let i=await routeAuth(n,e.auth);if(i instanceof Response)return i;let a=r.params.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=await parseCancelTurnBody(n);if(o instanceof Response)return o;let s;try{let e=readRouteAgent(r);if(e===void 0)throw Error(`Missing route agent.`);s=await e.cancelTurn({sessionId:a,turnId:o.turnId})}catch(e){let n=logError(log,`cancel-turn request failed`,e,{sessionId:a});return Response.json({error:`Failed to cancel the turn.`,errorId:n,ok:!1},{status:500})}return Response.json({ok:!0,sessionId:a,status:s.status},{headers:{"cache-control":`no-store`,[EVE_SESSION_ID_HEADER]:a},status:202})}),GET(`/eve/v1/session/:sessionId/stream`,async(t,{getSession:n,params:r})=>{let i=await routeAuth(t,e.auth);if(i instanceof Response)return i;let a=r.sessionId;if(!a)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let o=parseStartIndex(t);if(o instanceof Response)return o;let s=parseIncludeTailIndex(t);try{let e=n(a),t=s?await e.getStreamTailIndex():void 0,r=serializeAsNdjson(await e.getEventStream({startIndex:o}));return new Response(r,{headers:{"cache-control":`no-store, no-transform`,"content-type":EVE_MESSAGE_STREAM_CONTENT_TYPE,"x-accel-buffering":`no`,[EVE_SESSION_ID_HEADER]:a,[EVE_STREAM_FORMAT_HEADER]:EVE_MESSAGE_STREAM_FORMAT,...t===void 0?{}:{[EVE_STREAM_TAIL_INDEX_HEADER]:String(t)},[EVE_STREAM_VERSION_HEADER]:EVE_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})],events:e.events})}function normalizeEveCors(e){if(e===void 0||e===!1)return!1;if(e===!0)return!0;let t={};return e.origin!==void 0&&(t.origin=normalizeEveCorsOrigin(e.origin)),e.methods!==void 0&&(t.methods=e.methods),e.allowedHeaders!==void 0&&(t.allowHeaders=e.allowedHeaders),e.exposedHeaders!==void 0&&(t.exposeHeaders=e.exposedHeaders),e.credentials!==void 0&&(t.credentials=e.credentials),e.maxAge!==void 0&&(t.maxAge=e.maxAge),e.preflightStatus!==void 0&&(t.preflight={statusCode:e.preflightStatus}),t}function normalizeEveCorsOrigin(e){return e===`*`||e===`null`?e:typeof e==`string`?[e]:e}async function resolveOnMessage(e){let n=e.config.onMessage??defaultOnMessage,r;try{r=await n({eve:e.sessionId===void 0?{caller:e.auth,request:e.request}:{caller:e.auth,request:e.request,sessionId:e.sessionId}},e.message)}catch(n){let r=logError(log,`onMessage handler failed`,n,{sessionId:e.sessionId});return Response.json({error:`onMessage handler failed.`,errorId:r,ok:!1},{status:500})}return r==null?{dispatch:!1}:r.context===void 0?{auth:r.auth,dispatch:!0}:{auth:r.auth,context:r.context,dispatch:!0}}function defaultOnMessage(e){return{auth:defaultEveAuth(e)}}function droppedMessageResponse(){return new Response(null,{headers:{"cache-control":`no-store`},status:204})}function parseCreateBody(e){let t=parseMessageField(e.message);if(t instanceof Response)return t;let n=parseClientContextField(e.clientContext);if(n instanceof Response)return n;let r=parseCallbackField(e.callback);if(r instanceof Response)return r;let i=parseModeField(e.mode);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,context:n,outputSchema:a}}function parseContinueBody(e){if(e.forwardedPrincipal!==void 0)return Response.json({error:`A forwarded principal is only accepted on session creation.`,ok:!1},{status:400});let t=typeof e.continuationToken==`string`&&e.continuationToken.length>0?e.continuationToken:void 0;if(t===void 0)return Response.json({error:`Missing or empty 'continuationToken' field.`,ok:!1},{status:400});let n=parseMessageField(e.message);if(n instanceof Response)return n;let r=parseInputResponses(e.inputResponses);if(r instanceof Response)return r;let i=parseClientContextField(e.clientContext);if(i instanceof Response)return i;let a=parseOutputSchemaField(e.outputSchema);return a instanceof Response?a:n===void 0&&r===void 0?Response.json({error:`Expected a non-empty 'message', a non-empty 'inputResponses' array, or both.`,ok:!1},{status:400}):{message:n,continuationToken:t,inputResponses:r,context:i,outputSchema:a}}async function parseContinuationTokenBody(e){let t;try{t=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof t!=`object`||!t||Array.isArray(t))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let n=t.continuationToken;return typeof n!=`string`||n.length===0?Response.json({error:`Expected 'continuationToken' to be a non-empty string.`,ok:!1},{status:400}):{continuationToken:n}}async function parseCancelTurnBody(e){let t;try{t=await e.text()}catch{return Response.json({error:`Unreadable request body.`,ok:!1},{status:400})}if(t.trim().length===0)return{};let n;try{n=JSON.parse(t)}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof n!=`object`||!n||Array.isArray(n))return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let r=n.turnId;return r===void 0?{}:typeof r!=`string`||r.length===0?Response.json({error:`Expected 'turnId' to be a non-empty string.`,ok:!1},{status:400}):{turnId:r}}function createSendPayload(e,t=e.context){if(t===void 0&&e.outputSchema===void 0)return e.message;let n={message:e.message};return t!==void 0&&(n.context=t),e.outputSchema!==void 0&&(n.outputSchema=e.outputSchema),n}function parseOutputSchemaField(e){if(e!==void 0)try{return parseJsonObject(e)}catch{return Response.json({error:`Expected 'outputSchema' to be a JSON-serializable object.`,ok:!1},{status:400})}}function parseCallbackField(e){if(e===void 0)return;let t=parseSessionCallback(e);return t.ok?t.callback:Response.json({error:t.message,ok:!1},{status:400})}function parseModeField(e){if(e!==void 0)return e===`conversation`||e===`task`?e:Response.json({error:`Expected 'mode' to be either 'conversation' or 'task'.`,ok:!1},{status:400})}function parseMessageField(e){if(e===void 0)return;if(typeof e==`string`)return e.length>0?e:void 0;if(!Array.isArray(e))return Response.json({error:`Expected 'message' to be a string or an array of text/file parts.`,ok:!1},{status:400});if(e.length===0)return;let t=[];for(let n of e){let e=parseMessagePart(n);if(e instanceof Response)return e;t.push(e)}return t}function parseMessagePart(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected each message part to be an object.`,ok:!1},{status:400});let t=e;if(t.type===`text`)return typeof t.text!=`string`||t.text.length===0?Response.json({error:`Text parts require a non-empty 'text' string.`,ok:!1},{status:400}):{type:`text`,text:t.text};if(t.type===`file`){if(typeof t.mediaType!=`string`||t.mediaType.length===0)return Response.json({error:`File parts require a non-empty 'mediaType' string.`,ok:!1},{status:400});if(typeof t.data!=`string`)return Response.json({error:`File parts require a 'data' string (base64, data URL, or URL).`,ok:!1},{status:400});if(hasInternalRefScheme(t.data))return Response.json({error:`File part 'data' must not use a framework-internal ref scheme.`,ok:!1},{status:400});let e={type:`file`,mediaType:t.mediaType,data:t.data};return typeof t.filename==`string`&&t.filename.length>0&&(e.filename=t.filename),e}return Response.json({error:`Unsupported message part type "${String(t.type)}". Use 'text' or 'file'.`,ok:!1},{status:400})}function checkUploadPolicy(e,t){if(!e.message)return null;let n=collectUploadPolicyViolations(e.message,t);if(n.length===0)return null;let[r]=n;if(!r)return null;let i=r.kind===`too-large`?413:415;return Response.json({error:formatUploadPolicyViolation(r),ok:!1,violations:n.map(e=>e.kind===`too-large`?{byteLength:e.byteLength,filename:e.filename,kind:e.kind,limit:e.limit,mediaType:e.mediaType}:{allowedMediaTypes:e.allowedMediaTypes,filename:e.filename,kind:e.kind,mediaType:e.mediaType})},{status:i})}function parseInputResponses(e){if(e===void 0)return;if(!Array.isArray(e)||e.length===0)return Response.json({error:`Expected 'inputResponses' to be a non-empty array.`,ok:!1},{status:400});let t=e.filter(isInputResponse);return t.length===e.length?t:Response.json({error:`Expected every 'inputResponses' entry to match the HITL response schema.`,ok:!1},{status:400})}function mergeContext(e,t){return e===void 0?t:t===void 0?e:[...e,...t]}function parseClientContextField(e){if(e!==void 0){if(typeof e==`string`)return e.length>0?[toClientContextMessage(e)]:void 0;if(Array.isArray(e))return e.length===0?void 0:e.every(e=>typeof e==`string`&&e.length>0)?e.map(e=>toClientContextMessage(e)):Response.json({error:`Expected 'clientContext' array entries to be non-empty strings.`,ok:!1},{status:400});if(typeof e!=`object`||!e)return Response.json({error:`Expected 'clientContext' to be a string, string array, or JSON object.`,ok:!1},{status:400});try{let t=parseJsonObject(e);return[toClientContextMessage(JSON.stringify(t))]}catch{return Response.json({error:`Expected 'clientContext' to be a JSON-serializable object.`,ok:!1},{status:400})}}}function toClientContextMessage(e){return`Client context:
2
2
  ${e}`}function parseIncludeTailIndex(e){let t=new URL(e.url).searchParams.get(`includeTailIndex`);return t===`1`||t===`true`}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number(t);return!/^-?\d+$/.test(t)||!Number.isSafeInteger(n)?Response.json({error:`Expected startIndex to be an integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({start(e){e.enqueue(t.encode(`
3
3
  `))},transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{defaultEveAuth,eveChannel};
@@ -1,2 +1,2 @@
1
- import{isObject}from"#shared/guards.js";import{createSign}from"node:crypto";const installationTokenCache=new Map;async function resolveGitHubAppId(e){let t=e??process.env.GITHUB_APP_ID;if(t===void 0||t===``)throw Error(`githubChannel: GITHUB_APP_ID is required.`);let n=typeof t==`function`?await t():t;return String(n)}async function resolveGitHubPrivateKey(e){let t=e??process.env.GITHUB_APP_PRIVATE_KEY;if(!t)throw Error(`githubChannel: GITHUB_APP_PRIVATE_KEY is required.`);return normalizeGitHubPrivateKey(typeof t==`function`?await t():t)}async function resolveGitHubWebhookSecret(e){let t=e??process.env.GITHUB_WEBHOOK_SECRET;if(!t)throw Error(`githubChannel: GITHUB_WEBHOOK_SECRET is required.`);return typeof t==`function`?await t():t}function normalizeGitHubPrivateKey(e){return e.replace(/\\n/gu,`
2
- `)}async function createGitHubAppJwt(e){let n=await resolveGitHubAppId(e.appId),r=await resolveGitHubPrivateKey(e.privateKey),i=Math.floor((e.now?.getTime()??Date.now())/1e3),a={alg:`RS256`,typ:`JWT`},o={exp:i+600,iat:i-60,iss:n},s=`${base64UrlJson(a)}.${base64UrlJson(o)}`;return`${s}.${createSign(`RSA-SHA256`).update(s).sign(r,`base64url`)}`}async function resolveGitHubInstallationToken(e){let t=e.credentials?.installationToken;if(t!==void 0)return typeof t==`function`?await t():t;if(e.installationId===void 0)throw Error(`githubChannel: installationId is required for authenticated GitHub API calls.`);return createGitHubInstallationToken({api:e.api,appId:e.credentials?.appId,installationId:e.installationId,privateKey:e.credentials?.privateKey})}async function createGitHubInstallationToken(t){let r=await resolveGitHubAppId(t.appId),i=t.api?.apiBaseUrl??`https://api.github.com`,a=`${i}:${r}:${t.installationId}`,o=installationTokenCache.get(a);if(o!==void 0&&Date.now()<o.expiresAtMs-6e4)return o.token;let s=await createGitHubAppJwt({appId:r,privateKey:t.privateKey}),c=await(t.api?.fetch??fetch)(`${i}/app/installations/${t.installationId}/access_tokens`,{headers:{accept:`application/vnd.github+json`,authorization:`Bearer ${s}`,"x-github-api-version":`2022-11-28`},method:`POST`}),l=await parseJsonBody(c);if(!c.ok)throw Error(`githubChannel: create installation token failed with HTTP ${c.status}.`);if(!isObject(l)||typeof l.token!=`string`)throw Error(`githubChannel: installation token response did not include a token.`);let u=parseExpiryMs(l.expires_at);return installationTokenCache.set(a,{expiresAtMs:u,token:l.token}),l.token}function clearGitHubInstallationTokenCache(){installationTokenCache.clear()}function seedGitHubInstallationTokenForTests(e){let t=e.apiBaseUrl??`https://api.github.com`,r=e.appId??`test-app`;installationTokenCache.set(`${t}:${r}:${e.installationId}`,{expiresAtMs:Date.now()+3600*1e3,token:e.token})}function base64UrlJson(e){return Buffer.from(JSON.stringify(e)).toString(`base64url`)}async function parseJsonBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}function parseExpiryMs(e){if(typeof e==`string`){let t=Date.parse(e);if(Number.isFinite(t))return t}return Date.now()+3600*1e3}export{clearGitHubInstallationTokenCache,createGitHubAppJwt,createGitHubInstallationToken,normalizeGitHubPrivateKey,resolveGitHubAppId,resolveGitHubInstallationToken,resolveGitHubPrivateKey,resolveGitHubWebhookSecret,seedGitHubInstallationTokenForTests};
1
+ import{createSign}from"node:crypto";import{isObject}from"#shared/guards.js";const installationTokenCache=new Map;async function resolveGitHubAppId(e){let t=e??process.env.GITHUB_APP_ID;if(t===void 0||t===``)throw Error(`githubChannel: GITHUB_APP_ID is required.`);let n=typeof t==`function`?await t():t;return String(n)}async function resolveGitHubPrivateKey(e){let t=e??process.env.GITHUB_APP_PRIVATE_KEY;if(!t)throw Error(`githubChannel: GITHUB_APP_PRIVATE_KEY is required.`);return normalizeGitHubPrivateKey(typeof t==`function`?await t():t)}async function resolveGitHubWebhookSecret(e){let t=e??process.env.GITHUB_WEBHOOK_SECRET;if(!t)throw Error(`githubChannel: GITHUB_WEBHOOK_SECRET is required.`);return typeof t==`function`?await t():t}function normalizeGitHubPrivateKey(e){return e.replace(/\\n/gu,`
2
+ `)}async function createGitHubAppJwt(t){let n=await resolveGitHubAppId(t.appId),r=await resolveGitHubPrivateKey(t.privateKey),i=Math.floor((t.now?.getTime()??Date.now())/1e3),a={alg:`RS256`,typ:`JWT`},o={exp:i+600,iat:i-60,iss:n},s=`${base64UrlJson(a)}.${base64UrlJson(o)}`;return`${s}.${createSign(`RSA-SHA256`).update(s).sign(r,`base64url`)}`}async function resolveGitHubInstallationToken(e){let t=e.credentials?.installationToken;if(t!==void 0)return typeof t==`function`?await t():t;if(e.installationId===void 0)throw Error(`githubChannel: installationId is required for authenticated GitHub API calls.`);return createGitHubInstallationToken({api:e.api,appId:e.credentials?.appId,installationId:e.installationId,privateKey:e.credentials?.privateKey})}async function createGitHubInstallationToken(e){let r=await resolveGitHubAppId(e.appId),i=e.api?.apiBaseUrl??`https://api.github.com`,a=`${i}:${r}:${e.installationId}`,o=installationTokenCache.get(a);if(o!==void 0&&Date.now()<o.expiresAtMs-6e4)return o.token;let s=await createGitHubAppJwt({appId:r,privateKey:e.privateKey}),c=await(e.api?.fetch??fetch)(`${i}/app/installations/${e.installationId}/access_tokens`,{headers:{accept:`application/vnd.github+json`,authorization:`Bearer ${s}`,"x-github-api-version":`2022-11-28`},method:`POST`}),l=await parseJsonBody(c);if(!c.ok)throw Error(`githubChannel: create installation token failed with HTTP ${c.status}.`);if(!isObject(l)||typeof l.token!=`string`)throw Error(`githubChannel: installation token response did not include a token.`);let u=parseExpiryMs(l.expires_at);return installationTokenCache.set(a,{expiresAtMs:u,token:l.token}),l.token}function clearGitHubInstallationTokenCache(){installationTokenCache.clear()}function seedGitHubInstallationTokenForTests(e){let t=e.apiBaseUrl??`https://api.github.com`,r=e.appId??`test-app`;installationTokenCache.set(`${t}:${r}:${e.installationId}`,{expiresAtMs:Date.now()+3600*1e3,token:e.token})}function base64UrlJson(e){return Buffer.from(JSON.stringify(e)).toString(`base64url`)}async function parseJsonBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}function parseExpiryMs(e){if(typeof e==`string`){let t=Date.parse(e);if(Number.isFinite(t))return t}return Date.now()+3600*1e3}export{clearGitHubInstallationTokenCache,createGitHubAppJwt,createGitHubInstallationToken,normalizeGitHubPrivateKey,resolveGitHubAppId,resolveGitHubInstallationToken,resolveGitHubPrivateKey,resolveGitHubWebhookSecret,seedGitHubInstallationTokenForTests};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{getGitHubRepository}from"#public/channels/github/api.js";import{parseGitHubWebhookEvent}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromReceiveTarget}from"#public/channels/github/state.js";import{GITHUB_CHANNEL_DEFAULT_ROUTE}from"#public/channels/github/constants.js";import{createDefaultEvents,defaultOnComment}from"#public/channels/github/defaults.js";import{dispatchCheckRun,dispatchCheckSuite,dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment,dispatchWorkflowRun}from"#public/channels/github/dispatch.js";import{verifyGitHubRequest}from"#public/channels/github/verify.js";const log=createLogger(`github.channel`);function githubChannel(e={}){let s=e.botName??process.env.GITHUB_APP_SLUG,u={botName:s},d={...createDefaultEvents({api:e.api,credentials:e.credentials,progress:e.progress}),...e.events};return defineChannel({kindHint:`github`,state:initialGitHubState(),context(t,n){return rebuildGitHubContext(t,n,e)},routes:[POST(e.route??GITHUB_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let a=await verifyInbound(t,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o=missingGitHubWebhookHeaders(t.headers),c;try{c=parseGitHubWebhookEvent({body:a,contentType:t.headers.get(`content-type`)??void 0,headers:t.headers})}catch(e){return log.warn(`inbound GitHub body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return c===null?(o.length>0&&log.warn(`GitHub webhook ignored because standard headers were missing`,{missingHeaders:o}),jsonOk({ignored:!0,ok:!0})):(o.length>0&&log.warn(`GitHub webhook missing standard headers; inferred metadata from payload`,{deliveryId:c.delivery.id,event:c.delivery.event,missingHeaders:o,repository:c.repository.fullName}),c.kind===`ping`?jsonOk({ok:!0}):c.kind===`issue_comment`&&c.action===`created`?(r(dispatchIssueComment({botName:s,config:e,event:c,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):c.kind===`pull_request_review_comment`&&c.action===`created`?(r(dispatchPullRequestReviewComment({botName:s,config:e,event:c,handler:e.onComment??((e,t)=>defaultOnComment(e,t,u)),send:n})),jsonOk({ok:!0})):c.kind===`issues`&&e.onIssue!==void 0?(r(dispatchIssue({config:e,event:c,handler:e.onIssue,send:n})),jsonOk({ok:!0})):c.kind===`pull_request`&&e.onPullRequest!==void 0?(r(dispatchPullRequest({config:e,event:c,handler:e.onPullRequest,send:n})),jsonOk({ok:!0})):c.kind===`check_suite`&&e.onCheckSuite!==void 0?(r(dispatchCheckSuite({config:e,event:c,handler:e.onCheckSuite,send:n})),jsonOk({ok:!0})):c.kind===`check_run`&&e.onCheckRun!==void 0?(r(dispatchCheckRun({config:e,event:c,handler:e.onCheckRun,send:n})),jsonOk({ok:!0})):c.kind===`workflow_run`&&e.onWorkflowRun!==void 0?(r(dispatchWorkflowRun({config:e,event:c,handler:e.onWorkflowRun,send:n})),jsonOk({ok:!0})):jsonOk({ignored:!0,ok:!0}))})],async receive(t,{send:n}){let i=t.target,s=readNonEmptyString(i.owner),c=readNonEmptyString(i.repo);if(s===void 0||c===void 0)throw Error(`githubChannel().receive requires target.owner and target.repo.`);if([i.issueNumber!==void 0,i.pullRequestNumber!==void 0].filter(Boolean).length!==1)throw Error(`githubChannel().receive requires exactly one of issueNumber or pullRequestNumber.`);let l=stateFromReceiveTarget({target:i,owner:s,repo:c,repositoryId:i.repositoryId??(await getGitHubRepository({api:e.api,credentials:e.credentials,installationId:i.installationId,owner:s,repo:c})).id});if(i.initialMessage!==void 0){let{thread:t}=buildGitHubBinding({config:e,state:l});await t.post(i.initialMessage)}return n(t.message,{auth:t.auth,continuationToken:continuationTokenFromState(l),state:l})},events:d})}function rebuildGitHubContext(e,t,n){let r=buildGitHubBinding({config:n,state:e});return{conversation:conversationFromState(e),github:r.github,repository:r.github.repository,state:e,thread:r.thread}}async function verifyInbound(e,t){try{return await verifyGitHubRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`github inbound verification failed`,{error:e}),null}}function readNonEmptyString(e){return typeof e==`string`&&e.length>0?e:void 0}function missingGitHubWebhookHeaders(e){return[`x-github-event`,`x-github-delivery`].filter(t=>{let n=e.get(t);return n===null||n.trim().length===0})}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{githubChannel};
1
+ import{createLogger}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{getGitHubRepository}from"#public/channels/github/api.js";import{parseGitHubWebhookEvent}from"#public/channels/github/inbound.js";import{buildGitHubBinding}from"#public/channels/github/binding.js";import{continuationTokenFromState,conversationFromState,initialGitHubState,stateFromReceiveTarget}from"#public/channels/github/state.js";import{GITHUB_CHANNEL_DEFAULT_ROUTE}from"#public/channels/github/constants.js";import{createDefaultEvents,defaultOnComment}from"#public/channels/github/defaults.js";import{dispatchCheckRun,dispatchCheckSuite,dispatchIssue,dispatchIssueComment,dispatchPullRequest,dispatchPullRequestReviewComment,dispatchWorkflowRun}from"#public/channels/github/dispatch.js";import{verifyGitHubRequest}from"#public/channels/github/verify.js";const log=createLogger(`github.channel`);function githubChannel(e={}){let c=e.botName??process.env.GITHUB_APP_SLUG,d={botName:c},f={...createDefaultEvents({api:e.api,credentials:e.credentials,progress:e.progress}),...e.events};return defineChannel({kindHint:`github`,state:initialGitHubState(),context(t,n){return rebuildGitHubContext(t,n,e)},routes:[POST(e.route??GITHUB_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let i=await verifyInbound(t,e.credentials);if(i===null)return new Response(`unauthorized`,{status:401});let o=missingGitHubWebhookHeaders(t.headers),s;try{s=parseGitHubWebhookEvent({body:i,contentType:t.headers.get(`content-type`)??void 0,headers:t.headers})}catch(e){return log.warn(`inbound GitHub body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return s===null?(o.length>0&&log.warn(`GitHub webhook ignored because standard headers were missing`,{missingHeaders:o}),jsonOk({ignored:!0,ok:!0})):(o.length>0&&log.warn(`GitHub webhook missing standard headers; inferred metadata from payload`,{deliveryId:s.delivery.id,event:s.delivery.event,missingHeaders:o,repository:s.repository.fullName}),s.kind===`ping`?jsonOk({ok:!0}):s.kind===`issue_comment`&&s.action===`created`?(r(dispatchIssueComment({botName:c,config:e,event:s,handler:e.onComment??((e,t)=>defaultOnComment(e,t,d)),send:n})),jsonOk({ok:!0})):s.kind===`pull_request_review_comment`&&s.action===`created`?(r(dispatchPullRequestReviewComment({botName:c,config:e,event:s,handler:e.onComment??((e,t)=>defaultOnComment(e,t,d)),send:n})),jsonOk({ok:!0})):s.kind===`issues`&&e.onIssue!==void 0?(r(dispatchIssue({config:e,event:s,handler:e.onIssue,send:n})),jsonOk({ok:!0})):s.kind===`pull_request`&&e.onPullRequest!==void 0?(r(dispatchPullRequest({config:e,event:s,handler:e.onPullRequest,send:n})),jsonOk({ok:!0})):s.kind===`check_suite`&&e.onCheckSuite!==void 0?(r(dispatchCheckSuite({config:e,event:s,handler:e.onCheckSuite,send:n})),jsonOk({ok:!0})):s.kind===`check_run`&&e.onCheckRun!==void 0?(r(dispatchCheckRun({config:e,event:s,handler:e.onCheckRun,send:n})),jsonOk({ok:!0})):s.kind===`workflow_run`&&e.onWorkflowRun!==void 0?(r(dispatchWorkflowRun({config:e,event:s,handler:e.onWorkflowRun,send:n})),jsonOk({ok:!0})):jsonOk({ignored:!0,ok:!0}))})],async receive(n,{send:r}){let a=n.target,c=readNonEmptyString(a.owner),l=readNonEmptyString(a.repo);if(c===void 0||l===void 0)throw Error(`githubChannel().receive requires target.owner and target.repo.`);if([a.issueNumber!==void 0,a.pullRequestNumber!==void 0].filter(Boolean).length!==1)throw Error(`githubChannel().receive requires exactly one of issueNumber or pullRequestNumber.`);let u=stateFromReceiveTarget({target:a,owner:c,repo:l,repositoryId:a.repositoryId??(await getGitHubRepository({api:e.api,credentials:e.credentials,installationId:a.installationId,owner:c,repo:l})).id});if(a.initialMessage!==void 0){let{thread:t}=buildGitHubBinding({config:e,state:u});await t.post(a.initialMessage)}return r(n.message,{auth:n.auth,continuationToken:continuationTokenFromState(u),state:u})},events:f})}function rebuildGitHubContext(e,t,n){let r=buildGitHubBinding({config:n,state:e});return{conversation:conversationFromState(e),github:r.github,repository:r.github.repository,state:e,thread:r.thread}}async function verifyInbound(e,t){try{return await verifyGitHubRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`github inbound verification failed`,{error:e}),null}}function missingGitHubWebhookHeaders(e){return[`x-github-event`,`x-github-delivery`].filter(t=>{let n=e.get(t);return n===null||n.trim().length===0})}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{githubChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{createHmac,timingSafeEqual}from"node:crypto";import{resolveGitHubWebhookSecret}from"#public/channels/github/auth.js";const log=createLogger(`github.verify`);async function verifyGitHubRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`githubChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let i=await resolveGitHubWebhookSecret(t.webhookSecret),a=e.headers.get(`x-hub-signature-256`)??``;if(!a)throw Error(`githubChannel: inbound request missing X-Hub-Signature-256.`);if(!constantTimeCompare(signGitHubWebhookBody(n,i),a))throw Error(`githubChannel: inbound request signature mismatch.`);return n}function signGitHubWebhookBody(e,n){return`sha256=${createHmac(`sha256`,n).update(e).digest(`hex`)}`}function constantTimeCompare(e,t){if(e.length!==t.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(t))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{signGitHubWebhookBody,verifyGitHubRequest};
1
+ import{createHmac,timingSafeEqual}from"node:crypto";import{createLogger}from"#internal/logging.js";import{resolveGitHubWebhookSecret}from"#public/channels/github/auth.js";const log=createLogger(`github.verify`);async function verifyGitHubRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`githubChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let i=await resolveGitHubWebhookSecret(t.webhookSecret),a=e.headers.get(`x-hub-signature-256`)??``;if(!a)throw Error(`githubChannel: inbound request missing X-Hub-Signature-256.`);if(!constantTimeCompare(signGitHubWebhookBody(n,i),a))throw Error(`githubChannel: inbound request signature mismatch.`);return n}function signGitHubWebhookBody(t,n){return`sha256=${createHmac(`sha256`,n).update(t).digest(`hex`)}`}function constantTimeCompare(e,n){if(e.length!==n.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(n))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{signGitHubWebhookBody,verifyGitHubRequest};
@@ -1,4 +1,4 @@
1
- export { defineChannel, GET, POST, PUT, PATCH, DELETE, WS, type CancelFn, type CancelOptions, type CancelTurnResult, type Channel, type ChannelCors, type ChannelCorsOptions, type ChannelDefinition, type ChannelSessionOps, type ChannelEvents, type InferChannelMetadata, type Session, type SessionHandle, type RouteDefinition, type RouteHandlerArgs, type ResetFn, type ResetOptions, type ResetResult, type SendFn, type SendOptions, type SendPayload, type GetSessionFn, type HttpRouteDefinition, type WebSocketMessage, type WebSocketPeer, type WebSocketRouteDefinition, type WebSocketRouteHandler, type WebSocketRouteHooks, type WebSocketUpgradeRequest, type WebSocketUpgradeResult, } from "#public/definitions/channel.js";
1
+ export { defineChannel, GET, POST, PUT, PATCH, DELETE, WS, type CancelFn, type CancelOptions, type CancelTurnResult, type ClearFn, type ClearOptions, type ClearSessionResult, type CompactFn, type CompactOptions, type CompactSessionResult, type Channel, type ChannelCors, type ChannelCorsOptions, type ChannelDefinition, type ChannelSessionOps, type ChannelEvents, type InferChannelMetadata, type Session, type SessionHandle, type RouteDefinition, type RouteHandlerArgs, type ResetFn, type ResetOptions, type ResetResult, type SendFn, type SendOptions, type SendPayload, type GetSessionFn, type HttpRouteDefinition, type WebSocketMessage, type WebSocketPeer, type WebSocketRouteDefinition, type WebSocketRouteHandler, type WebSocketRouteHooks, type WebSocketUpgradeRequest, type WebSocketUpgradeResult, } from "#public/definitions/channel.js";
2
2
  export { createWebSocketUpgradeServer, type WebSocketUpgradeServerBridge, } from "#channel/websocket-upgrade-server.js";
3
3
  import type { Channel, InferChannelMetadata } from "#public/definitions/channel.js";
4
4
  /**
@@ -1,2 +1,2 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";function linearContinuationToken(e){return`agent-session:${e}`}function parseLinearWebhookEvent(e){let n=parseJsonObject(JSON.parse(e.body)),r={event:e.headers.get(`linear-event`)??void 0,id:e.headers.get(`linear-delivery`)??void 0},i=readString(n.type);if(!i)return null;if(i===`AgentSessionEvent`){let e=readAgentSession(n.agentSession);return e===null?null:{action:readString(n.action)??`created`,agentActivity:readAgentActivity(n.agentActivity),agentSession:e,appUserId:readString(n.appUserId),createdAt:readString(n.createdAt),delivery:r,guidance:readString(n.guidance),kind:`agent_session`,oauthClientId:readString(n.oauthClientId),organizationId:readString(n.organizationId),previousComments:readPreviousComments(n.previousComments),promptContext:readString(n.promptContext),raw:n}}return{action:readString(n.action),delivery:r,kind:`data`,organizationId:readString(n.organizationId),raw:n,type:i}}function messageFromLinearAgentSessionEvent(e){if(e.action===`prompted`){let t=e.agentActivity?.body;if(t!==void 0&&t.trim().length>0)return t}let t=e.promptContext?.trim();if(t!==void 0&&t.length>0)return t;let n=e.agentSession.summary?.trim();if(n!==void 0&&n.length>0)return n;let r=e.agentSession.issue;return r?.title?`${r.identifier?`${r.identifier}: `:``}${r.title}`:`Linear agent session started.`}function formatLinearContextBlock(e){let t=e.agentSession,n=t.issue;return[`<linear_context>`,`action: ${e.action}`,`agent_session_id: ${t.id}`,`agent_session_url: ${t.url??``}`,`organization_id: ${e.organizationId??t.organizationId??``}`,`issue_id: ${t.issueId??n?.id??``}`,`issue_identifier: ${n?.identifier??``}`,`issue_title: ${n?.title??``}`,`issue_url: ${n?.url??``}`,`comment_id: ${t.commentId??``}`,`source_comment_id: ${t.sourceCommentId??``}`,`response_medium: linear_agent_activity`,`</linear_context>`].join(`
2
- `)}function readAgentSession(t){if(!isObject(t)||typeof t.id!=`string`)return null;let n={id:t.id};typeof t.appUserId==`string`&&(n.appUserId=t.appUserId),(typeof t.commentId==`string`||t.commentId===null)&&(n.commentId=t.commentId),n.creator=readUser(t.creator),(typeof t.creatorId==`string`||t.creatorId===null)&&(n.creatorId=t.creatorId);let r=readIssue(t.issue);return r!==void 0&&(n.issue=r),(typeof t.issueId==`string`||t.issueId===null)&&(n.issueId=t.issueId),typeof t.organizationId==`string`&&(n.organizationId=t.organizationId),(typeof t.sourceCommentId==`string`||t.sourceCommentId===null)&&(n.sourceCommentId=t.sourceCommentId),typeof t.status==`string`&&(n.status=t.status),(typeof t.summary==`string`||t.summary===null)&&(n.summary=t.summary),(typeof t.url==`string`||t.url===null)&&(n.url=t.url),n}function readAgentActivity(n){if(!isObject(n)||typeof n.id!=`string`)return;let r=isObject(n.content)?parseJsonObject(n.content):{},i={body:readActivityBody(n.content),content:r,id:n.id};return(typeof n.signal==`string`||n.signal===null)&&(i.signal=n.signal),isObject(n.signalMetadata)&&(i.signalMetadata=parseJsonObject(n.signalMetadata)),n.signalMetadata===null&&(i.signalMetadata=null),(typeof n.sourceCommentId==`string`||n.sourceCommentId===null)&&(i.sourceCommentId=n.sourceCommentId),i.user=readUser(n.user),(typeof n.userId==`string`||n.userId===null)&&(i.userId=n.userId),i}function readActivityBody(t){if(isObject(t))return readString(t.body)}function readIssue(t){if(t===null)return null;if(!isObject(t)||typeof t.id!=`string`)return;let n={id:t.id};return typeof t.identifier==`string`&&(n.identifier=t.identifier),typeof t.title==`string`&&(n.title=t.title),typeof t.url==`string`&&(n.url=t.url),n}function readUser(t){if(!isObject(t)||typeof t.id!=`string`)return;let n={id:t.id};return typeof t.displayName==`string`&&(n.displayName=t.displayName),typeof t.name==`string`&&(n.name=t.name),typeof t.email==`string`&&(n.email=t.email),typeof t.url==`string`&&(n.url=t.url),n}function readPreviousComments(t){return Array.isArray(t)?t.map(t=>typeof t==`string`?t:isObject(t)&&typeof t.body==`string`?t.body:null).filter(e=>e!==null):[]}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent};
1
+ import{isObject,readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";function linearContinuationToken(e){return`agent-session:${e}`}function parseLinearWebhookEvent(e){let r=parseJsonObject(JSON.parse(e.body)),i={event:e.headers.get(`linear-event`)??void 0,id:e.headers.get(`linear-delivery`)??void 0},a=readNonEmptyString(r.type);if(!a)return null;if(a===`AgentSessionEvent`){let e=readAgentSession(r.agentSession);return e===null?null:{action:readNonEmptyString(r.action)??`created`,agentActivity:readAgentActivity(r.agentActivity),agentSession:e,appUserId:readNonEmptyString(r.appUserId),createdAt:readNonEmptyString(r.createdAt),delivery:i,guidance:readNonEmptyString(r.guidance),kind:`agent_session`,oauthClientId:readNonEmptyString(r.oauthClientId),organizationId:readNonEmptyString(r.organizationId),previousComments:readPreviousComments(r.previousComments),promptContext:readNonEmptyString(r.promptContext),raw:r}}return{action:readNonEmptyString(r.action),delivery:i,kind:`data`,organizationId:readNonEmptyString(r.organizationId),raw:r,type:a}}function messageFromLinearAgentSessionEvent(e){if(e.action===`prompted`){let t=e.agentActivity?.body;if(t!==void 0&&t.trim().length>0)return t}let t=e.promptContext?.trim();if(t!==void 0&&t.length>0)return t;let n=e.agentSession.summary?.trim();if(n!==void 0&&n.length>0)return n;let r=e.agentSession.issue;return r?.title?`${r.identifier?`${r.identifier}: `:``}${r.title}`:`Linear agent session started.`}function formatLinearContextBlock(e){let t=e.agentSession,n=t.issue;return[`<linear_context>`,`action: ${e.action}`,`agent_session_id: ${t.id}`,`agent_session_url: ${t.url??``}`,`organization_id: ${e.organizationId??t.organizationId??``}`,`issue_id: ${t.issueId??n?.id??``}`,`issue_identifier: ${n?.identifier??``}`,`issue_title: ${n?.title??``}`,`issue_url: ${n?.url??``}`,`comment_id: ${t.commentId??``}`,`source_comment_id: ${t.sourceCommentId??``}`,`response_medium: linear_agent_activity`,`</linear_context>`].join(`
2
+ `)}function readAgentSession(t){if(!isObject(t)||typeof t.id!=`string`)return null;let n={id:t.id};typeof t.appUserId==`string`&&(n.appUserId=t.appUserId),(typeof t.commentId==`string`||t.commentId===null)&&(n.commentId=t.commentId),n.creator=readUser(t.creator),(typeof t.creatorId==`string`||t.creatorId===null)&&(n.creatorId=t.creatorId);let r=readIssue(t.issue);return r!==void 0&&(n.issue=r),(typeof t.issueId==`string`||t.issueId===null)&&(n.issueId=t.issueId),typeof t.organizationId==`string`&&(n.organizationId=t.organizationId),(typeof t.sourceCommentId==`string`||t.sourceCommentId===null)&&(n.sourceCommentId=t.sourceCommentId),typeof t.status==`string`&&(n.status=t.status),(typeof t.summary==`string`||t.summary===null)&&(n.summary=t.summary),(typeof t.url==`string`||t.url===null)&&(n.url=t.url),n}function readAgentActivity(t){if(!isObject(t)||typeof t.id!=`string`)return;let r=isObject(t.content)?parseJsonObject(t.content):{},i={body:readActivityBody(t.content),content:r,id:t.id};return(typeof t.signal==`string`||t.signal===null)&&(i.signal=t.signal),isObject(t.signalMetadata)&&(i.signalMetadata=parseJsonObject(t.signalMetadata)),t.signalMetadata===null&&(i.signalMetadata=null),(typeof t.sourceCommentId==`string`||t.sourceCommentId===null)&&(i.sourceCommentId=t.sourceCommentId),i.user=readUser(t.user),(typeof t.userId==`string`||t.userId===null)&&(i.userId=t.userId),i}function readActivityBody(n){if(isObject(n))return readNonEmptyString(n.body)}function readIssue(t){if(t===null)return null;if(!isObject(t)||typeof t.id!=`string`)return;let n={id:t.id};return typeof t.identifier==`string`&&(n.identifier=t.identifier),typeof t.title==`string`&&(n.title=t.title),typeof t.url==`string`&&(n.url=t.url),n}function readUser(t){if(!isObject(t)||typeof t.id!=`string`)return;let n={id:t.id};return typeof t.displayName==`string`&&(n.displayName=t.displayName),typeof t.name==`string`&&(n.name=t.name),typeof t.email==`string`&&(n.email=t.email),typeof t.url==`string`&&(n.url=t.url),n}function readPreviousComments(t){return Array.isArray(t)?t.map(t=>typeof t==`string`?t:isObject(t)&&typeof t.body==`string`?t.body:null).filter(e=>e!==null):[]}export{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";import{attachLinearInboundImages}from"#public/channels/linear/inbound-images.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,a={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:n}){let r=t.target,a=await resolveReceiveSession(r,e),o=readString(r.initialActivity);return o!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:a.id,content:{body:o,type:`thought`}}}),n(t.message,{auth:t.auth,continuationToken:linearContinuationToken(a.id),state:stateFromAgentSession(a)})},events:a})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);if(r===null)return;let i=await attachLinearInboundImages({content:messageFromLinearAgentSessionEvent(t),credentials:e.config.credentials,fetch:e.config.api?.fetch});await e.send({context:[formatLinearContextBlock(t),...t.previousComments,...r.context??[]],message:i},{auth:r.auth,continuationToken:linearContinuationToken(t.agentSession.id),state:stateFromAgentSession(t.agentSession)})}async function resolveReceiveSession(e,t){if(hasString(e,`agentSessionId`))return{id:e.agentSessionId};if(hasString(e,`issueId`))return createLinearAgentSessionOnIssue({api:t.api,credentials:t.credentials,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls),issueId:e.issueId});if(hasString(e,`commentId`))return createLinearAgentSessionOnComment({api:t.api,credentials:t.credentials,commentId:e.commentId,externalLink:readString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls)});throw Error(`linearChannel().receive requires target.agentSessionId, issueId, or commentId.`)}function stateFromAgentSession(e){return{agentSessionId:e.id,agentSessionUrl:e.url??null,commentId:e.commentId??null,issueId:e.issueId??e.issue?.id??null,issueIdentifier:e.issue?.identifier??null,issueTitle:e.issue?.title??null,issueUrl:e.issue?.url??null,organizationId:`organizationId`in e?e.organizationId??null:null,pendingToolCallMessage:null,sourceCommentId:e.sourceCommentId??null}}function initialLinearState(){return{agentSessionId:null,agentSessionUrl:null,commentId:null,issueId:null,issueIdentifier:null,issueTitle:null,issueUrl:null,organizationId:null,pendingToolCallMessage:null,sourceCommentId:null}}async function verifyInbound(e,t){try{return await verifyLinearRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`linear inbound verification failed`,{error:e}),null}}function hasString(e,t){return typeof e[t]==`string`&&e[t].length>0}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}function readExternalUrls(e){if(!Array.isArray(e))return;let n=e.filter(e=>isObject(e)&&typeof e.label==`string`&&typeof e.url==`string`);return n.length>0?n:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{linearChannel};
1
+ import{createLogger}from"#internal/logging.js";import{isObject,readNonEmptyString}from"#shared/guards.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{createLinearAgentActivity,createLinearAgentSessionOnComment,createLinearAgentSessionOnIssue,listLinearAgentSessionActivities,updateLinearAgentSession}from"#public/channels/linear/api.js";import{LINEAR_CHANNEL_DEFAULT_ROUTE}from"#public/channels/linear/constants.js";import{createDefaultEvents,defaultOnAgentSession}from"#public/channels/linear/defaults.js";import{formatLinearContextBlock,linearContinuationToken,messageFromLinearAgentSessionEvent,parseLinearWebhookEvent}from"#public/channels/linear/inbound.js";import{verifyLinearRequest}from"#public/channels/linear/verify.js";import{attachLinearInboundImages}from"#public/channels/linear/inbound-images.js";const log=createLogger(`linear.channel`);function linearChannel(e={}){let t=e.onAgentSession??defaultOnAgentSession,o={...createDefaultEvents({api:e.api,credentials:e.credentials}),...e.events};return defineChannel({kindHint:`linear`,state:initialLinearState(),metadata(e){return{agentSessionId:e.agentSessionId,commentId:e.commentId??null,issueId:e.issueId??null,issueIdentifier:e.issueIdentifier??null,organizationId:e.organizationId??null}},context(t,n){return rebuildLinearContext(t,n,e)},routes:[POST(e.route??LINEAR_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);if(a===null)return new Response(`unauthorized`,{status:401});let o;try{o=parseLinearWebhookEvent({body:a,headers:n.headers})}catch(e){return log.warn(`inbound Linear body is not valid JSON`,{error:e}),jsonOk({ignored:!0,ok:!0})}return o===null?jsonOk({ignored:!0,ok:!0}):o.kind===`agent_session`?(i(dispatchAgentSession({config:e,event:o,onAgentSession:t,send:r})),jsonOk({ok:!0})):e.onDataWebhook===void 0?jsonOk({ignored:!0,ok:!0}):(i(Promise.resolve(e.onDataWebhook(o))),jsonOk({ok:!0}))})],async receive(t,{send:r}){let i=t.target,o=await resolveReceiveSession(i,e),s=readNonEmptyString(i.initialActivity);return s!==void 0&&await createLinearAgentActivity({api:e.api,credentials:e.credentials,activity:{agentSessionId:o.id,content:{body:s,type:`thought`}}}),r(t.message,{auth:t.auth,continuationToken:linearContinuationToken(o.id),state:stateFromAgentSession(o)})},events:o})}function rebuildLinearContext(e,t,n){return{linear:buildLinearHandle({agentSessionId:e.agentSessionId??``,config:n}),state:e}}function buildLinearHandle(e){return{agentSessionId:e.agentSessionId,createActivity(t,n){return createLinearAgentActivity({api:e.config.api,credentials:e.config.credentials,activity:{agentSessionId:e.agentSessionId,content:t,ephemeral:n?.ephemeral,signal:n?.signal,signalMetadata:n?.signalMetadata}})},listActivities(t){return listLinearAgentSessionActivities({api:e.config.api,credentials:e.config.credentials,agentSessionId:e.agentSessionId,last:t?.last})},updateSession(t){return updateLinearAgentSession({api:e.config.api,credentials:e.config.credentials,id:e.agentSessionId,update:t})}}}async function dispatchAgentSession(e){let{event:t}=e,n={delivery:t.delivery,linear:buildLinearHandle({agentSessionId:t.agentSession.id,config:e.config}),session:t.agentSession},r=await e.onAgentSession(n,t);if(r===null)return;let i=await attachLinearInboundImages({content:messageFromLinearAgentSessionEvent(t),credentials:e.config.credentials,fetch:e.config.api?.fetch});await e.send({context:[formatLinearContextBlock(t),...t.previousComments,...r.context??[]],message:i},{auth:r.auth,continuationToken:linearContinuationToken(t.agentSession.id),state:stateFromAgentSession(t.agentSession)})}async function resolveReceiveSession(e,t){if(hasString(e,`agentSessionId`))return{id:e.agentSessionId};if(hasString(e,`issueId`))return createLinearAgentSessionOnIssue({api:t.api,credentials:t.credentials,externalLink:readNonEmptyString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls),issueId:e.issueId});if(hasString(e,`commentId`))return createLinearAgentSessionOnComment({api:t.api,credentials:t.credentials,commentId:e.commentId,externalLink:readNonEmptyString(e.externalLink),externalUrls:readExternalUrls(e.externalUrls)});throw Error(`linearChannel().receive requires target.agentSessionId, issueId, or commentId.`)}function stateFromAgentSession(e){return{agentSessionId:e.id,agentSessionUrl:e.url??null,commentId:e.commentId??null,issueId:e.issueId??e.issue?.id??null,issueIdentifier:e.issue?.identifier??null,issueTitle:e.issue?.title??null,issueUrl:e.issue?.url??null,organizationId:`organizationId`in e?e.organizationId??null:null,pendingToolCallMessage:null,sourceCommentId:e.sourceCommentId??null}}function initialLinearState(){return{agentSessionId:null,agentSessionUrl:null,commentId:null,issueId:null,issueIdentifier:null,issueTitle:null,issueUrl:null,organizationId:null,pendingToolCallMessage:null,sourceCommentId:null}}async function verifyInbound(e,t){try{return await verifyLinearRequest(e,{webhookSecret:t?.webhookSecret,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`linear inbound verification failed`,{error:e}),null}}function hasString(e,t){return typeof e[t]==`string`&&e[t].length>0}function readExternalUrls(e){if(!Array.isArray(e))return;let n=e.filter(e=>isObject(e)&&typeof e.label==`string`&&typeof e.url==`string`);return n.length>0?n:void 0}function jsonOk(e){return new Response(JSON.stringify(e),{headers:{"content-type":`application/json; charset=utf-8`},status:200})}export{linearChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{createHmac,timingSafeEqual}from"node:crypto";import{resolveLinearWebhookSecret}from"#public/channels/linear/auth.js";const log=createLogger(`linear.verify`);async function verifyLinearRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`linearChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveLinearWebhookSecret(t.webhookSecret),a=e.headers.get(`linear-signature`)??``;if(!a)throw Error(`linearChannel: inbound request missing Linear-Signature.`);if(!constantTimeCompare(signLinearWebhookBody(n,r),a))throw Error(`linearChannel: inbound request signature mismatch.`);return verifyWebhookTimestamp(n,t.maxSkewMs??6e4),n}function signLinearWebhookBody(e,t){return createHmac(`sha256`,t).update(e).digest(`hex`)}function verifyWebhookTimestamp(e,n){let r;try{r=JSON.parse(e)}catch{throw Error(`linearChannel: inbound request body is not valid JSON.`)}let i=isObject(r)?r.webhookTimestamp:void 0;if(typeof i!=`number`||!Number.isFinite(i))throw Error(`linearChannel: inbound request missing webhookTimestamp.`);if(Math.abs(Date.now()-i)>n)throw Error(`linearChannel: inbound request timestamp outside allowed skew.`)}function constantTimeCompare(e,t){if(e.length!==t.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(t))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{signLinearWebhookBody,verifyLinearRequest};
1
+ import{createHmac,timingSafeEqual}from"node:crypto";import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{resolveLinearWebhookSecret}from"#public/channels/linear/auth.js";const log=createLogger(`linear.verify`);async function verifyLinearRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`linearChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveLinearWebhookSecret(t.webhookSecret),a=e.headers.get(`linear-signature`)??``;if(!a)throw Error(`linearChannel: inbound request missing Linear-Signature.`);if(!constantTimeCompare(signLinearWebhookBody(n,r),a))throw Error(`linearChannel: inbound request signature mismatch.`);return verifyWebhookTimestamp(n,t.maxSkewMs??6e4),n}function signLinearWebhookBody(t,n){return createHmac(`sha256`,n).update(t).digest(`hex`)}function verifyWebhookTimestamp(e,t){let n;try{n=JSON.parse(e)}catch{throw Error(`linearChannel: inbound request body is not valid JSON.`)}let i=isObject(n)?n.webhookTimestamp:void 0;if(typeof i!=`number`||!Number.isFinite(i))throw Error(`linearChannel: inbound request missing webhookTimestamp.`);if(Math.abs(Date.now()-i)>t)throw Error(`linearChannel: inbound request timestamp outside allowed skew.`)}function constantTimeCompare(e,n){if(e.length!==n.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(n))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{signLinearWebhookBody,verifyLinearRequest};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,readTeamsInputReplyToActivityId,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),a=e.onMessage??defaultOnMessage,o=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),s={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/eve/v1/teams`,async(r,{resolveActiveSession:i,send:s,waitUntil:c})=>{let l=await verifyInbound(r,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(c(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,onInputResponse:o,send:s}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:a,resolveActiveSession:i,send:s})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:o,send:s,waitUntil:c}):teamsOk()})],async receive(t,{send:n}){let r=t.target,i=readString(r.serviceUrl),a=readString(r.conversationId);if(!i||!a)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let o=readString(r.conversationType)??null,s=readString(r.replyToActivityId)??null,c=r.initialMessage;if(c!==void 0&&s!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let l={...initialTeamsState(),channelId:readString(r.channelId)??null,conversationId:a,conversationType:o,replyToActivityId:s,serviceUrl:i,teamId:readString(r.teamId)??null,tenantId:readString(r.tenantId)??null};if(c!==void 0){let t=await buildTeamsBinding({config:e,state:l}).thread.post(c);o!==`personal`&&t.id&&(s=t.id,l.replyToActivityId=t.id)}return n(t.message,{auth:t.auth,continuationToken:teamsContinuationToken({conversationId:a,replyToActivityId:s,tenantId:l.tenantId}),state:l})},events:s})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.setContinuationToken(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let o=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:o.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildOutboundActivity(t,i),credentials:r,activityId:e,conversationId:a.conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveActiveSession({continuationToken:r})!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.send({message:s,context:[formatTeamsContextBlock(c),...l]},{auth:a.auth,continuationToken:r,state:t})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,send:e.send})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.send({inputResponses:t},{auth:i.auth,continuationToken:resolveInputContinuationToken(e.activity,n),state:n})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function mergeChannelData(e,t){let r={...t};return e.tenantId&&(r.tenant={id:e.tenantId}),e.teamId&&(r.team={id:e.teamId}),e.channelId&&(r.channel={id:e.channelId}),Object.keys(r).length>0?parseJsonObject(r):void 0}function teamsOk(){return new Response(`ok`,{status:200})}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{teamsChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,readTeamsInputReplyToActivityId,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),o=e.onMessage??defaultOnMessage,s=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),c={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/eve/v1/teams`,async(n,{resolveActiveSession:i,send:a,waitUntil:c})=>{let l=await verifyInbound(n,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(c(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,onInputResponse:s,send:a}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:o,resolveActiveSession:i,send:a})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:s,send:a,waitUntil:c}):teamsOk()})],async receive(t,{send:r}){let i=t.target,a=readNonEmptyString(i.serviceUrl),o=readNonEmptyString(i.conversationId);if(!a||!o)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let s=readNonEmptyString(i.conversationType)??null,c=readNonEmptyString(i.replyToActivityId)??null,l=i.initialMessage;if(l!==void 0&&c!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readNonEmptyString(i.channelId)??null,conversationId:o,conversationType:s,replyToActivityId:c,serviceUrl:a,teamId:readNonEmptyString(i.teamId)??null,tenantId:readNonEmptyString(i.tenantId)??null};if(l!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(l);s!==`personal`&&t.id&&(c=t.id,u.replyToActivityId=t.id)}return r(t.message,{auth:t.auth,continuationToken:teamsContinuationToken({conversationId:o,replyToActivityId:c,tenantId:u.tenantId}),state:u})},events:c})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.setContinuationToken(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildOutboundActivity(t,i),credentials:r,activityId:e,conversationId:a.conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveActiveSession({continuationToken:r})!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.send({message:s,context:[formatTeamsContextBlock(c),...l]},{auth:a.auth,continuationToken:r,state:t})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,send:e.send})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.send({inputResponses:t},{auth:i.auth,continuationToken:resolveInputContinuationToken(e.activity,n),state:n})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{timingSafeEqual}from"node:crypto";const log=createLogger(`telegram.verify`);async function resolveTelegramWebhookSecretToken(e){let t=e??process.env.TELEGRAM_WEBHOOK_SECRET_TOKEN;if(!t)throw Error(`TELEGRAM_WEBHOOK_SECRET_TOKEN is required.`);return typeof t==`function`?await t():t}async function verifyTelegramRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`telegramChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveTelegramWebhookSecretToken(t.secretToken),i=e.headers.get(`x-telegram-bot-api-secret-token`)??``;if(!i)throw Error(`telegramChannel: inbound request missing Telegram secret-token header.`);if(!constantTimeCompare(r,i))throw Error(`telegramChannel: inbound request secret-token mismatch.`);return n}function constantTimeCompare(e,r){if(e.length!==r.length)return!1;try{return timingSafeEqual(Buffer.from(e),Buffer.from(r))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{resolveTelegramWebhookSecretToken,verifyTelegramRequest};
1
+ import{timingSafeEqual}from"node:crypto";import{createLogger}from"#internal/logging.js";const log=createLogger(`telegram.verify`);async function resolveTelegramWebhookSecretToken(e){let t=e??process.env.TELEGRAM_WEBHOOK_SECRET_TOKEN;if(!t)throw Error(`TELEGRAM_WEBHOOK_SECRET_TOKEN is required.`);return typeof t==`function`?await t():t}async function verifyTelegramRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`telegramChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=await resolveTelegramWebhookSecretToken(t.secretToken),i=e.headers.get(`x-telegram-bot-api-secret-token`)??``;if(!i)throw Error(`telegramChannel: inbound request missing Telegram secret-token header.`);if(!constantTimeCompare(r,i))throw Error(`telegramChannel: inbound request secret-token mismatch.`);return n}function constantTimeCompare(t,r){if(t.length!==r.length)return!1;try{return timingSafeEqual(Buffer.from(t),Buffer.from(r))}catch(e){return log.debug(`timingSafeEqual threw`,{error:e}),!1}}export{resolveTelegramWebhookSecretToken,verifyTelegramRequest};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/twilio/verify.js";import{callTwilioApi,sendTwilioMessage,twilioContinuationToken,updateTwilioCall}from"#public/channels/twilio/api.js";import{emptyTwilioResponse,gatherSpeechTwilioResponse,sayTwilioResponse}from"#public/channels/twilio/twiml.js";import{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription}from"#public/channels/twilio/defaults.js";import{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription}from"#public/channels/twilio/inbound.js";import{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound}from"#public/channels/twilio/routing.js";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let i=buildTwilioRoutes(e.route??`/eve/v1/twilio`),a=e.onText??defaultOnText,s=e.onVoice??defaultOnVoice,c=e.onVoiceTranscription??defaultOnVoiceTranscription,l={...defaultEvents,...e.events},u=handleTwilioMessages({config:e,onText:a}),d=handleTwilioVoice({config:e,onVoice:s,routes:i}),f=handleTwilioTranscription({config:e,onVoiceTranscription:c,routes:i});return defineChannel({kindHint:`twilio`,state:{from:null,to:null,lastCallSid:null,lastMessageSid:null},metadata(e){return{from:e.from,lastCallSid:e.lastCallSid??null,lastMessageSid:e.lastMessageSid??null,to:e.to}},context(t,n){return rebuildTwilioContext(t,n,e)},routes:[GET(i.messages,u),POST(i.messages,u),GET(i.voice,d),POST(i.voice,d),GET(i.transcription,f),POST(i.transcription,f)],async receive(t,{send:n}){let r=readString(t.target.phoneNumber);if(!r)throw Error(`twilioChannel().receive requires target.phoneNumber.`);let i=readString(t.target.from)??e.messaging?.from??null;return n(t.message,{auth:t.auth,continuationToken:twilioContinuationToken(r,i??void 0),state:{from:r,lastCallSid:null,lastMessageSid:null,to:i}})},events:l})}function handleTwilioMessages(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioTextMessage(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchText({config:e.config,message:a,onText:e.onText,send:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}}function handleTwilioVoice(e){return async t=>{let n=await verifyTwilioInbound(t,e.config);if(n===null)return new Response(`unauthorized`,{status:401});let r=parseTwilioVoiceCall(n.params);if(!r)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(r.from,e.config.allowFrom))return new Response(`forbidden`,{status:403});let i=await acceptVoiceCall({call:r,config:e.config,onVoice:e.onVoice});if(i===null)return new Response(`forbidden`,{status:403});let a=i??{};return gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),hints:a.hints??e.config.voice?.hints,language:a.language??e.config.voice?.language,profanityFilter:a.profanityFilter??e.config.voice?.profanityFilter,prompt:a.prompt??e.config.voice?.prompt??`Please say your message after the tone.`,speechModel:a.speechModel??e.config.voice?.speechModel,speechTimeout:a.speechTimeout??e.config.voice?.speechTimeout??`auto`,timeoutSeconds:a.timeoutSeconds??e.config.voice?.timeoutSeconds,voice:a.voice??e.config.voice?.voice})}}function handleTwilioTranscription(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioVoiceTranscription(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchVoiceTranscription({config:e.config,onVoiceTranscription:e.onVoiceTranscription,send:n,transcription:a})),sayTwilioResponse(e.config.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),language:e.config.voice?.language,prompt:e.config.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.config.voice?.speechTimeout??`auto`,timeoutSeconds:e.config.voice?.timeoutSeconds})}}function rebuildTwilioContext(e,t,n){return{state:e,twilio:buildTwilioHandle({callSid:e.lastCallSid??void 0,config:n,from:e.from??``,to:e.to??void 0})}}function buildTwilioHandle(e){let t=e.config.api,n=e.config.credentials,r=e.config.messaging?.from??e.to,o=e.config.messaging?.messagingServiceSid,c=e.config.messaging?.statusCallbackUrl;return{callSid:e.callSid,from:e.from,to:e.to,request(e,r){return callTwilioApi({apiBaseUrl:t?.apiBaseUrl,body:r,credentials:n,fetch:t?.fetch,path:e})},sendMessage(i,s){return sendTwilioMessage({apiBaseUrl:t?.apiBaseUrl,body:i,credentials:n,fetch:t?.fetch,from:s?.from??r,messagingServiceSid:s?.messagingServiceSid??o,statusCallbackUrl:s?.statusCallbackUrl??c,to:s?.to??e.from})},updateCall(e,r){return updateTwilioCall({apiBaseUrl:t?.apiBaseUrl,callSid:e,credentials:n,fetch:t?.fetch,twiml:r})}}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function dispatchText(e){let{message:t}=e,n={twilio:buildTwilioHandle({callSid:void 0,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onText(n,t)}catch(e){log.error(`text handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({channel:`text`,from:t.from,messageSid:t.messageSid,to:t.to});try{await e.send({message:t.body,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:null,lastMessageSid:t.messageSid??null,to:t.to??null}})}catch(e){log.error(`text delivery failed`,{error:e})}}async function acceptVoiceCall(e){let{call:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})};try{return await e.onVoice(n,t)}catch(e){return log.error(`voice handler failed`,{error:e}),null}}async function dispatchVoiceTranscription(e){let{transcription:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onVoiceTranscription(n,t)}catch(e){log.error(`voice transcription handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({callSid:t.callSid,channel:`voice`,from:t.from,to:t.to});try{await e.send({message:t.text,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:t.callSid??null,lastMessageSid:null,to:t.to??null}})}catch(e){log.error(`voice transcription delivery failed`,{error:e})}}async function isAllowed(e,t){let n=typeof t==`function`?await t():t;return n===`*`?!0:typeof n==`string`?n===e:n.includes(e)}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{twilioChannel};
1
+ import{createLogger}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/twilio/verify.js";import{callTwilioApi,sendTwilioMessage,twilioContinuationToken,updateTwilioCall}from"#public/channels/twilio/api.js";import{emptyTwilioResponse,gatherSpeechTwilioResponse,sayTwilioResponse}from"#public/channels/twilio/twiml.js";import{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription}from"#public/channels/twilio/defaults.js";import{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription}from"#public/channels/twilio/inbound.js";import{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound}from"#public/channels/twilio/routing.js";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let a=buildTwilioRoutes(e.route??`/eve/v1/twilio`),o=e.onText??defaultOnText,c=e.onVoice??defaultOnVoice,l=e.onVoiceTranscription??defaultOnVoiceTranscription,u={...defaultEvents,...e.events},d=handleTwilioMessages({config:e,onText:o}),f=handleTwilioVoice({config:e,onVoice:c,routes:a}),p=handleTwilioTranscription({config:e,onVoiceTranscription:l,routes:a});return defineChannel({kindHint:`twilio`,state:{from:null,to:null,lastCallSid:null,lastMessageSid:null},metadata(e){return{from:e.from,lastCallSid:e.lastCallSid??null,lastMessageSid:e.lastMessageSid??null,to:e.to}},context(t,n){return rebuildTwilioContext(t,n,e)},routes:[GET(a.messages,d),POST(a.messages,d),GET(a.voice,f),POST(a.voice,f),GET(a.transcription,p),POST(a.transcription,p)],async receive(n,{send:r}){let i=readNonEmptyString(n.target.phoneNumber);if(!i)throw Error(`twilioChannel().receive requires target.phoneNumber.`);let a=readNonEmptyString(n.target.from)??e.messaging?.from??null;return r(n.message,{auth:n.auth,continuationToken:twilioContinuationToken(i,a??void 0),state:{from:i,lastCallSid:null,lastMessageSid:null,to:a}})},events:u})}function handleTwilioMessages(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioTextMessage(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchText({config:e.config,message:a,onText:e.onText,send:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}}function handleTwilioVoice(e){return async t=>{let n=await verifyTwilioInbound(t,e.config);if(n===null)return new Response(`unauthorized`,{status:401});let r=parseTwilioVoiceCall(n.params);if(!r)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(r.from,e.config.allowFrom))return new Response(`forbidden`,{status:403});let i=await acceptVoiceCall({call:r,config:e.config,onVoice:e.onVoice});if(i===null)return new Response(`forbidden`,{status:403});let a=i??{};return gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),hints:a.hints??e.config.voice?.hints,language:a.language??e.config.voice?.language,profanityFilter:a.profanityFilter??e.config.voice?.profanityFilter,prompt:a.prompt??e.config.voice?.prompt??`Please say your message after the tone.`,speechModel:a.speechModel??e.config.voice?.speechModel,speechTimeout:a.speechTimeout??e.config.voice?.speechTimeout??`auto`,timeoutSeconds:a.timeoutSeconds??e.config.voice?.timeoutSeconds,voice:a.voice??e.config.voice?.voice})}}function handleTwilioTranscription(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioVoiceTranscription(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchVoiceTranscription({config:e.config,onVoiceTranscription:e.onVoiceTranscription,send:n,transcription:a})),sayTwilioResponse(e.config.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),language:e.config.voice?.language,prompt:e.config.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.config.voice?.speechTimeout??`auto`,timeoutSeconds:e.config.voice?.timeoutSeconds})}}function rebuildTwilioContext(e,t,n){return{state:e,twilio:buildTwilioHandle({callSid:e.lastCallSid??void 0,config:n,from:e.from??``,to:e.to??void 0})}}function buildTwilioHandle(e){let t=e.config.api,n=e.config.credentials,r=e.config.messaging?.from??e.to,i=e.config.messaging?.messagingServiceSid,s=e.config.messaging?.statusCallbackUrl;return{callSid:e.callSid,from:e.from,to:e.to,request(e,r){return callTwilioApi({apiBaseUrl:t?.apiBaseUrl,body:r,credentials:n,fetch:t?.fetch,path:e})},sendMessage(a,c){return sendTwilioMessage({apiBaseUrl:t?.apiBaseUrl,body:a,credentials:n,fetch:t?.fetch,from:c?.from??r,messagingServiceSid:c?.messagingServiceSid??i,statusCallbackUrl:c?.statusCallbackUrl??s,to:c?.to??e.from})},updateCall(e,r){return updateTwilioCall({apiBaseUrl:t?.apiBaseUrl,callSid:e,credentials:n,fetch:t?.fetch,twiml:r})}}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function dispatchText(e){let{message:t}=e,n={twilio:buildTwilioHandle({callSid:void 0,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onText(n,t)}catch(e){log.error(`text handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({channel:`text`,from:t.from,messageSid:t.messageSid,to:t.to});try{await e.send({message:t.body,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:null,lastMessageSid:t.messageSid??null,to:t.to??null}})}catch(e){log.error(`text delivery failed`,{error:e})}}async function acceptVoiceCall(e){let{call:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})};try{return await e.onVoice(n,t)}catch(e){return log.error(`voice handler failed`,{error:e}),null}}async function dispatchVoiceTranscription(e){let{transcription:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onVoiceTranscription(n,t)}catch(e){log.error(`voice transcription handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({callSid:t.callSid,channel:`voice`,from:t.from,to:t.to});try{await e.send({message:t.text,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:t.callSid??null,lastMessageSid:null,to:t.to??null}})}catch(e){log.error(`voice transcription delivery failed`,{error:e})}}async function isAllowed(e,t){let n=typeof t==`function`?await t():t;return n===`*`?!0:typeof n==`string`?n===e:n.includes(e)}export{twilioChannel};
@@ -1,5 +1,7 @@
1
1
  import type { PublicAgentDefinition } from "#shared/agent-definition.js";
2
2
  import type { ExactDefinition } from "#public/definitions/exact.js";
3
+ import type { DynamicEvents, DynamicEventsWithFallback, DynamicSentinel } from "#shared/dynamic-tool-definition.js";
4
+ declare const DEFINED_AGENT: unique symbol;
3
5
  export type { AgentModelResolveContext, AgentModelOptionsDefinition, AgentModelResolver, AgentReasoningDefinition, AgentBuildDefinition, PublicAgentDynamicModelDefinition as AgentDynamicModelDefinition, PublicAgentDynamicModelResult as AgentDynamicModelResult, AgentExperimentalDefinition, AgentLimitsDefinition, PublicAgentModelSelectionDefinition as AgentModelSelectionDefinition, AgentWorkflowDefinition, AgentWorkflowWorldDefinition, PublicAgentModelDefinition as AgentModelDefinition, PublicAgentStaticModelDefinition as AgentStaticModelDefinition, PublicAgentCompactionDefinition as AgentCompactionDefinition, } from "#shared/agent-definition.js";
4
6
  /**
5
7
  * Additive public agent configuration authored in `agent.ts`.
@@ -12,6 +14,35 @@ export type { AgentModelResolveContext, AgentModelOptionsDefinition, AgentModelR
12
14
  * channel uses to gate its `fetch` handler.
13
15
  */
14
16
  export type AgentDefinition = PublicAgentDefinition;
17
+ /** Literal-preserving value returned by {@link defineAgent}. */
18
+ export type DefinedAgent<TAgent extends AgentDefinition = AgentDefinition> = TAgent & {
19
+ readonly [DEFINED_AGENT]: true;
20
+ };
21
+ /**
22
+ * Agent configuration returned by a dynamic subagent resolver. The description
23
+ * tells the parent agent when to delegate.
24
+ */
25
+ export type DynamicSubagentDefinition = AgentDefinition & {
26
+ readonly description: string;
27
+ };
28
+ type DynamicEventHandler<TEvents extends DynamicEvents> = Extract<NonNullable<TEvents[keyof TEvents]>, (...args: never[]) => unknown>;
29
+ type DynamicEventResult<TEvents extends DynamicEvents> = Awaited<ReturnType<DynamicEventHandler<TEvents>>>;
30
+ type DynamicSubagentDescriptionConstraint<TEvents extends DynamicEvents> = Exclude<Extract<DynamicEventResult<TEvents>, DefinedAgent>, DynamicSubagentDefinition> extends never ? unknown : {
31
+ readonly "Dynamic subagent definitions require a description": never;
32
+ };
33
+ /**
34
+ * Defines dynamic agent configuration. A returned subagent requires a
35
+ * description so its parent knows when to delegate.
36
+ */
37
+ export declare const defineDynamic: {
38
+ <const TEvents extends DynamicEventsWithFallback, TFallback = unknown>(definition: {
39
+ readonly fallback: TFallback;
40
+ readonly events: TEvents;
41
+ } & DynamicSubagentDescriptionConstraint<TEvents>): DynamicSentinel<Exclude<DynamicEventResult<TEvents>, undefined>, TFallback>;
42
+ <const TEvents extends DynamicEvents>(definition: {
43
+ readonly events: TEvents;
44
+ } & DynamicSubagentDescriptionConstraint<TEvents>): DynamicSentinel<DynamicEventResult<TEvents>>;
45
+ };
15
46
  /**
16
47
  * Defines the agent configuration authored in `agent.ts` and returns it
17
48
  * unchanged, preserving its literal type.
@@ -21,4 +52,4 @@ export type AgentDefinition = PublicAgentDefinition;
21
52
  * at compile time from `manifest.agentId` (the package name or app-root
22
53
  * basename), so do not author a `name` field.
23
54
  */
24
- export declare function defineAgent<TAgent extends AgentDefinition>(definition: ExactDefinition<TAgent, AgentDefinition>): TAgent;
55
+ export declare function defineAgent<TAgent extends AgentDefinition>(definition: ExactDefinition<TAgent, AgentDefinition>): DefinedAgent<TAgent>;
@@ -1 +1 @@
1
- function defineAgent(e){return e}export{defineAgent};
1
+ import{defineDynamic as defineDynamic$1}from"#public/definitions/tool.js";const defineDynamic=defineDynamic$1;function defineAgent(e){return e}export{defineAgent,defineDynamic};