eve 0.84.1 → 0.85.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/src/channel/channel-operations.d.ts +2 -18
  3. package/dist/src/channel/compiled-channel.d.ts +3 -7
  4. package/dist/src/channel/cross-channel-receive.d.ts +9 -10
  5. package/dist/src/channel/cross-channel-receive.js +1 -1
  6. package/dist/src/channel/schedule.js +1 -1
  7. package/dist/src/channel/session.d.ts +26 -4
  8. package/dist/src/channel/session.js +1 -1
  9. package/dist/src/chunks/{use-eve-agent-DMeP0JOF.js → use-eve-agent-B2jCfcnG.js} +3 -2
  10. package/dist/src/chunks/{use-eve-agent-DP5Rso9C.js → use-eve-agent-DCLFi26P.js} +3 -2
  11. package/dist/src/client/client.js +1 -1
  12. package/dist/src/client/open-stream.js +1 -1
  13. package/dist/src/client/types.d.ts +5 -4
  14. package/dist/src/compiled/.vendor-stamp.json +1 -1
  15. package/dist/src/context/keys.d.ts +7 -0
  16. package/dist/src/context/keys.js +1 -1
  17. package/dist/src/execution/agent-sessions/context.d.ts +5 -1
  18. package/dist/src/execution/agent-sessions/context.js +1 -1
  19. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  20. package/dist/src/execution/legacy-session/snapshot.d.ts +1 -2
  21. package/dist/src/execution/legacy-session/snapshot.js +1 -1
  22. package/dist/src/execution/proxied-deliver-step.js +1 -1
  23. package/dist/src/execution/public-destination.d.ts +3 -0
  24. package/dist/src/execution/public-destination.js +1 -1
  25. package/dist/src/execution/publish-session-events.js +1 -1
  26. package/dist/src/execution/session/checkpoint-migrations.d.ts +16 -5
  27. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  28. package/dist/src/execution/session/checkpoint-refusal.d.ts +4 -0
  29. package/dist/src/execution/session/checkpoint-refusal.js +1 -0
  30. package/dist/src/execution/session/entry.js +1 -1
  31. package/dist/src/execution/session/handoff-steps.d.ts +7 -1
  32. package/dist/src/execution/session/handoff-steps.js +1 -1
  33. package/dist/src/execution/session/imported-conversation.d.ts +2 -0
  34. package/dist/src/execution/session/imported-conversation.js +1 -0
  35. package/dist/src/execution/session/interrupted-step.js +1 -1
  36. package/dist/src/execution/session/pre-v27-checkpoint.d.ts +36 -0
  37. package/dist/src/execution/session/pre-v27-checkpoint.js +1 -0
  38. package/dist/src/execution/session/program.d.ts +2 -0
  39. package/dist/src/execution/session/program.js +1 -1
  40. package/dist/src/execution/session/turn-step.js +1 -1
  41. package/dist/src/execution/session-callback-request.js +1 -1
  42. package/dist/src/execution/tool-auth.js +1 -1
  43. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  44. package/dist/src/execution/tools/channel-to.d.ts +12 -0
  45. package/dist/src/execution/tools/channel-to.js +1 -0
  46. package/dist/src/execution/tools/workflow/body.d.ts +3 -0
  47. package/dist/src/execution/tools/workflow/body.js +1 -1
  48. package/dist/src/execution/tools/workflow/step-context.d.ts +5 -0
  49. package/dist/src/execution/tools/workflow/step-execution.js +1 -1
  50. package/dist/src/execution/tools/workflow/step.js +1 -1
  51. package/dist/src/execution/workflow-callback-url.d.ts +2 -3
  52. package/dist/src/execution/workflow-callback-url.js +1 -1
  53. package/dist/src/execution/workflow-runtime.js +1 -1
  54. package/dist/src/harness/compaction/step.js +1 -1
  55. package/dist/src/harness/model-call/call.js +1 -1
  56. package/dist/src/harness/model-call/run.js +1 -1
  57. package/dist/src/harness/session-machine/transitions.js +1 -1
  58. package/dist/src/internal/application/stamped-package-version.js +1 -1
  59. package/dist/src/internal/attachments/limited-read.d.ts +2 -0
  60. package/dist/src/internal/attachments/limited-read.js +1 -1
  61. package/dist/src/internal/attachments/url-refs.js +1 -1
  62. package/dist/src/internal/capability-error.d.ts +3 -0
  63. package/dist/src/internal/capability-error.js +1 -0
  64. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +1 -1
  65. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  66. package/dist/src/public/channels/github/githubChannel.js +1 -1
  67. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  68. package/dist/src/public/channels/linq/inboundContent.js +1 -1
  69. package/dist/src/public/channels/slack/answers.d.ts +2 -3
  70. package/dist/src/public/channels/slack/answers.js +1 -1
  71. package/dist/src/public/channels/slack/api.d.ts +23 -3
  72. package/dist/src/public/channels/slack/api.js +1 -1
  73. package/dist/src/public/channels/slack/app-manifest.d.ts +2 -0
  74. package/dist/src/public/channels/slack/app-manifest.js +1 -1
  75. package/dist/src/public/channels/slack/auth.d.ts +2 -1
  76. package/dist/src/public/channels/slack/auth.js +1 -1
  77. package/dist/src/public/channels/slack/code-channel.d.ts +42 -0
  78. package/dist/src/public/channels/slack/code-channel.js +1 -0
  79. package/dist/src/public/channels/slack/defaults.d.ts +7 -3
  80. package/dist/src/public/channels/slack/defaults.js +3 -3
  81. package/dist/src/public/channels/slack/hitl.d.ts +7 -17
  82. package/dist/src/public/channels/slack/hitl.js +1 -1
  83. package/dist/src/public/channels/slack/index.d.ts +4 -3
  84. package/dist/src/public/channels/slack/index.js +1 -1
  85. package/dist/src/public/channels/slack/interaction-cards.d.ts +0 -2
  86. package/dist/src/public/channels/slack/interaction-cards.js +1 -1
  87. package/dist/src/public/channels/slack/interactions.js +1 -1
  88. package/dist/src/public/channels/slack/open-code-channel.d.ts +30 -0
  89. package/dist/src/public/channels/slack/open-code-channel.js +1 -0
  90. package/dist/src/public/channels/slack/private-approval-delivery.d.ts +16 -4
  91. package/dist/src/public/channels/slack/private-approval-delivery.js +1 -1
  92. package/dist/src/public/channels/slack/renderers.d.ts +58 -6
  93. package/dist/src/public/channels/slack/renderers.js +1 -1
  94. package/dist/src/public/channels/slack/reply-delivery.d.ts +4 -0
  95. package/dist/src/public/channels/slack/reply-delivery.js +1 -1
  96. package/dist/src/public/channels/slack/request-card-render.d.ts +45 -0
  97. package/dist/src/public/channels/slack/request-card-render.js +1 -0
  98. package/dist/src/public/channels/slack/request-cards.d.ts +35 -0
  99. package/dist/src/public/channels/slack/request-cards.js +3 -0
  100. package/dist/src/public/channels/slack/sign-in-cancel.d.ts +3 -5
  101. package/dist/src/public/channels/slack/sign-in-cancel.js +1 -1
  102. package/dist/src/public/channels/slack/slackChannel.d.ts +109 -22
  103. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  104. package/dist/src/public/channels/slack/task-card.d.ts +3 -3
  105. package/dist/src/public/channels/slack/task-card.js +1 -1
  106. package/dist/src/public/channels/slack/thread-status.js +1 -1
  107. package/dist/src/public/channels/teams/api.js +1 -1
  108. package/dist/src/public/channels/teams/defaults.js +1 -1
  109. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  110. package/dist/src/public/channels/teams/verify.d.ts +9 -5
  111. package/dist/src/public/channels/teams/verify.js +1 -1
  112. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  113. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  114. package/dist/src/public/schedules/subscription.d.ts +10 -1
  115. package/dist/src/runtime/subagents/workflow.js +1 -1
  116. package/dist/src/setup/index.d.ts +1 -1
  117. package/dist/src/setup/primitives/index.d.ts +1 -1
  118. package/dist/src/setup/primitives/pm/run.d.ts +0 -2
  119. package/dist/src/setup/scaffold/create/project.js +1 -1
  120. package/dist/src/shared/channel-definition.d.ts +4 -4
  121. package/dist/src/subagents/adapter.js +1 -1
  122. package/dist/src/subagents/parent-notification.js +1 -1
  123. package/dist/src/svelte/index.js +1 -1
  124. package/dist/src/svelte/use-eve-agent.js +1 -1
  125. package/dist/src/tools/definition.d.ts +21 -0
  126. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  127. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  128. package/dist/src/tools/workflow-definition.d.ts +4 -4
  129. package/dist/src/vue/index.js +1 -1
  130. package/dist/src/vue/use-eve-agent.js +1 -1
  131. package/docs/channels/custom.mdx +16 -3
  132. package/docs/channels/eve.mdx +2 -0
  133. package/docs/channels/linq.mdx +1 -1
  134. package/docs/channels/slack.mdx +185 -18
  135. package/docs/channels/teams.mdx +6 -2
  136. package/docs/concepts/upgrade-to-v27-events.md +2 -2
  137. package/docs/experimental/dynamic-schedules.mdx +2 -2
  138. package/docs/guides/client/overview.mdx +1 -1
  139. package/docs/guides/remote-agents.md +8 -0
  140. package/docs/patterns/fork-conversations-into-new-threads.md +159 -0
  141. package/docs/patterns/meta.json +1 -0
  142. package/docs/schedules.mdx +1 -1
  143. package/docs/tools/overview.mdx +34 -0
  144. package/docs/tools/workflows.mdx +47 -5
  145. package/package.json +1 -1
  146. package/dist/src/public/channels/slack/approval-cards.d.ts +0 -25
  147. package/dist/src/public/channels/slack/approval-cards.js +0 -2
