experimental-ash 0.28.0 → 0.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (329) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/docs/internals/hooks.md +1 -1
  3. package/dist/src/channel/adapter.js +1 -1
  4. package/dist/src/channel/compiled-channel.js +1 -1
  5. package/dist/src/channel/http.js +1 -1
  6. package/dist/src/channel/schedule.js +1 -1
  7. package/dist/src/channel/send.js +1 -1
  8. package/dist/src/channel/session-callback.js +1 -1
  9. package/dist/src/channel/session.js +1 -1
  10. package/dist/src/cli/commands/channels.js +1 -1
  11. package/dist/src/cli/dev/environment.js +1 -1
  12. package/dist/src/cli/dev/input-requests.js +1 -1
  13. package/dist/src/cli/dev/repl.js +1 -1
  14. package/dist/src/cli/dev/terminal.js +1 -1
  15. package/dist/src/cli/dev/url.js +1 -1
  16. package/dist/src/compiler/artifacts.js +1 -1
  17. package/dist/src/compiler/manifest.js +1 -1
  18. package/dist/src/compiler/model-catalog.js +1 -1
  19. package/dist/src/compiler/module-map.js +1 -1
  20. package/dist/src/compiler/normalize-subagent.js +1 -1
  21. package/dist/src/compiler/remote-agent-node.js +1 -1
  22. package/dist/src/compiler/workspace-resources.js +1 -1
  23. package/dist/src/context/accessors.js +1 -1
  24. package/dist/src/context/container.js +1 -1
  25. package/dist/src/context/hook-lifecycle.d.ts +3 -3
  26. package/dist/src/context/hook-lifecycle.js +1 -1
  27. package/dist/src/context/key.js +1 -1
  28. package/dist/src/context/keys.d.ts +31 -10
  29. package/dist/src/context/keys.js +1 -1
  30. package/dist/src/context/node.js +1 -1
  31. package/dist/src/context/providers/connection.js +1 -1
  32. package/dist/src/context/providers/sandbox.js +1 -1
  33. package/dist/src/context/providers/session.js +1 -1
  34. package/dist/src/context/run-step.js +1 -1
  35. package/dist/src/context/serialize.js +1 -1
  36. package/dist/src/discover/connections.js +1 -1
  37. package/dist/src/discover/diagnostics.js +1 -1
  38. package/dist/src/discover/discover-subagent.js +1 -1
  39. package/dist/src/discover/filesystem.js +1 -1
  40. package/dist/src/discover/grammar.js +1 -1
  41. package/dist/src/discover/lib.js +1 -1
  42. package/dist/src/discover/manifest.js +1 -1
  43. package/dist/src/discover/sandbox.js +1 -1
  44. package/dist/src/discover/schedules.js +1 -1
  45. package/dist/src/discover/skills.js +1 -1
  46. package/dist/src/evals/runner/discover.js +1 -1
  47. package/dist/src/evals/runner/execute-suite.js +1 -1
  48. package/dist/src/evals/runner/reporters/braintrust.js +1 -1
  49. package/dist/src/evals/scores/index.js +1 -1
  50. package/dist/src/execution/await-authorization-orchestrator.js +1 -1
  51. package/dist/src/execution/connection-auth-steps.js +1 -1
  52. package/dist/src/execution/runtime-context.d.ts +1 -1
  53. package/dist/src/execution/runtime-context.js +1 -1
  54. package/dist/src/execution/sandbox/bindings/local.js +1 -1
  55. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  56. package/dist/src/execution/sandbox/glob-tool.js +1 -1
  57. package/dist/src/execution/sandbox/grep-tool.js +1 -1
  58. package/dist/src/execution/sandbox/read-file-tool.js +1 -1
  59. package/dist/src/execution/sandbox/require-sandbox.js +1 -1
  60. package/dist/src/execution/sandbox/ripgrep-probe.js +1 -1
  61. package/dist/src/execution/sandbox/truncate-output.js +1 -1
  62. package/dist/src/execution/session-callback-step.js +1 -1
  63. package/dist/src/execution/session.js +1 -1
  64. package/dist/src/execution/subagent-adapter.js +1 -1
  65. package/dist/src/execution/tool-compaction.js +1 -1
  66. package/dist/src/execution/turn-workflow.js +1 -1
  67. package/dist/src/execution/web-fetch/html.js +1 -1
  68. package/dist/src/execution/web-fetch/tool.js +1 -1
  69. package/dist/src/execution/workflow-entry.js +1 -1
  70. package/dist/src/execution/workflow-runtime.js +1 -1
  71. package/dist/src/execution/workflow-steps.js +1 -1
  72. package/dist/src/harness/attachment-staging.js +1 -1
  73. package/dist/src/harness/compaction.js +2 -2
  74. package/dist/src/harness/emission.js +1 -1
  75. package/dist/src/harness/input-requests.js +1 -1
  76. package/dist/src/harness/instrumentation-config.js +1 -1
  77. package/dist/src/harness/model-call-error.js +1 -1
  78. package/dist/src/harness/otel-integration.js +1 -1
  79. package/dist/src/harness/prompt-cache.js +1 -1
  80. package/dist/src/harness/provider-tools.js +1 -1
  81. package/dist/src/harness/proxy-input-requests.js +1 -1
  82. package/dist/src/harness/runtime-actions.js +1 -1
  83. package/dist/src/harness/step-hooks.js +1 -1
  84. package/dist/src/harness/tool-loop.js +1 -1
  85. package/dist/src/harness/tool-result-pruning.js +1 -1
  86. package/dist/src/internal/application/cache-metadata.js +1 -1
  87. package/dist/src/internal/application/compiled-artifacts.js +1 -1
  88. package/dist/src/internal/application/import-specifier.js +1 -1
  89. package/dist/src/internal/application/package.js +1 -1
  90. package/dist/src/internal/attachments/refs.js +1 -1
  91. package/dist/src/internal/attachments/sandbox-refs.js +1 -1
  92. package/dist/src/internal/attachments/url-refs.js +1 -1
  93. package/dist/src/internal/authored-asset-import-plugin.js +1 -1
  94. package/dist/src/internal/authored-definition/connection.js +1 -1
  95. package/dist/src/internal/authored-module-loader.js +1 -1
  96. package/dist/src/internal/authored-package-tsconfig-paths.js +1 -1
  97. package/dist/src/internal/bundler/nitro-rolldown.js +1 -1
  98. package/dist/src/internal/helpers/markdown.js +2 -2
  99. package/dist/src/internal/json-schema.js +1 -1
  100. package/dist/src/internal/logging.js +1 -1
  101. package/dist/src/internal/nitro/host/channel-routes.js +1 -1
  102. package/dist/src/internal/nitro/host/compiled-sandbox-backend-prune-plugin.js +1 -1
  103. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  104. package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
  105. package/dist/src/internal/nitro/host/schedule-task-routes.js +1 -1
  106. package/dist/src/internal/nitro/host/server-external-packages.js +1 -1
  107. package/dist/src/internal/nitro/host/start-development-server.js +1 -1
  108. package/dist/src/internal/nitro/routes/index.js +3 -3
  109. package/dist/src/internal/nitro/routes/workflow-route-helpers.js +1 -1
  110. package/dist/src/internal/node-esm-compat-banner.js +1 -1
  111. package/dist/src/internal/package-name.js +1 -1
  112. package/dist/src/internal/vercel-agent-summary.js +1 -1
  113. package/dist/src/internal/workflow-bundle/ash-service-route-output.js +1 -1
  114. package/dist/src/internal/workflow-bundle/builder-support.js +1 -1
  115. package/dist/src/internal/workflow-bundle/builder.js +2 -2
  116. package/dist/src/internal/workflow-bundle/vercel-workflow-output.js +1 -1
  117. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  118. package/dist/src/internal/workflow-bundle/workflow-core-shim.js +1 -1
  119. package/dist/src/internal/workflow-bundle/workflow-transformer.js +1 -1
  120. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/ajv.js +1 -1
  121. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/code.js +1 -1
  122. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/index.js +2 -2
  123. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/codegen/scope.js +1 -1
  124. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/errors.js +1 -1
  125. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/index.js +1 -1
  126. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/names.js +1 -1
  127. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/ref_error.js +1 -1
  128. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/resolve.js +1 -1
  129. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/rules.js +1 -1
  130. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/util.js +1 -1
  131. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/boolSchema.js +1 -1
  132. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/dataType.js +2 -2
  133. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/defaults.js +1 -1
  134. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/index.js +1 -1
  135. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/keyword.js +1 -1
  136. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/compile/validate/subschema.js +1 -1
  137. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/core.js +1 -1
  138. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/runtime/equal.js +1 -1
  139. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/runtime/uri.js +1 -1
  140. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/additionalItems.js +1 -1
  141. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/additionalProperties.js +1 -1
  142. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/allOf.js +1 -1
  143. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/contains.js +1 -1
  144. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/dependencies.js +2 -2
  145. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/if.js +1 -1
  146. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/index.js +1 -1
  147. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/items.js +1 -1
  148. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/items2020.js +1 -1
  149. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/not.js +1 -1
  150. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/oneOf.js +1 -1
  151. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/patternProperties.js +1 -1
  152. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/prefixItems.js +1 -1
  153. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/properties.js +1 -1
  154. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/propertyNames.js +1 -1
  155. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/applicator/thenElse.js +1 -1
  156. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/code.js +1 -1
  157. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/core/index.js +1 -1
  158. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/core/ref.js +1 -1
  159. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/discriminator/index.js +1 -1
  160. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/draft7.js +1 -1
  161. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/format/format.js +1 -1
  162. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/const.js +1 -1
  163. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/enum.js +1 -1
  164. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/index.js +1 -1
  165. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/limitItems.js +1 -1
  166. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/limitLength.js +1 -1
  167. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/limitNumber.js +1 -1
  168. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/limitProperties.js +1 -1
  169. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/multipleOf.js +1 -1
  170. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/pattern.js +1 -1
  171. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/required.js +1 -1
  172. package/dist/src/node_modules/.pnpm/ajv@8.20.0/node_modules/ajv/dist/vocabularies/validation/uniqueItems.js +1 -1
  173. package/dist/src/node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/index.js +1 -1
  174. package/dist/src/node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/schemes.js +1 -1
  175. package/dist/src/node_modules/.pnpm/fast-uri@3.1.2/node_modules/fast-uri/lib/utils.js +1 -1
  176. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/_vendor/partial-json-parser/parser.js +2 -2
  177. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/auth/workload-identity-auth.js +1 -1
  178. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/azure.js +1 -1
  179. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/client.js +2 -2
  180. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/detect-platform.js +1 -1
  181. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/errors.js +1 -1
  182. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/headers.js +1 -1
  183. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/qs/formats.js +1 -1
  184. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/qs/stringify.js +1 -1
  185. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/qs/utils.js +1 -1
  186. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/request-options.js +1 -1
  187. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/to-file.js +1 -1
  188. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/uploads.js +1 -1
  189. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/base64.js +1 -1
  190. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/bytes.js +1 -1
  191. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/env.js +1 -1
  192. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/log.js +1 -1
  193. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/path.js +1 -1
  194. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/sleep.js +1 -1
  195. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/uuid.js +1 -1
  196. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/internal/utils/values.js +1 -1
  197. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/lib/AbstractChatCompletionRunner.js +1 -1
  198. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/lib/Util.js +1 -1
  199. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/lib/chatCompletionUtils.js +1 -1
  200. package/dist/src/node_modules/.pnpm/openai@6.39.0_ws@8.21.0_zod@3.25.76/node_modules/openai/version.js +1 -1
  201. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Options.js +1 -1
  202. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/Refs.js +1 -1
  203. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/getRelativePath.js +1 -1
  204. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parseDef.js +1 -1
  205. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/catch.js +1 -1
  206. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/date.js +1 -1
  207. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/intersection.js +1 -1
  208. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/optional.js +1 -1
  209. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/pipeline.js +1 -1
  210. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/readonly.js +1 -1
  211. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/string.js +1 -1
  212. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/parsers/union.js +1 -1
  213. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/selectParser.js +1 -1
  214. package/dist/src/node_modules/.pnpm/zod-to-json-schema@3.25.2_zod@3.25.76/node_modules/zod-to-json-schema/dist/esm/zodToJsonSchema.js +1 -1
  215. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/ZodError.js +1 -1
  216. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/errors.js +1 -1
  217. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js +1 -1
  218. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/util.js +1 -1
  219. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/locales/en.js +1 -1
  220. package/dist/src/node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js +1 -1
  221. package/dist/src/packages/ash-scaffold/src/channels.js +2 -2
  222. package/dist/src/packages/ash-scaffold/src/module-files.js +1 -1
  223. package/dist/src/protocol/message.js +1 -1
  224. package/dist/src/protocol/routes.js +1 -1
  225. package/dist/src/public/channels/ash.js +2 -2
  226. package/dist/src/public/channels/auth.js +1 -1
  227. package/dist/src/public/channels/discord/api.js +1 -1
  228. package/dist/src/public/channels/discord/defaults.js +1 -1
  229. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  230. package/dist/src/public/channels/discord/hitl.js +1 -1
  231. package/dist/src/public/channels/discord/inbound.js +1 -1
  232. package/dist/src/public/channels/discord/verify.js +1 -1
  233. package/dist/src/public/channels/discord/verifyInbound.js +1 -1
  234. package/dist/src/public/channels/slack/api.js +1 -1
  235. package/dist/src/public/channels/slack/attachments.js +1 -1
  236. package/dist/src/public/channels/slack/constants.js +1 -1
  237. package/dist/src/public/channels/slack/defaults.js +2 -2
  238. package/dist/src/public/channels/slack/hitl.js +1 -1
  239. package/dist/src/public/channels/slack/interactions.js +1 -1
  240. package/dist/src/public/channels/slack/limits.js +1 -1
  241. package/dist/src/public/channels/slack/mrkdwn.js +1 -1
  242. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  243. package/dist/src/public/channels/slack/verify.js +1 -1
  244. package/dist/src/public/channels/teams/api.js +1 -1
  245. package/dist/src/public/channels/teams/attachments.js +1 -1
  246. package/dist/src/public/channels/teams/defaults.js +1 -1
  247. package/dist/src/public/channels/teams/hitl.js +1 -1
  248. package/dist/src/public/channels/teams/inbound.js +1 -1
  249. package/dist/src/public/channels/teams/limits.js +1 -1
  250. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  251. package/dist/src/public/channels/teams/verify.js +1 -1
  252. package/dist/src/public/channels/telegram/api.js +1 -1
  253. package/dist/src/public/channels/telegram/attachments.js +1 -1
  254. package/dist/src/public/channels/telegram/defaults.js +1 -1
  255. package/dist/src/public/channels/telegram/hitl.js +1 -1
  256. package/dist/src/public/channels/telegram/inbound.js +1 -1
  257. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  258. package/dist/src/public/channels/telegram/verify.js +1 -1
  259. package/dist/src/public/channels/twilio/defaults.js +1 -1
  260. package/dist/src/public/channels/twilio/inbound.js +1 -1
  261. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  262. package/dist/src/public/channels/twilio/verify.js +1 -1
  263. package/dist/src/public/channels/upload-policy.js +1 -1
  264. package/dist/src/public/definitions/channel.js +1 -1
  265. package/dist/src/public/definitions/tool.js +1 -1
  266. package/dist/src/public/next/index.js +1 -1
  267. package/dist/src/public/next/server.js +1 -1
  268. package/dist/src/public/next/vercel-json.js +1 -1
  269. package/dist/src/public/tool-result-narrowing.js +1 -1
  270. package/dist/src/public/tools/defaults.js +1 -1
  271. package/dist/src/react/use-ash-agent.js +1 -1
  272. package/dist/src/runtime/actions/types.js +1 -1
  273. package/dist/src/runtime/agent/bootstrap-model-utils.js +1 -1
  274. package/dist/src/runtime/agent/bootstrap-model.js +1 -1
  275. package/dist/src/runtime/agent/bootstrap.js +1 -1
  276. package/dist/src/runtime/agent/mock-model-adapter.js +1 -1
  277. package/dist/src/runtime/channels/registry.js +1 -1
  278. package/dist/src/runtime/connections/authorization-tokens.js +1 -1
  279. package/dist/src/runtime/connections/callback-route.js +1 -1
  280. package/dist/src/runtime/connections/principal-context.js +1 -1
  281. package/dist/src/runtime/connections/principal.js +1 -1
  282. package/dist/src/runtime/framework-channels/index.js +1 -1
  283. package/dist/src/runtime/framework-tools/ask-question.js +1 -1
  284. package/dist/src/runtime/framework-tools/bash.js +1 -1
  285. package/dist/src/runtime/framework-tools/connection-search.js +1 -1
  286. package/dist/src/runtime/framework-tools/file-state.js +1 -1
  287. package/dist/src/runtime/framework-tools/glob.js +1 -1
  288. package/dist/src/runtime/framework-tools/grep.js +1 -1
  289. package/dist/src/runtime/framework-tools/index.js +1 -1
  290. package/dist/src/runtime/framework-tools/pending-connection-tool-calls.js +1 -1
  291. package/dist/src/runtime/framework-tools/read-file.js +1 -1
  292. package/dist/src/runtime/framework-tools/skill.js +1 -1
  293. package/dist/src/runtime/framework-tools/todo.js +2 -2
  294. package/dist/src/runtime/framework-tools/web-fetch.js +1 -1
  295. package/dist/src/runtime/framework-tools/web-search.js +1 -1
  296. package/dist/src/runtime/framework-tools/write-file.js +1 -1
  297. package/dist/src/runtime/governance/auth/jwt-ecdsa.js +1 -1
  298. package/dist/src/runtime/governance/auth/oidc.js +1 -1
  299. package/dist/src/runtime/governance/auth/token-claims.js +1 -1
  300. package/dist/src/runtime/graph.js +1 -1
  301. package/dist/src/runtime/input/types.js +1 -1
  302. package/dist/src/runtime/loaders/compile-metadata.js +1 -1
  303. package/dist/src/runtime/loaders/manifest.js +1 -1
  304. package/dist/src/runtime/loaders/module-map.js +1 -1
  305. package/dist/src/runtime/prompt/compose.js +2 -2
  306. package/dist/src/runtime/prompt/connections.js +1 -1
  307. package/dist/src/runtime/resolve-agent-graph.js +1 -1
  308. package/dist/src/runtime/resolve-hook.js +1 -1
  309. package/dist/src/runtime/sandbox/keys.js +1 -1
  310. package/dist/src/runtime/sandbox/registry.js +1 -1
  311. package/dist/src/runtime/schedules/register.js +1 -1
  312. package/dist/src/runtime/session-callback-route.js +1 -1
  313. package/dist/src/runtime/sessions/auth.js +1 -1
  314. package/dist/src/runtime/sessions/compiled-agent-cache.js +1 -1
  315. package/dist/src/runtime/sessions/runtime-context-keys.d.ts +11 -0
  316. package/dist/src/runtime/sessions/runtime-context-keys.js +1 -0
  317. package/dist/src/runtime/sessions/runtime-session.js +1 -1
  318. package/dist/src/runtime/skills/fragment-context.js +1 -1
  319. package/dist/src/runtime/skills/sandbox-access.js +1 -1
  320. package/dist/src/runtime/subagents/registry.js +1 -1
  321. package/dist/src/runtime/workspace/types.js +1 -1
  322. package/dist/src/services/dev-client/request-headers.js +1 -1
  323. package/dist/src/services/dev-client/vercel-auth-error.js +1 -1
  324. package/dist/src/shared/json-schemas.js +1 -1
  325. package/dist/src/shared/json.js +1 -1
  326. package/dist/src/shared/skill-package.js +1 -1
  327. package/package.json +1 -1
  328. package/dist/src/context/seed-keys.d.ts +0 -39
  329. package/dist/src/context/seed-keys.js +0 -1