@@ -1 +1 @@
1
- import{createHash}from"node:crypto";import{callLabel,callOutputSource,callState,openInteractions}from"#protocol/session-projection/selectors.js";import{createLogger,logError}from"#internal/logging.js";import{normalizeChannelAudience}from"#shared/channel-audience.js";import{sessionTables}from"#protocol/session-projection/session-view.js";import{contextStorage}from"#context/container.js";import{ScheduleIdKey}from"#context/keys.js";import{displayName}from"#protocol/session-projection/display-name.js";import{AGENT_TOOL_NAME}from"#tools/framework/agent-contract.js";import{formatDuration}from"#shared/format-duration.js";import{firstSentence,normalizePresentationText}from"#shared/presentation-text.js";import{truncateMessageText}from"#public/channels/slack/limits.js";import{taskCards}from"#channel/task-card.js";import{restoreStatus}from"#public/channels/slack/thread-status.js";const log=createLogger(`slack.task-card`);function renderDefaultSlackTaskCard(e){let t=sessionTables(e.view),n={...e,view:t,calls:e.calls.flatMap(e=>t.calls[e.callId]??[])},r=n.calls.filter(e=>e.taskId!==void 0);if(r.length===0)return null;let{earlier:i,rows:a}=collapseEarlierRows(n.view,r),o=planTitle(n,r),s=[...i===void 0?[]:[i],...a.map(e=>toSlackTask(n,e))],c=slackBlockId(n.turnId),l=s.length===1?[{block_id:c,type:`task_card`,...s[0]}]:[{block_id:c,type:`plan`,tasks:s,title:o}],u=r.map(e=>callLabel(e)).join(`, `);return{blocks:l,text:truncateMessageText(`${o}: ${u}`)}}function planTitle(e,t){let{view:n}=e;if(e.state===`blocked`)return waitingText(t.flatMap(e=>openInteractions(n,{about:{callId:e.callId}}))[0]?.request.kind);let r=t.length,names=e=>r>1?agentNames(n,e):void 0;if(e.state===`working`){let e=t.filter(e=>e.status!==`settled`),n=r-e.length;if(n===0){let e=names(t);return e===void 0?`Working on ${countTasks(r)}`:`Asking ${e}`}let i=`${String(n)} of ${countTasks(r)} done`,a=names(e);return a===void 0?i:`Waiting on ${a} · ${i}`}let i=t.filter(e=>failedTask(n,e)).length,a=t.filter(e=>isInterrupted(n,e)).length,o=[];i>0&&o.push(`${String(i)} failed`),a>0&&o.push(`${String(a)} stopped`);let s=turnDuration(t),c=`Finished ${countTasks(r)}${s===void 0?``:` in ${s}`}`;return o.length===0?c:`${c}: ${o.join(`, `)}`}function agentNames(e,t){let agent=t=>(t.taskId===void 0?void 0:e.tasks[t.taskId]?.kind)??t.capability.kind;if(t.some(e=>agent(e)!==`agent`||e.capability.name===AGENT_TOOL_NAME))return;let n=[...new Set(t.map(e=>displayName(e.capability.name)))];if(!(n.length===0||n.length>3))return n.length<=2?n.join(` and `):`${n.slice(0,-1).join(`, `)}, and ${n.at(-1)}`}function turnDuration(e){let t=e.flatMap(e=>e.endedAt===void 0?[]:[Date.parse(e.endedAt)]);if(t.length===0)return;let n=Math.min(...e.map(e=>Date.parse(e.startedAt)));return shownDuration(Math.max(...t)-n)}function taskDuration(e){if(e.endedAt!==void 0)return shownDuration(Date.parse(e.endedAt)-Date.parse(e.startedAt))}function shownDuration(e){return Number.isFinite(e)&&e>=1e3?formatDuration(e):void 0}function failedTask(e,t){let n=callState(e,t.callId);return n===`failed`||n===`rejected`}function isInterrupted(e,t){return callState(e,t.callId)===`cancelled`&&t.reason!==`task-cancel`}function countTasks(e){return e===1?`1 task`:`${String(e)} tasks`}function collapseEarlierRows(e,t){if(t.length<=50)return{rows:t};let n=t.length-49,r=t.filter(e=>e.status===`settled`).slice(0,n),i=new Set(r.map(e=>e.callId)),a=t.filter(e=>!i.has(e.callId));return r.length===0?{rows:a.slice(-50)}:{earlier:{status:r.some(t=>failedTask(e,t)||isInterrupted(e,t))?`error`:`complete`,task_id:`earlier`,title:truncate(`${countTasks(r.length)} finished earlier`,80)},rows:a.slice(-49)}}function toSlackTask(e,t){let{view:n}=e,r={status:slackStatus(n,t),task_id:slackTaskId(t.callId),title:truncate(callLabel(t),80)},i=openInteractions(n,{about:{callId:t.callId}}).at(-1);i!==void 0&&(r.details=richText(blockerLine(e,i)));let a=outputLine(e,t);return a!==void 0&&(r.output=richText(a)),r}function slackStatus(e,t){switch(callState(e,t.callId)){case`completed`:return`complete`;case`cancelled`:return isInterrupted(e,t)?`error`:`complete`;case`failed`:case`rejected`:return`error`;default:return`in_progress`}}function outputLine(e,t){let{view:n}=e,r=taskDuration(t);switch(callState(n,t.callId)){case`completed`:{let e=brief(resultText(callOutputSource(n,t.callId)?.output??t.output));if(r===void 0)return e;let i=`Done in ${r}`;return e===void 0?i:`${i}: ${e}`}case`failed`:case`rejected`:{let n=r===void 0?`Failed`:`Failed after ${r}`,i=e.audience===`private`?brief(t.error?.message):void 0;return i===void 0?n:`${n}: ${i}`}case`cancelled`:return stoppedLine(t.reason);default:return}}function stoppedLine(e){switch(e){case`task-cancel`:return`Stopped early since it was no longer needed`;case`turn-cancelled`:return`Stopped by request`;case`turn-ended`:return`Stopped when the turn ended`;default:return`Stopped`}}function blockerLine(e,t){let{request:n}=t,r=waitingText(n.kind);if(e.audience!==`private`)return r;let i=n.kind===`sign-in`?n.signIn?.displayName??n.signIn?.name??n.prompt:n.prompt,a=i===void 0?``:normalizePresentationText(i);return a===``?r:`${r}: ${a.slice(0,200)}`}function waitingText(e){switch(e){case`approval`:return`Waiting for approval`;case`sign-in`:return`Waiting for sign-in`;default:return`Waiting for a response`}}function resultText(e){if(typeof e==`string`)return e;if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e;return t.message??t.text??t.summary}function brief(e){return typeof e==`string`?firstSentence(e):void 0}function richText(e){return{elements:[{elements:[{text:truncate(e,100),type:`text`}],type:`rich_text_section`}],type:`rich_text`}}function truncate(e,t){if(e.length<=t)return e;let n=e.slice(0,t-1),r=n.lastIndexOf(` `);return`${(r>t/2?n.slice(0,r):n).trimEnd()}…`}function slackTaskId(e){return e.replace(/[^a-zA-Z0-9_-]/g,`_`).slice(-200)}function slackBlockId(e){return`eve_task_card_${slackTaskId(e)}`}function withTaskCards(e,t){let n=e.committed;return{...e,async committed(e,r){try{await n?.(e,r)}finally{let{channel:n,view:i}=r,a=new Set([...e.facts.flatMap(e=>e.scope?.turnId??[]),...Object.keys(n.state.taskCards??{})]);for(let e of a)await writeTaskCards(n,sessionTables(i),e,t)}}}}async function writeTaskCards(e,t,n,r){if(t.turns[n]===void 0)return;let i=normalizeChannelAudience(e.state.audience),a=taskCards(t,n,i),o=e.state.taskCards?.[n]?.since??0;for(let t of a)t.since<o||(t.since>(e.state.taskCards?.[n]?.since??0)&&rememberCard(e.state,n,{since:t.since}),await writeChangedCard(e,n,t,r));a.at(-1)?.state===`finished`&&forgetTurn(e.state,n)}async function writeChangedCard(e,t,n,r){let{channelId:i,threadTs:a}=e.state,o=contextStorage.getStore()?.get(ScheduleIdKey)!==void 0;if(!i||!a||o)return;let s=renderCard(r,n);if(s===null)return;let c=e.state.taskCards?.[t]??{},l=createHash(`sha256`).update(JSON.stringify(s)).digest(`base64url`);if(l===c.fingerprint)return;let u=await writeCardWithRetry(e.slack,{card:s,channelId:i,threadTs:a,ts:c.ts});u!==void 0&&(rememberCard(e.state,t,{...c,fingerprint:l,ts:u}),u!==c.ts&&n.state===`working`&&await restoreStatus(e))}function rememberCard(e,t,n){let r={...e.taskCards,[t]:n},i=Object.keys(r);for(let e of i.slice(0,Math.max(0,i.length-20)))delete r[e];e.taskCards=r}function forgetTurn(e,t){let{[t]:n,...r}=e.taskCards??{};e.taskCards=r}function renderCard(e,t){try{return e(t)}catch(e){return logError(log,`task card renderer failed`,e,{turnId:t.turnId}),null}}async function writeCardWithRetry(e,t){for(let n of[1,2])try{return await writeCard(e,t)}catch(e){logError(log,`task card write failed`,e,{attempt:n}),n===1&&await new Promise(e=>setTimeout(e,1e3))}}async function writeCard(e,t){let n={blocks:t.card.blocks,channel:t.channelId,text:t.card.text};if(t.ts!==void 0){let r=await e.request(`chat.update`,{...n,ts:t.ts});if(r.ok===!0)return t.ts;if(r.error!==`message_not_found`)throw slackError(r.error)}let r=await e.request(`chat.postMessage`,{...n,thread_ts:t.threadTs,unfurl_links:!1,unfurl_media:!1});if(r.ok!==!0)throw slackError(r.error);if(typeof r.ts!=`string`||r.ts===``)throw Error(`Slack did not return a ts for the task card.`);return r.ts}function slackError(e){return Error(`Slack task card failed: ${e??`unknown_error`}`)}export{renderDefaultSlackTaskCard,withTaskCards};
1
+ import{createHash}from"node:crypto";import{callLabel,callOutputSource,callState,openInteractions}from"#protocol/session-projection/selectors.js";import{createLogger,logError}from"#internal/logging.js";import{normalizeChannelAudience}from"#shared/channel-audience.js";import{sessionTables}from"#protocol/session-projection/session-view.js";import{contextStorage}from"#context/container.js";import{ScheduleIdKey}from"#context/keys.js";import{displayName}from"#protocol/session-projection/display-name.js";import{AGENT_TOOL_NAME}from"#tools/framework/agent-contract.js";import{formatDuration}from"#shared/format-duration.js";import{firstSentence,normalizePresentationText}from"#shared/presentation-text.js";import{slackThreadTsParam}from"#public/channels/slack/code-channel.js";import{truncateMessageText}from"#public/channels/slack/limits.js";import{taskCards}from"#channel/task-card.js";import{restoreStatus}from"#public/channels/slack/thread-status.js";const log=createLogger(`slack.task-card`);function renderDefaultSlackTaskCard(e){let t=sessionTables(e.view),n={...e,view:t,calls:e.calls.flatMap(e=>t.calls[e.callId]??[])},r=n.calls.filter(e=>e.taskId!==void 0);if(r.length===0)return null;let{earlier:i,rows:a}=collapseEarlierRows(n.view,r),o=planTitle(n,r),s=[...i===void 0?[]:[i],...a.map(e=>toSlackTask(n,e))],c=slackBlockId(n.turnId),l=s.length===1?[{block_id:c,type:`task_card`,...s[0]}]:[{block_id:c,type:`plan`,tasks:s,title:o}],u=r.map(e=>callLabel(e)).join(`, `);return{blocks:l,text:truncateMessageText(`${o}: ${u}`)}}function planTitle(e,t){let{view:n}=e;if(e.state===`blocked`)return waitingText(t.flatMap(e=>openInteractions(n,{about:{callId:e.callId}}))[0]?.request.kind);let r=t.length,names=e=>r>1?agentNames(n,e):void 0;if(e.state===`working`){let e=t.filter(e=>e.status!==`settled`),n=r-e.length;if(n===0){let e=names(t);return e===void 0?`Working on ${countTasks(r)}`:`Asking ${e}`}let i=`${String(n)} of ${countTasks(r)} done`,a=names(e);return a===void 0?i:`Waiting on ${a} · ${i}`}let i=t.filter(e=>failedTask(n,e)).length,a=t.filter(e=>isInterrupted(n,e)).length,o=[];i>0&&o.push(`${String(i)} failed`),a>0&&o.push(`${String(a)} stopped`);let s=turnDuration(t),c=`Finished ${countTasks(r)}${s===void 0?``:` in ${s}`}`;return o.length===0?c:`${c}: ${o.join(`, `)}`}function agentNames(e,t){let agent=t=>(t.taskId===void 0?void 0:e.tasks[t.taskId]?.kind)??t.capability.kind;if(t.some(e=>agent(e)!==`agent`||e.capability.name===AGENT_TOOL_NAME))return;let n=[...new Set(t.map(e=>displayName(e.capability.name)))];if(!(n.length===0||n.length>3))return n.length<=2?n.join(` and `):`${n.slice(0,-1).join(`, `)}, and ${n.at(-1)}`}function turnDuration(e){let t=e.flatMap(e=>e.endedAt===void 0?[]:[Date.parse(e.endedAt)]);if(t.length===0)return;let n=Math.min(...e.map(e=>Date.parse(e.startedAt)));return shownDuration(Math.max(...t)-n)}function taskDuration(e){if(e.endedAt!==void 0)return shownDuration(Date.parse(e.endedAt)-Date.parse(e.startedAt))}function shownDuration(e){return Number.isFinite(e)&&e>=1e3?formatDuration(e):void 0}function failedTask(e,t){let n=callState(e,t.callId);return n===`failed`||n===`rejected`}function isInterrupted(e,t){return callState(e,t.callId)===`cancelled`&&t.reason!==`task-cancel`}function countTasks(e){return e===1?`1 task`:`${String(e)} tasks`}function collapseEarlierRows(e,t){if(t.length<=50)return{rows:t};let n=t.length-49,r=t.filter(e=>e.status===`settled`).slice(0,n),i=new Set(r.map(e=>e.callId)),a=t.filter(e=>!i.has(e.callId));return r.length===0?{rows:a.slice(-50)}:{earlier:{status:r.some(t=>failedTask(e,t)||isInterrupted(e,t))?`error`:`complete`,task_id:`earlier`,title:truncate(`${countTasks(r.length)} finished earlier`,80)},rows:a.slice(-49)}}function toSlackTask(e,t){let{view:n}=e,r={status:slackStatus(n,t),task_id:slackTaskId(t.callId),title:truncate(callLabel(t),80)},i=openInteractions(n,{about:{callId:t.callId}}).at(-1);i!==void 0&&(r.details=richText(blockerLine(e,i)));let a=outputLine(e,t);return a!==void 0&&(r.output=richText(a)),r}function slackStatus(e,t){switch(callState(e,t.callId)){case`completed`:return`complete`;case`cancelled`:return isInterrupted(e,t)?`error`:`complete`;case`failed`:case`rejected`:return`error`;default:return`in_progress`}}function outputLine(e,t){let{view:n}=e,r=taskDuration(t);switch(callState(n,t.callId)){case`completed`:{let e=brief(resultText(callOutputSource(n,t.callId)?.output??t.output));if(r===void 0)return e;let i=`Done in ${r}`;return e===void 0?i:`${i}: ${e}`}case`failed`:case`rejected`:{let n=r===void 0?`Failed`:`Failed after ${r}`,i=e.audience===`private`?brief(t.error?.message):void 0;return i===void 0?n:`${n}: ${i}`}case`cancelled`:return stoppedLine(t.reason);default:return}}function stoppedLine(e){switch(e){case`task-cancel`:return`Stopped early since it was no longer needed`;case`turn-cancelled`:return`Stopped by request`;case`turn-ended`:return`Stopped when the turn ended`;default:return`Stopped`}}function blockerLine(e,t){let{request:n}=t,r=waitingText(n.kind);if(e.audience!==`private`)return r;let i=n.kind===`sign-in`?n.signIn?.displayName??n.signIn?.name??n.prompt:n.prompt,a=i===void 0?``:normalizePresentationText(i);return a===``?r:`${r}: ${a.slice(0,200)}`}function waitingText(e){switch(e){case`approval`:return`Waiting for approval`;case`sign-in`:return`Waiting for sign-in`;default:return`Waiting for a response`}}function resultText(e){if(typeof e==`string`)return e;if(typeof e!=`object`||!e||Array.isArray(e))return;let t=e;return t.message??t.text??t.summary}function brief(e){return typeof e==`string`?firstSentence(e):void 0}function richText(e){return{elements:[{elements:[{text:truncate(e,100),type:`text`}],type:`rich_text_section`}],type:`rich_text`}}function truncate(e,t){if(e.length<=t)return e;let n=e.slice(0,t-1),r=n.lastIndexOf(` `);return`${(r>t/2?n.slice(0,r):n).trimEnd()}…`}function slackTaskId(e){return e.replace(/[^a-zA-Z0-9_-]/g,`_`).slice(-200)}function slackBlockId(e){return`eve_task_card_${slackTaskId(e)}`}function withTaskCards(e,t){let n=e.committed;return{...e,async committed(e,r){try{await n?.(e,r)}finally{let{channel:n,view:i}=r,a=new Set([...e.facts.flatMap(e=>e.scope?.turnId??[]),...Object.keys(n.state.taskCards??{})]);for(let e of a)await writeTaskCards(n,sessionTables(i),e,t)}}}}async function writeTaskCards(e,t,n,r){if(t.turns[n]===void 0)return;let i=normalizeChannelAudience(e.state.audience),a=taskCards(t,n,i),o=e.state.taskCards?.[n]?.since??0;for(let t of a)t.since<o||(t.since>(e.state.taskCards?.[n]?.since??0)&&rememberCard(e.state,n,{since:t.since}),await writeChangedCard(e,n,t,r));a.at(-1)?.state===`finished`&&forgetTurn(e.state,n)}async function writeChangedCard(e,t,n,r){let{channelId:i,codeChannel:a}=e.state,o=(a?e.state.replyThreadTs:e.state.threadTs)??``,s=contextStorage.getStore()?.get(ScheduleIdKey)!==void 0;if(!i||!(o||a)||s)return;let c=renderCard(r,n);if(c===null)return;let l=e.state.taskCards?.[t]??{},u=createHash(`sha256`).update(JSON.stringify(c)).digest(`base64url`);if(u===l.fingerprint)return;let d=await writeCardWithRetry(e.slack,{card:c,channelId:i,threadTs:o,ts:l.ts});d!==void 0&&(rememberCard(e.state,t,{...l,fingerprint:u,ts:d}),d!==l.ts&&n.state===`working`&&await restoreStatus(e))}function rememberCard(e,t,n){let r={...e.taskCards,[t]:n},i=Object.keys(r);for(let e of i.slice(0,Math.max(0,i.length-20)))delete r[e];e.taskCards=r}function forgetTurn(e,t){let{[t]:n,...r}=e.taskCards??{};e.taskCards=r}function renderCard(e,t){try{return e(t)}catch(e){return logError(log,`task card renderer failed`,e,{turnId:t.turnId}),null}}async function writeCardWithRetry(e,t){for(let n of[1,2])try{return await writeCard(e,t)}catch(e){logError(log,`task card write failed`,e,{attempt:n}),n===1&&await new Promise(e=>setTimeout(e,1e3))}}async function writeCard(e,t){let n={blocks:t.card.blocks,channel:t.channelId,text:t.card.text};if(t.ts!==void 0){let r=await e.request(`chat.update`,{...n,ts:t.ts});if(r.ok===!0)return t.ts;if(r.error!==`message_not_found`)throw slackError(r.error)}let r=await e.request(`chat.postMessage`,{...n,thread_ts:slackThreadTsParam(t.threadTs),unfurl_links:!1,unfurl_media:!1});if(r.ok!==!0)throw slackError(r.error);if(typeof r.ts!=`string`||r.ts===``)throw Error(`Slack did not return a ts for the task card.`);return r.ts}function slackError(e){return Error(`Slack task card failed: ${e??`unknown_error`}`)}export{renderDefaultSlackTaskCard,withTaskCards};
@@ -1 +1 @@
1
- import{SLACK_TYPING_STATUS_MAX_LENGTH,truncateTypingStatus}from"#public/channels/slack/limits.js";async function showStatus(e,t,n){let r=truncateTypingStatus(t),i=Date.now(),a=e.state.threadStatus;a?.text===r&&i-a.atMs>=0&&i-a.atMs<3e4&&n?.force!==!0||(await e.thread.startTyping(r),e.state.threadStatus={atMs:i,text:r})}async function restoreStatus(e){let t=e.state.threadStatus;t&&await showStatus(e,t.text,{force:!0})}async function hideStatus(e){let t=e.state.threadStatus;t&&(e.state.threadStatus={...t,atMs:0}),await e.thread.startTyping()}async function clearStatus(e){e.state.threadStatus=null,await e.thread.startTyping()}const HEADING=/(?:^|\n)[ \t]*\*\*([^*\n]+)\*\*/gu,SENTENCE_BOUNDARY=/(?<=[.!?])(?<!(?:^|\s)\d{1,2}\.)\s+(?=[\p{Lu}"'`(])/u,LIST_MARKER=/^(?:[-*+]|\d{1,2}[.)])\s+/u;function reasoningStatus(e,t){let n=[...e.matchAll(HEADING)].findLast(e=>e[1].trim()!==``);if(n)return n[1].trim();let r=e.split(/\r?\n/u).flatMap(e=>e.split(SENTENCE_BOUNDARY)).map(e=>e.trim().replace(LIST_MARKER,``)),i=t?.complete===!0?-1:r.length-1;for(let e=r.length-1;e>=0;--e){let t=r[e],n=e===i?SLACK_TYPING_STATUS_MAX_LENGTH:12;if(t.length>=n&&isProse(t))return t}}function isProse(e){return!e.startsWith("```")&&/\p{L}/u.test(e)}export{clearStatus,hideStatus,reasoningStatus,restoreStatus,showStatus};
1
+ import{setSlackCodeChannelStatus}from"#public/channels/slack/code-channel.js";import{SLACK_TYPING_STATUS_MAX_LENGTH,truncateTypingStatus}from"#public/channels/slack/limits.js";async function showStatus(e,t,n){let r=truncateTypingStatus(t),i=Date.now(),a=e.state.threadStatus;if(isCodeChannel(e)&&a!=null&&a.atMs>0){e.state.threadStatus={atMs:i,text:r};return}a?.text===r&&i-a.atMs>=0&&i-a.atMs<3e4&&n?.force!==!0||(await e.thread.startTyping(r),e.state.threadStatus={atMs:i,text:r})}async function restoreStatus(e){let t=e.state.threadStatus;t&&await showStatus(e,t.text,{force:!0})}async function hideStatus(e){let t=e.state.threadStatus;if(t&&(e.state.threadStatus={...t,atMs:0}),isCodeChannel(e)){await setSlackCodeChannelStatus(e.slack.request,e.slack.channelId,`suspended`);return}await e.thread.startTyping()}function isCodeChannel(e){return e.slack.codeChannel}async function clearStatus(e){e.state.threadStatus=null,await e.thread.startTyping()}const HEADING=/(?:^|\n)[ \t]*\*\*([^*\n]+)\*\*/gu,SENTENCE_BOUNDARY=/(?<=[.!?])(?<!(?:^|\s)\d{1,2}\.)\s+(?=[\p{Lu}"'`(])/u,LIST_MARKER=/^(?:[-*+]|\d{1,2}[.)])\s+/u;function reasoningStatus(e,t){let n=[...e.matchAll(HEADING)].findLast(e=>e[1].trim()!==``);if(n)return n[1].trim();let r=e.split(/\r?\n/u).flatMap(e=>e.split(SENTENCE_BOUNDARY)).map(e=>e.trim().replace(LIST_MARKER,``)),i=t?.complete===!0?-1:r.length-1;for(let e=r.length-1;e>=0;--e){let t=r[e],n=e===i?SLACK_TYPING_STATUS_MAX_LENGTH:12;if(t.length>=n&&isProse(t))return t}}function isProse(e){return!e.startsWith("```")&&/\p{L}/u.test(e)}export{clearStatus,hideStatus,reasoningStatus,restoreStatus,showStatus};
@@ -1,4 +1,4 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=81920,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){let t=normalizeTeamsContinuationAddress(e);return[e.tenantId??`_`,t.conversationId,t.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}function normalizeTeamsContinuationAddress(e){let t=e.conversationId.lastIndexOf(`;messageid=`);return t<0?{conversationId:e.conversationId,replyToActivityId:e.replyToActivityId??null}:{conversationId:e.conversationId.slice(0,t),replyToActivityId:e.conversationId.slice(t+11)||e.replyToActivityId||null}}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(e={}){let t=e.credentials;if(t?.tokenProvider!==void 0)return normalizeAccessTokenResult(await t.tokenProvider()).accessToken;let n=await resolveTeamsAppId(t?.appId),r=await resolveTeamsAppPassword(t?.appPassword),i=await resolveTeamsTenantId(t?.tenantId),a=trimTrailingSlash(e.loginBaseUrl??`https://login.microsoftonline.com`),o=`${a}:${i??BOT_FRAMEWORK_TENANT}:${n}`,s=accessTokenCache.get(o),c=Date.now();if(s!==void 0&&s.expiresAt-6e4>c)return s.accessToken;let l=`${a}/${encodeURIComponent(i??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,u=new URLSearchParams({client_id:n,client_secret:r,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),d=await(e.fetch??fetch)(l,{body:u,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),f=await parseResponseBody(d);if(!d.ok)throw Error(`Teams access-token request failed with HTTP ${d.status}.`);let p=isObject(f)?f:{},m=typeof p.access_token==`string`?p.access_token:``;if(!m)throw Error(`Teams access-token response did not include access_token.`);let h=typeof p.expires_in==`number`?p.expires_in:3600;return accessTokenCache.set(o,{accessToken:m,expiresAt:c+h*1e3}),m}async function callTeamsConnectorApi(e){let t=e.fetch??fetch,n=new Headers;n.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),n.set(`content-type`,`application/json; charset=utf-8`);let r={headers:n,method:e.method??`POST`};e.body!==void 0&&(r.body=JSON.stringify(parseJsonObject(e.body)));let i=await t(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,r);return{body:await parseResponseBody(i),ok:i.ok,status:i.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} for conversation "${e.conversationId}" activity "${e.activityId}": ${formatConnectorErrorBody(t.body)}`);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=[],n=e;for(;n.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=n.lastIndexOf(`
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=81920,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){let t=normalizeTeamsContinuationAddress(e);return[e.tenantId??`_`,t.conversationId,t.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}function normalizeTeamsContinuationAddress(e){let t=e.conversationId.lastIndexOf(`;messageid=`);return t<0?{conversationId:e.conversationId,replyToActivityId:e.replyToActivityId??null}:{conversationId:e.conversationId.slice(0,t),replyToActivityId:e.conversationId.slice(t+11)||e.replyToActivityId||null}}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(e={}){let t=e.credentials;if(t?.tokenProvider!==void 0)return normalizeAccessTokenResult(await t.tokenProvider()).accessToken;let n=await resolveTeamsAppId(t?.appId),r=await resolveTeamsAppPassword(t?.appPassword),i=await resolveTeamsTenantId(t?.tenantId),a=trimTrailingSlash(e.loginBaseUrl??`https://login.microsoftonline.com`),o=`${a}:${i??BOT_FRAMEWORK_TENANT}:${n}`,s=accessTokenCache.get(o),c=Date.now();if(s!==void 0&&s.expiresAt-6e4>c)return s.accessToken;let l=`${a}/${encodeURIComponent(i??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,u=new URLSearchParams({client_id:n,client_secret:r,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),d=await(e.fetch??fetch)(l,{body:u,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),f=await parseResponseBody(d);if(!d.ok)throw Error(`Teams access-token request failed with HTTP ${d.status}.`);let p=isObject(f)?f:{},m=typeof p.access_token==`string`?p.access_token:``;if(!m)throw Error(`Teams access-token response did not include access_token.`);let h=typeof p.expires_in==`number`?p.expires_in:3600;return accessTokenCache.set(o,{accessToken:m,expiresAt:c+h*1e3}),m}async function callTeamsConnectorApi(e){let t=URL.parse(e.serviceUrl);if(t===null||t.protocol!==`https:`||t.username!==``||t.password!==``||t.search!==``||t.hash!==``)throw Error(`Teams Connector service URL must be an absolute HTTPS URL without credentials, query, or fragment.`);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`,redirect:`error`};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} for conversation "${e.conversationId}" activity "${e.activityId}": ${formatConnectorErrorBody(t.body)}`);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=[],n=e;for(;n.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=n.lastIndexOf(`
2
2
 
3
3
  `,TEAMS_MESSAGE_TEXT_MAX_LENGTH);e<=0&&(e=n.lastIndexOf(`
4
4
  `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=n.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(n.slice(0,e).trimEnd()),n=n.slice(e).trimStart()}return t.push(n),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(e){let t=isObject(e)?e:{};return{id:typeof t.id==`string`?t.id:``,raw:e}}function formatConnectorErrorBody(e){let t=typeof e==`string`?e:JSON.stringify(e);return t===void 0||t.length===0?`empty response body`:t.length<=1e3?t:`${t.slice(0,997)}...`}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,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};
@@ -1 +1 @@
1
- import{postedIn,signInEndedText}from"#channel/sign-in.js";import{displayProperName}from"#protocol/session-projection/display-name.js";import{resolvedPromptAnswer}from"#channel/resolved-prompt.js";import{surfaceEvents}from"#channel/surface.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInteractionMessage,renderInteractionMessage}from"#public/channels/teams/hitl.js";import{renderTeamsAuthorizationPrompt,renderTeamsAuthorizationStatus}from"#public/channels/teams/authorization.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.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}async function showTeamsRequest(e,t){let n=await e.thread.post(renderInteractionMessage(t,{adaptiveCardVersion:e.adaptiveCardVersion,replyToActivityId:e.teams.replyToActivityId}));if(!n.id)return;let r={activityId:n.id,prompt:t.request.prompt};e.state.pendingPromptCards={...e.state.pendingPromptCards,[t.interactionId]:t.request.kind===`question`?{...r,options:(t.request.options??[]).map(({id:e,label:t})=>({id:e,label:t}))}:r}}async function settleTeamsRequest(e,t){let{[t.interactionId]:n,...r}=e.state.pendingPromptCards??{};if(n===void 0)return;let{kind:i,outcome:a,responder:o}=t,s=i===`approval`&&o!==void 0&&(a===`accepted`||a===`declined`),c=resolvedPromptAnswer(t,n.options);if(s){let t=e.state.approvalResponderAccounts?.[o.id],n=t?.name??t?.id,r=a===`accepted`?`Approved`:`Cancelled`;c=n===void 0?r:`${r} by ${n}`}await e.thread.update(n.activityId,renderAnsweredInteractionMessage({includeText:!1,label:c,prompt:n.prompt})),e.state.pendingPromptCards=r}function teamsSignIns(e){return{private:e.state.conversationType===`personal`,postChallenge:async t=>(await e.thread.post(renderTeamsAuthorizationPrompt(t,signInOptions(e,t)))).id,post:async t=>(await e.thread.post({text:t})).id,postStatus:async t=>(await e.thread.post(renderTeamsAuthorizationStatus(t,signInOptions(e,t)))).id,async edit(t,n){await e.thread.update(t,renderAnsweredInteractionMessage({prompt:n}))},typing:()=>e.thread.startTyping(),posted:postedIn(e.state,`pendingAuthActivityIds`)}}function signInOptions(e,t){let n=(t.principalId===void 0?void 0:e.state.approvalResponderAccounts?.[t.principalId])??(t.responseId===void 0?e.state.triggeringUser:null);return{adaptiveCardVersion:e.adaptiveCardVersion,replyToActivityId:e.teams.replyToActivityId,requester:n==null?void 0:n.name??n.id}}const defaultEvents=surfaceEvents({typing:e=>e.thread.startTyping(),async post(e,t){for(let n of splitTeamsMessageText(t))await e.thread.post(n)},restart:`Teams conversation`,requests:{show:showTeamsRequest,settle:settleTeamsRequest},signIns:teamsSignIns});function formatConnectionDisplayName(e){return displayProperName(e)}const buildAuthCompletedText=signInEndedText;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
+ import{postedIn,signInEndedText}from"#channel/sign-in.js";import{displayProperName}from"#protocol/session-projection/display-name.js";import{resolvedPromptAnswer}from"#channel/resolved-prompt.js";import{surfaceEvents}from"#channel/surface.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInteractionMessage,renderInteractionMessage}from"#public/channels/teams/hitl.js";import{renderTeamsAuthorizationPrompt,renderTeamsAuthorizationStatus}from"#public/channels/teams/authorization.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.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}async function showTeamsRequest(e,t){let n=await e.thread.post(renderInteractionMessage(t,{adaptiveCardVersion:e.adaptiveCardVersion,replyToActivityId:e.teams.replyToActivityId}));if(!n.id)return;let r={activityId:n.id,prompt:t.request.prompt};e.state.pendingPromptCards={...e.state.pendingPromptCards,[t.interactionId]:t.request.kind===`question`?{...r,options:(t.request.options??[]).map(({id:e,label:t})=>({id:e,label:t}))}:r}}async function settleTeamsRequest(e,t){let{[t.interactionId]:n,...r}=e.state.pendingPromptCards??{};if(n===void 0)return;let{kind:i,outcome:a,responder:o}=t,s=i===`approval`&&o!==void 0&&(a===`accepted`||a===`declined`),c=resolvedPromptAnswer(t,n.options);if(s){let t=e.state.approvalResponderAccounts?.[o.id],n=t?.name??t?.id,r=a===`accepted`?`Approved`:`Cancelled`;c=n===void 0?r:`${r} by ${n}`}await e.thread.update(n.activityId,renderAnsweredInteractionMessage({includeText:!1,label:c,prompt:n.prompt})),e.state.pendingPromptCards=r}function teamsSignIns(e){return{private:e.state.conversationType===`personal`,postChallenge:async t=>(await e.thread.post(renderTeamsAuthorizationPrompt(t,signInOptions(e,t)))).id,post:async t=>(await e.thread.post({text:t})).id,postStatus:async t=>(await e.thread.post(renderTeamsAuthorizationStatus(t,signInOptions(e,t)))).id,async edit(t,n){await e.thread.update(t,renderAnsweredInteractionMessage({prompt:n}))},typing:()=>e.thread.startTyping(),posted:postedIn(e.state,`pendingAuthActivityIds`)}}function signInOptions(e,t){let n=(t.principalId===void 0?void 0:e.state.approvalResponderAccounts?.[t.principalId])??(t.responseId===void 0?e.state.triggeringUser:null);return{adaptiveCardVersion:e.adaptiveCardVersion,replyToActivityId:e.teams.replyToActivityId,requester:n==null?void 0:n.name??n.id}}const defaultEvents=surfaceEvents({typing:e=>e.thread.startTyping(),async post(e,t){for(let n of splitTeamsMessageText(t))await e.thread.post(n)},restart:`Teams conversation`,requests:{show:showTeamsRequest,settle:settleTeamsRequest},signIns:teamsSignIns});function formatConnectionDisplayName(e){return displayProperName(e)}const buildAuthCompletedText=signInEndedText;function teamsMentionUser(e){let t=(e.name??e.id).replaceAll(`&`,`&amp;`).replaceAll(`<`,`&lt;`).replaceAll(`>`,`&gt;`);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{createLogger,logError}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{INACTIVE_REQUEST_NOTICE,respondOrRetireInactivePrompt}from"#channel/inactive-prompt.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsAnswers,isTeamsAnswerActivity,isTeamsToolApprovalResponseActivity,readTeamsInputPrompt,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,renderInactiveInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{answerTeamsAuthorizationReveal,readTeamsAuthorizationReveal}from"#public/channels/teams/authorization.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),n=e.onMessage??defaultOnMessage,r=e.onAnswers??(e.onMessage===void 0?defaultOnAnswers:rejectInput),i={...defaultEvents,...e.events};return defineChannel({turnPolicy:e.turnPolicy,uploadPolicy:e.files?.uploadPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t,{...e.api,credentials:e.credentials}),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),audience:({state:e})=>teamsAudience(e.conversationType),context(t,n){return rebuildTeamsContext(t,n,e)},deliver(e,t){let n=e.state,r=n?.pendingPromptCards;r!==void 0&&(t.state.pendingPromptCards={...r,...t.state.pendingPromptCards});let i=n?.approvalResponderAccounts;i!==void 0&&(t.state.approvalResponderAccounts={...t.state.approvalResponderAccounts,...i})},routes:[POST(e.route??`/eve/v1/teams`,async(i,{from:a,resolveSession:o,waitUntil:s})=>{let c=await verifyInbound(i,e.credentials);if(c===null)return new Response(`unauthorized`,{status:401});let l;try{l=parseJsonObject(JSON.parse(c))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let u=parseTeamsActivity(l);return u===null?teamsOk():u.type===`message`?(s(isTeamsAnswerActivity(u)?dispatchAnswers({activity:u,config:e,from:a,onAnswers:r}).then(e=>e?.outcome===`inactive`?e.retirement:void 0):dispatchMessage({activity:u,config:e,filesPolicy:t,onMessage:n,from:a,resolveSession:o})),teamsOk()):u.type===`invoke`?handleInvoke({activity:u,config:e,onAnswers:r,resolveSession:o,waitUntil:s,from:a}):teamsOk()})],async receive(t,{from:n}){let r=t.target,i=readNonEmptyString(r.serviceUrl),a=readNonEmptyString(r.conversationId);if(!i||!a)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let o=readNonEmptyString(r.conversationType)??null,s=readNonEmptyString(r.replyToActivityId)??null,c=r.initialMessage;if(c!==void 0&&s!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let l={...initialTeamsState(),channelId:readNonEmptyString(r.channelId)??null,conversationId:a,conversationType:o,replyToActivityId:s,serviceUrl:i,teamId:readNonEmptyString(r.teamId)??null,tenantId:readNonEmptyString(r.tenantId)??null};if(c!==void 0){let t=await buildTeamsBinding({config:e,state:l}).thread.post(c);o!==`personal`&&t.id&&(s=t.id,l.replyToActivityId=t.id)}return n(teamsContinuationToken({conversationId:a,replyToActivityId:s,tenantId:l.tenantId})).send(t.message,{auth:t.auth,state:l})},events:i})}function teamsAudience(e){return e===`personal`||e===`groupChat`?`private`:`unknown`}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let t=buildTeamsHandle(e);return{teams:t,thread:{mentionUser:teamsMentionUser,post(e){return t.sendActivity(e)},async startTyping(){try{await t.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,n){return t.updateActivity(e,n)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.alias(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildUpdateActivity(t,i),credentials:r,activityId:e,conversationId:normalizeTeamsContinuationAddress({conversationId:a.conversationId}).conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveSession(r)!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,botId:e.activity.recipient.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,isMentioned:e.activity.isBotMentioned,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],history:a.history,state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){let t=readTeamsAuthorizationReveal(e.activity);if(t!==null)return Response.json(await revealAuthorization({...e,reveal:t}));if(isTeamsAnswerActivity(e.activity)){let t=await dispatchAnswers({activity:e.activity,config:e.config,onAnswers:e.onAnswers,from:e.from});return t?.outcome===`inactive`?(e.waitUntil(t.retirement),Response.json(teamsInvokeResponse({message:INACTIVE_REQUEST_NOTICE}))):Response.json(teamsInvokeResponse())}if(e.config.onInvoke===void 0)return teamsOk();let n=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),r=await e.config.onInvoke(n,e.activity);return r instanceof Response?r:r&&typeof r==`object`?Response.json(r):teamsOk()}async function revealAuthorization(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=null;try{r=(await e.onAnswers(n,e.activity))?.auth??null}catch(e){log.error(`Teams sign-in press authorization failed`,{error:e})}let i=cardContinuationToken(e.activity,t,e.reveal.replyToActivityId??null);return await answerTeamsAuthorizationReveal({adaptiveCardVersion:e.config.adaptiveCardVersion??`1.5`,auth:r,presser:e.activity.from,resolveSession:()=>e.resolveSession(i),reveal:e.reveal})}async function dispatchAnswers(e){let t=deriveTeamsAnswers(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onAnswers(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i===null)return;let a=i.auth,o=e.activity;return respondOrRetireInactivePrompt(()=>e.from(cardContinuationToken(o,n,readTeamsInputReplyToActivityId(o))).respond(t,{auth:a,state:approvalResponseStatePatch(o,a)}),{async retirePrompt(e){o.replyToId!==void 0&&await r.thread.update(o.replyToId,renderInactiveInputRequestMessage(readTeamsInputPrompt(o),e))}},log)}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityIds:{},replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function cardContinuationToken(e,t,n){return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function approvalResponseStatePatch(e,t){if(t?.principalId===void 0||!isTeamsToolApprovalResponseActivity(e))return;let n=deriveTeamsAnswers(e)[0]?.interactionId,r=e.replyToId;return n===void 0||r===void 0?{approvalResponderAccounts:{[t.principalId]:e.from}}:{approvalResponderAccounts:{[t.principalId]:e.from},pendingPromptCards:{[n]:{activityId:r,prompt:readTeamsToolApprovalPrompt(e)??`Tool approval`}}}}function defaultOnAnswers(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,approvalResponderAccounts:{},pendingPromptCards:{},pendingAuthActivityIds:{},replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function buildUpdateActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)throw Error(`teamsChannel: cannot replace an activity with a typing indicator.`);let{channelData:n,conversation:r,from:i,recipient:a,replyToId:o,type:s,...c}=normalizeTeamsPostInput(t);return{...c,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{INACTIVE_REQUEST_NOTICE,respondOrRetireInactivePrompt}from"#channel/inactive-prompt.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsAnswers,isTeamsAnswerActivity,isTeamsToolApprovalResponseActivity,readTeamsInputPrompt,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,renderInactiveInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{answerTeamsAuthorizationReveal,readTeamsAuthorizationReveal}from"#public/channels/teams/authorization.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),n=e.onMessage??defaultOnMessage,r=e.onAnswers??(e.onMessage===void 0?defaultOnAnswers:rejectInput),i={...defaultEvents,...e.events};return defineChannel({turnPolicy:e.turnPolicy,uploadPolicy:e.files?.uploadPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t,{...e.api,credentials:e.credentials}),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),audience:({state:e})=>teamsAudience(e.conversationType),context(t,n){return rebuildTeamsContext(t,n,e)},deliver(e,t){let n=e.state,r=n?.pendingPromptCards;r!==void 0&&(t.state.pendingPromptCards={...r,...t.state.pendingPromptCards});let i=n?.approvalResponderAccounts;i!==void 0&&(t.state.approvalResponderAccounts={...t.state.approvalResponderAccounts,...i})},routes:[POST(e.route??`/eve/v1/teams`,async(i,{from:a,resolveSession:o,waitUntil:s})=>{let c=await verifyInbound(i,e.credentials);if(c===null)return new Response(`unauthorized`,{status:401});let l;try{l=parseJsonObject(JSON.parse(c.body))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}if(c.serviceUrl!==void 0&&l.serviceUrl!==c.serviceUrl)return log.warn(`Teams activity service URL does not match the verified token.`),new Response(`unauthorized`,{status:401});let u=parseTeamsActivity(l);return u===null?teamsOk():u.type===`message`?(s(isTeamsAnswerActivity(u)?dispatchAnswers({activity:u,config:e,from:a,onAnswers:r}).then(e=>e?.outcome===`inactive`?e.retirement:void 0):dispatchMessage({activity:u,config:e,filesPolicy:t,onMessage:n,from:a,resolveSession:o})),teamsOk()):u.type===`invoke`?handleInvoke({activity:u,config:e,onAnswers:r,resolveSession:o,waitUntil:s,from:a}):teamsOk()})],async receive({message:t,target:n,...r},{from:i}){let a=n,o=readNonEmptyString(a.serviceUrl),s=readNonEmptyString(a.conversationId);if(!o||!s)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let c=readNonEmptyString(a.conversationType)??null,l=readNonEmptyString(a.replyToActivityId)??null,u=a.initialMessage;if(u!==void 0&&l!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let d={...initialTeamsState(),channelId:readNonEmptyString(a.channelId)??null,conversationId:s,conversationType:c,replyToActivityId:l,serviceUrl:o,teamId:readNonEmptyString(a.teamId)??null,tenantId:readNonEmptyString(a.tenantId)??null};if(u!==void 0){let t=await buildTeamsBinding({config:e,state:d}).thread.post(u);c!==`personal`&&t.id&&(l=t.id,d.replyToActivityId=t.id)}return i(teamsContinuationToken({conversationId:s,replyToActivityId:l,tenantId:d.tenantId})).send(t,{...r,state:d})},events:i})}function teamsAudience(e){return e===`personal`||e===`groupChat`?`private`:`unknown`}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let t=buildTeamsHandle(e);return{teams:t,thread:{mentionUser:teamsMentionUser,post(e){return t.sendActivity(e)},async startTyping(){try{await t.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,n){return t.updateActivity(e,n)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.alias(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildUpdateActivity(t,i),credentials:r,activityId:e,conversationId:normalizeTeamsContinuationAddress({conversationId:a.conversationId}).conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveSession(r)!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,botId:e.activity.recipient.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,isMentioned:e.activity.isBotMentioned,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],history:a.history,state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){let t=readTeamsAuthorizationReveal(e.activity);if(t!==null)return Response.json(await revealAuthorization({...e,reveal:t}));if(isTeamsAnswerActivity(e.activity)){let t=await dispatchAnswers({activity:e.activity,config:e.config,onAnswers:e.onAnswers,from:e.from});return t?.outcome===`inactive`?(e.waitUntil(t.retirement),Response.json(teamsInvokeResponse({message:INACTIVE_REQUEST_NOTICE}))):Response.json(teamsInvokeResponse())}if(e.config.onInvoke===void 0)return teamsOk();let n=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),r=await e.config.onInvoke(n,e.activity);return r instanceof Response?r:r&&typeof r==`object`?Response.json(r):teamsOk()}async function revealAuthorization(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=null;try{r=(await e.onAnswers(n,e.activity))?.auth??null}catch(e){log.error(`Teams sign-in press authorization failed`,{error:e})}let i=cardContinuationToken(e.activity,t,e.reveal.replyToActivityId??null);return await answerTeamsAuthorizationReveal({adaptiveCardVersion:e.config.adaptiveCardVersion??`1.5`,auth:r,presser:e.activity.from,resolveSession:()=>e.resolveSession(i),reveal:e.reveal})}async function dispatchAnswers(e){let t=deriveTeamsAnswers(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onAnswers(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i===null)return;let a=i.auth,o=e.activity;return respondOrRetireInactivePrompt(()=>e.from(cardContinuationToken(o,n,readTeamsInputReplyToActivityId(o))).respond(t,{auth:a,state:approvalResponseStatePatch(o,a)}),{async retirePrompt(e){o.replyToId!==void 0&&await r.thread.update(o.replyToId,renderInactiveInputRequestMessage(readTeamsInputPrompt(o),e))}},log)}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityIds:{},replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function cardContinuationToken(e,t,n){return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function approvalResponseStatePatch(e,t){if(t?.principalId===void 0||!isTeamsToolApprovalResponseActivity(e))return;let n=deriveTeamsAnswers(e)[0]?.interactionId,r=e.replyToId;return n===void 0||r===void 0?{approvalResponderAccounts:{[t.principalId]:e.from}}:{approvalResponderAccounts:{[t.principalId]:e.from},pendingPromptCards:{[n]:{activityId:r,prompt:readTeamsToolApprovalPrompt(e)??`Tool approval`}}}}function defaultOnAnswers(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,approvalResponderAccounts:{},pendingPromptCards:{},pendingAuthActivityIds:{},replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function buildUpdateActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)throw Error(`teamsChannel: cannot replace an activity with a typing indicator.`);let{channelData:n,conversation:r,from:i,recipient:a,replyToId:o,type:s,...c}=normalizeTeamsPostInput(t);return{...c,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
@@ -36,15 +36,19 @@ export interface TeamsJwtVerifyOptions {
36
36
  readonly maxSkewSeconds?: number;
37
37
  readonly openIdMetadataUrl?: string;
38
38
  }
39
+ export interface VerifiedTeamsRequest {
40
+ readonly body: string;
41
+ /** Native Connector claim; a trusted custom verifier owns its own binding. */
42
+ readonly serviceUrl?: string;
43
+ }
39
44
  /**
40
- * Verifies an inbound Teams request and returns the raw body.
45
+ * Verifies an inbound Teams request and returns its body and native service URL binding.
41
46
  *
42
47
  * Uses `webhookVerifier` when provided, otherwise validates the bearer JWT
43
48
  * against Bot Connector keys and the resolved app id. Throws when the
44
- * verifier rejects the request, the bearer token is missing, no app id can be
45
- * resolved (`appId` option or `MICROSOFT_APP_ID`/`TEAMS_APP_ID`), metadata or
46
- * keys cannot be loaded, or JWT verification fails.
49
+ * verifier rejects the request, the bearer token or native service URL claim
50
+ * is missing, no app id can be resolved, keys cannot be loaded, or JWT verification fails.
47
51
  */
48
- export declare function verifyTeamsRequest(request: Request, options: TeamsVerifyOptions): Promise<string>;
52
+ export declare function verifyTeamsRequest(request: Request, options: TeamsVerifyOptions): Promise<VerifiedTeamsRequest>;
49
53
  /** Verifies one Bot Connector JWT and returns its payload. */
50
54
  export declare function verifyTeamsJwt(token: string, options: TeamsJwtVerifyOptions): Promise<JWTPayload>;
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{importJWK,jwtVerify}from"#compiled/jose/index.js";import{resolveTeamsAppId}from"#public/channels/teams/api.js";const log=createLogger(`teams.verify`);async function verifyTeamsRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`teamsChannel: inbound webhook verifier rejected the request.`);return typeof r==`string`?r:n}let r=readBearerToken(e.headers.get(`authorization`)??``);if(!r)throw Error(`teamsChannel: inbound request missing bearer token.`);return await verifyTeamsJwt(r,t),n}async function verifyTeamsJwt(e,t){let n=await resolveTeamsAppId(t.appId),r=await loadJwks(t);return(await jwtVerify(e,async e=>{let t=selectJwk(r,e),n=typeof e.alg==`string`?e.alg:void 0;return importJWK(t,n)},{audience:n,clockTolerance:t.maxSkewSeconds??300,issuer:`https://api.botframework.com`})).payload}function readBearerToken(e){let[t,n]=e.split(/\s+/,2);return t?.toLowerCase()!==`bearer`||!n?null:n}async function loadJwks(e){let t=e.fetch??fetch,n=await t(e.jwksUrl??await loadJwksUrl(e,t),{headers:{accept:`application/json`}});if(!n.ok)throw Error(`Teams JWKS route returned HTTP ${n.status}.`);let r=await n.json();if(!isObject(r)||!Array.isArray(r.keys))throw Error(`Teams JWKS response is malformed.`);return r.keys.filter(isObject)}async function loadJwksUrl(e,t){let n=await t(e.openIdMetadataUrl??`https://login.botframework.com/v1/.well-known/openidconfiguration`,{headers:{accept:`application/json`}});if(!n.ok)throw Error(`Teams OpenID metadata route returned HTTP ${n.status}.`);let r=await n.json();if(!isObject(r)||typeof r.jwks_uri!=`string`)throw Error(`Teams OpenID metadata response is missing jwks_uri.`);return r.jwks_uri}function selectJwk(e,t){let n=typeof t.kid==`string`?t.kid:void 0,r=typeof t.x5t==`string`?t.x5t:void 0,i=e.find(e=>n!==void 0&&e.kid===n||r!==void 0&&e.x5t===r)??(e.length===1?e[0]:void 0);if(i===void 0)throw log.debug(`Teams JWT key not found`,{kid:n,x5t:r}),Error(`teamsChannel: inbound JWT key was not found in JWKS.`);return i}export{verifyTeamsJwt,verifyTeamsRequest};
1
+ import{createLogger}from"#internal/logging.js";import{isObject}from"#shared/guards.js";import{importJWK,jwtVerify}from"#compiled/jose/index.js";import{resolveTeamsAppId}from"#public/channels/teams/api.js";const log=createLogger(`teams.verify`);async function verifyTeamsRequest(e,t){let n=await e.text();if(t.webhookVerifier!==void 0){let r=await t.webhookVerifier(e,n);if(!r)throw Error(`teamsChannel: inbound webhook verifier rejected the request.`);return{body:typeof r==`string`?r:n}}let r=readBearerToken(e.headers.get(`authorization`)??``);if(!r)throw Error(`teamsChannel: inbound request missing bearer token.`);let i=await verifyTeamsJwt(r,t);if(typeof i.serviceurl!=`string`)throw Error(`teamsChannel: verified token is missing its service URL claim.`);return{body:n,serviceUrl:i.serviceurl}}async function verifyTeamsJwt(e,t){let n=await resolveTeamsAppId(t.appId),r=await loadJwks(t);return(await jwtVerify(e,async e=>{let t=selectJwk(r,e),n=typeof e.alg==`string`?e.alg:void 0;return importJWK(t,n)},{audience:n,clockTolerance:t.maxSkewSeconds??300,issuer:`https://api.botframework.com`})).payload}function readBearerToken(e){let[t,n]=e.split(/\s+/,2);return t?.toLowerCase()!==`bearer`||!n?null:n}async function loadJwks(e){let t=e.fetch??fetch,n=await t(e.jwksUrl??await loadJwksUrl(e,t),{headers:{accept:`application/json`}});if(!n.ok)throw Error(`Teams JWKS route returned HTTP ${n.status}.`);let r=await n.json();if(!isObject(r)||!Array.isArray(r.keys))throw Error(`Teams JWKS response is malformed.`);return r.keys.filter(isObject)}async function loadJwksUrl(e,t){let n=await t(e.openIdMetadataUrl??`https://login.botframework.com/v1/.well-known/openidconfiguration`,{headers:{accept:`application/json`}});if(!n.ok)throw Error(`Teams OpenID metadata route returned HTTP ${n.status}.`);let r=await n.json();if(!isObject(r)||typeof r.jwks_uri!=`string`)throw Error(`Teams OpenID metadata response is missing jwks_uri.`);return r.jwks_uri}function selectJwk(e,t){let n=typeof t.kid==`string`?t.kid:void 0,r=typeof t.x5t==`string`?t.x5t:void 0,i=e.find(e=>n!==void 0&&e.kid===n||r!==void 0&&e.x5t===r)??(e.length===1?e[0]:void 0);if(i===void 0)throw log.debug(`Teams JWT key not found`,{kid:n,x5t:r}),Error(`teamsChannel: inbound JWT key was not found in JWKS.`);return i}export{verifyTeamsJwt,verifyTeamsRequest};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{INACTIVE_REQUEST_NOTICE,respondOrRetireInactivePrompt}from"#channel/inactive-prompt.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,editTelegramMessageText,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX}from"#public/channels/telegram/authorization.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramAnswers,telegramCallbackAnswer,telegramReplyAnswers,telegramResolvedPromptText}from"#public/channels/telegram/hitl.js";import{defaultEvents,defaultOnMessage,defaultTelegramAuth,isTelegramBotMentioned}from"#public/channels/telegram/defaults.js";import{dispatchTelegramAuthorizationCallback}from"#public/channels/telegram/authorization-callback.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{initialTelegramState,stateFromTelegramCallbackQuery,stateFromTelegramMessage,telegramContinuationTokenFromState}from"#public/channels/telegram/state.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";import{telegramInstrumentation}from"#public/channels/telegram/audience.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},i=defineChannel({turnPolicy:e.turnPolicy,uploadPolicy:e.uploadPolicy,state:initialTelegramState(e.botUsername),...telegramInstrumentation,fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/eve/v1/telegram`,async(r,{from:i,resolveSession:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,uploadPolicy:t,from:i})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,from:i,resolveSession:a})),new Response(`ok`))})],async receive(t,{from:n}){let r=t.target,i=readChatId(r.chatId);if(i===void 0)throw Error(`telegramChannel().receive requires target.chatId.`);let a=typeof r.messageThreadId==`number`?r.messageThreadId:void 0,o=readChatId(r.conversationId),s=r.initialMessage;if(s!==void 0&&o!==void 0)throw Error("telegramChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c={...initialTelegramState(e.botUsername),chatId:i,conversationId:o??null,messageThreadId:a??null};return s!==void 0&&await buildTelegramHandle({config:e,state:c}).sendMessage(s),n(telegramContinuationTokenFromState(c)).send(t.message,{auth:t.auth,state:c})},events:r});return attachTelegramDeliver(i),i}function rebuildTelegramContext(e,t,n){return{state:e,telegram:buildTelegramHandle({config:n,session:t,state:e})}}function buildTelegramHandle(e){let t=e.config.api,n=e.state,r=e.config.credentials;function anchor(t){let r=n.chatType??t.chatType??null;n.chatType===null&&t.chatType!==void 0&&(n.chatType=t.chatType),t.id&&shouldAnchorTelegramConversation(r)&&(n.conversationId=t.id,n.chatId&&e.session?.continuation?.alias(telegramContinuationToken({chatId:n.chatId,conversationId:t.id,messageThreadId:n.messageThreadId??void 0})))}async function sendOne(e){let t=await sendMessage(e);return anchor(t),t}async function sendMessage(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for outbound message.`);return sendTelegramMessage({apiBaseUrl:t?.apiBaseUrl,body:{...e,message_thread_id:e.message_thread_id??n.messageThreadId??void 0},credentials:r,fetch:t?.fetch,fileBaseUrl:t?.fileBaseUrl,chatId:i})}return{botUsername:n.botUsername??e.config.botUsername,chatId:n.chatId??``,chatType:n.chatType??void 0,conversationId:n.conversationId??void 0,messageThreadId:n.messageThreadId??void 0,answerCallbackQuery(e){return answerTelegramCallbackQuery({apiBaseUrl:t?.apiBaseUrl,callbackQueryId:e.callbackQueryId,credentials:r,fetch:t?.fetch,showAlert:e.showAlert,text:e.text})},editMessageReplyMarkup(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for reply-markup edit.`);return editTelegramMessageReplyMarkup({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup})},editMessageText(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for text edit.`);return editTelegramMessageText({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup,text:e.text})},post(e){return postTelegramMessage(e,sendOne)},postEphemeral(e,t,n){return postTelegramMessage({...typeof t==`string`?{text:t}:t,ephemeral_message_parameters:{...n?.callbackQueryId===void 0?{}:{callback_query_id:n.callbackQueryId},receiver_user_id:e}},sendMessage)},request(e,n){return callTelegramApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:r?.botToken,fetch:t?.fetch,method:e})},sendMessage(e){return postTelegramMessage(e,sendOne)},async startTyping(e=`typing`){let i=n.chatId??``;if(i)try{await sendTelegramChatAction({action:e,apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageThreadId:n.messageThreadId??void 0})}catch(e){logError(log,`Telegram typing indicator failed — swallowed`,e,{chatId:i})}}}}function shouldAnchorTelegramConversation(e){return e===`group`||e===`supergroup`}async function postTelegramMessage(e,t){let n=typeof e==`string`?{text:e}:e,r=splitTelegramMessageText(n.text),i;for(let[e,a]of r.entries()){let r=await t(e===0?{...n,text:a}:{...n.ephemeral_message_parameters===void 0?{}:{ephemeral_message_parameters:n.ephemeral_message_parameters},text:a});i===void 0&&(i=r)}return i??{id:``,raw:null}}async function verifyInbound(e,t){try{return await verifyTelegramRequest(e,{secretToken:t?.webhookVerifier?void 0:t?.webhookSecretToken,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`telegram inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){if(e.message.from?.isBot===!0)return;let t=stateFromTelegramMessage(e.message,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})},r;try{r=await e.onMessage(n,e.message)}catch(e){log.error(`message handler failed`,{error:e});return}if(r==null)return;let i=collectTelegramFileParts(e.message.attachments,e.uploadPolicy),a=buildTelegramTurnMessage(e.message,i),o=formatTelegramContextBlock({botUsername:e.config.botUsername,chatId:e.message.chat.id,chatTitle:e.message.chat.title,chatType:e.message.chat.type,isMentioned:isTelegramBotMentioned(e.message,e.config.botUsername),messageId:e.message.messageId,messageThreadId:e.message.messageThreadId,userId:e.message.from?.id,username:e.message.from?.username}),s=r.context??[];try{await e.from(telegramContinuationTokenFromState(t)).send(a,{auth:r.auth,context:[o,...s],history:r.history,state:t,title:r.title})}catch(e){log.error(`message delivery failed`,{error:e})}}async function dispatchCallbackQuery(e){let t=stateFromTelegramCallbackQuery(e.query,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})};if(e.query.data?.startsWith(TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX)===!0){await dispatchTelegramAuthorizationCallback({continuationToken:telegramContinuationTokenFromState(t),query:e.query,resolveSession:e.resolveSession,state:t,telegram:n});return}if(e.query.data?.startsWith(TELEGRAM_HITL_CALLBACK_PREFIX)===!0){let r=e.query.message,i=e.query.data,a=r&&t.chatId?await respondOrRetireInactivePrompt(()=>e.from(telegramContinuationTokenFromState(t)).respond([telegramCallbackAnswer(i)],{auth:defaultTelegramAuth({...r,from:e.query.from})}),{retirePrompt:e=>retireInactivePrompt(n,r,e)},log):void 0;try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:a?.outcome===`inactive`?INACTIVE_REQUEST_NOTICE:`Answer received.`})}catch(e){log.warn(`Telegram callback-query acknowledgement failed`,{error:e})}a?.outcome===`inactive`&&await a.retirement;return}if(e.config.onCallbackQuery!==void 0){try{await e.config.onCallbackQuery(n,e.query)}catch(e){log.error(`custom callback-query handler failed`,{error:e})}return}try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Unsupported action.`})}catch(e){log.warn(`Telegram unsupported callback-query acknowledgement failed`,{error:e})}}async function retireInactivePrompt(e,t,n){let r={inline_keyboard:[]};if(t.text===void 0){await e.telegram.editMessageReplyMarkup({messageId:t.messageId,replyMarkup:r});return}await e.telegram.editMessageText({messageId:t.messageId,replyMarkup:r,text:telegramResolvedPromptText(t.text,n)})}function attachTelegramDeliver(e){if(!isCompiledChannel(e))return;let t=e.adapter;t.deliver=(e,t)=>{let n=e.state,r=[...e.answers??[],...telegramReplyAnswers(n?.replyToBotMessageId,e.message)];if(r.some(isTelegramSyntheticResponse)){let n=resolveTelegramAnswers(t.state,r);return n.length>0?{answers:n,context:e.context}:e.message===void 0?void 0:{message:e.message,context:e.context}}return defaultDeliverResult(e)}}function readChatId(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}export{telegramChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{INACTIVE_REQUEST_NOTICE,respondOrRetireInactivePrompt}from"#channel/inactive-prompt.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,editTelegramMessageText,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX}from"#public/channels/telegram/authorization.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramAnswers,telegramCallbackAnswer,telegramReplyAnswers,telegramResolvedPromptText}from"#public/channels/telegram/hitl.js";import{defaultEvents,defaultOnMessage,defaultTelegramAuth,isTelegramBotMentioned}from"#public/channels/telegram/defaults.js";import{dispatchTelegramAuthorizationCallback}from"#public/channels/telegram/authorization-callback.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{initialTelegramState,stateFromTelegramCallbackQuery,stateFromTelegramMessage,telegramContinuationTokenFromState}from"#public/channels/telegram/state.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";import{telegramInstrumentation}from"#public/channels/telegram/audience.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},i=defineChannel({turnPolicy:e.turnPolicy,uploadPolicy:e.uploadPolicy,state:initialTelegramState(e.botUsername),...telegramInstrumentation,fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/eve/v1/telegram`,async(r,{from:i,resolveSession:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,uploadPolicy:t,from:i})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,from:i,resolveSession:a})),new Response(`ok`))})],async receive({message:t,target:n,...r},{from:i}){let a=n,o=readChatId(a.chatId);if(o===void 0)throw Error(`telegramChannel().receive requires target.chatId.`);let s=typeof a.messageThreadId==`number`?a.messageThreadId:void 0,c=readChatId(a.conversationId),l=a.initialMessage;if(l!==void 0&&c!==void 0)throw Error("telegramChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let u={...initialTelegramState(e.botUsername),chatId:o,conversationId:c??null,messageThreadId:s??null};return l!==void 0&&await buildTelegramHandle({config:e,state:u}).sendMessage(l),i(telegramContinuationTokenFromState(u)).send(t,{...r,state:u})},events:r});return attachTelegramDeliver(i),i}function rebuildTelegramContext(e,t,n){return{state:e,telegram:buildTelegramHandle({config:n,session:t,state:e})}}function buildTelegramHandle(e){let t=e.config.api,n=e.state,r=e.config.credentials;function anchor(t){let r=n.chatType??t.chatType??null;n.chatType===null&&t.chatType!==void 0&&(n.chatType=t.chatType),t.id&&shouldAnchorTelegramConversation(r)&&(n.conversationId=t.id,n.chatId&&e.session?.continuation?.alias(telegramContinuationToken({chatId:n.chatId,conversationId:t.id,messageThreadId:n.messageThreadId??void 0})))}async function sendOne(e){let t=await sendMessage(e);return anchor(t),t}async function sendMessage(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for outbound message.`);return sendTelegramMessage({apiBaseUrl:t?.apiBaseUrl,body:{...e,message_thread_id:e.message_thread_id??n.messageThreadId??void 0},credentials:r,fetch:t?.fetch,fileBaseUrl:t?.fileBaseUrl,chatId:i})}return{botUsername:n.botUsername??e.config.botUsername,chatId:n.chatId??``,chatType:n.chatType??void 0,conversationId:n.conversationId??void 0,messageThreadId:n.messageThreadId??void 0,answerCallbackQuery(e){return answerTelegramCallbackQuery({apiBaseUrl:t?.apiBaseUrl,callbackQueryId:e.callbackQueryId,credentials:r,fetch:t?.fetch,showAlert:e.showAlert,text:e.text})},editMessageReplyMarkup(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for reply-markup edit.`);return editTelegramMessageReplyMarkup({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup})},editMessageText(e){let i=n.chatId??``;if(!i)throw Error(`telegramChannel: missing chat id for text edit.`);return editTelegramMessageText({apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup,text:e.text})},post(e){return postTelegramMessage(e,sendOne)},postEphemeral(e,t,n){return postTelegramMessage({...typeof t==`string`?{text:t}:t,ephemeral_message_parameters:{...n?.callbackQueryId===void 0?{}:{callback_query_id:n.callbackQueryId},receiver_user_id:e}},sendMessage)},request(e,n){return callTelegramApi({apiBaseUrl:t?.apiBaseUrl,body:n,botToken:r?.botToken,fetch:t?.fetch,method:e})},sendMessage(e){return postTelegramMessage(e,sendOne)},async startTyping(e=`typing`){let i=n.chatId??``;if(i)try{await sendTelegramChatAction({action:e,apiBaseUrl:t?.apiBaseUrl,chatId:i,credentials:r,fetch:t?.fetch,messageThreadId:n.messageThreadId??void 0})}catch(e){logError(log,`Telegram typing indicator failed — swallowed`,e,{chatId:i})}}}}function shouldAnchorTelegramConversation(e){return e===`group`||e===`supergroup`}async function postTelegramMessage(e,t){let n=typeof e==`string`?{text:e}:e,r=splitTelegramMessageText(n.text),i;for(let[e,a]of r.entries()){let r=await t(e===0?{...n,text:a}:{...n.ephemeral_message_parameters===void 0?{}:{ephemeral_message_parameters:n.ephemeral_message_parameters},text:a});i===void 0&&(i=r)}return i??{id:``,raw:null}}async function verifyInbound(e,t){try{return await verifyTelegramRequest(e,{secretToken:t?.webhookVerifier?void 0:t?.webhookSecretToken,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`telegram inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){if(e.message.from?.isBot===!0)return;let t=stateFromTelegramMessage(e.message,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})},r;try{r=await e.onMessage(n,e.message)}catch(e){log.error(`message handler failed`,{error:e});return}if(r==null)return;let i=collectTelegramFileParts(e.message.attachments,e.uploadPolicy),a=buildTelegramTurnMessage(e.message,i),o=formatTelegramContextBlock({botUsername:e.config.botUsername,chatId:e.message.chat.id,chatTitle:e.message.chat.title,chatType:e.message.chat.type,isMentioned:isTelegramBotMentioned(e.message,e.config.botUsername),messageId:e.message.messageId,messageThreadId:e.message.messageThreadId,userId:e.message.from?.id,username:e.message.from?.username}),s=r.context??[];try{await e.from(telegramContinuationTokenFromState(t)).send(a,{auth:r.auth,context:[o,...s],history:r.history,state:t,title:r.title})}catch(e){log.error(`message delivery failed`,{error:e})}}async function dispatchCallbackQuery(e){let t=stateFromTelegramCallbackQuery(e.query,e.config.botUsername),n={telegram:buildTelegramHandle({config:e.config,state:t})};if(e.query.data?.startsWith(TELEGRAM_AUTHORIZATION_CALLBACK_PREFIX)===!0){await dispatchTelegramAuthorizationCallback({continuationToken:telegramContinuationTokenFromState(t),query:e.query,resolveSession:e.resolveSession,state:t,telegram:n});return}if(e.query.data?.startsWith(TELEGRAM_HITL_CALLBACK_PREFIX)===!0){let r=e.query.message,i=e.query.data,a=r&&t.chatId?await respondOrRetireInactivePrompt(()=>e.from(telegramContinuationTokenFromState(t)).respond([telegramCallbackAnswer(i)],{auth:defaultTelegramAuth({...r,from:e.query.from})}),{retirePrompt:e=>retireInactivePrompt(n,r,e)},log):void 0;try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:a?.outcome===`inactive`?INACTIVE_REQUEST_NOTICE:`Answer received.`})}catch(e){log.warn(`Telegram callback-query acknowledgement failed`,{error:e})}a?.outcome===`inactive`&&await a.retirement;return}if(e.config.onCallbackQuery!==void 0){try{await e.config.onCallbackQuery(n,e.query)}catch(e){log.error(`custom callback-query handler failed`,{error:e})}return}try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Unsupported action.`})}catch(e){log.warn(`Telegram unsupported callback-query acknowledgement failed`,{error:e})}}async function retireInactivePrompt(e,t,n){let r={inline_keyboard:[]};if(t.text===void 0){await e.telegram.editMessageReplyMarkup({messageId:t.messageId,replyMarkup:r});return}await e.telegram.editMessageText({messageId:t.messageId,replyMarkup:r,text:telegramResolvedPromptText(t.text,n)})}function attachTelegramDeliver(e){if(!isCompiledChannel(e))return;let t=e.adapter;t.deliver=(e,t)=>{let n=e.state,r=[...e.answers??[],...telegramReplyAnswers(n?.replyToBotMessageId,e.message)];if(r.some(isTelegramSyntheticResponse)){let n=resolveTelegramAnswers(t.state,r);return n.length>0?{answers:n,context:e.context}:e.message===void 0?void 0:{message:e.message,context:e.context}}return defaultDeliverResult(e)}}function readChatId(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}export{telegramChannel};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/twilio/verify.js";import{callTwilioApi,createTwilioFetchFile,sendTwilioMessage,twilioContinuationToken,updateTwilioCall}from"#public/channels/twilio/api.js";import{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription}from"#public/channels/twilio/defaults.js";import{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription,twilioMessageContent}from"#public/channels/twilio/inbound.js";import{emptyTwilioResponse,gatherSpeechTwilioResponse,sayTwilioResponse}from"#public/channels/twilio/twiml.js";import{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound}from"#public/channels/twilio/routing.js";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let t=buildTwilioRoutes(e.route??`/eve/v1/twilio`),n=e.onText??defaultOnText,r=e.onVoice??defaultOnVoice,i=e.onVoiceTranscription??defaultOnVoiceTranscription,a={...defaultEvents,...e.events},o=handleTwilioMessages({config:e,onText:n}),s=handleTwilioVoice({config:e,onVoice:r,routes:t}),c=handleTwilioTranscription({config:e,onVoiceTranscription:i,routes:t});return defineChannel({turnPolicy:e.turnPolicy,state:{from:null,to:null,lastCallSid:null,lastMessageSid:null},metadata(e){return{from:e.from,lastCallSid:e.lastCallSid??null,lastMessageSid:e.lastMessageSid??null,to:e.to}},audience:()=>`private`,fetchFile:createTwilioFetchFile({...e.api,credentials:e.credentials}),context(t,n){return rebuildTwilioContext(t,n,e)},routes:[GET(t.messages,o),POST(t.messages,o),GET(t.voice,s),POST(t.voice,s),GET(t.transcription,c),POST(t.transcription,c)],async receive(t,{from:n}){let r=readNonEmptyString(t.target.phoneNumber);if(!r)throw Error(`twilioChannel().receive requires target.phoneNumber.`);let i=readNonEmptyString(t.target.from)??e.messaging?.from??null;return n(twilioContinuationToken({from:r,to:i??void 0})).send(t.message,{auth:t.auth,state:{from:r,lastCallSid:null,lastMessageSid:null,to:i}})},events:a})}function handleTwilioMessages(e){return async(t,{from:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioTextMessage(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchText({config:e.config,message:a,onText:e.onText,from:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}}function handleTwilioVoice(e){return async t=>{let n=await verifyTwilioInbound(t,e.config);if(n===null)return new Response(`unauthorized`,{status:401});let r=parseTwilioVoiceCall(n.params);if(!r)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(r.from,e.config.allowFrom))return new Response(`forbidden`,{status:403});let i=await acceptVoiceCall({call:r,config:e.config,onVoice:e.onVoice});if(i===null)return new Response(`forbidden`,{status:403});let a=i??{};return gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),hints:a.hints??e.config.voice?.hints,language:a.language??e.config.voice?.language,profanityFilter:a.profanityFilter??e.config.voice?.profanityFilter,prompt:a.prompt??e.config.voice?.prompt??`Please say your message after the tone.`,speechModel:a.speechModel??e.config.voice?.speechModel,speechTimeout:a.speechTimeout??e.config.voice?.speechTimeout??`auto`,timeoutSeconds:a.timeoutSeconds??e.config.voice?.timeoutSeconds,voice:a.voice??e.config.voice?.voice})}}function handleTwilioTranscription(e){return async(t,{from:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioVoiceTranscription(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchVoiceTranscription({config:e.config,onVoiceTranscription:e.onVoiceTranscription,from:n,transcription:a})),sayTwilioResponse(e.config.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),language:e.config.voice?.language,prompt:e.config.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.config.voice?.speechTimeout??`auto`,timeoutSeconds:e.config.voice?.timeoutSeconds})}}function rebuildTwilioContext(e,t,n){return{state:e,twilio:buildTwilioHandle({callSid:e.lastCallSid??void 0,config:n,from:e.from??``,to:e.to??void 0})}}function buildTwilioHandle(e){let t=e.config.api,n=e.config.credentials,r=e.config.messaging?.from??e.to,i=e.config.messaging?.messagingServiceSid,a=e.config.messaging?.statusCallbackUrl;return{callSid:e.callSid,from:e.from,to:e.to,request(e,r){return callTwilioApi({apiBaseUrl:t?.apiBaseUrl,body:r,credentials:n,fetch:t?.fetch,path:e})},sendMessage(o,s){return sendTwilioMessage({apiBaseUrl:t?.apiBaseUrl,body:o,credentials:n,fetch:t?.fetch,from:s?.from??r,messagingServiceSid:s?.messagingServiceSid??i,statusCallbackUrl:s?.statusCallbackUrl??a,to:s?.to??e.from})},updateCall(e,r){return updateTwilioCall({apiBaseUrl:t?.apiBaseUrl,callSid:e,credentials:n,fetch:t?.fetch,twiml:r})}}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function dispatchText(e){let{message:t}=e,n={twilio:buildTwilioHandle({callSid:void 0,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onText(n,t)}catch(e){log.error(`text handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({channel:`text`,from:t.from,messageSid:t.messageSid,to:t.to});try{await e.from(twilioContinuationToken({from:t.from,to:t.to})).send(twilioMessageContent(t),{auth:r.auth,context:[i],state:{from:t.from,lastCallSid:null,lastMessageSid:t.messageSid??null,to:t.to??null},title:r.title})}catch(e){log.error(`text delivery failed`,{error:e})}}async function acceptVoiceCall(e){let{call:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})};try{return await e.onVoice(n,t)}catch(e){return log.error(`voice handler failed`,{error:e}),null}}async function dispatchVoiceTranscription(e){let{transcription:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onVoiceTranscription(n,t)}catch(e){log.error(`voice transcription handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({callSid:t.callSid,channel:`voice`,from:t.from,to:t.to});try{await e.from(twilioContinuationToken({from:t.from,to:t.to})).send(t.text,{auth:r.auth,context:[i],state:{from:t.from,lastCallSid:t.callSid??null,lastMessageSid:null,to:t.to??null},title:r.title})}catch(e){log.error(`voice transcription delivery failed`,{error:e})}}async function isAllowed(e,t){let n=typeof t==`function`?await t():t;return n===`*`?!0:typeof n==`string`?n===e:n.includes(e)}export{twilioChannel};
1
+ import{createLogger}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{GET,POST,defineChannel}from"#public/definitions/channel.js";import"#public/channels/twilio/verify.js";import{callTwilioApi,createTwilioFetchFile,sendTwilioMessage,twilioContinuationToken,updateTwilioCall}from"#public/channels/twilio/api.js";import{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription}from"#public/channels/twilio/defaults.js";import{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription,twilioMessageContent}from"#public/channels/twilio/inbound.js";import{emptyTwilioResponse,gatherSpeechTwilioResponse,sayTwilioResponse}from"#public/channels/twilio/twiml.js";import{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound}from"#public/channels/twilio/routing.js";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let t=buildTwilioRoutes(e.route??`/eve/v1/twilio`),n=e.onText??defaultOnText,r=e.onVoice??defaultOnVoice,i=e.onVoiceTranscription??defaultOnVoiceTranscription,a={...defaultEvents,...e.events},o=handleTwilioMessages({config:e,onText:n}),s=handleTwilioVoice({config:e,onVoice:r,routes:t}),c=handleTwilioTranscription({config:e,onVoiceTranscription:i,routes:t});return defineChannel({turnPolicy:e.turnPolicy,state:{from:null,to:null,lastCallSid:null,lastMessageSid:null},metadata(e){return{from:e.from,lastCallSid:e.lastCallSid??null,lastMessageSid:e.lastMessageSid??null,to:e.to}},audience:()=>`private`,fetchFile:createTwilioFetchFile({...e.api,credentials:e.credentials}),context(t,n){return rebuildTwilioContext(t,n,e)},routes:[GET(t.messages,o),POST(t.messages,o),GET(t.voice,s),POST(t.voice,s),GET(t.transcription,c),POST(t.transcription,c)],async receive({message:t,target:n,...r},{from:i}){let a=readNonEmptyString(n.phoneNumber);if(!a)throw Error(`twilioChannel().receive requires target.phoneNumber.`);let o=readNonEmptyString(n.from)??e.messaging?.from??null;return i(twilioContinuationToken({from:a,to:o??void 0})).send(t,{...r,state:{from:a,lastCallSid:null,lastMessageSid:null,to:o}})},events:a})}function handleTwilioMessages(e){return async(t,{from:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioTextMessage(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchText({config:e.config,message:a,onText:e.onText,from:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}}function handleTwilioVoice(e){return async t=>{let n=await verifyTwilioInbound(t,e.config);if(n===null)return new Response(`unauthorized`,{status:401});let r=parseTwilioVoiceCall(n.params);if(!r)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(r.from,e.config.allowFrom))return new Response(`forbidden`,{status:403});let i=await acceptVoiceCall({call:r,config:e.config,onVoice:e.onVoice});if(i===null)return new Response(`forbidden`,{status:403});let a=i??{};return gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),hints:a.hints??e.config.voice?.hints,language:a.language??e.config.voice?.language,profanityFilter:a.profanityFilter??e.config.voice?.profanityFilter,prompt:a.prompt??e.config.voice?.prompt??`Please say your message after the tone.`,speechModel:a.speechModel??e.config.voice?.speechModel,speechTimeout:a.speechTimeout??e.config.voice?.speechTimeout??`auto`,timeoutSeconds:a.timeoutSeconds??e.config.voice?.timeoutSeconds,voice:a.voice??e.config.voice?.voice})}}function handleTwilioTranscription(e){return async(t,{from:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioVoiceTranscription(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchVoiceTranscription({config:e.config,onVoiceTranscription:e.onVoiceTranscription,from:n,transcription:a})),sayTwilioResponse(e.config.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),language:e.config.voice?.language,prompt:e.config.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.config.voice?.speechTimeout??`auto`,timeoutSeconds:e.config.voice?.timeoutSeconds})}}function rebuildTwilioContext(e,t,n){return{state:e,twilio:buildTwilioHandle({callSid:e.lastCallSid??void 0,config:n,from:e.from??``,to:e.to??void 0})}}function buildTwilioHandle(e){let t=e.config.api,n=e.config.credentials,r=e.config.messaging?.from??e.to,i=e.config.messaging?.messagingServiceSid,a=e.config.messaging?.statusCallbackUrl;return{callSid:e.callSid,from:e.from,to:e.to,request(e,r){return callTwilioApi({apiBaseUrl:t?.apiBaseUrl,body:r,credentials:n,fetch:t?.fetch,path:e})},sendMessage(o,s){return sendTwilioMessage({apiBaseUrl:t?.apiBaseUrl,body:o,credentials:n,fetch:t?.fetch,from:s?.from??r,messagingServiceSid:s?.messagingServiceSid??i,statusCallbackUrl:s?.statusCallbackUrl??a,to:s?.to??e.from})},updateCall(e,r){return updateTwilioCall({apiBaseUrl:t?.apiBaseUrl,callSid:e,credentials:n,fetch:t?.fetch,twiml:r})}}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function dispatchText(e){let{message:t}=e,n={twilio:buildTwilioHandle({callSid:void 0,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onText(n,t)}catch(e){log.error(`text handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({channel:`text`,from:t.from,messageSid:t.messageSid,to:t.to});try{await e.from(twilioContinuationToken({from:t.from,to:t.to})).send(twilioMessageContent(t),{auth:r.auth,context:[i],state:{from:t.from,lastCallSid:null,lastMessageSid:t.messageSid??null,to:t.to??null},title:r.title})}catch(e){log.error(`text delivery failed`,{error:e})}}async function acceptVoiceCall(e){let{call:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})};try{return await e.onVoice(n,t)}catch(e){return log.error(`voice handler failed`,{error:e}),null}}async function dispatchVoiceTranscription(e){let{transcription:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onVoiceTranscription(n,t)}catch(e){log.error(`voice transcription handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({callSid:t.callSid,channel:`voice`,from:t.from,to:t.to});try{await e.from(twilioContinuationToken({from:t.from,to:t.to})).send(t.text,{auth:r.auth,context:[i],state:{from:t.from,lastCallSid:t.callSid??null,lastMessageSid:null,to:t.to??null},title:r.title})}catch(e){log.error(`voice transcription delivery failed`,{error:e})}}async function isAllowed(e,t){let n=typeof t==`function`?await t():t;return n===`*`?!0:typeof n==`string`?n===e:n.includes(e)}export{twilioChannel};
@@ -1,3 +1,4 @@
1
+ import type { SessionSendOptions } from "#channel/session.js";
1
2
  import type { InstrumentationChannel } from "#shared/instrumentation-channel.js";
2
3
  import type { StandardSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
3
4
  import type { SessionSchedule } from "#context/session-schedule.js";
@@ -163,7 +164,15 @@ export interface ScheduleClient<TPayload> {
163
164
  }
164
165
  /** Starts fresh unattended work bound to the resolved creator; callers cannot choose another identity. */
165
166
  export type DynamicSchedulesToFn = <TChannel extends ChannelReference<unknown>>(channel: TChannel, target: InferReceiveTarget<TChannel>) => {
166
- send(message: MessageContent): Promise<Delivery>;
167
+ /**
168
+ * Accepts the `to().send()` options that apply to a fresh session. `auth` is
169
+ * the schedule's creator. A send never reaches a session the schedule didn't
170
+ * start, so `turnPolicy` has nothing to act on. A send with an
171
+ * `idempotencyKey` reaches the session an earlier send from this schedule
172
+ * with the same key and target started, so a retried callback whose key
173
+ * includes `occurrence.executionId` doesn't start a second session.
174
+ */
175
+ send(message: MessageContent, options?: Omit<SessionSendOptions, "auth" | "turnPolicy">): Promise<Delivery>;
167
176
  };
168
177
  type SchedulePayloadApproval<TPrepared> = ((context: ApprovalContext & {
169
178
  readonly payload: TPrepared;
@@ -1 +1 @@
1
- async function agentToolServeWorkflow(e,t){"use workflow";let n=t.agent(t.toolName),r=sendToAgent(n,await e()),i=e();for(;;){let a=await nextCallOrResult(i,r);if(a.kind===`call`){r=await forwardCall(n,r,a.call),i=e();continue}if(!r.signal.aborted){if(a.result.status===`failed`)throw Error(`The agent's turn failed: ${a.result.error.message}\nThis task has ended; to retry, call ${t.toolName} without taskId.`);let o=e();if(o!==i){r=sendToAgent(n,await i),i=o;continue}t.reply(a.result.reply??``)}r=sendToAgent(n,await i),i=e()}}async function agentWithModelServeWorkflow(e,t){"use workflow";let n=await e(),r=n.input.model.trim();if(r===``)throw TypeError(`agent model must not be empty.`);let i=t.agent(`agent`,{model:r}),a=sendToModelAgent(i,n,r),o=e();for(;;){let n=await nextModelCallOrResult(o,a);if(n.kind===`call`){a=await forwardModelCall(i,a,n.call,r),o=e();continue}if(!a.signal.aborted){if(n.result.status===`failed`)throw Error(`The agent's turn failed: ${n.result.error.message}\nThis task has ended; to retry, call ${t.toolName} without taskId.`);let s=e();if(s!==o){a=sendToModelAgent(i,await o,r),o=s;continue}t.reply(n.result.reply??``)}a=sendToModelAgent(i,await o,r),o=e()}}function sendToAgent(e,t){return{result:e.send(t.input.message,{signal:t.abortSignal}).then(e=>e.result()),signal:t.abortSignal}}function sendToModelAgent(e,t,n){if(t.input.model!==n)throw Error(`An agent task keeps the model it started with. This task has ended; start a new task to use another model.`);return{result:e.send(t.input.message,{signal:t.abortSignal}).then(e=>e.result()),signal:t.abortSignal}}async function nextCallOrResult(e,t){return await Promise.race([t.result.then(e=>({kind:`result`,result:e})),e.then(e=>({call:e,kind:`call`}))])}async function nextModelCallOrResult(e,t){return await Promise.race([t.result.then(e=>({kind:`result`,result:e})),e.then(e=>({call:e,kind:`call`}))])}async function forwardCall(e,t,n){return t.signal.aborted&&await t.result.catch(()=>void 0),sendToAgent(e,n)}async function forwardModelCall(e,t,n,r){return t.signal.aborted&&await t.result.catch(()=>void 0),sendToModelAgent(e,n,r)}agentToolServeWorkflow.workflowId=`workflow//eve//agentToolServeWorkflow`,agentWithModelServeWorkflow.workflowId=`workflow//eve@0.84.1//agentWithModelServeWorkflow`;export{agentToolServeWorkflow,agentWithModelServeWorkflow};
1
+ async function agentToolServeWorkflow(e,t){"use workflow";let n=t.agent(t.toolName),r=sendToAgent(n,await e()),i=e();for(;;){let a=await nextCallOrResult(i,r);if(a.kind===`call`){r=await forwardCall(n,r,a.call),i=e();continue}if(!r.signal.aborted){if(a.result.status===`failed`)throw Error(`The agent's turn failed: ${a.result.error.message}\nThis task has ended; to retry, call ${t.toolName} without taskId.`);let o=e();if(o!==i){r=sendToAgent(n,await i),i=o;continue}t.reply(a.result.reply??``)}r=sendToAgent(n,await i),i=e()}}async function agentWithModelServeWorkflow(e,t){"use workflow";let n=await e(),r=n.input.model.trim();if(r===``)throw TypeError(`agent model must not be empty.`);let i=t.agent(`agent`,{model:r}),a=sendToModelAgent(i,n,r),o=e();for(;;){let n=await nextModelCallOrResult(o,a);if(n.kind===`call`){a=await forwardModelCall(i,a,n.call,r),o=e();continue}if(!a.signal.aborted){if(n.result.status===`failed`)throw Error(`The agent's turn failed: ${n.result.error.message}\nThis task has ended; to retry, call ${t.toolName} without taskId.`);let s=e();if(s!==o){a=sendToModelAgent(i,await o,r),o=s;continue}t.reply(n.result.reply??``)}a=sendToModelAgent(i,await o,r),o=e()}}function sendToAgent(e,t){return{result:e.send(t.input.message,{signal:t.abortSignal}).then(e=>e.result()),signal:t.abortSignal}}function sendToModelAgent(e,t,n){if(t.input.model!==n)throw Error(`An agent task keeps the model it started with. This task has ended; start a new task to use another model.`);return{result:e.send(t.input.message,{signal:t.abortSignal}).then(e=>e.result()),signal:t.abortSignal}}async function nextCallOrResult(e,t){return await Promise.race([t.result.then(e=>({kind:`result`,result:e})),e.then(e=>({call:e,kind:`call`}))])}async function nextModelCallOrResult(e,t){return await Promise.race([t.result.then(e=>({kind:`result`,result:e})),e.then(e=>({call:e,kind:`call`}))])}async function forwardCall(e,t,n){return t.signal.aborted&&await t.result.catch(()=>void 0),sendToAgent(e,n)}async function forwardModelCall(e,t,n,r){return t.signal.aborted&&await t.result.catch(()=>void 0),sendToModelAgent(e,n,r)}agentToolServeWorkflow.workflowId=`workflow//eve//agentToolServeWorkflow`,agentWithModelServeWorkflow.workflowId=`workflow//eve@0.85.0//agentWithModelServeWorkflow`;export{agentToolServeWorkflow,agentWithModelServeWorkflow};
@@ -5,7 +5,7 @@ export { type AnySetupBox, runHeadless, runInteractive, type RunnerOptions, type
5
5
  export { createPrompter, type MultiSelectOptions, type NoteTone, type Prompter, type PrompterValue, type SelectCommonOptions, type SelectOption, type SingleSelectOptions, } from "./prompter.js";
6
6
  export { createHeadlessPrompter, formatHeadlessEvent, type HeadlessEvent, type HeadlessLogSink, type HeadlessNextStep, HeadlessPromptError, } from "./headless.js";
7
7
  export { createPromptCommandOutput, type PromptCommandLog } from "./cli/index.js";
8
- export { getPackageManagerStrategy, runPackageManagerInstall, runPnpmInstall, runVercel, spawnPackageManager, spawnPnpm, type PackageManagerStrategy, type RunPackageManagerOptions, type RunPnpmOptions, type RunVercelOptions, } from "./primitives/index.js";
8
+ export { getPackageManagerStrategy, runPackageManagerInstall, runPnpmInstall, runVercel, spawnPackageManager, spawnPnpm, type PackageManagerStrategy, type RunPackageManagerOptions, type RunVercelOptions, } from "./primitives/index.js";
9
9
  export { detectDeployment, detectProjectResolution, projectProductionUrlFromResolution, type DeploymentInfo, type DeploymentState, type ProjectResolution, } from "./project-resolution.js";
10
10
  export { runVercelEnvPull } from "./run-vercel-link.js";
11
11
  export { inspectSlackbotConnectors, provisionSlackbot, reconcileSlackUid, type ProvisionSlackbotResult, type SlackbotConnectorInspection, type SlackConnectorCandidate, type SlackConnectorSelection, } from "./slackbot.js";
@@ -1,4 +1,4 @@
1
- export { eveDevArguments, packageManagerInstallFailureMessage, packageManagerInstallSucceeded, runPackageManagerInstall, runPnpmInstall, spawnPackageManager, spawnPnpm, type PackageManagerInstallResult, type RunInstallOptions, type RunPackageManagerOptions, type RunPnpmOptions, } from "./pm/run.js";
1
+ export { eveDevArguments, packageManagerInstallFailureMessage, packageManagerInstallSucceeded, runPackageManagerInstall, runPnpmInstall, spawnPackageManager, spawnPnpm, type PackageManagerInstallResult, type RunInstallOptions, type RunPackageManagerOptions, } from "./pm/run.js";
2
2
  export { resultSucceeded, type PackageManagerProcessResult, type PackageManagerProcessTermination, } from "./pm/process-result.js";
3
3
  export { getPackageManagerStrategy, type PackageManagerConfigurationResult, type PackageManagerInvocation, type PackageManagerStrategy, } from "./pm/index.js";
4
4
  export { captureVercel, runVercel, type RunVercelOptions, type VercelCaptureFailure, type VercelCaptureResult, } from "./run-vercel.js";
@@ -13,8 +13,6 @@ export interface RunPackageManagerOptions {
13
13
  /** Closes stdin so the child cannot contend with a parent-owned TUI. */
14
14
  nonInteractive?: boolean;
15
15
  }
16
- /** @deprecated Use {@link RunPackageManagerOptions}. */
17
- export type RunPnpmOptions = RunPackageManagerOptions;
18
16
  /** Runs one package-manager command and returns its complete process evidence. */
19
17
  export declare function spawnPackageManager(kind: PackageManagerKind, projectRoot: string, args: readonly string[], options?: RunPackageManagerOptions): Promise<PackageManagerProcessResult>;
20
18
  export interface RunInstallOptions extends RunPackageManagerOptions, PackageManagerInstallOptions {
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{DEFAULT_CONNECT_PACKAGE_VERSION,resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_CHANNEL_TEMPLATES}from"./web-template.js";import{AGENT_INSTRUCTIONS_TEMPLATE}from"./instructions-template.js";import{SCAFFOLDED_AGENT_PATHS}from"./agent-paths.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.137`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.84.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{[SCAFFOLDED_AGENT_PATHS.config]:renderAgentTemplate(e,t),[SCAFFOLDED_AGENT_PATHS.channel]:WEB_CHANNEL_TEMPLATES.default,[SCAFFOLDED_AGENT_PATHS.instructions]:AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{DEFAULT_CONNECT_PACKAGE_VERSION,resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_CHANNEL_TEMPLATES}from"./web-template.js";import{AGENT_INSTRUCTIONS_TEMPLATE}from"./instructions-template.js";import{SCAFFOLDED_AGENT_PATHS}from"./agent-paths.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.137`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.85.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{[SCAFFOLDED_AGENT_PATHS.config]:renderAgentTemplate(e,t),[SCAFFOLDED_AGENT_PATHS.channel]:WEB_CHANNEL_TEMPLATES.default,[SCAFFOLDED_AGENT_PATHS.instructions]:AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -2,9 +2,10 @@ import { type ChannelCors } from "#channel/cors.js";
2
2
  import type { MessageContent } from "#shared/message-content.js";
3
3
  import type { ChannelReceiveContext } from "#channel/channel-operations.js";
4
4
  import type { RouteDefinition } from "#channel/routes.js";
5
+ import type { SessionSendOptions } from "#channel/session.js";
5
6
  import type { ChannelContext } from "#shared/channel-context.js";
6
7
  import type { Delivery } from "#shared/delivery.js";
7
- import type { SessionAuthContext, TurnPolicy } from "#channel/types.js";
8
+ import type { TurnPolicy } from "#channel/types.js";
8
9
  import type { ChannelDelivery, ChannelDeliveryReplacement } from "#shared/channel-delivery.js";
9
10
  import type { UploadPolicyInput } from "#public/channels/upload-policy.js";
10
11
  import type { AudienceContext } from "#shared/conversation-context.js";
@@ -34,11 +35,10 @@ export type FetchFileFunction = (url: string, context?: FetchFileContext) => Pro
34
35
  * Input passed to a channel's `receive` callback when another channel or
35
36
  * schedule proactively routes a message to it.
36
37
  */
37
- export interface GenericReceiveInput<TReceiveTarget = Record<string, unknown>> {
38
+ export type GenericReceiveInput<TReceiveTarget = Record<string, unknown>> = SessionSendOptions & {
38
39
  readonly message: MessageContent;
39
40
  readonly target: Readonly<TReceiveTarget>;
40
- readonly auth: SessionAuthContext | null;
41
- }
41
+ };
42
42
  /**
43
43
  * The object passed to {@link defineChannel}. `routes` is required; `state`
44
44
  * seeds durable adapter state, `context` builds the per-step `ctx.channel`
@@ -1 +1 @@
1
- import{createErrorId,createLogger}from"#internal/logging.js";import{ContinuationTokenKey,SessionIdKey,SessionInboxKey}from"#context/keys.js";import{relayedInteractionEvents}from"#harness/interaction-relay.js";import{SUBAGENT_ADAPTER_KIND,isSubagentAdapterState}from"#subagents/adapter-state.js";const log=createLogger(`execution.subagent-adapter`),SUBAGENT_ADAPTER={kind:SUBAGENT_ADAPTER_KIND,async"interaction.opened"(e,t){await relay(e,t)},async"interaction.settled"(e,t){await relay(e,t)},async"response.admitted"(e,t){await relay(e,t)},async"response.settled"(e,t){await relay(e,t)}};async function relay(e,t){let n=t.state;if(!isSubagentAdapterState(n)||t.view===void 0)return;let r=t.ctx.require(SessionIdKey),i=relayedInteractionEvents(t.view,e,r);i.length!==0&&await forwardToParentStep({hookPayload:{callId:n.callId,childSessionId:r,events:i,kind:`subagent-interaction`,subagentName:n.subagentName,...i.some(e=>e.type===`interaction.opened`&&e.data.request.kind!==`sign-in`)&&{route:{childContinuationToken:t.ctx.require(ContinuationTokenKey),...t.ctx.get(SessionInboxKey)!==void 0&&{childSessionInbox:t.ctx.get(SessionInboxKey)},...t.inputSource!==void 0&&{inputSource:t.inputSource}}}},parentContinuationToken:n.parentContinuationToken})}async function forwardToParentStep(e){"use step";try{let{resumeHook:t}=await import(`#internal/workflow/runtime.js`);await t(e.parentContinuationToken,e.hookPayload)}catch(t){throw log.warn(`failed to forward a child's interaction to its parent`,{callId:e.hookPayload.callId,childSessionId:e.hookPayload.childSessionId,errorId:createErrorId(),eventTypes:e.hookPayload.events.map(e=>e.type),parentContinuationToken:e.parentContinuationToken,subagentName:e.hookPayload.subagentName,error:t}),t}}export{SUBAGENT_ADAPTER};
1
+ import{createErrorId,createLogger}from"#internal/logging.js";import{ContinuationTokenKey,SessionIdKey,SessionInboxKey}from"#context/keys.js";import{relayedInteractionEvents}from"#harness/interaction-relay.js";import{formatCapabilityError}from"#internal/capability-error.js";import{SUBAGENT_ADAPTER_KIND,isSubagentAdapterState}from"#subagents/adapter-state.js";const log=createLogger(`execution.subagent-adapter`),SUBAGENT_ADAPTER={kind:SUBAGENT_ADAPTER_KIND,async"interaction.opened"(e,t){await relay(e,t)},async"interaction.settled"(e,t){await relay(e,t)},async"response.admitted"(e,t){await relay(e,t)},async"response.settled"(e,t){await relay(e,t)}};async function relay(e,t){let n=t.state;if(!isSubagentAdapterState(n)||t.view===void 0)return;let r=t.ctx.require(SessionIdKey),i=relayedInteractionEvents(t.view,e,r);i.length!==0&&await forwardToParentStep({hookPayload:{callId:n.callId,childSessionId:r,events:i,kind:`subagent-interaction`,subagentName:n.subagentName,...i.some(e=>e.type===`interaction.opened`&&e.data.request.kind!==`sign-in`)&&{route:{childContinuationToken:t.ctx.require(ContinuationTokenKey),...t.ctx.get(SessionInboxKey)!==void 0&&{childSessionInbox:t.ctx.get(SessionInboxKey)},...t.inputSource!==void 0&&{inputSource:t.inputSource}}}},parentContinuationToken:n.parentContinuationToken})}async function forwardToParentStep(e){"use step";try{let{resumeHook:t}=await import(`#internal/workflow/runtime.js`);await t(e.parentContinuationToken,e.hookPayload)}catch(t){throw log.warn(`failed to forward a child's interaction to its parent`,{callId:e.hookPayload.callId,childSessionId:e.hookPayload.childSessionId,errorId:createErrorId(),eventTypes:e.hookPayload.events.map(e=>e.type),subagentName:e.hookPayload.subagentName,error:formatCapabilityError(t,[e.parentContinuationToken,e.hookPayload.route?.childContinuationToken])}),t}}export{SUBAGENT_ADAPTER};
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{SessionCallbackKey}from"#context/keys.js";import{toErrorMessage}from"#shared/errors.js";import{parseJsonValue}from"#shared/json.js";import{ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{resumeHook}from"#internal/workflow/runtime.js";import{REMOTE_CALLBACK_NOT_PENDING,REMOTE_CALLBACK_NOT_PENDING_MESSAGE}from"#protocol/remote-agent-protocol.js";import{parseSessionCallback}from"#channel/session-callback.js";import{deserializeContext}from"#context/serialize.js";import{postSessionCallbackRequest}from"#execution/session-callback-request.js";import{HookNotFoundError}from"#compiled/@workflow/errors/index.js";import{SUBAGENT_ADAPTER_KIND,isSubagentAdapterState}from"#subagents/adapter-state.js";const log=createLogger(`execution.delegated-parent-notification`),SUBAGENT_EXECUTION_FAILED=`SUBAGENT_EXECUTION_FAILED`,ZERO_TOKEN_USAGE={cacheReadTokens:0,cacheWriteTokens:0,inputTokens:0,outputTokens:0};async function notifyTurnCallerStep(e){"use step";if(e.caller===void 0)return;let t=createSettledTurnResult({caller:e.caller,lifecycle:e.lifecycle,sessionId:e.sessionId,settled:e.settled});if(e.caller.replyTo.kind===`callback`){await postSettledTurnCallback({result:t,sessionId:e.sessionId,url:e.caller.replyTo.url});return}await resumeSettledTurnHook(e.caller.replyTo.token,t)}async function notifyCancelledTaskCallerStep(e){"use step";let t=e.usage??ZERO_TOKEN_USAGE,n={code:SUBAGENT_EXECUTION_FAILED,message:`The agent invocation was cancelled.`},r={callId:e.caller.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:`parked`,result:{kind:`cancelled`},usageDelta:t},output:n,subagentName:e.caller.subagentName},i=e.usage===void 0?r:{...r,usage:e.usage};if(e.caller.replyTo.kind===`callback`){await postSettledTurnCallback({result:i,sessionId:e.sessionId,url:e.caller.replyTo.url});return}await resumeSettledTurnHook(e.caller.replyTo.token,i)}function createSettledTurnResult(e){let t=e.settled.usage??ZERO_TOKEN_USAGE;if(e.settled.isError===!0){let n={code:SUBAGENT_EXECUTION_FAILED,message:toErrorMessage(e.settled.output)};return{callId:e.caller.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:e.lifecycle,result:{error:n,kind:`failed`},usageDelta:t},output:n,subagentName:e.caller.subagentName}}let n=parseJsonValue(e.settled.output),r={callId:e.caller.callId,kind:`subagent-result`,origin:`child`,outcome:{kind:e.lifecycle,result:{kind:`succeeded`,output:n},usageDelta:t},output:n,subagentName:e.caller.subagentName};return e.settled.usage===void 0?r:{...r,usage:e.settled.usage}}async function resolveInitialTurnCallerStep(e){"use step";let t=e.serializedContext[SessionCallbackKey.name];if(t!==void 0){let e=parseSessionCallback(t);if(!e.ok)throw Error(`Serialized session callback is invalid.`,{cause:e.cause});return{callId:e.callback.callId,replyTo:{kind:`callback`,token:e.callback.token,url:e.callback.url},subagentName:e.callback.subagentName}}let n=(await deserializeContext(e.serializedContext)).get(ChannelKey);if(n?.kind===SUBAGENT_ADAPTER_KIND&&isSubagentAdapterState(n.state))return{callId:n.state.callId,replyTo:{kind:`hook`,token:n.state.parentContinuationToken},subagentName:n.state.subagentName}}function bindTurnCallerContext(e,t){if(e===void 0)return t;if(e.replyTo.kind===`callback`){let n={callId:e.callId,subagentName:e.subagentName,token:e.replyTo.token,url:e.replyTo.url};return{...t,[SessionCallbackKey.name]:n}}let n=t[ChannelKey.name];if(typeof n!=`object`||!n||Reflect.get(n,`kind`)!==SUBAGENT_ADAPTER_KIND||!isSubagentAdapterState(Reflect.get(n,`state`)))throw Error(`Delegated local turn is missing its subagent adapter binding.`);let r={...Reflect.get(n,`state`),callId:e.callId,parentContinuationToken:e.replyTo.token,subagentName:e.subagentName};return{...t,[ChannelKey.name]:{...n,state:r}}}async function postSettledTurnCallback(e){let{sessionId:t}=e;if(e.result.isError===!0){await postCallbackPayload({payload:{callId:e.result.callId,error:e.result.output,kind:`turn.failed`,outcome:e.result.outcome,sessionId:t,subagentName:e.result.subagentName},url:e.url});return}await postCallbackPayload({payload:{callId:e.result.callId,kind:`turn.completed`,outcome:e.result.outcome,output:e.result.output,sessionId:t,subagentName:e.result.subagentName},url:e.url})}const NOT_PENDING_RETRY_DELAYS_MS=[250,500,1e3,2e3,4e3];async function postCallbackPayload(e){for(let t=0;;t+=1){let n=await postSessionCallbackRequest({body:e.payload,url:e.url});if(n.ok)return;if(!await isCallbackNotPending(n))throw Error(`Turn callback failed with HTTP ${n.status}.`);let r=NOT_PENDING_RETRY_DELAYS_MS[t];if(r===void 0){log.warn(`turn caller no longer waits for this result`,{kind:Reflect.get(e.payload,`kind`)});return}await new Promise(e=>setTimeout(e,r))}}async function isCallbackNotPending(e){if(e.status!==404)return!1;let t=await e.json().catch(()=>void 0);return typeof t!=`object`||!t?!1:Reflect.get(t,`code`)===REMOTE_CALLBACK_NOT_PENDING||Reflect.get(t,`error`)===REMOTE_CALLBACK_NOT_PENDING_MESSAGE}async function resumeSettledTurnHook(e,t){try{await resumeHook(e,{kind:`runtime-action-result`,results:[t]})}catch(n){if(!HookNotFoundError.is(n))throw n;log.warn(`turn caller hook no longer exists`,{callId:t.callId,callerToken:e})}}export{NOT_PENDING_RETRY_DELAYS_MS,bindTurnCallerContext,notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep};
1
+ import{createLogger}from"#internal/logging.js";import{SessionCallbackKey}from"#context/keys.js";import{toErrorMessage}from"#shared/errors.js";import{parseJsonValue}from"#shared/json.js";import{ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{resumeHook}from"#internal/workflow/runtime.js";import{REMOTE_CALLBACK_NOT_PENDING,REMOTE_CALLBACK_NOT_PENDING_MESSAGE}from"#protocol/remote-agent-protocol.js";import{parseSessionCallback}from"#channel/session-callback.js";import{deserializeContext}from"#context/serialize.js";import{postSessionCallbackRequest}from"#execution/session-callback-request.js";import{HookNotFoundError}from"#compiled/@workflow/errors/index.js";import{SUBAGENT_ADAPTER_KIND,isSubagentAdapterState}from"#subagents/adapter-state.js";const log=createLogger(`execution.delegated-parent-notification`),SUBAGENT_EXECUTION_FAILED=`SUBAGENT_EXECUTION_FAILED`,ZERO_TOKEN_USAGE={cacheReadTokens:0,cacheWriteTokens:0,inputTokens:0,outputTokens:0};async function notifyTurnCallerStep(e){"use step";if(e.caller===void 0)return;let t=createSettledTurnResult({caller:e.caller,lifecycle:e.lifecycle,sessionId:e.sessionId,settled:e.settled});if(e.caller.replyTo.kind===`callback`){await postSettledTurnCallback({result:t,sessionId:e.sessionId,url:e.caller.replyTo.url});return}await resumeSettledTurnHook(e.caller.replyTo.token,t)}async function notifyCancelledTaskCallerStep(e){"use step";let t=e.usage??ZERO_TOKEN_USAGE,n={code:SUBAGENT_EXECUTION_FAILED,message:`The agent invocation was cancelled.`},r={callId:e.caller.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:`parked`,result:{kind:`cancelled`},usageDelta:t},output:n,subagentName:e.caller.subagentName},i=e.usage===void 0?r:{...r,usage:e.usage};if(e.caller.replyTo.kind===`callback`){await postSettledTurnCallback({result:i,sessionId:e.sessionId,url:e.caller.replyTo.url});return}await resumeSettledTurnHook(e.caller.replyTo.token,i)}function createSettledTurnResult(e){let t=e.settled.usage??ZERO_TOKEN_USAGE;if(e.settled.isError===!0){let n={code:SUBAGENT_EXECUTION_FAILED,message:toErrorMessage(e.settled.output)};return{callId:e.caller.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:e.lifecycle,result:{error:n,kind:`failed`},usageDelta:t},output:n,subagentName:e.caller.subagentName}}let n=parseJsonValue(e.settled.output),r={callId:e.caller.callId,kind:`subagent-result`,origin:`child`,outcome:{kind:e.lifecycle,result:{kind:`succeeded`,output:n},usageDelta:t},output:n,subagentName:e.caller.subagentName};return e.settled.usage===void 0?r:{...r,usage:e.settled.usage}}async function resolveInitialTurnCallerStep(e){"use step";let t=e.serializedContext[SessionCallbackKey.name];if(t!==void 0){let e=parseSessionCallback(t);if(!e.ok)throw Error(`Serialized session callback is invalid.`,{cause:e.cause});return{callId:e.callback.callId,replyTo:{kind:`callback`,token:e.callback.token,url:e.callback.url},subagentName:e.callback.subagentName}}let n=(await deserializeContext(e.serializedContext)).get(ChannelKey);if(n?.kind===SUBAGENT_ADAPTER_KIND&&isSubagentAdapterState(n.state))return{callId:n.state.callId,replyTo:{kind:`hook`,token:n.state.parentContinuationToken},subagentName:n.state.subagentName}}function bindTurnCallerContext(e,t){if(e===void 0)return t;if(e.replyTo.kind===`callback`){let n={callId:e.callId,subagentName:e.subagentName,token:e.replyTo.token,url:e.replyTo.url};return{...t,[SessionCallbackKey.name]:n}}let n=t[ChannelKey.name];if(typeof n!=`object`||!n||Reflect.get(n,`kind`)!==SUBAGENT_ADAPTER_KIND||!isSubagentAdapterState(Reflect.get(n,`state`)))throw Error(`Delegated local turn is missing its subagent adapter binding.`);let r={...Reflect.get(n,`state`),callId:e.callId,parentContinuationToken:e.replyTo.token,subagentName:e.subagentName};return{...t,[ChannelKey.name]:{...n,state:r}}}async function postSettledTurnCallback(e){let{sessionId:t}=e;if(e.result.isError===!0){await postCallbackPayload({payload:{callId:e.result.callId,error:e.result.output,kind:`turn.failed`,outcome:e.result.outcome,sessionId:t,subagentName:e.result.subagentName},url:e.url});return}await postCallbackPayload({payload:{callId:e.result.callId,kind:`turn.completed`,outcome:e.result.outcome,output:e.result.output,sessionId:t,subagentName:e.result.subagentName},url:e.url})}const NOT_PENDING_RETRY_DELAYS_MS=[250,500,1e3,2e3,4e3];async function postCallbackPayload(e){for(let t=0;;t+=1){let n=await postSessionCallbackRequest({body:e.payload,url:e.url});if(n.ok)return;if(!await isCallbackNotPending(n))throw Error(`Turn callback failed with HTTP ${n.status}.`);let r=NOT_PENDING_RETRY_DELAYS_MS[t];if(r===void 0){log.warn(`turn caller no longer waits for this result`,{kind:Reflect.get(e.payload,`kind`)});return}await new Promise(e=>setTimeout(e,r))}}async function isCallbackNotPending(e){if(e.status!==404)return!1;let t=await e.json().catch(()=>void 0);return typeof t!=`object`||!t?!1:Reflect.get(t,`code`)===REMOTE_CALLBACK_NOT_PENDING||Reflect.get(t,`error`)===REMOTE_CALLBACK_NOT_PENDING_MESSAGE}async function resumeSettledTurnHook(e,t){try{await resumeHook(e,{kind:`runtime-action-result`,results:[t]})}catch(e){if(!HookNotFoundError.is(e))throw e;log.warn(`turn caller hook no longer exists`,{callId:t.callId})}}export{NOT_PENDING_RETRY_DELAYS_MS,bindTurnCallerContext,notifyCancelledTaskCallerStep,notifyTurnCallerStep,resolveInitialTurnCallerStep};
@@ -1,3 +1,3 @@
1
- import { n as signInEnding, t as useEveAgent } from "../chunks/use-eve-agent-DP5Rso9C.js";
1
+ import { n as signInEnding, t as useEveAgent } from "../chunks/use-eve-agent-DCLFi26P.js";
2
2
 
3
3
  export { signInEnding, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-DP5Rso9C.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-DCLFi26P.js";
2
2
 
3
3
  export { useEveAgent };
@@ -3,6 +3,8 @@ import type { ToolExecutionOptions } from "ai";
3
3
  import type { HistoryMessage as ModelMessage } from "#shared/history-message.js";
4
4
  import type { StandardJSONSchemaV1, StandardSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
5
5
  import type { Approval } from "#approval/definition.js";
6
+ import type { CrossChannelToFn } from "#channel/cross-channel-receive.js";
7
+ import type { InstrumentationChannel } from "#shared/instrumentation-channel.js";
6
8
  import type { SessionAuthContext } from "#channel/types.js";
7
9
  import type { SessionContext } from "#context/session-context.js";
8
10
  import type { JsonObject } from "#shared/json.js";
@@ -165,6 +167,25 @@ export type ToolContext = SessionContext & {
165
167
  * token returned by {@link getToken}.
166
168
  */
167
169
  requireAuth(provider: ToolAuthProvider, options?: ToolAuthOptions): never;
170
+ /**
171
+ * Starts or continues a session on one of the agent's channels, as a route
172
+ * handler's `ctx.to()` does: `ctx.to(slack, target).send(message, options)`
173
+ * runs the channel's `receive()` hook and returns the delivery. The session
174
+ * belongs to the channel, not this one, and keeps running after the tool
175
+ * returns. The tool runs again when its step retries, so pass
176
+ * `` idempotencyKey: `${ctx.session.id}:${ctx.callId}` `` to deliver once.
177
+ * `callId` alone is unique only within this session, and every sender to the
178
+ * destination shares its keys. Throws in a delegated
179
+ * session: a subagent, a root copy, or a remote agent call.
180
+ */
181
+ readonly to: CrossChannelToFn;
182
+ /**
183
+ * The channel serving the calling session, as hooks and dynamic resolvers
184
+ * read it: the channel's `kind`, the session's `continuationToken` there, and
185
+ * what the channel's `metadata(state)` hook projects, such as a Slack
186
+ * thread's `channelId` and `threadTs`.
187
+ */
188
+ readonly channel: InstrumentationChannel;
168
189
  /**
169
190
  * The person who approved this call. Present only when the call runs after a
170
191
  * person approved it; absent for calls that needed no approval.
@@ -1 +1 @@
1
- async function executeAskQuestionTool(e,t){"use workflow";return toAskQuestionOutput(await t.ask(toAskQuestionRequest(e)))}function toAskQuestionRequest(e){let t=e.options?.map(e=>({description:e.description,id:e.label,label:e.label}));return{allowFreeform:!0,display:t===void 0?`text`:`select`,prompt:e.question,...t!==void 0&&{options:t}}}function toAskQuestionOutput(e){switch(e.status){case`answered`:return{answer:e.optionId??e.text??``,status:`answered`};case`cancelled`:return{interrupted:!0};case`unavailable`:return{status:`unavailable`}}}executeAskQuestionTool.workflowId=`workflow//eve@0.84.1//executeAskQuestionTool`;export{executeAskQuestionTool,toAskQuestionOutput,toAskQuestionRequest};
1
+ async function executeAskQuestionTool(e,t){"use workflow";return toAskQuestionOutput(await t.ask(toAskQuestionRequest(e)))}function toAskQuestionRequest(e){let t=e.options?.map(e=>({description:e.description,id:e.label,label:e.label}));return{allowFreeform:!0,display:t===void 0?`text`:`select`,prompt:e.question,...t!==void 0&&{options:t}}}function toAskQuestionOutput(e){switch(e.status){case`answered`:return{answer:e.optionId??e.text??``,status:`answered`};case`cancelled`:return{interrupted:!0};case`unavailable`:return{status:`unavailable`}}}executeAskQuestionTool.workflowId=`workflow//eve@0.85.0//executeAskQuestionTool`;export{executeAskQuestionTool,toAskQuestionOutput,toAskQuestionRequest};
@@ -1 +1 @@
1
- import{sleep}from"#compiled/@workflow/core/index.js";async function executeSleepTool(e,t){"use workflow";if(t.abortSignal.aborted)return{interrupted:!0};let n=new Promise(e=>t.abortSignal.addEventListener(`abort`,()=>e(`interrupted`),{once:!0})),r=sleep(Math.ceil(e.seconds*1e3)).then(()=>`elapsed`);return await Promise.race([r,n])===`elapsed`?{waitedSeconds:e.seconds}:{interrupted:!0}}executeSleepTool.workflowId=`workflow//eve@0.84.1//executeSleepTool`;export{executeSleepTool};
1
+ import{sleep}from"#compiled/@workflow/core/index.js";async function executeSleepTool(e,t){"use workflow";if(t.abortSignal.aborted)return{interrupted:!0};let n=new Promise(e=>t.abortSignal.addEventListener(`abort`,()=>e(`interrupted`),{once:!0})),r=sleep(Math.ceil(e.seconds*1e3)).then(()=>`elapsed`);return await Promise.race([r,n])===`elapsed`?{waitedSeconds:e.seconds}:{interrupted:!0}}executeSleepTool.workflowId=`workflow//eve@0.85.0//executeSleepTool`;export{executeSleepTool};
@@ -35,7 +35,7 @@ export interface AgentSessionOptions {
35
35
  * it, and `stop()` and `delete()` throw. The session deletes it when the
36
36
  * session ends. Steps can retry, so make sandbox writes safe to repeat.
37
37
  */
38
- export type WorkflowStepToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName" | "getSandbox" | "getToken" | "requireAuth">;
38
+ export type WorkflowStepToolContext = Pick<ToolContext, "abortSignal" | "callId" | "channel" | "session" | "toolName" | "getSandbox" | "getToken" | "requireAuth" | "to">;
39
39
  /** Options for one message to a `ctx.agent` session. */
40
40
  export interface AgentSendOptions<TOutput = unknown> {
41
41
  /** Structured output for the turn, as on the client's `send`. */
@@ -76,10 +76,10 @@ export interface AgentSession {
76
76
  }
77
77
  /**
78
78
  * Members the context of every workflow tool entry point shares.
79
- * `getSandbox`, `getToken`, and `requireAuth` work only after `ctx` is passed
80
- * to a `"use step"` helper; the workflow body throws when it calls them.
79
+ * `getSandbox`, `getToken`, `requireAuth`, and `to` work only after `ctx` is
80
+ * passed to a `"use step"` helper; the workflow body throws when it calls them.
81
81
  */
82
- export type WorkflowSharedContext = Pick<ToolContext, "session" | "toolName" | "getSandbox" | "getToken" | "requireAuth"> & {
82
+ export type WorkflowSharedContext = Pick<ToolContext, "channel" | "session" | "toolName" | "getSandbox" | "getToken" | "requireAuth" | "to"> & {
83
83
  /**
84
84
  * Returns a new session with the agent of this invocation name. Nothing
85
85
  * starts until the first `send`.
@@ -1,3 +1,3 @@
1
- import { n as signInEnding, t as useEveAgent } from "../chunks/use-eve-agent-DMeP0JOF.js";
1
+ import { n as signInEnding, t as useEveAgent } from "../chunks/use-eve-agent-B2jCfcnG.js";
2
2
 
3
3
  export { signInEnding, useEveAgent };
@@ -1,3 +1,3 @@
1
- import { t as useEveAgent } from "../chunks/use-eve-agent-DMeP0JOF.js";
1
+ import { t as useEveAgent } from "../chunks/use-eve-agent-B2jCfcnG.js";
2
2
 
3
3
  export { useEveAgent };