@@ -1 +1 @@
1
- var SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS=[`.cts`,`.mts`,`.cjs`,`.mjs`,`.ts`,`.js`];function getSupportedModuleBaseName(t){for(let n of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)if(t.endsWith(n)&&t.length>n.length)return t.slice(0,-n.length);return null}function matchesSupportedModuleBaseName(e,t){return getSupportedModuleBaseName(e)===t}export{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS,getSupportedModuleBaseName,matchesSupportedModuleBaseName};
1
+ const SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS=[`.cts`,`.mts`,`.cjs`,`.mjs`,`.ts`,`.js`];function getSupportedModuleBaseName(t){for(let n of SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS)if(t.endsWith(n)&&t.length>n.length)return t.slice(0,-n.length);return null}function matchesSupportedModuleBaseName(e,t){return getSupportedModuleBaseName(e)===t}export{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS,getSupportedModuleBaseName,matchesSupportedModuleBaseName};
@@ -1,2 +1,2 @@
1
- var ASH_SESSION_ID_HEADER=`x-ash-session-id`,ASH_STREAM_FORMAT_HEADER=`x-ash-stream-format`,ASH_STREAM_VERSION_HEADER=`x-ash-stream-version`,ASH_MESSAGE_STREAM_CONTENT_TYPE=`application/x-ndjson; charset=utf-8`,ASH_MESSAGE_STREAM_FORMAT=`ndjson`,ASH_MESSAGE_STREAM_VERSION=`14`,textEncoder=new TextEncoder;function isCurrentTurnBoundaryEvent(e){return e.type===`session.completed`||e.type===`session.failed`||e.type===`session.waiting`}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),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(`
1
+ const ASH_SESSION_ID_HEADER=`x-ash-session-id`,ASH_STREAM_FORMAT_HEADER=`x-ash-stream-format`,ASH_STREAM_VERSION_HEADER=`x-ash-stream-version`,ASH_MESSAGE_STREAM_CONTENT_TYPE=`application/x-ndjson; charset=utf-8`,ASH_MESSAGE_STREAM_FORMAT=`ndjson`,ASH_MESSAGE_STREAM_VERSION=`14`,textEncoder=new TextEncoder;function isCurrentTurnBoundaryEvent(e){return e.type===`session.completed`||e.type===`session.failed`||e.type===`session.waiting`}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),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
2
  `)}function createActionsRequestedEvent(e){return{data:{actions:e.actions,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`actions.requested`}}function createConnectionAuthorizationRequiredEvent(e){let t={connectionName:e.connectionName,description:e.description,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:`connection.authorization_required`}}function createConnectionAuthorizationPendingEvent(e){return{data:{connectionNames:e.connectionNames,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId},type:`connection.authorization_pending`}}function createConnectionAuthorizationCompletedEvent(e){let t={connectionName:e.connectionName,outcome:e.outcome,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId};return e.reason!==void 0&&(t.reason=e.reason),{data:t,type:`connection.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=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 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),{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 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(){return{data:{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 timestampHandleMessageStreamEvent(e,t=new Date().toISOString()){return{...e,meta:{at:t}}}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{ASH_MESSAGE_STREAM_CONTENT_TYPE,ASH_MESSAGE_STREAM_FORMAT,ASH_MESSAGE_STREAM_VERSION,ASH_SESSION_ID_HEADER,ASH_STREAM_FORMAT_HEADER,ASH_STREAM_VERSION_HEADER,createActionResultEvent,createActionsRequestedEvent,createCompactionCompletedEvent,createCompactionRequestedEvent,createConnectionAuthorizationCompletedEvent,createConnectionAuthorizationPendingEvent,createConnectionAuthorizationRequiredEvent,createInputRequestedEvent,createMessageAppendedEvent,createMessageCompletedEvent,createMessageReceivedEvent,createReasoningAppendedEvent,createReasoningCompletedEvent,createSessionCompletedEvent,createSessionFailedEvent,createSessionStartedEvent,createSessionWaitingEvent,createStepCompletedEvent,createStepFailedEvent,createStepStartedEvent,createSubagentCalledEvent,createTurnCompletedEvent,createTurnFailedEvent,createTurnStartedEvent,encodeMessageStreamEvent,isCurrentTurnBoundaryEvent,timestampHandleMessageStreamEvent};
@@ -1 +1 @@
1
- var ASH_ROUTE_PREFIX=`/ash/v1`,ASH_HEALTH_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/health`,ASH_INFO_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/info`,ASH_CREATE_SESSION_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/session`,ASH_CONTINUE_SESSION_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId`,ASH_MESSAGE_STREAM_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId/stream`,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/connections/:name/callback/:token`,ASH_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/callback/:token`;function createAshMessageStreamRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createAshContinueSessionRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createAshConnectionCallbackRoutePath(e,t){return`${ASH_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createAshCallbackRoutePath(e){return`${ASH_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{ASH_CALLBACK_ROUTE_PATTERN,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN,ASH_CONTINUE_SESSION_ROUTE_PATTERN,ASH_CREATE_SESSION_ROUTE_PATH,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH,ASH_MESSAGE_STREAM_ROUTE_PATTERN,ASH_ROUTE_PREFIX,createAshCallbackRoutePath,createAshConnectionCallbackRoutePath,createAshContinueSessionRoutePath,createAshMessageStreamRoutePath};
1
+ const ASH_ROUTE_PREFIX=`/ash/v1`,ASH_HEALTH_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/health`,ASH_INFO_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/info`,ASH_CREATE_SESSION_ROUTE_PATH=`${ASH_ROUTE_PREFIX}/session`,ASH_CONTINUE_SESSION_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId`,ASH_MESSAGE_STREAM_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/session/:sessionId/stream`,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/connections/:name/callback/:token`,ASH_CALLBACK_ROUTE_PATTERN=`${ASH_ROUTE_PREFIX}/callback/:token`;function createAshMessageStreamRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}/stream`}function createAshContinueSessionRoutePath(e){return`${ASH_ROUTE_PREFIX}/session/${encodeURIComponent(e)}`}function createAshConnectionCallbackRoutePath(e,t){return`${ASH_ROUTE_PREFIX}/connections/${encodeURIComponent(e)}/callback/${encodeURIComponent(t)}`}function createAshCallbackRoutePath(e){return`${ASH_ROUTE_PREFIX}/callback/${encodeURIComponent(e)}`}export{ASH_CALLBACK_ROUTE_PATTERN,ASH_CONNECTION_CALLBACK_ROUTE_PATTERN,ASH_CONTINUE_SESSION_ROUTE_PATTERN,ASH_CREATE_SESSION_ROUTE_PATH,ASH_HEALTH_ROUTE_PATH,ASH_INFO_ROUTE_PATH,ASH_MESSAGE_STREAM_ROUTE_PATTERN,ASH_ROUTE_PREFIX,createAshCallbackRoutePath,createAshConnectionCallbackRoutePath,createAshContinueSessionRoutePath,createAshMessageStreamRoutePath};
@@ -1,2 +1,2 @@
1
- import{ASH_MESSAGE_STREAM_CONTENT_TYPE,ASH_MESSAGE_STREAM_FORMAT,ASH_MESSAGE_STREAM_VERSION,ASH_SESSION_ID_HEADER,ASH_STREAM_FORMAT_HEADER,ASH_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{createUnauthorizedResponse}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";import{GET,POST,defineChannel}from"#public/definitions/defineChannel.js";function ashChannel(o){let s=mergeUploadPolicy(o.uploadPolicy);return defineChannel({routes:[POST(`/ash/v1/session`,async(e,{send:t})=>{let n=await runRouteAuth(o.auth,e);if(n instanceof Response)return n;let i=n,a;try{a=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof a!=`object`||!a)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let c=parseCreateBody(a);if(c instanceof Response)return c;let l=checkUploadPolicy(c,s);if(l!==null)return l;let u=`ash:${crypto.randomUUID()}`,d=await t(createSendPayload(c),{auth:i,callback:c.callback,continuationToken:u,mode:c.mode});return Response.json({continuationToken:d.continuationToken,ok:!0,sessionId:d.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:d.id},status:202})}),POST(`/ash/v1/session/:sessionId`,async(e,{send:t,getSession:n,params:i})=>{let a=await runRouteAuth(o.auth,e);if(a instanceof Response)return a;let c=a,l=i.sessionId;if(!l)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{n(l)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let u;try{u=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof u!=`object`||!u)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let d=parseContinueBody(u);if(d instanceof Response)return d;let f=checkUploadPolicy(d,s);if(f!==null)return f;let p=await t({inputResponses:d.inputResponses,message:d.message,modelContext:d.modelContext},{auth:c,continuationToken:d.continuationToken});return Response.json({ok:!0,sessionId:p.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:p.id},status:200})}),GET(`/ash/v1/session/:sessionId/stream`,async(s,{getSession:c,params:l})=>{let u=await runRouteAuth(o.auth,s);if(u instanceof Response)return u;let d=l.sessionId;if(!d)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let f=parseStartIndex(s);if(f instanceof Response)return f;try{let o=serializeAsNdjson(await c(d).getEventStream({startIndex:f}));return new Response(o,{headers:{"cache-control":`no-store`,"content-type":ASH_MESSAGE_STREAM_CONTENT_TYPE,[ASH_SESSION_ID_HEADER]:d,[ASH_STREAM_FORMAT_HEADER]:ASH_MESSAGE_STREAM_FORMAT,[ASH_STREAM_VERSION_HEADER]:ASH_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})]})}async function runRouteAuth(e,t){let n=await e(t);return n===null?createUnauthorizedResponse({challenges:[{scheme:`Bearer`}]}):n??null}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);return i instanceof Response?i:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,modelContext:n}}function parseContinueBody(e){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);return i instanceof Response?i: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,modelContext:i}}function createSendPayload(e){return e.modelContext===void 0?e.message:{message:e.message,modelContext:e.modelContext}}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});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})}var CLIENT_CONTEXT_PREFIX=`Ephemeral client context:
2
- `;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{role:`user`,content:`${CLIENT_CONTEXT_PREFIX}${e}`}}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number.parseInt(t,10);return!Number.isSafeInteger(n)||n<0?Response.json({error:`Expected startIndex to be a non-negative integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{ashChannel};
1
+ import{ASH_MESSAGE_STREAM_CONTENT_TYPE,ASH_MESSAGE_STREAM_FORMAT,ASH_MESSAGE_STREAM_VERSION,ASH_SESSION_ID_HEADER,ASH_STREAM_FORMAT_HEADER,ASH_STREAM_VERSION_HEADER}from"#protocol/message.js";import{isInputResponse}from"#runtime/input/types.js";import{parseJsonObject}from"#shared/json.js";import"ai";import{parseSessionCallback}from"#channel/session-callback.js";import{createUnauthorizedResponse}from"#public/channels/auth.js";import{collectUploadPolicyViolations,formatUploadPolicyViolation,mergeUploadPolicy}from"#public/channels/upload-policy.js";import{GET,POST,defineChannel}from"#public/definitions/defineChannel.js";function ashChannel(o){let s=mergeUploadPolicy(o.uploadPolicy);return defineChannel({routes:[POST(`/ash/v1/session`,async(e,{send:t})=>{let n=await runRouteAuth(o.auth,e);if(n instanceof Response)return n;let i=n,a;try{a=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof a!=`object`||!a)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let c=parseCreateBody(a);if(c instanceof Response)return c;let l=checkUploadPolicy(c,s);if(l!==null)return l;let u=`ash:${crypto.randomUUID()}`,d=await t(createSendPayload(c),{auth:i,callback:c.callback,continuationToken:u,mode:c.mode});return Response.json({continuationToken:d.continuationToken,ok:!0,sessionId:d.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:d.id},status:202})}),POST(`/ash/v1/session/:sessionId`,async(e,{send:t,getSession:n,params:i})=>{let a=await runRouteAuth(o.auth,e);if(a instanceof Response)return a;let c=a,l=i.sessionId;if(!l)return Response.json({error:`Missing session id.`,ok:!1},{status:400});try{n(l)}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}let u;try{u=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}if(typeof u!=`object`||!u)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let d=parseContinueBody(u);if(d instanceof Response)return d;let f=checkUploadPolicy(d,s);if(f!==null)return f;let p=await t({inputResponses:d.inputResponses,message:d.message,modelContext:d.modelContext},{auth:c,continuationToken:d.continuationToken});return Response.json({ok:!0,sessionId:p.id},{headers:{"cache-control":`no-store`,[ASH_SESSION_ID_HEADER]:p.id},status:200})}),GET(`/ash/v1/session/:sessionId/stream`,async(s,{getSession:c,params:l})=>{let u=await runRouteAuth(o.auth,s);if(u instanceof Response)return u;let d=l.sessionId;if(!d)return Response.json({error:`Missing session id.`,ok:!1},{status:400});let f=parseStartIndex(s);if(f instanceof Response)return f;try{let o=serializeAsNdjson(await c(d).getEventStream({startIndex:f}));return new Response(o,{headers:{"cache-control":`no-store`,"content-type":ASH_MESSAGE_STREAM_CONTENT_TYPE,[ASH_SESSION_ID_HEADER]:d,[ASH_STREAM_FORMAT_HEADER]:ASH_MESSAGE_STREAM_FORMAT,[ASH_STREAM_VERSION_HEADER]:ASH_MESSAGE_STREAM_VERSION}})}catch{return Response.json({error:`Session not found.`,ok:!1},{status:404})}})]})}async function runRouteAuth(e,t){let n=await e(t);return n===null?createUnauthorizedResponse({challenges:[{scheme:`Bearer`}]}):n??null}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);return i instanceof Response?i:t===void 0?Response.json({error:`Missing or empty 'message' field.`,ok:!1},{status:400}):{callback:r,message:t,mode:i,modelContext:n}}function parseContinueBody(e){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);return i instanceof Response?i: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,modelContext:i}}function createSendPayload(e){return e.modelContext===void 0?e.message:{message:e.message,modelContext:e.modelContext}}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});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 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{role:`user`,content:`Ephemeral client context:
2
+ ${e}`}}function parseStartIndex(e){let t=new URL(e.url).searchParams.get(`startIndex`);if(t===null)return;let n=Number.parseInt(t,10);return!Number.isSafeInteger(n)||n<0?Response.json({error:`Expected startIndex to be a non-negative integer.`,ok:!1},{status:400}):n}function serializeAsNdjson(e){let t=new TextEncoder;return e.pipeThrough(new TransformStream({transform(e,n){n.enqueue(t.encode(`${JSON.stringify(e)}\n`))}}))}export{ashChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";var vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let r=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return r.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){return e===null||e.length===0?{kind:`not-authenticated`}:await authenticateOidcStrategy({strategy:{acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}function none(){return()=>void 0}var VERCEL_OIDC_ISSUER_PREFIX=`https://oidc.vercel.com/`;async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return vercelOidcLog.debug(`Rejected request without a bearer token.`),{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(VERCEL_OIDC_ISSUER_PREFIX))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};let r=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,issuer:n.issuer,subjects:t.subjects??[]});return r.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:r.principal.principalType,subject:r.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:r.kind,subjectsConfigured:(t.subjects??[]).length>0,...r.kind===`misconfigured`?{detail:r.message}:{}}),{ok:!1})}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return async t=>{let n=await verifyVercelOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function httpBasic(e){return t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null}}function jwtHmac(e){return async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function jwtEcdsa(e){return async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function oidc(e){return async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function decodeUnverifiedJwtClaims(e){let n;try{n=decodeJwt(e)}catch{return null}return typeof n.iss!=`string`||n.iss.length===0?null:{audiences:typeof n.aud==`string`?[n.aud]:Array.isArray(n.aud)?n.aud.filter(e=>typeof e==`string`):[],issuer:n.iss}}export{createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,jwtEcdsa,jwtHmac,none,oidc,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc};
1
+ import{createLogger}from"#internal/logging.js";import{decodeJwt}from"#compiled/jose/index.js";import{authenticateHttpBasicStrategy}from"#runtime/governance/auth/http-basic.js";import{authenticateJwtEcdsaStrategy}from"#runtime/governance/auth/jwt-ecdsa.js";import{authenticateJwtHmacStrategy}from"#runtime/governance/auth/jwt-hmac.js";import{authenticateOidcStrategy}from"#runtime/governance/auth/oidc.js";import{createRuntimeSessionAuthContext}from"#runtime/governance/auth/types.js";import{createRuntimeIpAllowList,isRuntimeIpAllowed}from"#runtime/governance/network/ip-allow-list.js";const vercelOidcLog=createLogger(`auth.vercel-oidc`);function verifyHttpBasic(e,t){if(e===null)return{ok:!1};let r=authenticateHttpBasicStrategy({authorization:e,strategy:{kind:`http-basic`,password:t.password,username:t.username}});return r.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}:{ok:!1}}async function verifyJwtHmac(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtHmacStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-hmac`,secret:t.secret,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyJwtEcdsa(e,t){if(e===null||e.length===0)return{ok:!1};let n=await authenticateJwtEcdsaStrategy({strategy:{algorithm:t.algorithm,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,issuer:t.issuer,kind:`jwt-ecdsa`,publicKey:t.publicKey,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function verifyOidc(e,t){let n=await runOidcVerification(e,{...t,acceptCurrentVercelProject:!1});return n.kind===`authenticated`?{ok:!0,sessionAuth:createRuntimeSessionAuthContext(n.principal)}:{ok:!1}}async function runOidcVerification(e,t){return e===null||e.length===0?{kind:`not-authenticated`}:await authenticateOidcStrategy({strategy:{acceptCurrentVercelProject:t.acceptCurrentVercelProject,audiences:[...t.audiences],clockSkewSeconds:t.clockSkewSeconds??30,discoveryUrl:t.discoveryUrl??`${t.issuer.replace(/\/$/,``)}/.well-known/openid-configuration`,issuer:t.issuer,kind:`oidc`,...t.claims===void 0?{}:{claims:t.claims},...t.subjects===void 0?{}:{subjects:t.subjects}},token:e})}function extractBearerToken(e){if(e===null)return null;let t=/^Bearer\s+(.+)$/i.exec(e)?.[1]?.trim();return t===void 0||t.length===0?null:t}function createIpAllowList(e){return createRuntimeIpAllowList(e)}function isIpAllowed(e,t){return e===null?!1:isRuntimeIpAllowed(e,t)}function createUnauthorizedResponse(e={}){let t=e.status??401,n=e.code??(t===403?`forbidden`:`unauthorized`),r=e.message??(t===403?`Forbidden.`:`Authorization is required for this route.`),i=e.challenges??[],a=new Headers({"cache-control":`no-store`});for(let e of i)a.append(`www-authenticate`,formatChallenge(e));return Response.json({code:n,error:r,ok:!1},{headers:a,status:t})}function formatChallenge(e){if(e.parameters===void 0||Object.keys(e.parameters).length===0)return e.scheme;let t=Object.entries(e.parameters).map(([e,t])=>`${e}="${escapeChallengeValue(t)}"`).join(`, `);return`${e.scheme} ${t}`}function escapeChallengeValue(e){return e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`)}function none(){return()=>void 0}async function verifyVercelOidc(e,t={}){if(e===null||e.length===0)return vercelOidcLog.debug(`Rejected request without a bearer token.`),{ok:!1};let n=decodeUnverifiedJwtClaims(e);if(n===null)return vercelOidcLog.debug(`Rejected token that failed to decode as a JWT.`),{ok:!1};if(!n.issuer.startsWith(`https://oidc.vercel.com/`))return vercelOidcLog.debug(`Rejected token whose issuer is not a Vercel OIDC issuer.`,{issuer:n.issuer}),{ok:!1};if(n.audiences.length===0)return vercelOidcLog.debug(`Rejected token with no audience claim.`,{issuer:n.issuer}),{ok:!1};let r=await runOidcVerification(e,{acceptCurrentVercelProject:!0,audiences:n.audiences,issuer:n.issuer,subjects:t.subjects??[]});return r.kind===`authenticated`?(vercelOidcLog.debug(`Accepted Vercel OIDC token.`,{issuer:n.issuer,principalType:r.principal.principalType,subject:r.principal.subject}),{ok:!0,sessionAuth:createRuntimeSessionAuthContext(r.principal)}):(vercelOidcLog.debug(`Rejected Vercel OIDC token after verification.`,{audiences:n.audiences,issuer:n.issuer,reason:r.kind,subjectsConfigured:(t.subjects??[]).length>0,...r.kind===`misconfigured`?{detail:r.message}:{}}),{ok:!1})}function vercelSubject(e){assertVercelSubjectSegment(`teamSlug`,e.teamSlug),assertVercelSubjectSegment(`projectName`,e.projectName);let t=e.environment??`production`;if(t!==`production`&&t!==`preview`&&t!==`development`&&t!==`*`)throw Error(`vercelSubject: invalid environment ${JSON.stringify(t)}; expected "production", "preview", "development", or "*".`);return`owner:${e.teamSlug}:project:${e.projectName}:environment:${t}`}function assertVercelSubjectSegment(e,t){if(t.length===0)throw Error(`vercelSubject: ${e} must be a non-empty string.`);if(t.includes(`*`)||t.includes(`:`))throw Error(`vercelSubject: ${e} ${JSON.stringify(t)} may not contain ${t.includes(`:`)?`':'`:`'*'`}. Hand-write the subject string when wildcards are intentional.`)}function vercelOidc(e={}){return async t=>{let n=await verifyVercelOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function httpBasic(e){return t=>{let n=verifyHttpBasic(t.headers.get(`authorization`),e);return n.ok?n.sessionAuth:null}}function jwtHmac(e){return async t=>{let n=await verifyJwtHmac(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function jwtEcdsa(e){return async t=>{let n=await verifyJwtEcdsa(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function oidc(e){return async t=>{let n=await verifyOidc(extractBearerToken(t.headers.get(`authorization`)),e);return n.ok?n.sessionAuth:null}}function decodeUnverifiedJwtClaims(e){let n;try{n=decodeJwt(e)}catch{return null}return typeof n.iss!=`string`||n.iss.length===0?null:{audiences:typeof n.aud==`string`?[n.aud]:Array.isArray(n.aud)?n.aud.filter(e=>typeof e==`string`):[],issuer:n.iss}}export{createIpAllowList,createUnauthorizedResponse,extractBearerToken,httpBasic,isIpAllowed,jwtEcdsa,jwtHmac,none,oidc,vercelOidc,vercelSubject,verifyHttpBasic,verifyJwtEcdsa,verifyJwtHmac,verifyOidc,verifyVercelOidc};
@@ -1,2 +1,2 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{resolveDiscordPublicKey}from"#public/channels/discord/verify.js";var DISCORD_NO_MENTIONS={parse:[]},DISCORD_MESSAGE_CONTENT_MAX_LENGTH=2e3;function discordContinuationToken(e,t){return`${e}:${t??``}`}async function resolveDiscordApplicationId(e){let t=e??process.env.DISCORD_APPLICATION_ID;if(!t)throw Error(`DISCORD_APPLICATION_ID is required.`);return typeof t==`function`?await t():t}async function resolveDiscordBotToken(e){let t=e??process.env.DISCORD_BOT_TOKEN;if(!t)throw Error(`DISCORD_BOT_TOKEN is required.`);return typeof t==`function`?await t():t}async function callDiscordApi(e){let n=e.fetch??fetch,r=new Headers;if(r.set(`content-type`,`application/json; charset=utf-8`),e.botToken!==void 0){let t=await resolveDiscordBotToken(e.botToken);r.set(`authorization`,`Bot ${t}`)}let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${e.apiBaseUrl??`https://discord.com/api/v10`}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendDiscordChannelMessage(e){let t=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),botToken:e.credentials?.botToken,fetch:e.fetch,path:`/channels/${encodeURIComponent(e.channelId)}/messages`});if(!t.ok)throw Error(`Discord create message failed with HTTP ${t.status}.`);return toPostedMessage(t.body)}async function triggerDiscordTypingIndicator(e){let t=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,botToken:e.credentials?.botToken,fetch:e.fetch,path:`/channels/${encodeURIComponent(e.channelId)}/typing`});if(!t.ok)throw Error(`Discord typing indicator failed with HTTP ${t.status}.`)}async function editDiscordOriginalResponse(e){let t=await resolveDiscordApplicationId(e.credentials?.applicationId),n=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),fetch:e.fetch,method:`PATCH`,path:`/webhooks/${encodeURIComponent(t)}/${encodeURIComponent(e.interactionToken)}/messages/@original`});if(!n.ok)throw Error(`Discord edit original response failed with HTTP ${n.status}.`);return toPostedMessage(n.body)}async function createDiscordFollowupMessage(e){let t=await resolveDiscordApplicationId(e.credentials?.applicationId),n=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),fetch:e.fetch,path:`/webhooks/${encodeURIComponent(t)}/${encodeURIComponent(e.interactionToken)}`});if(!n.ok)throw Error(`Discord followup message failed with HTTP ${n.status}.`);return toPostedMessage(n.body)}function splitDiscordMessageContent(e){if(e.length<=2e3)return[e];let t=[],n=e;for(;n.length>DISCORD_MESSAGE_CONTENT_MAX_LENGTH;){let e=n.lastIndexOf(`
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{resolveDiscordPublicKey}from"#public/channels/discord/verify.js";const DISCORD_NO_MENTIONS={parse:[]},DISCORD_MESSAGE_CONTENT_MAX_LENGTH=2e3;function discordContinuationToken(e,t){return`${e}:${t??``}`}async function resolveDiscordApplicationId(e){let t=e??process.env.DISCORD_APPLICATION_ID;if(!t)throw Error(`DISCORD_APPLICATION_ID is required.`);return typeof t==`function`?await t():t}async function resolveDiscordBotToken(e){let t=e??process.env.DISCORD_BOT_TOKEN;if(!t)throw Error(`DISCORD_BOT_TOKEN is required.`);return typeof t==`function`?await t():t}async function callDiscordApi(e){let n=e.fetch??fetch,r=new Headers;if(r.set(`content-type`,`application/json; charset=utf-8`),e.botToken!==void 0){let t=await resolveDiscordBotToken(e.botToken);r.set(`authorization`,`Bot ${t}`)}let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${e.apiBaseUrl??`https://discord.com/api/v10`}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendDiscordChannelMessage(e){let t=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),botToken:e.credentials?.botToken,fetch:e.fetch,path:`/channels/${encodeURIComponent(e.channelId)}/messages`});if(!t.ok)throw Error(`Discord create message failed with HTTP ${t.status}.`);return toPostedMessage(t.body)}async function triggerDiscordTypingIndicator(e){let t=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,botToken:e.credentials?.botToken,fetch:e.fetch,path:`/channels/${encodeURIComponent(e.channelId)}/typing`});if(!t.ok)throw Error(`Discord typing indicator failed with HTTP ${t.status}.`)}async function editDiscordOriginalResponse(e){let t=await resolveDiscordApplicationId(e.credentials?.applicationId),n=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),fetch:e.fetch,method:`PATCH`,path:`/webhooks/${encodeURIComponent(t)}/${encodeURIComponent(e.interactionToken)}/messages/@original`});if(!n.ok)throw Error(`Discord edit original response failed with HTTP ${n.status}.`);return toPostedMessage(n.body)}async function createDiscordFollowupMessage(e){let t=await resolveDiscordApplicationId(e.credentials?.applicationId),n=await callDiscordApi({apiBaseUrl:e.apiBaseUrl,body:normalizeMessageBody(e.body),fetch:e.fetch,path:`/webhooks/${encodeURIComponent(t)}/${encodeURIComponent(e.interactionToken)}`});if(!n.ok)throw Error(`Discord followup message failed with HTTP ${n.status}.`);return toPostedMessage(n.body)}function splitDiscordMessageContent(e){if(e.length<=2e3)return[e];let t=[],n=e;for(;n.length>DISCORD_MESSAGE_CONTENT_MAX_LENGTH;){let e=n.lastIndexOf(`
2
2
  `,DISCORD_MESSAGE_CONTENT_MAX_LENGTH);e<=0&&(e=n.lastIndexOf(` `,DISCORD_MESSAGE_CONTENT_MAX_LENGTH)),e<=0&&(e=DISCORD_MESSAGE_CONTENT_MAX_LENGTH),t.push(n.slice(0,e).trimEnd()),n=n.slice(e).trimStart()}return t.push(n),t}function normalizeMessageBody(e){let n={...e};return n.allowed_mentions===void 0&&(n.allowed_mentions=DISCORD_NO_MENTIONS),parseJsonObject(n)}function toPostedMessage(e){let t=parseMaybeObject(e);return{channelId:typeof t.channel_id==`string`?t.channel_id:void 0,id:typeof t.id==`string`?t.id:``,raw:e}}function parseMaybeObject(t){return isObject(t)?t:{}}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{DISCORD_MESSAGE_CONTENT_MAX_LENGTH,DISCORD_NO_MENTIONS,callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,resolveDiscordApplicationId,resolveDiscordBotToken,resolveDiscordPublicKey,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator};
@@ -1,3 +1,3 @@
1
- import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{splitDiscordMessageContent}from"#public/channels/discord/api.js";import{renderInputRequestComponents}from"#public/channels/discord/hitl.js";function defaultDiscordAuth(e){let t={channel_id:e.channelId,interaction_id:e.id,user_id:e.user.id,username:e.user.username};return e.guildId!==void 0&&(t.guild_id=e.guildId),e.member?.nick!==void 0&&(t.member_nick=e.member.nick),{attributes:t,authenticator:`discord-interaction`,issuer:e.guildId?`discord:${e.guildId}`:`discord`,principalId:e.guildId?`discord:${e.guildId}:${e.user.id}`:`discord:${e.user.id}`,principalType:e.user.isBot?`service`:`user`}}function defaultOnCommand(e,t){return{auth:defaultDiscordAuth(t)}}var defaultEvents={async"turn.started"(e,t){await t.discord.startTyping()},async"actions.requested"(e,t){await t.discord.startTyping()},async"input.requested"(e,t){for(let i of e.requests){let e=splitDiscordMessageContent(i.prompt)[0]??i.prompt;await t.discord.post({components:renderInputRequestComponents(i),content:e})}},async"message.completed"(e,t){e.finishReason===`tool-calls`||!e.message||await t.discord.post(e.message)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.discord.post([`This session could not recover from an error${i}.`,``,`Start a new command to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
1
+ import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{splitDiscordMessageContent}from"#public/channels/discord/api.js";import{renderInputRequestComponents}from"#public/channels/discord/hitl.js";function defaultDiscordAuth(e){let t={channel_id:e.channelId,interaction_id:e.id,user_id:e.user.id,username:e.user.username};return e.guildId!==void 0&&(t.guild_id=e.guildId),e.member?.nick!==void 0&&(t.member_nick=e.member.nick),{attributes:t,authenticator:`discord-interaction`,issuer:e.guildId?`discord:${e.guildId}`:`discord`,principalId:e.guildId?`discord:${e.guildId}:${e.user.id}`:`discord:${e.user.id}`,principalType:e.user.isBot?`service`:`user`}}function defaultOnCommand(e,t){return{auth:defaultDiscordAuth(t)}}const defaultEvents={async"turn.started"(e,t){await t.discord.startTyping()},async"actions.requested"(e,t){await t.discord.startTyping()},async"input.requested"(e,t){for(let i of e.requests){let e=splitDiscordMessageContent(i.prompt)[0]??i.prompt;await t.discord.post({components:renderInputRequestComponents(i),content:e})}},async"message.completed"(e,t){e.finishReason===`tool-calls`||!e.message||await t.discord.post(e.message)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.discord.post([`This session could not recover from an error${i}.`,``,`Start a new command to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
2
2
  `))},async"turn.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.discord.post([`I hit an error while handling your request${i}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...a?[``,`Error id: ${a}`]:[]].join(`
3
3
  `))}};export{defaultDiscordAuth,defaultEvents,defaultOnCommand};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,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,parseDiscordInteraction,prependDiscordContext}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";var log=createLogger(`discord.channel`);function discordChannel(e={}){let i=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/ash/v1/discord`,async(n,{send:r,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:i,send:r,waitUntil:a})})],async receive(t,{send:n}){let r=t.args,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires args.channelId.`);let a=readString(r.conversationId),s=r.initialMessage;if(s!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(s!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(s);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}),session:t,state:e}}function buildDiscordHandle(e){let t=e.config.api,n=e.state,r=mergeCredentials(e.config.credentials,n);function anchor(t){!t.id||n.hasMessageAnchor||(n.conversationId=t.id,n.hasMessageAnchor=!0,n.channelId&&e.session?.setContinuationToken(discordContinuationToken(n.channelId,t.id)))}async function sendViaChannel(e){let i=n.channelId??``;if(!i)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,channelId:i});return anchor(a),a}async function editOriginal(e){let i=n.interactionToken??``;if(!i)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,interactionToken:i});return n.initialResponseSent=!0,anchor(a),a}async function followup(e){let i=n.interactionToken??``;if(!i)throw Error(`discordChannel: missing interaction token for followup message.`);let o=await createDiscordFollowupMessage({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,interactionToken:i});return anchor(o),o}async function startTyping(){let e=n.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:t?.apiBaseUrl,credentials:r,fetch:t?.fetch,channelId:e})}catch(e){log.debug(`Discord typing indicator failed — swallowed`,{error:e})}}return{applicationId:n.applicationId??void 0,channelId:n.channelId??``,conversationId:n.conversationId??``,guildId:n.guildId??void 0,interactionToken:n.interactionToken??void 0,request(e,n,a){return callDiscordApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:a?.botAuth===!0?r.botToken:void 0,fetch:t?.fetch,method:a?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),r;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:n});r===void 0&&(r=t)}return r??{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=prependDiscordContext(commandInteractionMessage(e.interaction),{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});try{await e.send({message:t,modelContext:e.result.modelContext},{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,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}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,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,parseDiscordInteraction,prependDiscordContext}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 i=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/ash/v1/discord`,async(n,{send:r,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:i,send:r,waitUntil:a})})],async receive(t,{send:n}){let r=t.args,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires args.channelId.`);let a=readString(r.conversationId),s=r.initialMessage;if(s!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(s!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(s);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}),session:t,state:e}}function buildDiscordHandle(e){let t=e.config.api,n=e.state,r=mergeCredentials(e.config.credentials,n);function anchor(t){!t.id||n.hasMessageAnchor||(n.conversationId=t.id,n.hasMessageAnchor=!0,n.channelId&&e.session?.setContinuationToken(discordContinuationToken(n.channelId,t.id)))}async function sendViaChannel(e){let i=n.channelId??``;if(!i)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,channelId:i});return anchor(a),a}async function editOriginal(e){let i=n.interactionToken??``;if(!i)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,interactionToken:i});return n.initialResponseSent=!0,anchor(a),a}async function followup(e){let i=n.interactionToken??``;if(!i)throw Error(`discordChannel: missing interaction token for followup message.`);let o=await createDiscordFollowupMessage({apiBaseUrl:t?.apiBaseUrl,body:normalizePostInput(e),credentials:r,fetch:t?.fetch,interactionToken:i});return anchor(o),o}async function startTyping(){let e=n.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:t?.apiBaseUrl,credentials:r,fetch:t?.fetch,channelId:e})}catch(e){log.debug(`Discord typing indicator failed — swallowed`,{error:e})}}return{applicationId:n.applicationId??void 0,channelId:n.channelId??``,conversationId:n.conversationId??``,guildId:n.guildId??void 0,interactionToken:n.interactionToken??void 0,request(e,n,a){return callDiscordApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:a?.botAuth===!0?r.botToken:void 0,fetch:t?.fetch,method:a?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),r;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:n});r===void 0&&(r=t)}return r??{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=prependDiscordContext(commandInteractionMessage(e.interaction),{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});try{await e.send({message:t,modelContext:e.result.modelContext},{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,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 +1 @@
1
- import{DISCORD_INTERACTION_RESPONSE_TYPE}from"#public/channels/discord/inbound.js";var DISCORD_COMPONENT_TYPE={ACTION_ROW:1,BUTTON:2,STRING_SELECT:3,TEXT_INPUT:4},DISCORD_HITL_CUSTOM_ID_PREFIX=`ash_input:`,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX=`ash_input_freeform:`,DISCORD_HITL_FREEFORM_TEXT_INPUT_ID=`ash_freeform_text`,DISCORD_CUSTOM_ID_MAX_LENGTH=100,DISCORD_LABEL_MAX_LENGTH=80,DISCORD_SELECT_OPTION_TEXT_MAX_LENGTH=100,DISCORD_MODAL_TITLE_MAX_LENGTH=45,DISCORD_ACTION_ROW_LIMIT=5,DISCORD_SELECT_OPTION_LIMIT=25;function renderInputRequestComponents(e){let i=e.options,a=e.allowFreeform===!0||!i||i.length===0;return i&&i.length>0&&e.display===`select`?[{components:[{custom_id:encodeHitlCustomId(DISCORD_HITL_CUSTOM_ID_PREFIX,{requestId:e.requestId}),options:i.slice(0,DISCORD_SELECT_OPTION_LIMIT).map(e=>{let t={label:truncate(e.label,DISCORD_SELECT_OPTION_TEXT_MAX_LENGTH),value:truncate(e.id,DISCORD_SELECT_OPTION_TEXT_MAX_LENGTH)};return e.description!==void 0&&(t.description=truncate(e.description,DISCORD_SELECT_OPTION_TEXT_MAX_LENGTH)),t}),placeholder:`Choose an option`,type:DISCORD_COMPONENT_TYPE.STRING_SELECT}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}]:i&&i.length>0?chunk(i.slice(0,DISCORD_ACTION_ROW_LIMIT*DISCORD_ACTION_ROW_LIMIT),5).map(r=>({components:r.map(r=>({custom_id:encodeHitlCustomId(DISCORD_HITL_CUSTOM_ID_PREFIX,{optionId:r.id,requestId:e.requestId}),label:truncate(r.label,DISCORD_LABEL_MAX_LENGTH),style:toDiscordButtonStyle(r.style),type:DISCORD_COMPONENT_TYPE.BUTTON})),type:DISCORD_COMPONENT_TYPE.ACTION_ROW})):a?[{components:[{custom_id:encodeHitlCustomId(DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,{requestId:e.requestId}),label:`Type your answer`,style:1,type:DISCORD_COMPONENT_TYPE.BUTTON}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}]:[]}function buildFreeformModalResponse(n){let a=decodeHitlCustomId(n.customId,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX);if(!a)throw Error(`discordChannel: freeform custom_id is malformed.`);return{data:{components:[{components:[{custom_id:DISCORD_HITL_FREEFORM_TEXT_INPUT_ID,label:`Answer`,max_length:4e3,min_length:1,placeholder:`Type your answer here...`,required:!0,style:2,type:DISCORD_COMPONENT_TYPE.TEXT_INPUT}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}],custom_id:encodeHitlCustomId(DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,{requestId:a.requestId}),title:truncate(n.prompt??`Your answer`,DISCORD_MODAL_TITLE_MAX_LENGTH)},type:DISCORD_INTERACTION_RESPONSE_TYPE.MODAL}}function isDiscordFreeformComponent(e){return decodeHitlCustomId(e,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX)!==null}function deriveComponentInputResponses(e){let t=decodeHitlCustomId(e.customId,DISCORD_HITL_CUSTOM_ID_PREFIX);if(!t)return[];if(t.optionId!==void 0)return[{optionId:t.optionId,requestId:t.requestId}];let r=e.values[0];return r===void 0?[]:[{optionId:r,requestId:t.requestId}]}function deriveModalInputResponses(e){let t=decodeHitlCustomId(e.customId,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX),n=e.textInputs[DISCORD_HITL_FREEFORM_TEXT_INPUT_ID];return!t||n===void 0?[]:[{requestId:t.requestId,text:n}]}function encodeHitlCustomId(e,t){let n=`${e}${Buffer.from(JSON.stringify(t),`utf8`).toString(`base64url`)}`;if(n.length>DISCORD_CUSTOM_ID_MAX_LENGTH)throw Error(`discordChannel: HITL custom_id exceeded Discord's 100-character limit.`);return n}function decodeHitlCustomId(e,t){if(!e.startsWith(t))return null;try{let n=Buffer.from(e.slice(t.length),`base64url`).toString(`utf8`),r=JSON.parse(n);if(typeof r.requestId!=`string`||r.requestId.length===0)return null;let i={requestId:r.requestId};return typeof r.optionId==`string`?{...i,optionId:r.optionId}:i}catch{return null}}function toDiscordButtonStyle(e){return e===`primary`?1:e===`danger`?4:2}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function chunk(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}export{DISCORD_COMPONENT_TYPE,DISCORD_HITL_CUSTOM_ID_PREFIX,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,DISCORD_HITL_FREEFORM_TEXT_INPUT_ID,buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent,renderInputRequestComponents};
1
+ import{DISCORD_INTERACTION_RESPONSE_TYPE}from"#public/channels/discord/inbound.js";const DISCORD_COMPONENT_TYPE={ACTION_ROW:1,BUTTON:2,STRING_SELECT:3,TEXT_INPUT:4},DISCORD_HITL_CUSTOM_ID_PREFIX=`ash_input:`,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX=`ash_input_freeform:`,DISCORD_HITL_FREEFORM_TEXT_INPUT_ID=`ash_freeform_text`;function renderInputRequestComponents(e){let i=e.options,a=e.allowFreeform===!0||!i||i.length===0;return i&&i.length>0&&e.display===`select`?[{components:[{custom_id:encodeHitlCustomId(DISCORD_HITL_CUSTOM_ID_PREFIX,{requestId:e.requestId}),options:i.slice(0,25).map(e=>{let t={label:truncate(e.label,100),value:truncate(e.id,100)};return e.description!==void 0&&(t.description=truncate(e.description,100)),t}),placeholder:`Choose an option`,type:DISCORD_COMPONENT_TYPE.STRING_SELECT}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}]:i&&i.length>0?chunk(i.slice(0,25),5).map(r=>({components:r.map(r=>({custom_id:encodeHitlCustomId(DISCORD_HITL_CUSTOM_ID_PREFIX,{optionId:r.id,requestId:e.requestId}),label:truncate(r.label,80),style:toDiscordButtonStyle(r.style),type:DISCORD_COMPONENT_TYPE.BUTTON})),type:DISCORD_COMPONENT_TYPE.ACTION_ROW})):a?[{components:[{custom_id:encodeHitlCustomId(DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,{requestId:e.requestId}),label:`Type your answer`,style:1,type:DISCORD_COMPONENT_TYPE.BUTTON}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}]:[]}function buildFreeformModalResponse(n){let a=decodeHitlCustomId(n.customId,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX);if(!a)throw Error(`discordChannel: freeform custom_id is malformed.`);return{data:{components:[{components:[{custom_id:DISCORD_HITL_FREEFORM_TEXT_INPUT_ID,label:`Answer`,max_length:4e3,min_length:1,placeholder:`Type your answer here...`,required:!0,style:2,type:DISCORD_COMPONENT_TYPE.TEXT_INPUT}],type:DISCORD_COMPONENT_TYPE.ACTION_ROW}],custom_id:encodeHitlCustomId(DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,{requestId:a.requestId}),title:truncate(n.prompt??`Your answer`,45)},type:DISCORD_INTERACTION_RESPONSE_TYPE.MODAL}}function isDiscordFreeformComponent(e){return decodeHitlCustomId(e,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX)!==null}function deriveComponentInputResponses(e){let t=decodeHitlCustomId(e.customId,DISCORD_HITL_CUSTOM_ID_PREFIX);if(!t)return[];if(t.optionId!==void 0)return[{optionId:t.optionId,requestId:t.requestId}];let r=e.values[0];return r===void 0?[]:[{optionId:r,requestId:t.requestId}]}function deriveModalInputResponses(e){let t=decodeHitlCustomId(e.customId,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX),n=e.textInputs[DISCORD_HITL_FREEFORM_TEXT_INPUT_ID];return!t||n===void 0?[]:[{requestId:t.requestId,text:n}]}function encodeHitlCustomId(e,t){let n=`${e}${Buffer.from(JSON.stringify(t),`utf8`).toString(`base64url`)}`;if(n.length>100)throw Error(`discordChannel: HITL custom_id exceeded Discord's 100-character limit.`);return n}function decodeHitlCustomId(e,t){if(!e.startsWith(t))return null;try{let n=Buffer.from(e.slice(t.length),`base64url`).toString(`utf8`),r=JSON.parse(n);if(typeof r.requestId!=`string`||r.requestId.length===0)return null;let i={requestId:r.requestId};return typeof r.optionId==`string`?{...i,optionId:r.optionId}:i}catch{return null}}function toDiscordButtonStyle(e){return e===`primary`?1:e===`danger`?4:2}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function chunk(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}export{DISCORD_COMPONENT_TYPE,DISCORD_HITL_CUSTOM_ID_PREFIX,DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX,DISCORD_HITL_FREEFORM_TEXT_INPUT_ID,buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent,renderInputRequestComponents};
@@ -1,2 +1,2 @@
1
- import{isNonEmptyString,isObject}from"#shared/guards.js";var DISCORD_INTERACTION_TYPE={APPLICATION_COMMAND:2,MESSAGE_COMPONENT:3,MODAL_SUBMIT:5,PING:1},DISCORD_INTERACTION_RESPONSE_TYPE={CHANNEL_MESSAGE_WITH_SOURCE:4,DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE:5,DEFERRED_UPDATE_MESSAGE:6,MODAL:9,PONG:1},DISCORD_EPHEMERAL_MESSAGE_FLAG=64,DISCORD_RESPONSE_INSTRUCTIONS=`Reply for Discord in concise Markdown. Avoid mass mentions, long tables, and messages that need more than a few short posts.`;function parseDiscordInteraction(e){if(!isObject(e))return null;let r=e.type;return r===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?parseCommandInteraction(e):r===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?parseComponentInteraction(e):r===DISCORD_INTERACTION_TYPE.MODAL_SUBMIT?parseModalSubmitInteraction(e):null}function commandInteractionMessage(e){let t=findOptionValue(e.options,`message`);if(typeof t==`string`&&t.trim().length>0)return t;let n=formatCommandOptions(e.options);return n?`/${e.commandName} ${n}`:`/${e.commandName}`}function formatDiscordContextBlock(e){return[`<discord_context>`,`response_medium: discord`,`response_instructions: ${DISCORD_RESPONSE_INSTRUCTIONS}`,`user_id: ${e.userId}`,...e.username?[`username: ${e.username}`]:[],`channel_id: ${e.channelId}`,...e.guildId?[`guild_id: ${e.guildId}`]:[],`interaction_id: ${e.interactionId}`,...e.commandName?[`command_name: ${e.commandName}`]:[],`</discord_context>`].join(`
1
+ import{isNonEmptyString,isObject}from"#shared/guards.js";const DISCORD_INTERACTION_TYPE={APPLICATION_COMMAND:2,MESSAGE_COMPONENT:3,MODAL_SUBMIT:5,PING:1},DISCORD_INTERACTION_RESPONSE_TYPE={CHANNEL_MESSAGE_WITH_SOURCE:4,DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE:5,DEFERRED_UPDATE_MESSAGE:6,MODAL:9,PONG:1},DISCORD_EPHEMERAL_MESSAGE_FLAG=64;function parseDiscordInteraction(e){if(!isObject(e))return null;let r=e.type;return r===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?parseCommandInteraction(e):r===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?parseComponentInteraction(e):r===DISCORD_INTERACTION_TYPE.MODAL_SUBMIT?parseModalSubmitInteraction(e):null}function commandInteractionMessage(e){let t=findOptionValue(e.options,`message`);if(typeof t==`string`&&t.trim().length>0)return t;let n=formatCommandOptions(e.options);return n?`/${e.commandName} ${n}`:`/${e.commandName}`}function formatDiscordContextBlock(e){return[`<discord_context>`,`response_medium: discord`,`response_instructions: Reply for Discord in concise Markdown. Avoid mass mentions, long tables, and messages that need more than a few short posts.`,`user_id: ${e.userId}`,...e.username?[`username: ${e.username}`]:[],`channel_id: ${e.channelId}`,...e.guildId?[`guild_id: ${e.guildId}`]:[],`interaction_id: ${e.interactionId}`,...e.commandName?[`command_name: ${e.commandName}`]:[],`</discord_context>`].join(`
2
2
  `)}function prependDiscordContext(e,t){let n=formatDiscordContextBlock(t);return typeof e==`string`?e.length>0?`${n}\n\n${e}`:n:[{type:`text`,text:n},...e]}function parseCommandInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;return!i||!a||!isNonEmptyString(a.name)?null:{...i,commandId:isNonEmptyString(a.id)?a.id:void 0,commandName:a.name,options:parseOptions(a.options),type:DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND}}function parseComponentInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null,o=isObject(r.message)?r.message:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let s=isNonEmptyString(o?.id)?o.id:``;return s?{...i,componentType:typeof a.component_type==`number`?a.component_type:0,customId:a.custom_id,messageId:s,type:DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT,values:Array.isArray(a.values)?a.values.filter(e=>typeof e==`string`):[]}:null}function parseModalSubmitInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let o=isObject(r.message)?r.message:null;return{...i,customId:a.custom_id,messageId:isNonEmptyString(o?.id)?o.id:void 0,textInputs:parseTextInputs(a.components),type:DISCORD_INTERACTION_TYPE.MODAL_SUBMIT}}function parseInteractionBase(t){if(!isNonEmptyString(t.id)||!isNonEmptyString(t.application_id)||!isNonEmptyString(t.channel_id)||!isNonEmptyString(t.token))return null;let n=parseInteractionUser(t);return n?{applicationId:t.application_id,channelId:t.channel_id,guildId:isNonEmptyString(t.guild_id)?t.guild_id:void 0,id:t.id,member:parseMember(t.member),raw:t,token:t.token,user:n}:null}function parseInteractionUser(e){return parseUser(e.user)||(parseMember(e.member)?.user??null)}function parseMember(n){if(!isObject(n))return;let r=parseUser(n.user);if(r)return{nick:isNonEmptyString(n.nick)?n.nick:void 0,roles:Array.isArray(n.roles)?n.roles.filter(e=>typeof e==`string`):[],user:r}}function parseUser(n){return!isObject(n)||!isNonEmptyString(n.id)||!isNonEmptyString(n.username)?null:{avatar:isNonEmptyString(n.avatar)?n.avatar:void 0,discriminator:isNonEmptyString(n.discriminator)?n.discriminator:void 0,globalName:isNonEmptyString(n.global_name)?n.global_name:void 0,id:n.id,isBot:n.bot===!0,username:n.username}}function parseOptions(n){if(!Array.isArray(n))return[];let r=[];for(let i of n){if(!isObject(i)||!isNonEmptyString(i.name))continue;let n={name:i.name,options:parseOptions(i.options),value:parseOptionValue(i.value)};r.push(n)}return r}function parseOptionValue(e){if(typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e}function parseTextInputs(n){let r={};if(!Array.isArray(n))return r;for(let i of n)if(!(!isObject(i)||!Array.isArray(i.components)))for(let n of i.components)isObject(n)&&isNonEmptyString(n.custom_id)&&typeof n.value==`string`&&(r[n.custom_id]=n.value);return r}function findOptionValue(e,t){for(let n of e){if(n.name===t&&n.value!==void 0)return n.value;let e=findOptionValue(n.options,t);if(e!==void 0)return e}}function formatCommandOptions(e){return e.map(formatOption).filter(e=>e.length>0).join(` `)}function formatOption(e){if(e.value!==void 0)return`${e.name}:${String(e.value)}`;let t=formatCommandOptions(e.options);return t?`${e.name} ${t}`:e.name}export{DISCORD_EPHEMERAL_MESSAGE_FLAG,DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction,prependDiscordContext};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{createPublicKey,verify}from"node:crypto";var 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{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 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{verifyDiscordRequest}from"#public/channels/discord/verify.js";var log=createLogger(`discord.channel`);async function verifyDiscordInbound(e,t){try{return await verifyDiscordRequest(e,{publicKey:t?.webhookVerifier?void 0:t?.publicKey,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`discord inbound verification failed`,{error:e}),null}}export{verifyDiscordInbound};
1
+ import{createLogger}from"#internal/logging.js";import{verifyDiscordRequest}from"#public/channels/discord/verify.js";const log=createLogger(`discord.channel`);async function verifyDiscordInbound(e,t){try{return await verifyDiscordRequest(e,{publicKey:t?.webhookVerifier?void 0:t?.publicKey,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`discord inbound verification failed`,{error:e}),null}}export{verifyDiscordInbound};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isCardElement}from"#compiled/chat/index.js";import{encodeSlackApiBody}from"#public/channels/slack/api-encoding.js";import{cardToBlocks,cardToFallbackText}from"#public/channels/slack/blocks.js";import{gfmToSlackMrkdwn,rewriteBareMentions,slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";var log=createLogger(`slack.api`);function slackContinuationToken(e,t){return`${e}:${t}`}async function resolveSlackBotToken(e){let t=e??process.env.SLACK_BOT_TOKEN;if(!t)throw Error(`SLACK_BOT_TOKEN is required.`);return typeof t==`function`?await t():t}async function callSlackApi(e){let t=await resolveSlackBotToken(e.botToken),r=encodeSlackApiBody(e.body);return(await fetch(`https://slack.com/api/${e.operation}`,{method:`POST`,headers:{authorization:`Bearer ${t}`,"content-type":r.contentType},body:r.body})).json()}function createSlackRequester(e){return(t,n)=>callSlackApi({botToken:e,operation:t,body:n})}function buildSlackBinding(e){let t=createSlackRequester(e.botToken),n=[],r=e.threadTs;function handleMessageTs(t){r||t===r||(r=t,e.onThreadTsChanged?.(t))}async function uploadFiles(t,n){if(t.length===0)return{fileIds:[],raw:{ok:!0}};let i=n?.channelId??e.channelId,a=n?.threadTs??r,o=await resolveSlackBotToken(e.botToken),s=[];for(let n of t){let t=await readFileBytes(n.data),r=await callSlackApi({botToken:e.botToken,operation:`files.getUploadURLExternal`,body:{filename:n.filename,length:t.byteLength}});if(r.ok!==!0||typeof r.upload_url!=`string`||typeof r.file_id!=`string`)throw Error(`Slack files.getUploadURLExternal failed: ${r.error??`unknown_error`}`);let i=await fetch(r.upload_url,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/octet-stream`},body:t});if(!i.ok)throw Error(`Slack upload POST returned HTTP ${i.status} for ${n.filename}.`);s.push(r.file_id)}let c={files:t.map((e,t)=>({id:s[t],title:e.filename}))};i&&(c.channel_id=i),a&&(c.thread_ts=a),n?.initialComment&&(c.initial_comment=n.initialComment);let l=await callSlackApi({botToken:e.botToken,operation:`files.completeUploadExternal`,body:c});if(l.ok!==!0)throw Error(`Slack files.completeUploadExternal failed: ${l.error??`unknown_error`}`);return{fileIds:s,raw:l}}return{thread:{recentMessages:n,async post(n){let i=normalizePostInput(n),s=i.files??[],l=`blocks`in i||`card`in i;if(s.length>0&&!l){let e=await uploadFiles(s,{initialComment:`markdown`in i?rewriteBareMentions(gfmToSlackMrkdwn(i.markdown)):`text`in i?rewriteBareMentions(i.text):void 0});return{id:Array.isArray(e.raw.files)&&e.raw.files.length>0?String(e.raw.files[0].id??``):``,raw:e.raw}}let u=await t(`chat.postMessage`,buildPostMessageBody(i,e.channelId,r));if(u.ok!==!0)throw Error(`Slack chat.postMessage failed: ${u.error??`unknown_error`}`);let d=typeof u.ts==`string`?u.ts:``;if(handleMessageTs(d),s.length>0&&l)try{await uploadFiles(s)}catch(e){log.warn(`file upload after structured post failed`,{error:e})}return{id:d,raw:u}},async postEphemeral(n,i){let a=buildPostMessageBody(normalizePostInput(i),e.channelId,r);a.user=n;let o=await t(`chat.postEphemeral`,a);if(o.ok!==!0)throw Error(`Slack chat.postEphemeral failed: ${o.error??`unknown_error`}`);return{id:typeof o.message_ts==`string`?o.message_ts:``,raw:o}},async startTyping(n){if(!(!e.channelId||!r))try{let i={channel_id:e.channelId,thread_ts:r,status:n??``};n!==void 0&&n.length>0&&(i.loading_messages=[n]);let a=await t(`assistant.threads.setStatus`,i);a.ok!==!0&&log.debug(`assistant.threads.setStatus returned not-ok`,{error:a.error})}catch(e){log.debug(`startTyping threw — swallowed`,{error:e})}},async refresh(){if(n.length=0,!(!e.channelId||!r))try{let i=await t(`conversations.replies`,{channel:e.channelId,ts:r,limit:50});if(i.ok!==!0||!Array.isArray(i.messages)){log.debug(`conversations.replies returned not-ok`,{error:i.error});return}for(let e of i.messages)n.push(parseThreadMessage(e,r))}catch(e){log.debug(`refresh threw — swallowed`,{error:e})}},mentionUser(e){return`<@${e}>`}},slack:{channelId:e.channelId,get threadTs(){return r},teamId:e.teamId,request:t,uploadFiles}}}function normalizePostInput(e){return typeof e==`string`?{markdown:e}:isCardElement(e)?{card:e}:e}function buildPostMessageBody(e,t,n){let a={channel:t,unfurl_links:!1,unfurl_media:!1};return n&&(a.thread_ts=n),`card`in e?(a.blocks=cardToBlocks(e.card),a.text=e.fallbackText??cardToFallbackText(e.card),a):`blocks`in e?(a.blocks=e.blocks,e.text!==void 0&&(a.text=e.text),a):`markdown`in e?(a.markdown_text=rewriteBareMentions(e.markdown),a):(a.text=rewriteBareMentions(e.text),a)}function parseThreadMessage(e,t){let n=typeof e.text==`string`?e.text:``,r=typeof e.ts==`string`?e.ts:``,i=typeof e.thread_ts==`string`?e.thread_ts:t,a=typeof e.user==`string`?e.user:void 0,o=typeof e.bot_id==`string`?e.bot_id:void 0;return{text:n,markdown:slackMrkdwnToGfm(n),user:a,botId:o,ts:r,threadTs:i,isMe:o!==void 0,raw:e}}async function readFileBytes(e){if(e instanceof ArrayBuffer)return Buffer.from(e);if(typeof Blob<`u`&&e instanceof Blob)return Buffer.from(await e.arrayBuffer());if(ArrayBuffer.isView(e)){let t=e;return Buffer.from(t.buffer,t.byteOffset,t.byteLength)}throw Error(`FileUpload.data must be a Buffer, ArrayBuffer, or Blob.`)}export{buildSlackBinding,callSlackApi,resolveSlackBotToken,slackContinuationToken};
1
+ import{createLogger}from"#internal/logging.js";import{isCardElement}from"#compiled/chat/index.js";import{encodeSlackApiBody}from"#public/channels/slack/api-encoding.js";import{cardToBlocks,cardToFallbackText}from"#public/channels/slack/blocks.js";import{gfmToSlackMrkdwn,rewriteBareMentions,slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";const log=createLogger(`slack.api`);function slackContinuationToken(e,t){return`${e}:${t}`}async function resolveSlackBotToken(e){let t=e??process.env.SLACK_BOT_TOKEN;if(!t)throw Error(`SLACK_BOT_TOKEN is required.`);return typeof t==`function`?await t():t}async function callSlackApi(e){let t=await resolveSlackBotToken(e.botToken),r=encodeSlackApiBody(e.body);return(await fetch(`https://slack.com/api/${e.operation}`,{method:`POST`,headers:{authorization:`Bearer ${t}`,"content-type":r.contentType},body:r.body})).json()}function createSlackRequester(e){return(t,n)=>callSlackApi({botToken:e,operation:t,body:n})}function buildSlackBinding(e){let t=createSlackRequester(e.botToken),n=[],r=e.threadTs;function handleMessageTs(t){r||t===r||(r=t,e.onThreadTsChanged?.(t))}async function uploadFiles(t,n){if(t.length===0)return{fileIds:[],raw:{ok:!0}};let i=n?.channelId??e.channelId,a=n?.threadTs??r,o=await resolveSlackBotToken(e.botToken),s=[];for(let n of t){let t=await readFileBytes(n.data),r=await callSlackApi({botToken:e.botToken,operation:`files.getUploadURLExternal`,body:{filename:n.filename,length:t.byteLength}});if(r.ok!==!0||typeof r.upload_url!=`string`||typeof r.file_id!=`string`)throw Error(`Slack files.getUploadURLExternal failed: ${r.error??`unknown_error`}`);let i=await fetch(r.upload_url,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/octet-stream`},body:t});if(!i.ok)throw Error(`Slack upload POST returned HTTP ${i.status} for ${n.filename}.`);s.push(r.file_id)}let c={files:t.map((e,t)=>({id:s[t],title:e.filename}))};i&&(c.channel_id=i),a&&(c.thread_ts=a),n?.initialComment&&(c.initial_comment=n.initialComment);let l=await callSlackApi({botToken:e.botToken,operation:`files.completeUploadExternal`,body:c});if(l.ok!==!0)throw Error(`Slack files.completeUploadExternal failed: ${l.error??`unknown_error`}`);return{fileIds:s,raw:l}}return{thread:{recentMessages:n,async post(n){let i=normalizePostInput(n),s=i.files??[],l=`blocks`in i||`card`in i;if(s.length>0&&!l){let e=await uploadFiles(s,{initialComment:`markdown`in i?rewriteBareMentions(gfmToSlackMrkdwn(i.markdown)):`text`in i?rewriteBareMentions(i.text):void 0});return{id:Array.isArray(e.raw.files)&&e.raw.files.length>0?String(e.raw.files[0].id??``):``,raw:e.raw}}let u=await t(`chat.postMessage`,buildPostMessageBody(i,e.channelId,r));if(u.ok!==!0)throw Error(`Slack chat.postMessage failed: ${u.error??`unknown_error`}`);let d=typeof u.ts==`string`?u.ts:``;if(handleMessageTs(d),s.length>0&&l)try{await uploadFiles(s)}catch(e){log.warn(`file upload after structured post failed`,{error:e})}return{id:d,raw:u}},async postEphemeral(n,i){let a=buildPostMessageBody(normalizePostInput(i),e.channelId,r);a.user=n;let o=await t(`chat.postEphemeral`,a);if(o.ok!==!0)throw Error(`Slack chat.postEphemeral failed: ${o.error??`unknown_error`}`);return{id:typeof o.message_ts==`string`?o.message_ts:``,raw:o}},async startTyping(n){if(!(!e.channelId||!r))try{let i={channel_id:e.channelId,thread_ts:r,status:n??``};n!==void 0&&n.length>0&&(i.loading_messages=[n]);let a=await t(`assistant.threads.setStatus`,i);a.ok!==!0&&log.debug(`assistant.threads.setStatus returned not-ok`,{error:a.error})}catch(e){log.debug(`startTyping threw — swallowed`,{error:e})}},async refresh(){if(n.length=0,!(!e.channelId||!r))try{let i=await t(`conversations.replies`,{channel:e.channelId,ts:r,limit:50});if(i.ok!==!0||!Array.isArray(i.messages)){log.debug(`conversations.replies returned not-ok`,{error:i.error});return}for(let e of i.messages)n.push(parseThreadMessage(e,r))}catch(e){log.debug(`refresh threw — swallowed`,{error:e})}},mentionUser(e){return`<@${e}>`}},slack:{channelId:e.channelId,get threadTs(){return r},teamId:e.teamId,request:t,uploadFiles}}}function normalizePostInput(e){return typeof e==`string`?{markdown:e}:isCardElement(e)?{card:e}:e}function buildPostMessageBody(e,t,n){let a={channel:t,unfurl_links:!1,unfurl_media:!1};return n&&(a.thread_ts=n),`card`in e?(a.blocks=cardToBlocks(e.card),a.text=e.fallbackText??cardToFallbackText(e.card),a):`blocks`in e?(a.blocks=e.blocks,e.text!==void 0&&(a.text=e.text),a):`markdown`in e?(a.markdown_text=rewriteBareMentions(e.markdown),a):(a.text=rewriteBareMentions(e.text),a)}function parseThreadMessage(e,t){let n=typeof e.text==`string`?e.text:``,r=typeof e.ts==`string`?e.ts:``,i=typeof e.thread_ts==`string`?e.thread_ts:t,a=typeof e.user==`string`?e.user:void 0,o=typeof e.bot_id==`string`?e.bot_id:void 0;return{text:n,markdown:slackMrkdwnToGfm(n),user:a,botId:o,ts:r,threadTs:i,isMe:o!==void 0,raw:e}}async function readFileBytes(e){if(e instanceof ArrayBuffer)return Buffer.from(e);if(typeof Blob<`u`&&e instanceof Blob)return Buffer.from(await e.arrayBuffer());if(ArrayBuffer.isView(e)){let t=e;return Buffer.from(t.buffer,t.byteOffset,t.byteLength)}throw Error(`FileUpload.data must be a Buffer, ArrayBuffer, or Blob.`)}export{buildSlackBinding,callSlackApi,resolveSlackBotToken,slackContinuationToken};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{evaluateFilePart,formatUploadPolicyViolation,isUploadsDisabled}from"#public/channels/upload-policy.js";import{resolveSlackBotToken}from"#public/channels/slack/api.js";var log=createLogger(`slack.attachments`);function collectSlackFileParts(e,r){let i=[];for(let o of e??[]){let e=toSlackFilePart(o,i.length);if(e===null)continue;let s=evaluateFilePart(e,r);if(s!==null){log.warn(`dropped attachment — ${formatUploadPolicyViolation(s)}`,{name:o.name});continue}i.push(e)}return i}function toSlackFilePart(e,t){return e.type===`audio`||e.type===`video`?null:e.url?{type:`file`,mediaType:e.mimeType??`application/octet-stream`,filename:e.name??`attachment-${t}`,data:new URL(e.url)}:(log.warn(`dropped attachment — no url available`,{name:e.name}),null)}async function collectInboundFileParts(e){let t=collectSlackFileParts(e.mention.attachments,e.policy);if(t.length>0)return t;if(isUploadsDisabled(e.policy))return[];try{await e.thread.refresh()}catch(e){return log.warn(`slack thread refresh failed for attachment collection`,{error:e}),[]}let n=e.thread.recentMessages;for(let t=n.length-1;t>=0;--t){let r=n[t];if(!r||r.isMe)continue;let i=r.raw,a=collectSlackFileParts(extractAttachmentsFromRaw(i?.files),e.policy);return a.length>0?a:[]}return[]}function extractAttachmentsFromRaw(e){return Array.isArray(e)?e.map(e=>{let t=typeof e.mimetype==`string`?e.mimetype:void 0;return{id:typeof e.id==`string`?e.id:``,type:inferAttachmentType(t),url:typeof e.url_private==`string`?e.url_private:void 0,name:typeof e.name==`string`?e.name:void 0,mimeType:t,size:typeof e.size==`number`?e.size:void 0}}):[]}function inferAttachmentType(e){return e===void 0?`file`:e.startsWith(`image/`)?`image`:e.startsWith(`video/`)?`video`:e.startsWith(`audio/`)?`audio`:`file`}function buildSlackTurnMessage(e,t){return t.length===0?e:e.trim().length===0?[...t]:[{type:`text`,text:e},...t]}function createSlackFetchFile(e){return async t=>{if(!t.startsWith(`https://files.slack.com/`))return null;let n=await resolveSlackBotToken(e.botToken),r=await fetch(t,{headers:{authorization:`Bearer ${n}`}});if(!r.ok)throw Error(`Slack file fetch returned HTTP ${r.status} for ${t}.`);return{bytes:Buffer.from(await r.arrayBuffer()),mediaType:r.headers.get(`content-type`)??void 0}}}export{buildSlackTurnMessage,collectInboundFileParts,collectSlackFileParts,createSlackFetchFile};
1
+ import{createLogger}from"#internal/logging.js";import{evaluateFilePart,formatUploadPolicyViolation,isUploadsDisabled}from"#public/channels/upload-policy.js";import{resolveSlackBotToken}from"#public/channels/slack/api.js";const log=createLogger(`slack.attachments`);function collectSlackFileParts(e,r){let i=[];for(let o of e??[]){let e=toSlackFilePart(o,i.length);if(e===null)continue;let s=evaluateFilePart(e,r);if(s!==null){log.warn(`dropped attachment — ${formatUploadPolicyViolation(s)}`,{name:o.name});continue}i.push(e)}return i}function toSlackFilePart(e,t){return e.type===`audio`||e.type===`video`?null:e.url?{type:`file`,mediaType:e.mimeType??`application/octet-stream`,filename:e.name??`attachment-${t}`,data:new URL(e.url)}:(log.warn(`dropped attachment — no url available`,{name:e.name}),null)}async function collectInboundFileParts(e){let t=collectSlackFileParts(e.mention.attachments,e.policy);if(t.length>0)return t;if(isUploadsDisabled(e.policy))return[];try{await e.thread.refresh()}catch(e){return log.warn(`slack thread refresh failed for attachment collection`,{error:e}),[]}let n=e.thread.recentMessages;for(let t=n.length-1;t>=0;--t){let r=n[t];if(!r||r.isMe)continue;let i=r.raw,a=collectSlackFileParts(extractAttachmentsFromRaw(i?.files),e.policy);return a.length>0?a:[]}return[]}function extractAttachmentsFromRaw(e){return Array.isArray(e)?e.map(e=>{let t=typeof e.mimetype==`string`?e.mimetype:void 0;return{id:typeof e.id==`string`?e.id:``,type:inferAttachmentType(t),url:typeof e.url_private==`string`?e.url_private:void 0,name:typeof e.name==`string`?e.name:void 0,mimeType:t,size:typeof e.size==`number`?e.size:void 0}}):[]}function inferAttachmentType(e){return e===void 0?`file`:e.startsWith(`image/`)?`image`:e.startsWith(`video/`)?`video`:e.startsWith(`audio/`)?`audio`:`file`}function buildSlackTurnMessage(e,t){return t.length===0?e:e.trim().length===0?[...t]:[{type:`text`,text:e},...t]}function createSlackFetchFile(e){return async t=>{if(!t.startsWith(`https://files.slack.com/`))return null;let n=await resolveSlackBotToken(e.botToken),r=await fetch(t,{headers:{authorization:`Bearer ${n}`}});if(!r.ok)throw Error(`Slack file fetch returned HTTP ${r.status} for ${t}.`);return{bytes:Buffer.from(await r.arrayBuffer()),mediaType:r.headers.get(`content-type`)??void 0}}}export{buildSlackTurnMessage,collectInboundFileParts,collectSlackFileParts,createSlackFetchFile};
@@ -1 +1 @@
1
- var SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`;export{SLACK_CHANNEL_DEFAULT_ROUTE};
1
+ const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`;export{SLACK_CHANNEL_DEFAULT_ROUTE};
@@ -1,4 +1,4 @@
1
- import{createLogger,extractErrorId,formatErrorHint}from"#internal/logging.js";import{truncateMessageText,truncateTypingStatus}from"#public/channels/slack/limits.js";import{buildAuthCompletedText,buildAuthEphemeralBlocks,buildAuthRequiredPublicText,formatConnectionDisplayName}from"#public/channels/slack/connections.js";import{renderInputRequestBlocks}from"#public/channels/slack/hitl.js";var log=createLogger(`slack.defaults`);function defaultSlackAuth(e,t){let n=e.author;if(!n)return null;let r=e.teamId,i=n.isBot,a=n.userId,o=r?i?`slack:${r}:bot:${a}`:`slack:${r}:${a}`:i?`slack:bot:${a}`:`slack:${a}`,s={author_type:i?`bot`:`user`,channel_id:t.slack.channelId,thread_ts:t.slack.threadTs,user_id:a};return n.userName&&(s.user_name=n.userName),n.fullName&&(s.full_name=n.fullName),r!==void 0&&(s.team_id=r),{attributes:s,authenticator:`slack-webhook`,issuer:r===void 0?`slack`:`slack:${r}`,principalId:o,principalType:i?`service`:`user`}}async function defaultOnAppMention(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}async function defaultOnDirectMessage(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}function firstNonEmptyLine(e){for(let t of e.split(/\r?\n/u)){let e=t.trim();if(e.length>0)return e}}function defaultInputRequestedHandler(){return async(e,t)=>{if(e.requests.length===0)return;let n=truncateMessageText(e.requests.map(e=>e.prompt).join(`
2
- `));await t.thread.post({blocks:e.requests.flatMap(renderInputRequestBlocks),text:n})}}var defaultEvents={async"turn.started"(e,t){t.state.pendingToolCallMessage=null,await t.thread.startTyping(`Working...`)},async"actions.requested"(e,t){let n=t.state.pendingToolCallMessage;if(t.state.pendingToolCallMessage=null,n){await t.thread.startTyping(truncateTypingStatus(n));return}let r=e.actions.map(e=>e.kind===`tool-call`?e.toolName:e.kind);await t.thread.startTyping(truncateTypingStatus(`Running ${r.join(`, `)}...`))},async"message.completed"(e,t){if(e.finishReason===`tool-calls`){t.state.pendingToolCallMessage=e.message?firstNonEmptyLine(e.message)??null:null;return}t.state.pendingToolCallMessage=null,e.message&&await t.thread.post(e.message)},async"turn.failed"(e,r){let i=formatErrorHint(e),a=extractErrorId(e.details);await r.thread.post([`I hit an error while handling your request${i}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...a?[``,`_Error id: \`${a}\`_`]:[]].join(`
1
+ import{createLogger,extractErrorId,formatErrorHint}from"#internal/logging.js";import{truncateMessageText,truncateTypingStatus}from"#public/channels/slack/limits.js";import{buildAuthCompletedText,buildAuthEphemeralBlocks,buildAuthRequiredPublicText,formatConnectionDisplayName}from"#public/channels/slack/connections.js";import{renderInputRequestBlocks}from"#public/channels/slack/hitl.js";const log=createLogger(`slack.defaults`);function defaultSlackAuth(e,t){let n=e.author;if(!n)return null;let r=e.teamId,i=n.isBot,a=n.userId,o=r?i?`slack:${r}:bot:${a}`:`slack:${r}:${a}`:i?`slack:bot:${a}`:`slack:${a}`,s={author_type:i?`bot`:`user`,channel_id:t.slack.channelId,thread_ts:t.slack.threadTs,user_id:a};return n.userName&&(s.user_name=n.userName),n.fullName&&(s.full_name=n.fullName),r!==void 0&&(s.team_id=r),{attributes:s,authenticator:`slack-webhook`,issuer:r===void 0?`slack`:`slack:${r}`,principalId:o,principalType:i?`service`:`user`}}async function defaultOnAppMention(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}async function defaultOnDirectMessage(e,t){return await e.thread.startTyping(`Thinking...`),{auth:defaultSlackAuth(t,e)}}function firstNonEmptyLine(e){for(let t of e.split(/\r?\n/u)){let e=t.trim();if(e.length>0)return e}}function defaultInputRequestedHandler(){return async(e,t)=>{if(e.requests.length===0)return;let n=truncateMessageText(e.requests.map(e=>e.prompt).join(`
2
+ `));await t.thread.post({blocks:e.requests.flatMap(renderInputRequestBlocks),text:n})}}const defaultEvents={async"turn.started"(e,t){t.state.pendingToolCallMessage=null,await t.thread.startTyping(`Working...`)},async"actions.requested"(e,t){let n=t.state.pendingToolCallMessage;if(t.state.pendingToolCallMessage=null,n){await t.thread.startTyping(truncateTypingStatus(n));return}let r=e.actions.map(e=>e.kind===`tool-call`?e.toolName:e.kind);await t.thread.startTyping(truncateTypingStatus(`Running ${r.join(`, `)}...`))},async"message.completed"(e,t){if(e.finishReason===`tool-calls`){t.state.pendingToolCallMessage=e.message?firstNonEmptyLine(e.message)??null:null;return}t.state.pendingToolCallMessage=null,e.message&&await t.thread.post(e.message)},async"turn.failed"(e,r){let i=formatErrorHint(e),a=extractErrorId(e.details);await r.thread.post([`I hit an error while handling your request${i}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...a?[``,`_Error id: \`${a}\`_`]:[]].join(`
3
3
  `))},async"session.failed"(e,r){let i=formatErrorHint(e),a=extractErrorId(e.details);await r.thread.post([`This session couldn't recover from an error${i}.`,``,`Start a new thread to continue — I can't pick this one back up.`,...a?[``,`_Error id: \`${a}\`_`]:[]].join(`
4
4
  `))},async"connection.authorization_required"(e,t){let n=formatConnectionDisplayName(e.connectionName),r=t.state.triggeringUserId??null,i=e.authorization?.url;if(r&&i)try{await t.thread.postEphemeral(r,{blocks:buildAuthEphemeralBlocks({displayName:n,url:i}),text:`Sign in with ${n}: ${i}`})}catch(t){log.error(`Slack auth ephemeral delivery failed`,{connectionName:e.connectionName,error:t})}let a=buildAuthRequiredPublicText({displayName:n,hasUser:r!==null});try{let n=await t.thread.post(a);n.id&&(t.state.pendingAuthMessageTs={...t.state.pendingAuthMessageTs,[e.connectionName]:n.id})}catch(t){log.error(`Slack auth public message delivery failed`,{connectionName:e.connectionName,error:t})}},async"connection.authorization_completed"(e,t){let n=t.state.pendingAuthMessageTs??{},r=n[e.connectionName];if(r===void 0)return;let i=buildAuthCompletedText({displayName:formatConnectionDisplayName(e.connectionName),outcome:e.outcome,reason:e.reason});try{await t.slack.request(`chat.update`,{channel:t.slack.channelId,ts:r,text:i})}catch(t){log.error(`Slack auth status edit failed`,{connectionName:e.connectionName,error:t})}let o={...n};delete o[e.connectionName],t.state.pendingAuthMessageTs=o}};export{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage,defaultSlackAuth};
@@ -1 +1 @@
1
- import{truncateModalTitle,truncatePlainText,truncateSectionText}from"#public/channels/slack/limits.js";var HITL_ACTION_PREFIX=`ash_input:`,HITL_FREEFORM_ACTION_PREFIX=`ash_input_freeform:`,HITL_FREEFORM_MODAL_CALLBACK_ID=`ash_input_freeform_submit`,HITL_FREEFORM_MODAL_BLOCK_ID=`ash_freeform_block`,HITL_FREEFORM_MODAL_ACTION_ID=`ash_freeform_text`,RADIO_SELECT_OPTION_LIMIT=6,BUTTON_ACTION_ID_RE=/^(?<requestId>.+):button:\d+$/u;function deriveHitlResponse(e){if(!e.actionId.startsWith(`ash_input:`))return null;let t=e.actionId.slice(HITL_ACTION_PREFIX.length);if(e.selectedOptionValue!==void 0)return t?{optionId:e.selectedOptionValue,requestId:t}:null;if(e.value!==void 0){let n=BUTTON_ACTION_ID_RE.exec(t)?.groups?.requestId;return n?{optionId:e.value,requestId:n}:null}return null}function isHitlAction(e){return e.startsWith(HITL_ACTION_PREFIX)}function renderInputRequestBlocks(e){let t={text:{text:truncateSectionText(e.prompt),type:`mrkdwn`},type:`section`},a=`${HITL_ACTION_PREFIX}${e.requestId}`,o=e.options,s=e.allowFreeform===!0||!o||o.length===0;return o&&o.length>0&&e.display===`select`?[t,{type:`actions`,elements:[o.length<=RADIO_SELECT_OPTION_LIMIT?{type:`radio_buttons`,action_id:a,options:o.map(buildOption)}:{type:`static_select`,action_id:a,options:o.map(buildOption),placeholder:{type:`plain_text`,text:`Choose an option`}}]}]:o&&o.length>0?[t,{type:`actions`,elements:o.map((e,t)=>buildButton(e,a,t))}]:s?[t,{type:`actions`,elements:[{type:`button`,action_id:`${HITL_FREEFORM_ACTION_PREFIX}${e.requestId}`,text:{type:`plain_text`,text:`Type your answer`},style:`primary`,value:e.requestId}]}]:[t]}function buildFreeformModalView(t){let r=t.prompt?truncateModalTitle(t.prompt):`Your answer`,i=t.prompt?[{type:`section`,text:{type:`mrkdwn`,text:truncateSectionText(t.prompt)}}]:[];return{type:`modal`,callback_id:HITL_FREEFORM_MODAL_CALLBACK_ID,private_metadata:JSON.stringify(t.metadata),title:{type:`plain_text`,text:r},submit:{type:`plain_text`,text:`Submit`},close:{type:`plain_text`,text:`Cancel`},blocks:[...i,{type:`input`,block_id:HITL_FREEFORM_MODAL_BLOCK_ID,element:{type:`plain_text_input`,action_id:HITL_FREEFORM_MODAL_ACTION_ID,multiline:!0,placeholder:{type:`plain_text`,text:`Type your answer here...`}},label:{type:`plain_text`,text:`Answer`}}]}}function isFreeformAction(e){return e.startsWith(HITL_FREEFORM_ACTION_PREFIX)}function freeformRequestIdFromActionId(e){if(!isFreeformAction(e))return;let t=e.slice(HITL_FREEFORM_ACTION_PREFIX.length);return t.length>0?t:void 0}function buildButton(e,n,r){let i={action_id:`${n}:button:${r}`,text:{text:truncatePlainText(e.label),type:`plain_text`},type:`button`,value:e.id};return(e.style===`primary`||e.style===`danger`)&&(i.style=e.style),i}function buildOption(e){let n={text:{text:truncatePlainText(e.label),type:`plain_text`},value:e.id},r=truncatePlainText(e.description);return r&&r.length>0&&(n.description={text:r,type:`plain_text`}),n}function buildAnsweredBlocks(e){let t=[];return e.promptBlock!==void 0&&e.promptBlock!==null&&t.push(e.promptBlock),t.push({type:`section`,text:{type:`mrkdwn`,text:`:white_check_mark: *${e.answerLabel}*`}}),e.userId&&e.userId.length>0&&t.push({type:`context`,elements:[{type:`mrkdwn`,text:`Answered by <@${e.userId}>`}]}),t}export{HITL_ACTION_PREFIX,HITL_FREEFORM_ACTION_PREFIX,HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction,renderInputRequestBlocks};
1
+ import{truncateModalTitle,truncatePlainText,truncateSectionText}from"#public/channels/slack/limits.js";const HITL_ACTION_PREFIX=`ash_input:`,HITL_FREEFORM_ACTION_PREFIX=`ash_input_freeform:`,HITL_FREEFORM_MODAL_CALLBACK_ID=`ash_input_freeform_submit`,HITL_FREEFORM_MODAL_BLOCK_ID=`ash_freeform_block`,HITL_FREEFORM_MODAL_ACTION_ID=`ash_freeform_text`,BUTTON_ACTION_ID_RE=/^(?<requestId>.+):button:\d+$/u;function deriveHitlResponse(e){if(!e.actionId.startsWith(`ash_input:`))return null;let t=e.actionId.slice(10);if(e.selectedOptionValue!==void 0)return t?{optionId:e.selectedOptionValue,requestId:t}:null;if(e.value!==void 0){let n=BUTTON_ACTION_ID_RE.exec(t)?.groups?.requestId;return n?{optionId:e.value,requestId:n}:null}return null}function isHitlAction(e){return e.startsWith(HITL_ACTION_PREFIX)}function renderInputRequestBlocks(e){let t={text:{text:truncateSectionText(e.prompt),type:`mrkdwn`},type:`section`},a=`${HITL_ACTION_PREFIX}${e.requestId}`,o=e.options,s=e.allowFreeform===!0||!o||o.length===0;return o&&o.length>0&&e.display===`select`?[t,{type:`actions`,elements:[o.length<=6?{type:`radio_buttons`,action_id:a,options:o.map(buildOption)}:{type:`static_select`,action_id:a,options:o.map(buildOption),placeholder:{type:`plain_text`,text:`Choose an option`}}]}]:o&&o.length>0?[t,{type:`actions`,elements:o.map((e,t)=>buildButton(e,a,t))}]:s?[t,{type:`actions`,elements:[{type:`button`,action_id:`${HITL_FREEFORM_ACTION_PREFIX}${e.requestId}`,text:{type:`plain_text`,text:`Type your answer`},style:`primary`,value:e.requestId}]}]:[t]}function buildFreeformModalView(t){let r=t.prompt?truncateModalTitle(t.prompt):`Your answer`,i=t.prompt?[{type:`section`,text:{type:`mrkdwn`,text:truncateSectionText(t.prompt)}}]:[];return{type:`modal`,callback_id:HITL_FREEFORM_MODAL_CALLBACK_ID,private_metadata:JSON.stringify(t.metadata),title:{type:`plain_text`,text:r},submit:{type:`plain_text`,text:`Submit`},close:{type:`plain_text`,text:`Cancel`},blocks:[...i,{type:`input`,block_id:HITL_FREEFORM_MODAL_BLOCK_ID,element:{type:`plain_text_input`,action_id:HITL_FREEFORM_MODAL_ACTION_ID,multiline:!0,placeholder:{type:`plain_text`,text:`Type your answer here...`}},label:{type:`plain_text`,text:`Answer`}}]}}function isFreeformAction(e){return e.startsWith(HITL_FREEFORM_ACTION_PREFIX)}function freeformRequestIdFromActionId(e){if(!isFreeformAction(e))return;let t=e.slice(19);return t.length>0?t:void 0}function buildButton(e,n,r){let i={action_id:`${n}:button:${r}`,text:{text:truncatePlainText(e.label),type:`plain_text`},type:`button`,value:e.id};return(e.style===`primary`||e.style===`danger`)&&(i.style=e.style),i}function buildOption(e){let n={text:{text:truncatePlainText(e.label),type:`plain_text`},value:e.id},r=truncatePlainText(e.description);return r&&r.length>0&&(n.description={text:r,type:`plain_text`}),n}function buildAnsweredBlocks(e){let t=[];return e.promptBlock!==void 0&&e.promptBlock!==null&&t.push(e.promptBlock),t.push({type:`section`,text:{type:`mrkdwn`,text:`:white_check_mark: *${e.answerLabel}*`}}),e.userId&&e.userId.length>0&&t.push({type:`context`,elements:[{type:`mrkdwn`,text:`Answered by <@${e.userId}>`}]}),t}export{HITL_ACTION_PREFIX,HITL_FREEFORM_ACTION_PREFIX,HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction,renderInputRequestBlocks};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";var log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){let t=e.actions;if(!Array.isArray(t))return null;let n=e.channel?.id,r=e.message,i=r?.thread_ts??r?.ts;if(!n||!i)return null;let a=e.team,o=e.user,s=a?.id??o.team_id,c={id:o.id,username:o.username,name:o.name},l=r?.blocks??[];return{actions:t.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:r?.ts,label:extractActionLabel(e),user:c})),channelId:n,threadTs:i,teamId:s,messageBlocks:l}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){for(let t of e)if(typeof t==`object`&&t&&t.type===`section`)return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}async function handleInteractionPost(e,n,i){let a=new Response(`ok`,{status:200}),o=new URLSearchParams(e).get(`payload`);if(!o)return a;let s;try{s=JSON.parse(o)}catch{return log.warn(`failed to parse Slack interaction payload`),a}if(s?.type===`view_submission`)return handleViewSubmission(s,n,i);let c=parseBlockActionsPayload(s);if(!c)return a;let u=c.actions.find(e=>isFreeformAction(e.actionId));if(u)return await openFreeformModal({payload:s,interaction:c,freeformAction:u,deps:i}),a;let p=slackContinuationToken(c.channelId,c.threadTs),m=c.actions.map(deriveHitlResponse).filter(e=>e!==null);m.length>0&&(n.waitUntil(n.send({inputResponses:m},{auth:null,continuationToken:p,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId??null,triggeringUserId:c.actions[0]?.user.id??null}}).catch(e=>{log.error(`HITL interaction delivery failed`,{error:e})})),n.waitUntil(updateAnsweredHitlCard(c,i).catch(e=>{log.error(`HITL answered-card update failed`,{error:e})})));let h=i.config.onInteraction;if(h){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let{thread:r,slack:a}=buildSlackBinding({botToken:i.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),o={thread:r,slack:a};for(let t of e)n.waitUntil(Promise.resolve(h(t,o)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return a}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let i=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!i){log.warn(`freeform button click missing requestId`);return}let a=e.freeformAction.messageTs;if(!a){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:a,requestId:i},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),l=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});l.ok||log.error(`Slack views.open returned non-2xx`,{status:l.status})}async function handleViewSubmission(e,t,n){let r=new Response(`ok`,{status:200}),s=e.view;if(s?.callback_id!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let c;try{c=JSON.parse(s.private_metadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!c.continuationToken||!c.requestId||!c.messageTs||!c.channelId||!c.threadTs)return r;let l=s.state?.values?.[HITL_FREEFORM_MODAL_BLOCK_ID]?.[HITL_FREEFORM_MODAL_ACTION_ID]?.value,u=typeof l==`string`?l:``;if(u.length===0)return r;let d=e.user,f=d.id,p=d.team_id??null;return t.waitUntil(t.send({inputResponses:[{requestId:c.requestId,text:u}]},{auth:null,continuationToken:c.continuationToken,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:p,triggeringUserId:f}}).catch(e=>{log.error(`freeform answer delivery failed`,{error:e})})),t.waitUntil(updateAnsweredFreeformCard({channelId:c.channelId,messageTs:c.messageTs,answerLabel:u,userId:f??void 0,deps:n}).catch(e=>{log.error(`freeform answered-card update failed`,{error:e})})),r}async function updateAnsweredHitlCard(e,t){let r=e.actions.find(e=>isHitlAction(e.actionId));if(!r||!r.messageTs)return;let i=r.label??r.selectedOptionValue??r.value;if(!i)return;let a=buildAnsweredBlocks({promptBlock:findPromptBlock(e.messageBlocks),answerLabel:i,userId:r.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),c=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:r.messageTs,blocks:a,text:`Answered: ${i}`})});if(!c.ok)throw Error(`Slack chat.update returned HTTP ${c.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlock:void 0,answerLabel:e.answerLabel,userId:e.userId}),r=await resolveSlackBotToken(e.deps.config.credentials?.botToken),i=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${r}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!i.ok)throw Error(`Slack chat.update returned HTTP ${i.status}`)}export{handleInteractionPost,parseBlockActionsPayload};
1
+ import{createLogger}from"#internal/logging.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){let t=e.actions;if(!Array.isArray(t))return null;let n=e.channel?.id,r=e.message,i=r?.thread_ts??r?.ts;if(!n||!i)return null;let a=e.team,o=e.user,s=a?.id??o.team_id,c={id:o.id,username:o.username,name:o.name},l=r?.blocks??[];return{actions:t.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:r?.ts,label:extractActionLabel(e),user:c})),channelId:n,threadTs:i,teamId:s,messageBlocks:l}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){for(let t of e)if(typeof t==`object`&&t&&t.type===`section`)return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}async function handleInteractionPost(e,n,i){let a=new Response(`ok`,{status:200}),o=new URLSearchParams(e).get(`payload`);if(!o)return a;let s;try{s=JSON.parse(o)}catch{return log.warn(`failed to parse Slack interaction payload`),a}if(s?.type===`view_submission`)return handleViewSubmission(s,n,i);let c=parseBlockActionsPayload(s);if(!c)return a;let u=c.actions.find(e=>isFreeformAction(e.actionId));if(u)return await openFreeformModal({payload:s,interaction:c,freeformAction:u,deps:i}),a;let p=slackContinuationToken(c.channelId,c.threadTs),m=c.actions.map(deriveHitlResponse).filter(e=>e!==null);m.length>0&&(n.waitUntil(n.send({inputResponses:m},{auth:null,continuationToken:p,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId??null,triggeringUserId:c.actions[0]?.user.id??null}}).catch(e=>{log.error(`HITL interaction delivery failed`,{error:e})})),n.waitUntil(updateAnsweredHitlCard(c,i).catch(e=>{log.error(`HITL answered-card update failed`,{error:e})})));let h=i.config.onInteraction;if(h){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let{thread:r,slack:a}=buildSlackBinding({botToken:i.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),o={thread:r,slack:a};for(let t of e)n.waitUntil(Promise.resolve(h(t,o)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return a}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let i=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!i){log.warn(`freeform button click missing requestId`);return}let a=e.freeformAction.messageTs;if(!a){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:a,requestId:i},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),l=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});l.ok||log.error(`Slack views.open returned non-2xx`,{status:l.status})}async function handleViewSubmission(e,t,n){let r=new Response(`ok`,{status:200}),s=e.view;if(s?.callback_id!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let c;try{c=JSON.parse(s.private_metadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!c.continuationToken||!c.requestId||!c.messageTs||!c.channelId||!c.threadTs)return r;let l=s.state?.values?.[HITL_FREEFORM_MODAL_BLOCK_ID]?.[HITL_FREEFORM_MODAL_ACTION_ID]?.value,u=typeof l==`string`?l:``;if(u.length===0)return r;let d=e.user,f=d.id,p=d.team_id??null;return t.waitUntil(t.send({inputResponses:[{requestId:c.requestId,text:u}]},{auth:null,continuationToken:c.continuationToken,state:{channelId:c.channelId,threadTs:c.threadTs,teamId:p,triggeringUserId:f}}).catch(e=>{log.error(`freeform answer delivery failed`,{error:e})})),t.waitUntil(updateAnsweredFreeformCard({channelId:c.channelId,messageTs:c.messageTs,answerLabel:u,userId:f??void 0,deps:n}).catch(e=>{log.error(`freeform answered-card update failed`,{error:e})})),r}async function updateAnsweredHitlCard(e,t){let r=e.actions.find(e=>isHitlAction(e.actionId));if(!r||!r.messageTs)return;let i=r.label??r.selectedOptionValue??r.value;if(!i)return;let a=buildAnsweredBlocks({promptBlock:findPromptBlock(e.messageBlocks),answerLabel:i,userId:r.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),c=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:r.messageTs,blocks:a,text:`Answered: ${i}`})});if(!c.ok)throw Error(`Slack chat.update returned HTTP ${c.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlock:void 0,answerLabel:e.answerLabel,userId:e.userId}),r=await resolveSlackBotToken(e.deps.config.credentials?.botToken),i=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${r}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!i.ok)throw Error(`Slack chat.update returned HTTP ${i.status}`)}export{handleInteractionPost,parseBlockActionsPayload};
@@ -1 +1 @@
1
- var SLACK_TYPING_STATUS_MAX_LENGTH=50,SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH=75,SLACK_SECTION_TEXT_MAX_LENGTH=3e3,SLACK_MESSAGE_TEXT_MAX_LENGTH=4e4,SLACK_MODAL_TITLE_MAX_LENGTH=24;function truncateTypingStatus(e){return truncateWithEllipsis(e.trim().replace(/\s+/gu,` `),50)}function truncatePlainText(e){if(e!==void 0)return truncateWithEllipsis(e,75)}function truncateSectionText(e){return truncateWithEllipsis(e,SLACK_SECTION_TEXT_MAX_LENGTH)}function truncateMessageText(e){return truncateWithEllipsis(e,SLACK_MESSAGE_TEXT_MAX_LENGTH)}function truncateModalTitle(e){return truncateWithEllipsis(e,24)}function truncateWithEllipsis(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH,SLACK_MESSAGE_TEXT_MAX_LENGTH,SLACK_MODAL_TITLE_MAX_LENGTH,SLACK_SECTION_TEXT_MAX_LENGTH,SLACK_TYPING_STATUS_MAX_LENGTH,truncateMessageText,truncateModalTitle,truncatePlainText,truncateSectionText,truncateTypingStatus};
1
+ const SLACK_TYPING_STATUS_MAX_LENGTH=50,SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH=75,SLACK_SECTION_TEXT_MAX_LENGTH=3e3,SLACK_MESSAGE_TEXT_MAX_LENGTH=4e4,SLACK_MODAL_TITLE_MAX_LENGTH=24;function truncateTypingStatus(e){return truncateWithEllipsis(e.trim().replace(/\s+/gu,` `),50)}function truncatePlainText(e){if(e!==void 0)return truncateWithEllipsis(e,75)}function truncateSectionText(e){return truncateWithEllipsis(e,SLACK_SECTION_TEXT_MAX_LENGTH)}function truncateMessageText(e){return truncateWithEllipsis(e,SLACK_MESSAGE_TEXT_MAX_LENGTH)}function truncateModalTitle(e){return truncateWithEllipsis(e,24)}function truncateWithEllipsis(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{SLACK_BLOCK_KIT_PLAIN_TEXT_MAX_LENGTH,SLACK_MESSAGE_TEXT_MAX_LENGTH,SLACK_MODAL_TITLE_MAX_LENGTH,SLACK_SECTION_TEXT_MAX_LENGTH,SLACK_TYPING_STATUS_MAX_LENGTH,truncateMessageText,truncateModalTitle,truncatePlainText,truncateSectionText,truncateTypingStatus};
@@ -1 +1 @@
1
- var BARE_MENTION_RE=/(?<![<\w])@(\w+)/gu;function rewriteBareMentions(t){return t.replace(BARE_MENTION_RE,`<@$1>`)}function gfmToSlackMrkdwn(e){return splitCodeFences(e).map(e=>e.kind===`code`?e.text:convertInline(e.text)).join(``)}function slackMrkdwnToGfm(e){return splitCodeFences(e).map(e=>e.kind===`code`?e.text:decodeInline(e.text)).join(``)}function splitCodeFences(e){let t=[],n=/```[\s\S]*?```|`[^`\n]+`/gu,r=0;for(let i of e.matchAll(n)){let n=i.index??0;n>r&&t.push({kind:`text`,text:e.slice(r,n)}),t.push({kind:`code`,text:i[0]}),r=n+i[0].length}return r<e.length&&t.push({kind:`text`,text:e.slice(r)}),t}function convertInline(e){let t=e;return t=t.replace(/\*\*([^*\n]+)\*\*/gu,`*$1*`),t=t.replace(/__([^_\n]+)__/gu,`*$1*`),t=t.replace(/~~([^~\n]+)~~/gu,`~$1~`),t=t.replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/gu,`<$2|$1>`),t}function decodeInline(e){let t=e;return t=t.replace(/<!(channel|here|everyone)>/gu,`@$1`),t=t.replace(/<@([A-Z0-9]+)\|([^>]+)>/gu,`@$2`),t=t.replace(/<@([A-Z0-9]+)>/gu,`@$1`),t=t.replace(/<#([A-Z0-9]+)\|([^>]+)>/gu,`#$2`),t=t.replace(/<#([A-Z0-9]+)>/gu,`#$1`),t=t.replace(/<(https?:\/\/[^|>\s]+)\|([^>]+)>/gu,`[$2]($1)`),t=t.replace(/<(https?:\/\/[^>\s]+)>/gu,`$1`),t=t.replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/gu,`$1**$2**`),t=t.replace(/(^|[^~])~([^~\n]+)~(?!~)/gu,`$1~~$2~~`),t}export{gfmToSlackMrkdwn,rewriteBareMentions,slackMrkdwnToGfm};
1
+ const BARE_MENTION_RE=/(?<![<\w])@(\w+)/gu;function rewriteBareMentions(t){return t.replace(BARE_MENTION_RE,`<@$1>`)}function gfmToSlackMrkdwn(e){return splitCodeFences(e).map(e=>e.kind===`code`?e.text:convertInline(e.text)).join(``)}function slackMrkdwnToGfm(e){return splitCodeFences(e).map(e=>e.kind===`code`?e.text:decodeInline(e.text)).join(``)}function splitCodeFences(e){let t=[],n=/```[\s\S]*?```|`[^`\n]+`/gu,r=0;for(let i of e.matchAll(n)){let n=i.index??0;n>r&&t.push({kind:`text`,text:e.slice(r,n)}),t.push({kind:`code`,text:i[0]}),r=n+i[0].length}return r<e.length&&t.push({kind:`text`,text:e.slice(r)}),t}function convertInline(e){let t=e;return t=t.replace(/\*\*([^*\n]+)\*\*/gu,`*$1*`),t=t.replace(/__([^_\n]+)__/gu,`*$1*`),t=t.replace(/~~([^~\n]+)~~/gu,`~$1~`),t=t.replace(/\[([^\]\n]+)\]\(([^)\s]+)\)/gu,`<$2|$1>`),t}function decodeInline(e){let t=e;return t=t.replace(/<!(channel|here|everyone)>/gu,`@$1`),t=t.replace(/<@([A-Z0-9]+)\|([^>]+)>/gu,`@$2`),t=t.replace(/<@([A-Z0-9]+)>/gu,`@$1`),t=t.replace(/<#([A-Z0-9]+)\|([^>]+)>/gu,`#$2`),t=t.replace(/<#([A-Z0-9]+)>/gu,`#$1`),t=t.replace(/<(https?:\/\/[^|>\s]+)\|([^>]+)>/gu,`[$2]($1)`),t=t.replace(/<(https?:\/\/[^>\s]+)>/gu,`$1`),t=t.replace(/(^|[^*])\*([^*\n]+)\*(?!\*)/gu,`$1**$2**`),t=t.replace(/(^|[^~])~([^~\n]+)~(?!~)/gu,`$1~~$2~~`),t}export{gfmToSlackMrkdwn,rewriteBareMentions,slackMrkdwnToGfm};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{parseAppMentionEvent,parseDirectMessageEvent,prependSlackContext}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";var log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:a}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:a,session:t,state:e}}function slackChannel(e={}){let l=mergeUploadPolicy(e.uploadPolicy),u=createSlackFetchFile({botToken:e.credentials?.botToken}),f=e.onAppMention??defaultOnAppMention,p=e.onDirectMessage??defaultOnDirectMessage,m={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler()};return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,pendingAuthMessageTs:{}},fetchFile:u,context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let i=await verifyInbound(t,e.credentials);return i===null?new Response(`unauthorized`,{status:401}):(t.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(i,{send:n,waitUntil:r},{config:e}):handleEventPost({body:i,send:n,waitUntil:r,onAppMention:f,onDirectMessage:p,uploadPolicy:l,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.args,a=r.channelId;if(!a||typeof a!=`string`)throw Error(`slackChannel().receive requires args.channelId.`);let o=typeof r.threadTs==`string`?r.threadTs:``,s=r.initialMessage;if(s&&o.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=o;if(s){let{thread:t}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:a,threadTs:``,teamId:void 0}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await t.post(n)).id}return n(t.message,{auth:t.auth,continuationToken:slackContinuationToken(a,c),state:{channelId:a,threadTs:c||null,teamId:null,triggeringUserId:null}})},events:m})}async function handleEventPost(e){let t;try{t=JSON.parse(e.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(typeof t.challenge==`string`)return new Response(t.challenge,{status:200,headers:{"content-type":`text/plain`}});let n=parseAppMentionEvent(t);if(n)return e.waitUntil(dispatchInboundMessage({kind:`app_mention`,message:n,handler:e.onAppMention,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`);let r=parseDirectMessageEvent(t);return r&&e.waitUntil(dispatchInboundMessage({kind:`direct_message`,message:r,handler:e.onDirectMessage,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`)}async function verifyInbound(e,t){try{return await verifySlackRequest(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function dispatchInboundMessage(e){let{message:t,kind:n}=e,{thread:r,slack:a}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId}),o={thread:r,slack:a},s;try{s=await e.handler(o,t)}catch(e){log.error(`${n} handler failed`,{error:e});return}if(s==null)return;let c=await collectInboundFileParts({mention:t,thread:r,policy:e.uploadPolicy}),d=buildSlackTurnMessage(t.markdown,c),f={channelId:t.channelId,fullName:t.author?.fullName,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},p=f.userId?prependSlackContext(d,f):d;try{await e.send({message:p,modelContext:s.modelContext},{auth:s.auth,continuationToken:slackContinuationToken(t.channelId,t.threadTs),state:{channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId??null,triggeringUserId:f.userId||null}})}catch(e){log.error(`${n} delivery failed`,{error:e})}}export{slackChannel};
1
+ import{createLogger}from"#internal/logging.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{parseAppMentionEvent,parseDirectMessageEvent,prependSlackContext}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:a}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:a,session:t,state:e}}function slackChannel(e={}){let l=mergeUploadPolicy(e.uploadPolicy),u=createSlackFetchFile({botToken:e.credentials?.botToken}),f=e.onAppMention??defaultOnAppMention,p=e.onDirectMessage??defaultOnDirectMessage,m={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler()};return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,pendingAuthMessageTs:{}},fetchFile:u,context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(t,{send:n,waitUntil:r})=>{let i=await verifyInbound(t,e.credentials);return i===null?new Response(`unauthorized`,{status:401}):(t.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(i,{send:n,waitUntil:r},{config:e}):handleEventPost({body:i,send:n,waitUntil:r,onAppMention:f,onDirectMessage:p,uploadPolicy:l,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.args,a=r.channelId;if(!a||typeof a!=`string`)throw Error(`slackChannel().receive requires args.channelId.`);let o=typeof r.threadTs==`string`?r.threadTs:``,s=r.initialMessage;if(s&&o.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=o;if(s){let{thread:t}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:a,threadTs:``,teamId:void 0}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await t.post(n)).id}return n(t.message,{auth:t.auth,continuationToken:slackContinuationToken(a,c),state:{channelId:a,threadTs:c||null,teamId:null,triggeringUserId:null}})},events:m})}async function handleEventPost(e){let t;try{t=JSON.parse(e.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(typeof t.challenge==`string`)return new Response(t.challenge,{status:200,headers:{"content-type":`text/plain`}});let n=parseAppMentionEvent(t);if(n)return e.waitUntil(dispatchInboundMessage({kind:`app_mention`,message:n,handler:e.onAppMention,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`);let r=parseDirectMessageEvent(t);return r&&e.waitUntil(dispatchInboundMessage({kind:`direct_message`,message:r,handler:e.onDirectMessage,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`)}async function verifyInbound(e,t){try{return await verifySlackRequest(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function dispatchInboundMessage(e){let{message:t,kind:n}=e,{thread:r,slack:a}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId}),o={thread:r,slack:a},s;try{s=await e.handler(o,t)}catch(e){log.error(`${n} handler failed`,{error:e});return}if(s==null)return;let c=await collectInboundFileParts({mention:t,thread:r,policy:e.uploadPolicy}),d=buildSlackTurnMessage(t.markdown,c),f={channelId:t.channelId,fullName:t.author?.fullName,teamId:t.teamId,threadTs:t.threadTs,userId:t.author?.userId??``,userName:t.author?.userName},p=f.userId?prependSlackContext(d,f):d;try{await e.send({message:p,modelContext:s.modelContext},{auth:s.auth,continuationToken:slackContinuationToken(t.channelId,t.threadTs),state:{channelId:t.channelId,threadTs:t.threadTs,teamId:t.teamId??null,triggeringUserId:f.userId||null}})}catch(e){log.error(`${n} delivery failed`,{error:e})}}export{slackChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{createHmac,timingSafeEqual}from"node:crypto";var log=createLogger(`slack.verify`);async function verifySlackRequest(e,n){let r=await e.text();if(n.webhookVerifier!==void 0){let t=await n.webhookVerifier(e,r);if(!t)throw Error(`slackChannel: inbound webhook verifier rejected the request.`);return typeof t==`string`?t:r}if(!n.signingSecret)throw Error(`slackChannel: missing signing secret. Pass credentials.signingSecret, set SLACK_SIGNING_SECRET, or supply credentials.webhookVerifier.`);let i=e.headers.get(`x-slack-request-timestamp`)??``,a=e.headers.get(`x-slack-signature`)??``;if(!i||!a)throw Error(`slackChannel: inbound request missing Slack signature headers.`);let o=Number(i);if(!Number.isFinite(o))throw Error(`slackChannel: inbound request has malformed timestamp.`);let s=n.maxSkewSeconds??300,c=Math.floor(Date.now()/1e3);if(Math.abs(c-o)>s)throw Error(`slackChannel: inbound request timestamp outside allowed skew.`);let l=`v0:${i}:${r}`;if(!constantTimeCompare(`v0=${createHmac(`sha256`,n.signingSecret).update(l).digest(`hex`)}`,a))throw Error(`slackChannel: inbound request signature mismatch.`);return r}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{verifySlackRequest};
1
+ import{createLogger}from"#internal/logging.js";import{createHmac,timingSafeEqual}from"node:crypto";const log=createLogger(`slack.verify`);async function verifySlackRequest(e,n){let r=await e.text();if(n.webhookVerifier!==void 0){let t=await n.webhookVerifier(e,r);if(!t)throw Error(`slackChannel: inbound webhook verifier rejected the request.`);return typeof t==`string`?t:r}if(!n.signingSecret)throw Error(`slackChannel: missing signing secret. Pass credentials.signingSecret, set SLACK_SIGNING_SECRET, or supply credentials.webhookVerifier.`);let i=e.headers.get(`x-slack-request-timestamp`)??``,a=e.headers.get(`x-slack-signature`)??``;if(!i||!a)throw Error(`slackChannel: inbound request missing Slack signature headers.`);let o=Number(i);if(!Number.isFinite(o))throw Error(`slackChannel: inbound request has malformed timestamp.`);let s=n.maxSkewSeconds??300,c=Math.floor(Date.now()/1e3);if(Math.abs(c-o)>s)throw Error(`slackChannel: inbound request timestamp outside allowed skew.`);let l=`v0:${i}:${r}`;if(!constantTimeCompare(`v0=${createHmac(`sha256`,n.signingSecret).update(l).digest(`hex`)}`,a))throw Error(`slackChannel: inbound request signature mismatch.`);return r}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{verifySlackRequest};
@@ -1,4 +1,4 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";var TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,DEFAULT_LOGIN_BASE_URL=`https://login.microsoftonline.com`,BOT_FRAMEWORK_TENANT=`botframework.com`,BOT_FRAMEWORK_SCOPE=`https://api.botframework.com/.default`,accessTokenCache=new Map;function teamsContinuationToken(e){return[e.tenantId??`_`,e.conversationId,e.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}async function resolveTeamsAppId(e){let t=e??process.env.MICROSOFT_APP_ID??process.env.TEAMS_APP_ID;if(!t)throw Error(`MICROSOFT_APP_ID or TEAMS_APP_ID is required.`);return typeof t==`function`?await t():t}async function resolveTeamsAppPassword(e){let t=e??process.env.MICROSOFT_APP_PASSWORD??process.env.TEAMS_APP_PASSWORD;if(!t)throw Error(`MICROSOFT_APP_PASSWORD or TEAMS_APP_PASSWORD is required.`);return typeof t==`function`?await t():t}async function resolveTeamsTenantId(e){let t=e??process.env.MICROSOFT_TENANT_ID??process.env.TEAMS_TENANT_ID;if(t)return typeof t==`function`?await t():t}async function resolveTeamsAccessToken(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let o=await resolveTeamsAppId(n?.appId),s=await resolveTeamsAppPassword(n?.appPassword),c=await resolveTeamsTenantId(n?.tenantId),l=trimTrailingSlash(t.loginBaseUrl??DEFAULT_LOGIN_BASE_URL),u=`${l}:${c??BOT_FRAMEWORK_TENANT}:${o}`,d=accessTokenCache.get(u),f=Date.now();if(d!==void 0&&d.expiresAt-6e4>f)return d.accessToken;let p=`${l}/${encodeURIComponent(c??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,m=new URLSearchParams({client_id:o,client_secret:s,grant_type:`client_credentials`,scope:BOT_FRAMEWORK_SCOPE}),h=await(t.fetch??fetch)(p,{body:m,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),g=await parseResponseBody(h);if(!h.ok)throw Error(`Teams access-token request failed with HTTP ${h.status}.`);let _=isObject(g)?g:{},v=typeof _.access_token==`string`?_.access_token:``;if(!v)throw Error(`Teams access-token response did not include access_token.`);let y=typeof _.expires_in==`number`?_.expires_in:3600;return accessTokenCache.set(u,{accessToken:v,expiresAt:f+y*1e3}),v}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function triggerTeamsTypingIndicator(e){let t=await callTeamsConnectorApi({...e,body:{type:`typing`},path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams typing indicator failed with HTTP ${t.status}.`)}function splitTeamsMessageText(e){if(e.length<=81920)return[e];let t=[],r=e;for(;r.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=r.lastIndexOf(`
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){return[e.tenantId??`_`,e.conversationId,e.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}async function resolveTeamsAppId(e){let t=e??process.env.MICROSOFT_APP_ID??process.env.TEAMS_APP_ID;if(!t)throw Error(`MICROSOFT_APP_ID or TEAMS_APP_ID is required.`);return typeof t==`function`?await t():t}async function resolveTeamsAppPassword(e){let t=e??process.env.MICROSOFT_APP_PASSWORD??process.env.TEAMS_APP_PASSWORD;if(!t)throw Error(`MICROSOFT_APP_PASSWORD or TEAMS_APP_PASSWORD is required.`);return typeof t==`function`?await t():t}async function resolveTeamsTenantId(e){let t=e??process.env.MICROSOFT_TENANT_ID??process.env.TEAMS_TENANT_ID;if(t)return typeof t==`function`?await t():t}async function resolveTeamsAccessToken(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let a=await resolveTeamsAppId(n?.appId),o=await resolveTeamsAppPassword(n?.appPassword),s=await resolveTeamsTenantId(n?.tenantId),c=trimTrailingSlash(t.loginBaseUrl??`https://login.microsoftonline.com`),l=`${c}:${s??BOT_FRAMEWORK_TENANT}:${a}`,u=accessTokenCache.get(l),d=Date.now();if(u!==void 0&&u.expiresAt-6e4>d)return u.accessToken;let f=`${c}/${encodeURIComponent(s??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,p=new URLSearchParams({client_id:a,client_secret:o,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),m=await(t.fetch??fetch)(f,{body:p,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),h=await parseResponseBody(m);if(!m.ok)throw Error(`Teams access-token request failed with HTTP ${m.status}.`);let g=isObject(h)?h:{},_=typeof g.access_token==`string`?g.access_token:``;if(!_)throw Error(`Teams access-token response did not include access_token.`);let v=typeof g.expires_in==`number`?g.expires_in:3600;return accessTokenCache.set(l,{accessToken:_,expiresAt:d+v*1e3}),_}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function triggerTeamsTypingIndicator(e){let t=await callTeamsConnectorApi({...e,body:{type:`typing`},path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams typing indicator failed with HTTP ${t.status}.`)}function splitTeamsMessageText(e){if(e.length<=81920)return[e];let t=[],r=e;for(;r.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=r.lastIndexOf(`
2
2
 
3
3
  `,TEAMS_MESSAGE_TEXT_MAX_LENGTH);e<=0&&(e=r.lastIndexOf(`
4
4
  `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=r.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(r.slice(0,e).trimEnd()),r=r.slice(e).trimStart()}return t.push(r),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(t){let n=isObject(t)?t:{};return{id:typeof n.id==`string`?n.id:``,raw:t}}function trimTrailingSlash(e){return e.replace(/\/+$/,``)}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{evaluateFilePart,formatUploadPolicyViolation,isUploadsDisabled,mergeUploadPolicy}from"#public/channels/upload-policy.js";var log=createLogger(`teams.attachments`);function normalizeTeamsFilesPolicy(e){return{allowedHosts:e?.allowedHosts??[],enabled:e?.enabled===!0,uploadPolicy:mergeUploadPolicy(e?.uploadPolicy)}}function collectTeamsFileParts(e,t){if(!t.enabled||isUploadsDisabled(t.uploadPolicy))return[];let a=[];for(let i of e){let e=toTeamsFilePart(i,a.length,t);if(e===null)continue;let o=evaluateFilePart(e,t.uploadPolicy);if(o!==null){log.warn(`dropped Teams attachment — ${formatUploadPolicyViolation(o)}`,{name:i.name});continue}a.push(e)}return a}function buildTeamsTurnMessage(e,t){return t.length===0?e:e.trim().length===0?[...t]:[{type:`text`,text:e},...t]}function createTeamsFetchFile(e){return async t=>{if(!e.enabled||!isAllowedUrl(t,e.allowedHosts))return null;let n=await fetch(t);if(!n.ok)throw Error(`Teams file fetch returned HTTP ${n.status} for ${t}.`);return{bytes:Buffer.from(await n.arrayBuffer()),mediaType:n.headers.get(`content-type`)??void 0}}}function toTeamsFilePart(e,t,n){let r=readAttachmentUrl(e);return!r||!isAllowedUrl(r,n.allowedHosts)?null:{data:new URL(r),filename:e.name??`teams-attachment-${t}`,mediaType:inferMediaType(e),type:`file`}}function readAttachmentUrl(e){return e.contentType===`application/vnd.microsoft.teams.file.download.info`&&isObject(e.content)&&typeof e.content.downloadUrl==`string`?e.content.downloadUrl:e.contentUrl&&!e.contentType.startsWith(`application/vnd.microsoft.card.`)?e.contentUrl:null}function inferMediaType(e){return e.contentType===`application/vnd.microsoft.teams.file.download.info`&&(isObject(e.content)&&typeof e.content.fileType==`string`?e.content.fileType:void 0)===`txt`?`text/plain`:e.contentType||`application/octet-stream`}function isAllowedUrl(e,t){if(t===`*`)return!0;let n;try{n=new URL(e)}catch{return!1}return t.some(e=>n.host===e||n.hostname===e)}export{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy};
1
+ import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{evaluateFilePart,formatUploadPolicyViolation,isUploadsDisabled,mergeUploadPolicy}from"#public/channels/upload-policy.js";const log=createLogger(`teams.attachments`);function normalizeTeamsFilesPolicy(e){return{allowedHosts:e?.allowedHosts??[],enabled:e?.enabled===!0,uploadPolicy:mergeUploadPolicy(e?.uploadPolicy)}}function collectTeamsFileParts(e,t){if(!t.enabled||isUploadsDisabled(t.uploadPolicy))return[];let a=[];for(let i of e){let e=toTeamsFilePart(i,a.length,t);if(e===null)continue;let o=evaluateFilePart(e,t.uploadPolicy);if(o!==null){log.warn(`dropped Teams attachment — ${formatUploadPolicyViolation(o)}`,{name:i.name});continue}a.push(e)}return a}function buildTeamsTurnMessage(e,t){return t.length===0?e:e.trim().length===0?[...t]:[{type:`text`,text:e},...t]}function createTeamsFetchFile(e){return async t=>{if(!e.enabled||!isAllowedUrl(t,e.allowedHosts))return null;let n=await fetch(t);if(!n.ok)throw Error(`Teams file fetch returned HTTP ${n.status} for ${t}.`);return{bytes:Buffer.from(await n.arrayBuffer()),mediaType:n.headers.get(`content-type`)??void 0}}}function toTeamsFilePart(e,t,n){let r=readAttachmentUrl(e);return!r||!isAllowedUrl(r,n.allowedHosts)?null:{data:new URL(r),filename:e.name??`teams-attachment-${t}`,mediaType:inferMediaType(e),type:`file`}}function readAttachmentUrl(e){return e.contentType===`application/vnd.microsoft.teams.file.download.info`&&isObject(e.content)&&typeof e.content.downloadUrl==`string`?e.content.downloadUrl:e.contentUrl&&!e.contentType.startsWith(`application/vnd.microsoft.card.`)?e.contentUrl:null}function inferMediaType(e){return e.contentType===`application/vnd.microsoft.teams.file.download.info`&&(isObject(e.content)&&typeof e.content.fileType==`string`?e.content.fileType:void 0)===`txt`?`text/plain`:e.contentType||`application/octet-stream`}function isAllowedUrl(e,t){if(t===`*`)return!0;let n;try{n=new URL(e)}catch{return!1}return t.some(e=>n.host===e||n.hostname===e)}export{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy};
@@ -1,3 +1,3 @@
1
- import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}var defaultEvents={async"turn.started"(e,t){await t.thread.startTyping()},async"actions.requested"(e,t){await t.thread.startTyping()},async"input.requested"(e,t){for(let n of e.requests)await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion}))},async"message.completed"(e,t){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
1
+ import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}const defaultEvents={async"turn.started"(e,t){await t.thread.startTyping()},async"actions.requested"(e,t){await t.thread.startTyping()},async"input.requested"(e,t){for(let n of e.requests)await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion}))},async"message.completed"(e,t){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
2
2
  `))},async"turn.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`I hit an error while handling your request${i}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...a?[``,`Error id: ${a}`]:[]].join(`
3
3
  `))},async"connection.authorization_required"(e,t){let r=formatConnectionDisplayName(e.connectionName),i=e.authorization?.url,a=i?`Authorization required for ${r}: ${i}`:`Authorization required for ${r}.`,o=await t.thread.post({attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:i?[{title:`Sign in with ${r}`,type:`Action.OpenUrl`,url:i}]:[],body:[{text:`Authorization required for ${r}`,type:`TextBlock`,weight:`Bolder`,wrap:!0},{text:t.state.triggeringUser?`Requested by ${t.state.triggeringUser.name??t.state.triggeringUser.id}.`:`No triggering user is available for a private prompt.`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:t.adaptiveCardVersion}),contentType:`application/vnd.microsoft.card.adaptive`}],text:a});o.id&&(t.state.pendingAuthActivityId=o.id)},async"connection.authorization_completed"(e,t){let n=t.state.pendingAuthActivityId;if(!n)return;let r=buildAuthCompletedText({displayName:formatConnectionDisplayName(e.connectionName),outcome:e.outcome,reason:e.reason});await t.thread.update(n,renderAnsweredInputRequestMessage({prompt:r})),t.state.pendingAuthActivityId=null}};function formatConnectionDisplayName(e){return e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1)}function buildAuthCompletedText(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;let t=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} authorization ${e.outcome}${t}.`}function teamsMentionUser(e){let t=e.name??e.id;return{mentioned:{id:e.id,name:e.name},text:`<at>${t}</at>`,type:`mention`}}export{buildAuthCompletedText,defaultEvents,defaultOnMessage,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser};
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";var TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`ash_input`,TEAMS_HITL_CHOICE_INPUT_ID=`ash_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`ash_freeform_text`;function renderInputRequestMessage(e,t={}){return{attachments:[renderInputRequestAttachment(e,t)],text:e.prompt}}function renderInputRequestAttachment(e,n={}){return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...renderInputs(e)],type:`AdaptiveCard`,version:n.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){return{attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},{color:`good`,text:e.label?`Answered: ${e.label}`:`Answered`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}],text:e.label?`Answered: ${e.label}`:`Answered`}}function isTeamsInputResponseActivity(e){return deriveTeamsInputResponses(e).length>0}function deriveTeamsInputResponses(e){let t=readActivityValue(e);if(!t)return[];let n=readHitlPayload(t);if(!n)return[];let r=typeof n.requestId==`string`?n.requestId:``;if(!r)return[];let i=typeof n.optionId==`string`?n.optionId:typeof t.ash_option==`string`?t[TEAMS_HITL_CHOICE_INPUT_ID]:void 0,a=typeof t.ash_freeform_text==`string`?t[TEAMS_HITL_FREEFORM_INPUT_ID]:void 0;return i===void 0?a===void 0?[{requestId:r}]:[{requestId:r,text:a}]:[{optionId:i,requestId:r}]}function teamsInvokeResponse(e={}){return{statusCode:e.statusCode??200,type:`application/vnd.microsoft.activity.message`,value:e.message??`Answer received.`}}function renderInputs(e){return e.display===`select`&&e.options&&e.options.length>0?[{choices:e.options.map(e=>({title:truncate(e.label,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH),value:e.id})),id:TEAMS_HITL_CHOICE_INPUT_ID,isMultiSelect:!1,style:`compact`,type:`Input.ChoiceSet`}]:e.allowFreeform===!0||!e.options||e.options.length===0?[{id:TEAMS_HITL_FREEFORM_INPUT_ID,isMultiline:!0,placeholder:`Type your answer`,type:`Input.Text`}]:[]}function renderActions(e){let t=e.options;return t&&t.length>0&&e.display!==`select`?t.slice(0,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT).map(t=>({data:{[TEAMS_HITL_DATA_KEY]:{optionId:t.id,requestId:e.requestId}},title:truncate(t.label,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH),type:`Action.Submit`})):[{data:{[TEAMS_HITL_DATA_KEY]:{requestId:e.requestId}},title:`Submit`,type:`Action.Submit`}]}function readActivityValue(e){return e.type===`message`?readMessageValue(e):e.type===`invoke`?readInvokeValue(e):null}function readMessageValue(e){return e.value??null}function readInvokeValue(t){let n=t.value;if(!n)return null;let r=isObject(n.action)?n.action:null;return(r&&isObject(r.data)?r.data:null)??n}function readHitlPayload(t){let n=t[TEAMS_HITL_DATA_KEY];if(isObject(n))return n;let r=isObject(t.action)?t.action:null,i=(r&&isObject(r.data)?r.data:null)?.[TEAMS_HITL_DATA_KEY];return isObject(i)?i:null}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,deriveTeamsInputResponses,isTeamsInputResponseActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse};
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";const TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`ash_input`,TEAMS_HITL_CHOICE_INPUT_ID=`ash_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`ash_freeform_text`;function renderInputRequestMessage(e,t={}){return{attachments:[renderInputRequestAttachment(e,t)],text:e.prompt}}function renderInputRequestAttachment(e,n={}){return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...renderInputs(e)],type:`AdaptiveCard`,version:n.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){return{attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},{color:`good`,text:e.label?`Answered: ${e.label}`:`Answered`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}],text:e.label?`Answered: ${e.label}`:`Answered`}}function isTeamsInputResponseActivity(e){return deriveTeamsInputResponses(e).length>0}function deriveTeamsInputResponses(e){let t=readActivityValue(e);if(!t)return[];let n=readHitlPayload(t);if(!n)return[];let r=typeof n.requestId==`string`?n.requestId:``;if(!r)return[];let i=typeof n.optionId==`string`?n.optionId:typeof t.ash_option==`string`?t[TEAMS_HITL_CHOICE_INPUT_ID]:void 0,a=typeof t.ash_freeform_text==`string`?t[TEAMS_HITL_FREEFORM_INPUT_ID]:void 0;return i===void 0?a===void 0?[{requestId:r}]:[{requestId:r,text:a}]:[{optionId:i,requestId:r}]}function teamsInvokeResponse(e={}){return{statusCode:e.statusCode??200,type:`application/vnd.microsoft.activity.message`,value:e.message??`Answer received.`}}function renderInputs(e){return e.display===`select`&&e.options&&e.options.length>0?[{choices:e.options.map(e=>({title:truncate(e.label,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH),value:e.id})),id:TEAMS_HITL_CHOICE_INPUT_ID,isMultiSelect:!1,style:`compact`,type:`Input.ChoiceSet`}]:e.allowFreeform===!0||!e.options||e.options.length===0?[{id:TEAMS_HITL_FREEFORM_INPUT_ID,isMultiline:!0,placeholder:`Type your answer`,type:`Input.Text`}]:[]}function renderActions(e){let t=e.options;return t&&t.length>0&&e.display!==`select`?t.slice(0,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT).map(t=>({data:{[TEAMS_HITL_DATA_KEY]:{optionId:t.id,requestId:e.requestId}},title:truncate(t.label,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH),type:`Action.Submit`})):[{data:{[TEAMS_HITL_DATA_KEY]:{requestId:e.requestId}},title:`Submit`,type:`Action.Submit`}]}function readActivityValue(e){return e.type===`message`?readMessageValue(e):e.type===`invoke`?readInvokeValue(e):null}function readMessageValue(e){return e.value??null}function readInvokeValue(t){let n=t.value;if(!n)return null;let r=isObject(n.action)?n.action:null;return(r&&isObject(r.data)?r.data:null)??n}function readHitlPayload(t){let n=t[TEAMS_HITL_DATA_KEY];if(isObject(n))return n;let r=isObject(t.action)?t.action:null,i=(r&&isObject(r.data)?r.data:null)?.[TEAMS_HITL_DATA_KEY];return isObject(i)?i:null}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,deriveTeamsInputResponses,isTeamsInputResponseActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse};
@@ -1,3 +1,3 @@
1
- import{isNonEmptyString,isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import TurndownService from"#compiled/turndown/index.js";var TEAMS_RESPONSE_INSTRUCTIONS=`Reply for Microsoft Teams in concise Markdown. Avoid broad mentions, large tables, and messages that need more than a few short posts.`,HTML_ENTITY_MAP={"&amp;":`&`,"&gt;":`>`,"&lt;":`<`,"&nbsp;":` `,"&quot;":`"`,"&#39;":`'`,"&#x27;":`'`},HTML_ENTITY_PATTERN=new RegExp(Object.keys(HTML_ENTITY_MAP).join(`|`),`gi`),turndownService=null;function parseTeamsActivity(e){return isObject(e)?e.type===`message`?parseMessageActivity(e):e.type===`invoke`?parseInvokeActivity(e):e.type===`conversationUpdate`?parseConversationUpdateActivity(e):null:null}function isTeamsPersonalMessage(e){return e.scope===`personal`}function teamsThreadRootActivityId(e){return e.scope===`personal`?null:e.replyToId??e.id}function formatTeamsContextBlock(e){return[`<teams_context>`,`response_medium: microsoft_teams`,`response_instructions: ${TEAMS_RESPONSE_INSTRUCTIONS}`,`user_id: ${e.userId}`,...e.userName?[`user_name: ${e.userName}`]:[],`conversation_id: ${e.conversationId}`,`scope: ${e.scope}`,...e.conversationType?[`conversation_type: ${e.conversationType}`]:[],...e.tenantId?[`tenant_id: ${e.tenantId}`]:[],...e.teamId?[`team_id: ${e.teamId}`]:[],...e.channelId?[`channel_id: ${e.channelId}`]:[],`activity_id: ${e.activityId}`,`</teams_context>`].join(`
1
+ import{isNonEmptyString,isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import TurndownService from"#compiled/turndown/index.js";const HTML_ENTITY_MAP={"&amp;":`&`,"&gt;":`>`,"&lt;":`<`,"&nbsp;":` `,"&quot;":`"`,"&#39;":`'`,"&#x27;":`'`},HTML_ENTITY_PATTERN=new RegExp(Object.keys(HTML_ENTITY_MAP).join(`|`),`gi`);let turndownService=null;function parseTeamsActivity(e){return isObject(e)?e.type===`message`?parseMessageActivity(e):e.type===`invoke`?parseInvokeActivity(e):e.type===`conversationUpdate`?parseConversationUpdateActivity(e):null:null}function isTeamsPersonalMessage(e){return e.scope===`personal`}function teamsThreadRootActivityId(e){return e.scope===`personal`?null:e.replyToId??e.id}function formatTeamsContextBlock(e){return[`<teams_context>`,`response_medium: microsoft_teams`,`response_instructions: Reply for Microsoft Teams in concise Markdown. Avoid broad mentions, large tables, and messages that need more than a few short posts.`,`user_id: ${e.userId}`,...e.userName?[`user_name: ${e.userName}`]:[],`conversation_id: ${e.conversationId}`,`scope: ${e.scope}`,...e.conversationType?[`conversation_type: ${e.conversationType}`]:[],...e.tenantId?[`tenant_id: ${e.tenantId}`]:[],...e.teamId?[`team_id: ${e.teamId}`]:[],...e.channelId?[`channel_id: ${e.channelId}`]:[],`activity_id: ${e.activityId}`,`</teams_context>`].join(`
2
2
  `)}function prependTeamsContext(e,t){let n=formatTeamsContextBlock(t);return typeof e==`string`?e.length>0?`${n}\n\n${e}`:n:[{type:`text`,text:n},...e]}function parseMessageActivity(n){let r=parseActivityBase(n);if(!r)return null;let i=parseMentions(n.entities),a=normalizeTeamsText(stripBotMention(readText(n),i,r.recipient.id));return{...r,attachments:parseAttachments(n.attachments),isBotMentioned:i.some(e=>e.mentioned.id===r.recipient.id),mentions:i,replyToId:isNonEmptyString(n.replyToId)?n.replyToId:void 0,scope:inferScope(r.conversation),text:a,textFormat:isNonEmptyString(n.textFormat)?n.textFormat:void 0,type:`message`,value:isObject(n.value)?n.value:void 0}}function parseInvokeActivity(n){let r=parseActivityBase(n);return!r||!isNonEmptyString(n.name)?null:{...r,name:n.name,replyToId:isNonEmptyString(n.replyToId)?n.replyToId:void 0,scope:inferScope(r.conversation),type:`invoke`,value:isObject(n.value)?n.value:void 0}}function parseConversationUpdateActivity(e){let t=parseActivityBase(e);return t?{...t,type:`conversationUpdate`}:null}function parseActivityBase(n){if(!isNonEmptyString(n.serviceUrl))return null;let r=parseConversation(n.conversation),i=parseChannelAccount(n.from),a=parseChannelAccount(n.recipient);if(!r||!i||!a)return null;let o=isObject(n.channelData)?n.channelData:{},s=readNestedString(o,[`tenant`,`id`])??r.tenantId,c=readNestedString(o,[`team`,`id`]),l=readNestedString(o,[`channel`,`id`]);return{channelData:o,conversation:r,conversationType:r.conversationType,from:i,id:isNonEmptyString(n.id)?n.id:``,raw:n,recipient:a,serviceUrl:n.serviceUrl,tenantId:s,teamId:c,teamsChannelId:l}}function parseConversation(n){return!isObject(n)||!isNonEmptyString(n.id)?null:{conversationType:isNonEmptyString(n.conversationType)?n.conversationType:void 0,id:n.id,isGroup:typeof n.isGroup==`boolean`?n.isGroup:void 0,name:isNonEmptyString(n.name)?n.name:void 0,tenantId:isNonEmptyString(n.tenantId)?n.tenantId:void 0}}function parseChannelAccount(n){return!isObject(n)||!isNonEmptyString(n.id)?null:{aadObjectId:isNonEmptyString(n.aadObjectId)?n.aadObjectId:void 0,id:n.id,name:isNonEmptyString(n.name)?n.name:void 0,role:isNonEmptyString(n.role)?n.role:void 0}}function parseMentions(n){if(!Array.isArray(n))return[];let r=[];for(let i of n){if(!isObject(i)||i.type!==`mention`||!isNonEmptyString(i.text))continue;let n=parseChannelAccount(i.mentioned);n&&r.push({mentioned:n,text:i.text,type:`mention`})}return r}function parseAttachments(r){if(!Array.isArray(r))return[];let i=[];for(let a of r){if(!isObject(a)||!isNonEmptyString(a.contentType))continue;let r={content:isObject(a.content)?parseJsonObject(a.content):void 0,contentType:a.contentType,contentUrl:isNonEmptyString(a.contentUrl)?a.contentUrl:void 0,name:isNonEmptyString(a.name)?a.name:void 0};i.push(r)}return i}function inferScope(e){let t=e.conversationType;return t===`personal`||t===`groupChat`||t===`channel`?t:e.isGroup===!0?`groupChat`:e.isGroup===!1?`personal`:`unknown`}function readText(e){return typeof e.text==`string`?e.text:``}function stripBotMention(e,t,n){let r=e;for(let e of t)e.mentioned.id===n&&(r=r.replace(e.text,``));return r.trim()}function normalizeTeamsText(e){let t=e.trim();return looksLikeHtml(t)?getTurndownService().turndown(t.replace(/<at>(.*?)<\/at>/gi,`@$1`)).replace(/ {2}\n/g,`
3
3
  `).trim():decodeHtmlEntities(t)}function readNestedString(n,r){let i=n;for(let e of r){if(!isObject(i))return;i=i[e]}return isNonEmptyString(i)?i:void 0}function looksLikeHtml(e){return/<\/?[a-z][\s\S]*>/i.test(e)}function decodeHtmlEntities(e){return e.replace(HTML_ENTITY_PATTERN,e=>HTML_ENTITY_MAP[e.toLowerCase()]??e)}function getTurndownService(){return turndownService??=new TurndownService({bulletListMarker:`-`,codeBlockStyle:`fenced`,emDelimiter:`*`,headingStyle:`atx`,hr:`---`}),turndownService}export{formatTeamsContextBlock,isTeamsPersonalMessage,parseTeamsActivity,prependTeamsContext,teamsThreadRootActivityId};
@@ -1 +1 @@
1
- var TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH=4e3,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH=80,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH=100,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT=6;export{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH};
1
+ const TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH=4e3,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH=80,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH=100,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT=6;export{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH};