eve 0.40.0 → 0.42.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 (72) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/channel/channel-operations.d.ts +2 -2
  3. package/dist/src/channel/channel-operations.js +1 -1
  4. package/dist/src/channel/session.d.ts +2 -2
  5. package/dist/src/channel/session.js +1 -1
  6. package/dist/src/chunks/{use-eve-agent-CTI9fHaO.js → use-eve-agent-C0SG1Ttk.js} +4 -1
  7. package/dist/src/chunks/{use-eve-agent-DlkXRQVo.js → use-eve-agent-D71oDil7.js} +4 -1
  8. package/dist/src/cli/dev/tui/tool-presentation.js +1 -1
  9. package/dist/src/client/index.d.ts +1 -1
  10. package/dist/src/client/index.js +1 -1
  11. package/dist/src/client/session.js +1 -1
  12. package/dist/src/compiled/.vendor-stamp.json +2 -1
  13. package/dist/src/compiled/@linqapp/chat-sdk-adapter/LICENSE +201 -0
  14. package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.d.ts +3 -0
  15. package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.js +8 -0
  16. package/dist/src/compiler/extension-compatibility.d.ts +4 -4
  17. package/dist/src/compiler/extension-compatibility.js +1 -1
  18. package/dist/src/execution/tasks/parent/hitl-proxy-steps.js +1 -1
  19. package/dist/src/execution/wire/session-inbox-wire.v1.js +1 -1
  20. package/dist/src/internal/application/package.js +1 -1
  21. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  22. package/dist/src/public/channels/discord/hitl.d.ts +3 -3
  23. package/dist/src/public/channels/discord/hitl.js +1 -1
  24. package/dist/src/public/channels/eve.js +1 -1
  25. package/dist/src/public/channels/linq/inboundContent.d.ts +4 -0
  26. package/dist/src/public/channels/linq/inboundContent.js +1 -0
  27. package/dist/src/public/channels/linq/index.d.ts +1 -0
  28. package/dist/src/public/channels/linq/index.js +1 -0
  29. package/dist/src/public/channels/linq/linqChannel.d.ts +66 -0
  30. package/dist/src/public/channels/linq/linqChannel.js +1 -0
  31. package/dist/src/public/channels/mcp.js +1 -1
  32. package/dist/src/public/channels/slack/hitl.d.ts +4 -5
  33. package/dist/src/public/channels/slack/hitl.js +2 -2
  34. package/dist/src/public/channels/slack/interactions.js +1 -1
  35. package/dist/src/public/channels/slack/session-operations.d.ts +2 -2
  36. package/dist/src/public/channels/slack/slackChannel.d.ts +4 -4
  37. package/dist/src/public/channels/teams/api.js +2 -2
  38. package/dist/src/public/channels/teams/defaults.js +1 -1
  39. package/dist/src/public/channels/teams/hitl.d.ts +11 -2
  40. package/dist/src/public/channels/teams/hitl.js +1 -1
  41. package/dist/src/public/channels/teams/index.d.ts +1 -1
  42. package/dist/src/public/channels/teams/index.js +1 -1
  43. package/dist/src/public/channels/teams/teamsChannel.d.ts +8 -0
  44. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  45. package/dist/src/public/channels/telegram/hitl.d.ts +4 -4
  46. package/dist/src/public/channels/telegram/hitl.js +1 -1
  47. package/dist/src/runtime/framework-tools/ask-question.js +1 -1
  48. package/dist/src/runtime/framework-tools/tasks.d.ts +3 -11
  49. package/dist/src/runtime/framework-tools/tasks.js +1 -1
  50. package/dist/src/runtime/input/types.d.ts +19 -1
  51. package/dist/src/runtime/input/types.js +1 -1
  52. package/dist/src/runtime/prompt/compose.js +1 -1
  53. package/dist/src/runtime/session-callback-route.js +1 -1
  54. package/dist/src/setup/integrations/linq/connect.d.ts +32 -0
  55. package/dist/src/setup/integrations/linq/connect.js +1 -0
  56. package/dist/src/setup/integrations/linq/setup.d.ts +22 -0
  57. package/dist/src/setup/integrations/linq/setup.js +15 -0
  58. package/dist/src/setup/integrations/registry.js +1 -1
  59. package/dist/src/setup/scaffold/create/project.js +1 -1
  60. package/dist/src/setup/scaffold/create/web-template.d.ts +2 -2
  61. package/dist/src/setup/scaffold/create/web-template.js +74 -50
  62. package/dist/src/svelte/index.js +1 -1
  63. package/dist/src/svelte/use-eve-agent.js +1 -1
  64. package/dist/src/vue/index.js +1 -1
  65. package/dist/src/vue/use-eve-agent.js +1 -1
  66. package/docs/channels/custom.mdx +12 -0
  67. package/docs/channels/linq.mdx +67 -0
  68. package/docs/channels/meta.json +1 -0
  69. package/docs/channels/overview.mdx +3 -2
  70. package/docs/channels/teams.mdx +2 -0
  71. package/docs/guides/client/streaming.mdx +1 -1
  72. package/package.json +7 -1
@@ -1 +1 @@
1
- import{createLogger}from"#internal/logging.js";import{SLACK_CARD_SUBTEXT_MAX_LENGTH,truncateCardSubtext}from"#public/channels/slack/limits.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{approvalResponderStatePatch,authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations}from"#public/channels/slack/session-operations.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=o?.id??s.team_id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,label:extractActionLabel(e),user:l})),channelId:r,threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,threadTs:e.threadTs,teamId:e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){return findPromptBlocks(e)[0]}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}function buildAnsweredHitlMessageBlocks(e){let t=findActionBlockIndex(e.messageBlocks,e.actionId);if(t===-1)return buildAnsweredBlocks({promptBlocks:findPromptBlocks(e.messageBlocks),answerLabel:e.answerLabel,userId:e.userId});let n=e.messageBlocks[t],r=answeredBlocksFromActionBlock({answerLabel:e.answerLabel,block:n,userId:e.userId})??buildAnsweredBlocks({promptBlocks:promptBlocksFromActionBlock(n),answerLabel:e.answerLabel,userId:e.userId});return[...e.messageBlocks.slice(0,t),...r,...e.messageBlocks.slice(t+1)]}function findActionBlockIndex(e,t){return e.findIndex(e=>blockContainsActionId(e,t))}function blockContainsActionId(e,t){return isObjectRecord(e)?actionsContainActionId(e.elements,t)||actionsContainActionId(e.actions,t):!1}function actionsContainActionId(e,t){return Array.isArray(e)?e.some(e=>isObjectRecord(e)&&e.action_id===t):!1}function isObjectRecord(e){return typeof e==`object`&&!!e}function answeredBlocksFromActionBlock(e){if(!isObjectRecord(e.block)||e.block.type!==`card`)return;let{actions:t,subtext:n,...r}=e.block,i={...r,subtext:{type:`mrkdwn`,text:formatAnsweredCardSubtext(e),verbatim:!1}};return hasCardContent(i)?[i]:void 0}function formatAnsweredCardSubtext(e){let r=e.userId.length>0?` by <@${e.userId}>`:``,i=SLACK_CARD_SUBTEXT_MAX_LENGTH-20-1-r.length;return truncateCardSubtext(`:white_check_mark: *${truncateWithEllipsis(e.answerLabel,i)}*${r}`)}function truncateWithEllipsis(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function promptBlocksFromActionBlock(e){if(!isObjectRecord(e)||e.type!==`card`)return[];let{actions:t,...n}=e;return hasCardContent(n)?[n]:[]}function hasCardContent(e){return e.body!==void 0||e.title!==void 0||e.hero_image!==void 0}async function handleInteractionPost(e,t,n){let i=new Response(`ok`,{status:200}),s;try{s=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),i}if(s.kind===`view_submission`)return handleViewSubmission(s,t,n);if(s.kind!==`block_actions`)return i;let c=parseBlockActionsPayload(s);if(!c)return i;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:s.raw,interaction:c,freeformAction:l,deps:n}),i;let u=slackContinuationToken(c.channelId,c.threadTs),d=c.actions.flatMap(e=>{let t=deriveHitlResponse(e);return t===null?[]:[{action:e,response:t}]});if(d.length>0){let e=d[0].action.user;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:c,submission:{type:`block_actions`,actions:d.map(({action:e})=>e),inputResponses:d.map(({response:e})=>e),messageTs:d[0].action.messageTs,user:e}}))}let p=n.config.onInteraction;if(p){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let i=e[0].user,{thread:a,slack:s}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),l={...bindSlackSessionOperations({address:u,defaultAuth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:i.id,userName:i.username??i.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:c.channelId,teamId:c.teamId??null,threadTs:c.threadTs,triggeringUserId:i.id}}),thread:a,slack:s};for(let n of e)t.waitUntil(Promise.resolve(p(n,l)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return i}async function dispatchBlockInputResponses(e){let t=await authorizeInputResponse({channelId:e.interaction.channelId,deps:e.deps,submission:e.submission,teamId:e.interaction.teamId,threadTs:e.interaction.threadTs});if(t!==null){try{await e.ctx.from(slackContinuationToken(e.interaction.channelId,e.interaction.threadTs)).respond(e.submission.inputResponses,{auth:t.auth,state:approvalResponderStatePatch(e.submission,t.auth)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>deriveHitlResponse(e)?.kind===`tool-approval`))try{await updateAnsweredHitlCard(e.interaction,e.deps)}catch(e){log.error(`HITL answered-card update failed`,{error:e})}}}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let o=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:o})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,t,n){let r=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return r;let i;try{i=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),r}if(!i.continuationToken||!i.requestId||!i.messageTs||!i.channelId||!i.threadTs)return r;let a=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(a.length===0)return r;let o=e.user,u=e.userId,d=o?.teamId??e.teamId??null,f={type:`view_submission`,inputResponses:[{requestId:i.requestId,text:a}],messageTs:i.messageTs,user:{id:u,username:o?.username,name:o?.name}};return t.waitUntil(dispatchViewInputResponse({ctx:t,deps:n,metadata:i,submission:f,teamId:d,text:a})),r}async function dispatchViewInputResponse(e){let t=await authorizeInputResponse({channelId:e.metadata.channelId,deps:e.deps,submission:e.submission,teamId:e.teamId,threadTs:e.metadata.threadTs});if(t!==null){try{await e.ctx.from(e.metadata.continuationToken).respond(e.submission.inputResponses,{auth:t.auth})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId:e.metadata.channelId,messageTs:e.metadata.messageTs,answerLabel:e.text,userId:e.submission.user.id,deps:e.deps})}catch(e){log.error(`freeform answered-card update failed`,{error:e})}}}async function updateAnsweredHitlCard(e,t){let n=e.actions.find(e=>isHitlAction(e.actionId));if(!n||!n.messageTs)return;let r=n.label??n.selectedOptionValue??n.value;if(!r)return;let a=buildAnsweredHitlMessageBlocks({actionId:n.actionId,answerLabel:r,messageBlocks:e.messageBlocks,userId:n.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),s=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:n.messageTs,blocks:a,text:`Answered: ${r}`})});if(!s.ok)throw Error(`Slack chat.update returned HTTP ${s.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlocks:[],answerLabel:e.answerLabel,userId:e.userId}),n=await resolveSlackBotToken(e.deps.config.credentials?.botToken),r=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${n}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!r.ok)throw Error(`Slack chat.update returned HTTP ${r.status}`)}export{handleInteractionPost,parseBlockActionsPayload};
1
+ import{createLogger}from"#internal/logging.js";import{parseInputResponse}from"#runtime/input/types.js";import{SLACK_CARD_SUBTEXT_MAX_LENGTH,truncateCardSubtext}from"#public/channels/slack/limits.js";import{buildSlackBinding,resolveSlackBotToken,slackContinuationToken}from"#public/channels/slack/api.js";import{buildSlackAuthContext}from"#public/channels/slack/auth.js";import{HITL_FREEFORM_MODAL_ACTION_ID,HITL_FREEFORM_MODAL_BLOCK_ID,HITL_FREEFORM_MODAL_CALLBACK_ID,buildAnsweredBlocks,buildFreeformModalView,deriveHitlResponse,freeformRequestIdFromActionId,isFreeformAction,isHitlAction}from"#public/channels/slack/hitl.js";import{parseSlackWebhookBody}from"#compiled/@chat-adapter/slack/webhook.js";import{approvalResponderStatePatch,authorizeInputResponse}from"#public/channels/slack/input-response.js";import{bindSlackSessionOperations}from"#public/channels/slack/session-operations.js";const log=createLogger(`slack.interactions`);function parseBlockActionsPayload(e){if(isSharedBlockActionsPayload(e))return parseSharedBlockActionsPayload(e);let t=e,n=t.actions;if(!Array.isArray(n))return null;let r=t.channel?.id,i=t.message,a=i?.thread_ts??i?.ts;if(!r||!a)return null;let o=t.team,s=t.user,c=o?.id??s.team_id,l={id:s.id,username:s.username,name:s.name},u=i?.blocks??[];return{actions:n.map(e=>({actionId:String(e.action_id??``),value:e.value==null?void 0:String(e.value),blockId:e.block_id==null?void 0:String(e.block_id),selectedOptionValue:extractSelectedOptionValue(e),messageTs:i?.ts,label:extractActionLabel(e),user:l})),channelId:r,threadTs:a,teamId:c,messageBlocks:u}}function isSharedBlockActionsPayload(e){return e.kind===`block_actions`&&Array.isArray(e.actions)}function parseSharedBlockActionsPayload(e){return!e.channelId||!e.threadTs?null:{actions:e.actions.map(t=>({actionId:t.actionId,value:t.value,blockId:t.blockId,selectedOptionValue:t.selectedOptionValue,messageTs:e.messageTs,label:t.label,user:{id:t.user?.id??e.userId,username:t.user?.username,name:t.user?.name}})),channelId:e.channelId,threadTs:e.threadTs,teamId:e.teamId,messageBlocks:e.messageBlocks??[]}}function extractSelectedOptionValue(e){let t=e.selected_option;return typeof t?.value==`string`?t.value:void 0}function extractActionLabel(e){let t=e.selected_option?.text?.text;if(typeof t==`string`&&t.length>0)return t;let n=e.text?.text;if(typeof n==`string`&&n.length>0)return n}function findPromptBlock(e){return findPromptBlocks(e)[0]}function findPromptBlocks(e){let t=[];for(let n of e){if(typeof n!=`object`||!n)continue;let e=n.type;if(e===`actions`)break;(e===`section`||e===`context`||e===`divider`||e===`image`)&&t.push(n)}return t}function readPromptTextFromBlocks(e){let t=findPromptBlock(e)?.text?.text;return typeof t==`string`&&t.length>0?t:void 0}function buildAnsweredHitlMessageBlocks(e){let t=findActionBlockIndex(e.messageBlocks,e.actionId);if(t===-1)return buildAnsweredBlocks({promptBlocks:findPromptBlocks(e.messageBlocks),answerLabel:e.answerLabel,userId:e.userId});let n=e.messageBlocks[t],r=answeredBlocksFromActionBlock({answerLabel:e.answerLabel,block:n,userId:e.userId})??buildAnsweredBlocks({promptBlocks:promptBlocksFromActionBlock(n),answerLabel:e.answerLabel,userId:e.userId});return[...e.messageBlocks.slice(0,t),...r,...e.messageBlocks.slice(t+1)]}function findActionBlockIndex(e,t){return e.findIndex(e=>blockContainsActionId(e,t))}function blockContainsActionId(e,t){return isObjectRecord(e)?actionsContainActionId(e.elements,t)||actionsContainActionId(e.actions,t):!1}function actionsContainActionId(e,t){return Array.isArray(e)?e.some(e=>isObjectRecord(e)&&e.action_id===t):!1}function isObjectRecord(e){return typeof e==`object`&&!!e}function answeredBlocksFromActionBlock(e){if(!isObjectRecord(e.block)||e.block.type!==`card`)return;let{actions:t,subtext:n,...r}=e.block,i={...r,subtext:{type:`mrkdwn`,text:formatAnsweredCardSubtext(e),verbatim:!1}};return hasCardContent(i)?[i]:void 0}function formatAnsweredCardSubtext(e){let t=e.userId.length>0?` by <@${e.userId}>`:``,i=SLACK_CARD_SUBTEXT_MAX_LENGTH-20-1-t.length;return truncateCardSubtext(`:white_check_mark: *${truncateWithEllipsis(e.answerLabel,i)}*${t}`)}function truncateWithEllipsis(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function promptBlocksFromActionBlock(e){if(!isObjectRecord(e)||e.type!==`card`)return[];let{actions:t,...n}=e;return hasCardContent(n)?[n]:[]}function hasCardContent(e){return e.body!==void 0||e.title!==void 0||e.hero_image!==void 0}async function handleInteractionPost(e,t,n){let r=new Response(`ok`,{status:200}),a;try{a=parseSlackWebhookBody(e,{contentType:`application/x-www-form-urlencoded`})}catch{return log.warn(`failed to parse Slack interaction payload`),r}if(a.kind===`view_submission`)return handleViewSubmission(a,t,n);if(a.kind!==`block_actions`)return r;let c=parseBlockActionsPayload(a);if(!c)return r;let l=c.actions.find(e=>isFreeformAction(e.actionId));if(l)return await openFreeformModal({payload:a.raw,interaction:c,freeformAction:l,deps:n}),r;let u=slackContinuationToken(c.channelId,c.threadTs),d=c.actions.flatMap(e=>{let t=deriveHitlResponse(e);return t===null?[]:[{action:e,derived:t}]});if(d.length>0){let e=d[0].action.user;t.waitUntil(dispatchBlockInputResponses({ctx:t,deps:n,interaction:c,submission:{type:`block_actions`,actions:d.map(({action:e})=>e),inputResponses:d.map(({derived:e})=>e.response),messageTs:d[0].action.messageTs,user:e}}))}let f=n.config.onInteraction;if(f){let e=c.actions.filter(e=>!isHitlAction(e.actionId));if(e.length>0){let r=e[0].user,{thread:a,slack:o}=buildSlackBinding({botToken:n.config.credentials?.botToken,channelId:c.channelId,threadTs:c.threadTs,teamId:c.teamId}),l={...bindSlackSessionOperations({address:u,defaultAuth:buildSlackAuthContext({channelId:c.channelId,teamId:c.teamId,threadTs:c.threadTs,userId:r.id,userName:r.username??r.name}),from:t.from,resolveSession:t.resolveSession,state:{channelId:c.channelId,teamId:c.teamId??null,threadTs:c.threadTs,triggeringUserId:r.id}}),thread:a,slack:o};for(let n of e)t.waitUntil(Promise.resolve(f(n,l)).catch(e=>{log.error(`custom interaction handler failed`,{error:e})}))}}return r}async function dispatchBlockInputResponses(e){let t=await authorizeInputResponse({channelId:e.interaction.channelId,deps:e.deps,submission:e.submission,teamId:e.interaction.teamId,threadTs:e.interaction.threadTs});if(t!==null){try{await e.ctx.from(slackContinuationToken(e.interaction.channelId,e.interaction.threadTs)).respond(e.submission.inputResponses,{auth:t.auth,state:approvalResponderStatePatch(e.submission,t.auth)})}catch(e){log.error(`HITL interaction delivery failed`,{error:e});return}if(!e.submission.actions.some(e=>deriveHitlResponse(e)?.kind===`tool-approval`))try{await updateAnsweredHitlCard(e.interaction,e.deps)}catch(e){log.error(`HITL answered-card update failed`,{error:e})}}}async function openFreeformModal(e){let t=e.payload.trigger_id;if(typeof t!=`string`||t.length===0){log.warn(`freeform button click missing trigger_id — cannot open modal`);return}let n=freeformRequestIdFromActionId(e.freeformAction.actionId)??e.freeformAction.value;if(!n){log.warn(`freeform button click missing requestId`);return}let r=e.freeformAction.messageTs;if(!r){log.warn(`freeform button click missing messageTs`);return}let i=buildFreeformModalView({metadata:{continuationToken:slackContinuationToken(e.interaction.channelId,e.interaction.threadTs),channelId:e.interaction.channelId,threadTs:e.interaction.threadTs,messageTs:r,requestId:n},prompt:readPromptTextFromBlocks(e.interaction.messageBlocks)}),s=await resolveSlackBotToken(e.deps.config.credentials?.botToken),c=await fetch(`https://slack.com/api/views.open`,{method:`POST`,headers:{authorization:`Bearer ${s}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({trigger_id:t,view:i})});c.ok||log.error(`Slack views.open returned non-2xx`,{status:c.status})}async function handleViewSubmission(e,n,r){let i=new Response(null,{status:200});if(e.callbackId!==HITL_FREEFORM_MODAL_CALLBACK_ID)return i;let a;try{a=JSON.parse(e.privateMetadata??``)}catch{return log.warn(`freeform view_submission carries invalid private_metadata`),i}if(!a.continuationToken||!a.requestId||!a.messageTs||!a.channelId||!a.threadTs)return i;let o=e.values?.find(e=>e.blockId===HITL_FREEFORM_MODAL_BLOCK_ID&&e.actionId===HITL_FREEFORM_MODAL_ACTION_ID)?.value??``;if(o.length===0)return i;let s=e.user,d=e.userId,f=s?.teamId??e.teamId??null,p={type:`view_submission`,inputResponses:[parseInputResponse({requestId:a.requestId,text:o})],messageTs:a.messageTs,user:{id:d,username:s?.username,name:s?.name}};return n.waitUntil(dispatchViewInputResponse({ctx:n,deps:r,metadata:a,submission:p,teamId:f,text:o})),i}async function dispatchViewInputResponse(e){let t=await authorizeInputResponse({channelId:e.metadata.channelId,deps:e.deps,submission:e.submission,teamId:e.teamId,threadTs:e.metadata.threadTs});if(t!==null){try{await e.ctx.from(e.metadata.continuationToken).respond(e.submission.inputResponses,{auth:t.auth})}catch(e){log.error(`freeform answer delivery failed`,{error:e});return}try{await updateAnsweredFreeformCard({channelId:e.metadata.channelId,messageTs:e.metadata.messageTs,answerLabel:e.text,userId:e.submission.user.id,deps:e.deps})}catch(e){log.error(`freeform answered-card update failed`,{error:e})}}}async function updateAnsweredHitlCard(e,t){let n=e.actions.find(e=>isHitlAction(e.actionId));if(!n||!n.messageTs)return;let r=n.label??n.selectedOptionValue??n.value;if(!r)return;let i=buildAnsweredHitlMessageBlocks({actionId:n.actionId,answerLabel:r,messageBlocks:e.messageBlocks,userId:n.user.id}),o=await resolveSlackBotToken(t.config.credentials?.botToken),s=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${o}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:n.messageTs,blocks:i,text:`Answered: ${r}`})});if(!s.ok)throw Error(`Slack chat.update returned HTTP ${s.status}`)}async function updateAnsweredFreeformCard(e){let t=buildAnsweredBlocks({promptBlocks:[],answerLabel:e.answerLabel,userId:e.userId}),n=await resolveSlackBotToken(e.deps.config.credentials?.botToken),r=await fetch(`https://slack.com/api/chat.update`,{method:`POST`,headers:{authorization:`Bearer ${n}`,"content-type":`application/json; charset=utf-8`},body:JSON.stringify({channel:e.channelId,ts:e.messageTs,blocks:t,text:`Answered: ${e.answerLabel}`})});if(!r.ok)throw Error(`Slack chat.update returned HTTP ${r.status}`)}export{handleInteractionPost,parseBlockActionsPayload};
@@ -1,6 +1,6 @@
1
1
  import type { ChannelFrom, ChannelResolveSession, ChannelRespondOptions, ChannelSendOptions, ChannelSource } from "#channel/channel-operations.js";
2
2
  import type { SessionAuthContext } from "#channel/types.js";
3
- import type { InputResponse } from "#runtime/input/types.js";
3
+ import type { InputResponse, StrictInputResponses } from "#runtime/input/types.js";
4
4
  import type { UserContent } from "ai";
5
5
  import type { SlackChannelState } from "#public/channels/slack/slackChannel.js";
6
6
  type SlackSource = ChannelSource<SlackChannelState>;
@@ -15,7 +15,7 @@ export type SlackRespondOptions = Omit<ChannelRespondOptions<SlackChannelState>,
15
15
  /** Current-owner operations already bound to one Slack thread. */
16
16
  export interface SlackSessionOperations {
17
17
  send(message: string | UserContent, options?: SlackSendOptions): ReturnType<SlackSource["send"]>;
18
- respond(inputResponses: readonly InputResponse[], options?: SlackRespondOptions): ReturnType<SlackSource["respond"]>;
18
+ respond<const TResponses extends readonly InputResponse[]>(inputResponses: StrictInputResponses<TResponses>, options?: SlackRespondOptions): ReturnType<SlackSource["respond"]>;
19
19
  cancel(options?: {
20
20
  readonly turnId?: string;
21
21
  }): ReturnType<SlackSource["cancel"]>;
@@ -6,7 +6,7 @@ import type { CardElement } from "#compiled/chat/index.js";
6
6
  import type { SessionContext } from "#public/definitions/callback-context.js";
7
7
  import type { ChannelContinuationOps } from "#public/definitions/channel.js";
8
8
  import type { UnstampedMessageStreamEvent } from "#protocol/message.js";
9
- import type { InputResponse } from "#runtime/input/types.js";
9
+ import type { InputResponse, StrictInputResponses, ValidatedInputResponse } from "#runtime/input/types.js";
10
10
  import { type SlackBotToken, type SlackHandle, type SlackThread, type SlackWorkspaceHandle } from "#public/channels/slack/api.js";
11
11
  import { type SlackEvent, type SlackEventEnvelope, type SlackMessage } from "#public/channels/slack/inbound.js";
12
12
  import { type LoadThreadContextMessagesOptions } from "#public/channels/slack/thread.js";
@@ -214,7 +214,7 @@ export interface SlackEventRespondOptions {
214
214
  */
215
215
  export type SlackEventSendFn = (message: string | UserContent, options: SlackEventSendOptions) => Promise<Session>;
216
216
  /** Answers pending input requests on one Slack thread. */
217
- export type SlackEventRespondFn = (inputResponses: Parameters<SlackSessionOperations["respond"]>[0], options: SlackEventRespondOptions) => ReturnType<SlackSessionOperations["respond"]>;
217
+ export type SlackEventRespondFn = <const TResponses extends readonly InputResponse[]>(inputResponses: StrictInputResponses<TResponses>, options: SlackEventRespondOptions) => ReturnType<SlackSessionOperations["respond"]>;
218
218
  /**
219
219
  * Slack thread identity used by workspace-scoped inbound helpers.
220
220
  */
@@ -326,13 +326,13 @@ export interface SlackInteractionUser {
326
326
  /** Decoded eve-owned HITL response submitted through Slack interactivity. */
327
327
  export type SlackInputResponseSubmission = {
328
328
  readonly type: "block_actions";
329
- readonly inputResponses: readonly InputResponse[];
329
+ readonly inputResponses: readonly ValidatedInputResponse[];
330
330
  readonly actions: readonly SlackInteractionAction[];
331
331
  readonly messageTs?: string;
332
332
  readonly user: SlackInteractionUser;
333
333
  } | {
334
334
  readonly type: "view_submission";
335
- readonly inputResponses: readonly InputResponse[];
335
+ readonly inputResponses: readonly ValidatedInputResponse[];
336
336
  readonly messageTs: string;
337
337
  readonly user: SlackInteractionUser;
338
338
  };
@@ -1,4 +1,4 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){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(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let a=await resolveTeamsAppId(n?.appId),o=await resolveTeamsAppPassword(n?.appPassword),s=await resolveTeamsTenantId(n?.tenantId),c=trimTrailingSlash(t.loginBaseUrl??`https://login.microsoftonline.com`),l=`${c}:${s??BOT_FRAMEWORK_TENANT}:${a}`,u=accessTokenCache.get(l),d=Date.now();if(u!==void 0&&u.expiresAt-6e4>d)return u.accessToken;let f=`${c}/${encodeURIComponent(s??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,p=new URLSearchParams({client_id:a,client_secret:o,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),m=await(t.fetch??fetch)(f,{body:p,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),h=await parseResponseBody(m);if(!m.ok)throw Error(`Teams access-token request failed with HTTP ${m.status}.`);let g=isObject(h)?h:{},_=typeof g.access_token==`string`?g.access_token:``;if(!_)throw Error(`Teams access-token response did not include access_token.`);let v=typeof g.expires_in==`number`?g.expires_in:3600;return accessTokenCache.set(l,{accessToken:_,expiresAt:d+v*1e3}),_}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function triggerTeamsTypingIndicator(e){let t=await callTeamsConnectorApi({...e,body:{type:`typing`},path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams typing indicator failed with HTTP ${t.status}.`)}function splitTeamsMessageText(e){if(e.length<=81920)return[e];let t=[],r=e;for(;r.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=r.lastIndexOf(`
1
+ import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){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(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let a=await resolveTeamsAppId(n?.appId),o=await resolveTeamsAppPassword(n?.appPassword),s=await resolveTeamsTenantId(n?.tenantId),c=trimTrailingSlash(t.loginBaseUrl??`https://login.microsoftonline.com`),l=`${c}:${s??BOT_FRAMEWORK_TENANT}:${a}`,u=accessTokenCache.get(l),d=Date.now();if(u!==void 0&&u.expiresAt-6e4>d)return u.accessToken;let f=`${c}/${encodeURIComponent(s??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,p=new URLSearchParams({client_id:a,client_secret:o,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),m=await(t.fetch??fetch)(f,{body:p,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),h=await parseResponseBody(m);if(!m.ok)throw Error(`Teams access-token request failed with HTTP ${m.status}.`);let g=isObject(h)?h:{},_=typeof g.access_token==`string`?g.access_token:``;if(!_)throw Error(`Teams access-token response did not include access_token.`);let v=typeof g.expires_in==`number`?g.expires_in:3600;return accessTokenCache.set(l,{accessToken:_,expiresAt:d+v*1e3}),_}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status} 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=[],r=e;for(;r.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=r.lastIndexOf(`
2
2
 
3
3
  `,TEAMS_MESSAGE_TEXT_MAX_LENGTH);e<=0&&(e=r.lastIndexOf(`
4
- `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=r.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(r.slice(0,e).trimEnd()),r=r.slice(e).trimStart()}return t.push(r),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(t){let n=isObject(t)?t:{};return{id:typeof n.id==`string`?n.id:``,raw:t}}function trimTrailingSlash(e){return e.replace(/\/+$/,``)}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};
4
+ `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=r.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(r.slice(0,e).trimEnd()),r=r.slice(e).trimStart()}return t.push(r),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(t){let n=isObject(t)?t:{};return{id:typeof n.id==`string`?n.id:``,raw:t}}function 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,3 +1,3 @@
1
- import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}const defaultEvents={async"turn.started"(e,t,n){await t.thread.startTyping()},async"actions.requested"(e,t,n){await t.thread.startTyping()},async"input.requested"(e,t,n){for(let n of e.requests)await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion,replyToActivityId:t.teams.replyToActivityId}))},async"message.completed"(e,t,n){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
1
+ import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}const defaultEvents={async"turn.started"(e,t,n){await t.thread.startTyping()},async"actions.requested"(e,t,n){await t.thread.startTyping()},async"input.requested"(e,t,n){for(let n of e.requests){let e=await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion,replyToActivityId:t.teams.replyToActivityId}));n.kind===`tool-approval`&&e.id&&(t.state.pendingApprovalCards={...t.state.pendingApprovalCards,[n.requestId]:{activityId:e.id,prompt:n.prompt}})}},async"approval.settled"(e,t,n){let r=t.state.pendingApprovalCards??{},a=r[e.requestId];if(a===void 0)return;let o=t.state.approvalResponderAccounts?.[e.responderPrincipalId],s=e.outcome===`approved`?`Approved`:`Cancelled`,c=o?.name??o?.id;await t.thread.update(a.activityId,renderAnsweredInputRequestMessage({includeText:!1,label:c===void 0?s:`${s} by ${c}`,prompt:a.prompt}));let l={...r};delete l[e.requestId],t.state.pendingApprovalCards=l},async"message.completed"(e,t,n){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
2
2
  `))},async"turn.failed"(n,r,i){let a=formatErrorHint(n),o=extractErrorId(n.details);await r.thread.post([`I hit an error while handling your request${a}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...o?[``,`Error id: ${o}`]:[]].join(`
3
3
  `))},async"authorization.required"(e,t,r){let i=e.authorization?.displayName??formatConnectionDisplayName(e.name),a=e.authorization?.url,o=a?`Authorization required for ${i}: ${a}`:`Authorization required for ${i}.`,s=await t.thread.post({attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:a?[{title:`Sign in with ${i}`,type:`Action.OpenUrl`,url:a}]:[],body:[{text:`Authorization required for ${i}`,type:`TextBlock`,weight:`Bolder`,wrap:!0},{text:t.state.triggeringUser?`Requested by ${t.state.triggeringUser.name??t.state.triggeringUser.id}.`:`No triggering user is available for a private prompt.`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:t.adaptiveCardVersion}),contentType:`application/vnd.microsoft.card.adaptive`}],text:o});s.id&&(t.state.pendingAuthActivityId=s.id)},async"authorization.completed"(e,t,n){e.outcome===`authorized`&&await t.thread.startTyping();let r=t.state.pendingAuthActivityId;if(!r)return;let a=buildAuthCompletedText({displayName:e.authorization?.displayName??formatConnectionDisplayName(e.name),outcome:e.outcome,reason:e.reason});await t.thread.update(r,renderAnsweredInputRequestMessage({prompt:a})),t.state.pendingAuthActivityId=null}};function formatConnectionDisplayName(e){return e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1)}function buildAuthCompletedText(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;let t=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} authorization ${e.outcome}${t}.`}function teamsMentionUser(e){let t=e.name??e.id;return{mentioned:{id:e.id,name:e.name},text:`<at>${t}</at>`,type:`mention`}}export{buildAuthCompletedText,defaultEvents,defaultOnMessage,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser};
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Teams Adaptive Card rendering and decode helpers for eve HITL prompts.
3
3
  */
4
- import type { InputRequest, InputResponse } from "#runtime/input/types.js";
4
+ import { type InputRequest, type ValidatedInputResponse } from "#runtime/input/types.js";
5
5
  import type { TeamsActivity } from "#public/channels/teams/inbound.js";
6
6
  import type { TeamsAttachment, TeamsMessageBody } from "#public/channels/teams/api.js";
7
7
  /** Adaptive Card attachment content type used by Teams. */
@@ -12,6 +12,10 @@ export declare const TEAMS_HITL_DATA_KEY = "eve_input";
12
12
  export declare const TEAMS_HITL_CHOICE_INPUT_ID = "eve_option";
13
13
  /** Text input id used for freeform HITL requests. */
14
14
  export declare const TEAMS_HITL_FREEFORM_INPUT_ID = "eve_freeform_text";
15
+ /** Request kind carried on approval actions so lifecycle handling can distinguish them from questions. */
16
+ export declare const TEAMS_HITL_REQUEST_KIND_KEY = "kind";
17
+ /** Prompt carried on approval actions so a response can recover its card record. */
18
+ export declare const TEAMS_HITL_PROMPT_KEY = "prompt";
15
19
  /** Renders one input request as a Teams message body containing an Adaptive Card. */
16
20
  export declare function renderInputRequestMessage(request: InputRequest, options?: {
17
21
  readonly adaptiveCardVersion?: string;
@@ -28,18 +32,23 @@ export declare function renderInputRequestAttachment(request: InputRequest, opti
28
32
  }): TeamsAttachment;
29
33
  /** Renders an answered Teams card that replaces a pending HITL prompt. */
30
34
  export declare function renderAnsweredInputRequestMessage(input: {
35
+ readonly includeText?: boolean;
31
36
  readonly label?: string;
32
37
  readonly prompt: string;
33
38
  }): TeamsMessageBody;
34
39
  /** Returns true when a Teams activity carries an eve HITL submit payload. */
35
40
  export declare function isTeamsInputResponseActivity(activity: TeamsActivity): boolean;
41
+ /** Returns whether an eve HITL activity answers a tool approval. */
42
+ export declare function isTeamsToolApprovalResponseActivity(activity: TeamsActivity): boolean;
43
+ /** Reads the original prompt from a tool-approval submit activity. */
44
+ export declare function readTeamsToolApprovalPrompt(activity: TeamsActivity): string | undefined;
36
45
  /**
37
46
  * Decodes the eve HITL submit payload from a Teams activity. Returns a single
38
47
  * `InputResponse` (option selection, freeform text, or a bare requestId
39
48
  * acknowledgement), or an empty array when the activity has no recognizable
40
49
  * HITL payload or requestId.
41
50
  */
42
- export declare function deriveTeamsInputResponses(activity: TeamsActivity): readonly InputResponse[];
51
+ export declare function deriveTeamsInputResponses(activity: TeamsActivity): readonly ValidatedInputResponse[];
43
52
  /**
44
53
  * Builds the HTTP body Teams expects after an Adaptive Card invoke action.
45
54
  * Defaults to statusCode 200 and message "Answer received."; `type` is always
@@ -1 +1 @@
1
- import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";const TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`eve_input`,TEAMS_HITL_CHOICE_INPUT_ID=`eve_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`eve_freeform_text`;function renderInputRequestMessage(e,t={}){let n=formatApprovalInput(e),r=n?truncate(n,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH):null;return{attachments:[renderInputRequestAttachment(e,t)],text:r?`${e.prompt}\n\nTool input:\n${r}`:e.prompt}}function renderInputRequestAttachment(e,n={}){let r=formatApprovalInput(e);return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e,n.replyToActivityId),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...r?[{fontType:`Monospace`,text:truncate(r,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0}]:[],...renderInputs(e)],type:`AdaptiveCard`,version:n.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){return{attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},{color:`good`,text:e.label?`Answered: ${e.label}`:`Answered`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}],text:e.label?`Answered: ${e.label}`:`Answered`}}function isTeamsInputResponseActivity(e){return deriveTeamsInputResponses(e).length>0}function deriveTeamsInputResponses(e){let t=readActivityValue(e);if(!t)return[];let n=readHitlPayload(t);if(!n)return[];let r=typeof n.requestId==`string`?n.requestId:``;if(!r)return[];let i=typeof n.optionId==`string`?n.optionId:typeof t.eve_option==`string`?t[TEAMS_HITL_CHOICE_INPUT_ID]:void 0,a=typeof t.eve_freeform_text==`string`?t[TEAMS_HITL_FREEFORM_INPUT_ID]:void 0;return i===void 0?a===void 0?[{requestId:r}]:[{requestId:r,text:a}]:[{optionId:i,requestId:r}]}function readTeamsInputReplyToActivityId(e){let t=readActivityValue(e);if(!t)return null;let n=readHitlPayload(t);return n&&typeof n.replyToActivityId==`string`?n.replyToActivityId:null}function teamsInvokeResponse(e={}){return{statusCode:e.statusCode??200,type:`application/vnd.microsoft.activity.message`,value:e.message??`Answer received.`}}function renderInputs(e){return e.display===`select`&&e.options&&e.options.length>0?[{choices:e.options.map(e=>({title:truncate(e.label,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH),value:e.id})),id:TEAMS_HITL_CHOICE_INPUT_ID,isMultiSelect:!1,style:`compact`,type:`Input.ChoiceSet`}]:e.allowFreeform===!0||!e.options||e.options.length===0?[{id:TEAMS_HITL_FREEFORM_INPUT_ID,isMultiline:!0,placeholder:`Type your answer`,type:`Input.Text`}]:[]}function renderActions(e,t){let payload=n=>{let r={requestId:e.requestId};return t!==void 0&&(r.replyToActivityId=t),n!==void 0&&(r.optionId=n),r},i=e.options;return i&&i.length>0&&e.display!==`select`?i.slice(0,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT).map(e=>({data:{[TEAMS_HITL_DATA_KEY]:payload(e.id)},title:truncate(e.label,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH),type:`Action.Submit`})):[{data:{[TEAMS_HITL_DATA_KEY]:payload()},title:`Submit`,type:`Action.Submit`}]}function readActivityValue(e){return e.type===`message`?readMessageValue(e):e.type===`invoke`?readInvokeValue(e):null}function readMessageValue(e){return e.value??null}function readInvokeValue(t){let n=t.value;if(!n)return null;let r=isObject(n.action)?n.action:null;return(r&&isObject(r.data)?r.data:null)??n}function readHitlPayload(t){let n=t[TEAMS_HITL_DATA_KEY];if(isObject(n))return n;let r=isObject(t.action)?t.action:null,i=(r&&isObject(r.data)?r.data:null)?.[TEAMS_HITL_DATA_KEY];return isObject(i)?i:null}function formatApprovalInput(e){if(e.kind!==`tool-approval`)return null;let t=JSON.stringify(e.action.input,null,2);return t===`{}`?null:t}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,deriveTeamsInputResponses,isTeamsInputResponseActivity,readTeamsInputReplyToActivityId,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse};
1
+ import{parseInputResponse}from"#runtime/input/types.js";import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";const TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`eve_input`,TEAMS_HITL_CHOICE_INPUT_ID=`eve_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`eve_freeform_text`,TEAMS_HITL_REQUEST_KIND_KEY=`kind`,TEAMS_HITL_PROMPT_KEY=`prompt`;function renderInputRequestMessage(e,t={}){let n=formatApprovalInput(e),r=n?truncate(n,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH):null;return{attachments:[renderInputRequestAttachment(e,t)],text:r?`${e.prompt}\n\nTool input:\n${r}`:e.prompt}}function renderInputRequestAttachment(e,t={}){let r=formatApprovalInput(e);return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e,t.replyToActivityId),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...r?[{fontType:`Monospace`,text:truncate(r,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0}]:[],...renderInputs(e)],type:`AdaptiveCard`,version:t.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){let t=e.label?`Answered: ${e.label}`:`Answered`,r={attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},{color:`good`,text:t,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}]};return e.includeText===!1?r:{...r,text:t}}function isTeamsInputResponseActivity(e){return deriveTeamsInputResponses(e).length>0}function isTeamsToolApprovalResponseActivity(e){let t=readActivityValue(e);return(t&&readHitlPayload(t))?.[TEAMS_HITL_REQUEST_KIND_KEY]===`tool-approval`}function readTeamsToolApprovalPrompt(e){let t=readActivityValue(e),n=(t&&readHitlPayload(t))?.[TEAMS_HITL_PROMPT_KEY];return typeof n==`string`&&n.length>0?n:void 0}function deriveTeamsInputResponses(t){let n=readActivityValue(t);if(!n)return[];let r=readHitlPayload(n);if(!r)return[];let i=typeof r.requestId==`string`?r.requestId:``;if(!i)return[];let a=typeof r.optionId==`string`?r.optionId:typeof n.eve_option==`string`?n[TEAMS_HITL_CHOICE_INPUT_ID]:void 0,o=typeof n.eve_freeform_text==`string`?n[TEAMS_HITL_FREEFORM_INPUT_ID]:void 0;return a===void 0?o===void 0?[parseInputResponse({requestId:i})]:[parseInputResponse({requestId:i,text:o})]:[parseInputResponse({optionId:a,requestId:i})]}function readTeamsInputReplyToActivityId(e){let t=readActivityValue(e);if(!t)return null;let n=readHitlPayload(t);return n&&typeof n.replyToActivityId==`string`?n.replyToActivityId:null}function teamsInvokeResponse(e={}){return{statusCode:e.statusCode??200,type:`application/vnd.microsoft.activity.message`,value:e.message??`Answer received.`}}function renderInputs(e){return e.display===`select`&&e.options&&e.options.length>0?[{choices:e.options.map(e=>({title:truncate(e.label,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH),value:e.id})),id:TEAMS_HITL_CHOICE_INPUT_ID,isMultiSelect:!1,style:`compact`,type:`Input.ChoiceSet`}]:e.allowFreeform===!0||!e.options||e.options.length===0?[{id:TEAMS_HITL_FREEFORM_INPUT_ID,isMultiline:!0,placeholder:`Type your answer`,type:`Input.Text`}]:[]}function renderActions(e,t){let payload=n=>{let r={requestId:e.requestId};return e.kind===`tool-approval`&&(r[TEAMS_HITL_REQUEST_KIND_KEY]=`tool-approval`,r[TEAMS_HITL_PROMPT_KEY]=e.prompt),t!==void 0&&(r.replyToActivityId=t),n!==void 0&&(r.optionId=n),r},n=e.options;return n&&n.length>0&&e.display!==`select`?n.slice(0,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT).map(e=>({data:{[TEAMS_HITL_DATA_KEY]:payload(e.id)},title:truncate(e.label,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH),type:`Action.Submit`})):[{data:{[TEAMS_HITL_DATA_KEY]:payload()},title:`Submit`,type:`Action.Submit`}]}function readActivityValue(e){return e.type===`message`?readMessageValue(e):e.type===`invoke`?readInvokeValue(e):null}function readMessageValue(e){return e.value??null}function readInvokeValue(e){let n=e.value;if(!n)return null;let r=isObject(n.action)?n.action:null;return(r&&isObject(r.data)?r.data:null)??n}function readHitlPayload(e){let n=e[TEAMS_HITL_DATA_KEY];if(isObject(n))return n;let r=isObject(e.action)?e.action:null,i=(r&&isObject(r.data)?r.data:null)?.[TEAMS_HITL_DATA_KEY];return isObject(i)?i:null}function formatApprovalInput(e){if(e.kind!==`tool-approval`)return null;let t=JSON.stringify(e.action.input,null,2);return t===`{}`?null:t}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse};
@@ -13,7 +13,7 @@ export interface TeamsInstrumentationMetadata extends Record<string, unknown> {
13
13
  export { teamsChannel, type TeamsChannel, type TeamsChannelConfig, type TeamsChannelCredentials, type TeamsChannelEvents, type TeamsChannelState, type TeamsContext, type TeamsEventContext, type TeamsHandle, type TeamsInboundMessageContext, type TeamsInboundResult, type TeamsInboundResultOrPromise, type TeamsInputResponseResult, type TeamsInvokeResult, type TeamsInvokeResultOrPromise, type TeamsReceiveTarget, type TeamsRequestOptions, type TeamsThread, } from "#public/channels/teams/teamsChannel.js";
14
14
  export { callTeamsConnectorApi, normalizeTeamsPostInput, replyToTeamsActivity, resolveTeamsAccessToken, resolveTeamsAppId, resolveTeamsAppPassword, resolveTeamsTenantId, sendTeamsActivity, splitTeamsMessageText, teamsContinuationToken, triggerTeamsTypingIndicator, updateTeamsActivity, TEAMS_MESSAGE_TEXT_MAX_LENGTH, type TeamsAccessTokenResult, type TeamsApiOptions, type TeamsApiResponse, type TeamsAppId, type TeamsAppPassword, type TeamsAttachment, type TeamsChannelAccount, type TeamsCredentials, type TeamsFetch, type TeamsMention, type TeamsMessageBody, type TeamsOutboundActivity, type TeamsPostedActivity, type TeamsTenantId, type TeamsTokenProvider, } from "#public/channels/teams/api.js";
15
15
  export { formatTeamsContextBlock, isTeamsPersonalMessage, parseTeamsActivity, teamsThreadRootActivityId, type TeamsActivity, type TeamsActivityBase, type TeamsConversationAccount, type TeamsConversationScope, type TeamsConversationUpdateActivity, type TeamsInboundContext, type TeamsInvokeActivity, type TeamsMessageActivity, } from "#public/channels/teams/inbound.js";
16
- export { deriveTeamsInputResponses, isTeamsInputResponseActivity, renderAnsweredInputRequestMessage, renderInputRequestAttachment, renderInputRequestMessage, teamsInvokeResponse, TEAMS_ADAPTIVE_CARD_CONTENT_TYPE, TEAMS_HITL_CHOICE_INPUT_ID, TEAMS_HITL_DATA_KEY, TEAMS_HITL_FREEFORM_INPUT_ID, } from "#public/channels/teams/hitl.js";
16
+ export { deriveTeamsInputResponses, isTeamsInputResponseActivity, isTeamsToolApprovalResponseActivity, readTeamsToolApprovalPrompt, renderAnsweredInputRequestMessage, renderInputRequestAttachment, renderInputRequestMessage, teamsInvokeResponse, TEAMS_ADAPTIVE_CARD_CONTENT_TYPE, TEAMS_HITL_CHOICE_INPUT_ID, TEAMS_HITL_DATA_KEY, TEAMS_HITL_FREEFORM_INPUT_ID, TEAMS_HITL_REQUEST_KIND_KEY, TEAMS_HITL_PROMPT_KEY, } from "#public/channels/teams/hitl.js";
17
17
  export { collectTeamsFileParts, buildTeamsTurnMessage, createTeamsFetchFile, normalizeTeamsFilesPolicy, type TeamsFilesConfig, type TeamsFilesPolicy, } from "#public/channels/teams/attachments.js";
18
18
  export { buildAuthCompletedText, defaultTeamsAuth, formatConnectionDisplayName, teamsMentionUser, } from "#public/channels/teams/defaults.js";
19
19
  export { verifyTeamsJwt, verifyTeamsRequest, type TeamsJwtVerifyOptions, type TeamsVerifyOptions, type TeamsWebhookVerifier, } from "#public/channels/teams/verify.js";
@@ -1 +1 @@
1
- import{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,deriveTeamsInputResponses,isTeamsInputResponseActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{teamsChannel}from"#public/channels/teams/teamsChannel.js";import{formatTeamsContextBlock,isTeamsPersonalMessage,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{buildAuthCompletedText,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsJwt,verifyTeamsRequest}from"#public/channels/teams/verify.js";export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_MESSAGE_TEXT_MAX_LENGTH,buildAuthCompletedText,buildTeamsTurnMessage,callTeamsConnectorApi,collectTeamsFileParts,createTeamsFetchFile,defaultTeamsAuth,deriveTeamsInputResponses,formatConnectionDisplayName,formatTeamsContextBlock,isTeamsInputResponseActivity,isTeamsPersonalMessage,normalizeTeamsFilesPolicy,normalizeTeamsPostInput,parseTeamsActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsChannel,teamsContinuationToken,teamsInvokeResponse,teamsMentionUser,teamsThreadRootActivityId,triggerTeamsTypingIndicator,updateTeamsActivity,verifyTeamsJwt,verifyTeamsRequest};
1
+ import{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{teamsChannel}from"#public/channels/teams/teamsChannel.js";import{formatTeamsContextBlock,isTeamsPersonalMessage,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{buildAuthCompletedText,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsJwt,verifyTeamsRequest}from"#public/channels/teams/verify.js";export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,TEAMS_MESSAGE_TEXT_MAX_LENGTH,buildAuthCompletedText,buildTeamsTurnMessage,callTeamsConnectorApi,collectTeamsFileParts,createTeamsFetchFile,defaultTeamsAuth,deriveTeamsInputResponses,formatConnectionDisplayName,formatTeamsContextBlock,isTeamsInputResponseActivity,isTeamsPersonalMessage,isTeamsToolApprovalResponseActivity,normalizeTeamsFilesPolicy,normalizeTeamsPostInput,parseTeamsActivity,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsChannel,teamsContinuationToken,teamsInvokeResponse,teamsMentionUser,teamsThreadRootActivityId,triggerTeamsTypingIndicator,updateTeamsActivity,verifyTeamsJwt,verifyTeamsRequest};
@@ -33,6 +33,10 @@ export interface TeamsChannelContext extends TeamsContext {
33
33
  export interface TeamsEventContext extends TeamsChannelContext, ChannelContinuationOps {
34
34
  }
35
35
  /** JSON-serializable Teams channel state. */
36
+ export interface TeamsPendingApprovalCard {
37
+ readonly activityId: string;
38
+ readonly prompt: string;
39
+ }
36
40
  export interface TeamsChannelState {
37
41
  /** Bot account captured from the inbound activity recipient. */
38
42
  bot: TeamsChannelAccount | null;
@@ -49,6 +53,8 @@ export interface TeamsChannelState {
49
53
  triggeringUser: TeamsChannelAccount | null;
50
54
  /** Activity id for the default connection-auth card, when posted. */
51
55
  pendingAuthActivityId?: string | null;
56
+ pendingApprovalCards?: Record<string, TeamsPendingApprovalCard>;
57
+ approvalResponderAccounts?: Record<string, TeamsChannelAccount>;
52
58
  }
53
59
  /** Teams channel credentials. */
54
60
  export interface TeamsChannelCredentials extends TeamsCredentials {
@@ -98,6 +104,8 @@ type TeamsEventHandler<T extends UnstampedMessageStreamEvent["type"]> = (data: E
98
104
  type TeamsSessionFailedHandler = (data: EventData<"session.failed">, channel: TeamsEventContext) => void | Promise<void>;
99
105
  /** Event handlers supported by `teamsChannel({ events })`. */
100
106
  export interface TeamsChannelEvents {
107
+ readonly "approval.candidate"?: TeamsEventHandler<"approval.candidate">;
108
+ readonly "approval.settled"?: TeamsEventHandler<"approval.settled">;
101
109
  readonly "turn.started"?: TeamsEventHandler<"turn.started">;
102
110
  readonly "actions.requested"?: TeamsEventHandler<"actions.requested">;
103
111
  readonly "action.partial"?: TeamsEventHandler<"action.partial">;
@@ -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{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,readTeamsInputReplyToActivityId,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),o=e.onMessage??defaultOnMessage,s=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),c={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,turnPolicy:e.turnPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/eve/v1/teams`,async(n,{from:i,resolveSession:a,waitUntil:c})=>{let l=await verifyInbound(n,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(c(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,from:i,onInputResponse:s}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:o,from:i,resolveSession:a})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:s,waitUntil:c,from:i}):teamsOk()})],async receive(t,{from:r}){let i=t.target,a=readNonEmptyString(i.serviceUrl),o=readNonEmptyString(i.conversationId);if(!a||!o)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let s=readNonEmptyString(i.conversationType)??null,c=readNonEmptyString(i.replyToActivityId)??null,l=i.initialMessage;if(l!==void 0&&c!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readNonEmptyString(i.channelId)??null,conversationId:o,conversationType:s,replyToActivityId:c,serviceUrl:a,teamId:readNonEmptyString(i.teamId)??null,tenantId:readNonEmptyString(i.tenantId)??null};if(l!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(l);s!==`personal`&&t.id&&(c=t.id,u.replyToActivityId=t.id)}return r(teamsContinuationToken({conversationId:o,replyToActivityId:c,tenantId:u.tenantId})).send(t.message,{auth:t.auth,state:u})},events:c})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.rekey(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildOutboundActivity(t,i),credentials:r,activityId:e,conversationId:a.conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.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,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,from:e.from})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.from(resolveInputContinuationToken(e.activity,n)).respond(t,{auth:i.auth})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{defaultDeliverResult}from"#channel/adapter.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),s=e.onMessage??defaultOnMessage,c=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),l={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,turnPolicy:e.turnPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},deliver(e,t){let r=e.state,i=r?.pendingApprovalCards;i!==void 0&&(t.state.pendingApprovalCards={...i,...t.state.pendingApprovalCards});let a=r?.approvalResponderAccounts;return a!==void 0&&(t.state.approvalResponderAccounts={...t.state.approvalResponderAccounts,...a}),defaultDeliverResult(e)},routes:[POST(e.route??`/eve/v1/teams`,async(n,{from:r,resolveSession:a,waitUntil:o})=>{let l=await verifyInbound(n,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(o(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,from:r,onInputResponse:c}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:s,from:r,resolveSession:a})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:c,waitUntil:o,from:r}):teamsOk()})],async receive(t,{from:n}){let i=t.target,a=readNonEmptyString(i.serviceUrl),o=readNonEmptyString(i.conversationId);if(!a||!o)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let s=readNonEmptyString(i.conversationType)??null,c=readNonEmptyString(i.replyToActivityId)??null,l=i.initialMessage;if(l!==void 0&&c!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readNonEmptyString(i.channelId)??null,conversationId:o,conversationType:s,replyToActivityId:c,serviceUrl:a,teamId:readNonEmptyString(i.teamId)??null,tenantId:readNonEmptyString(i.tenantId)??null};if(l!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(l);s!==`personal`&&t.id&&(c=t.id,u.replyToActivityId=t.id)}return n(teamsContinuationToken({conversationId:o,replyToActivityId:c,tenantId:u.tenantId})).send(t.message,{auth:t.auth,state:u})},events:l})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.rekey(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,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,from:e.from})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.from(resolveInputContinuationToken(e.activity,n)).respond(t,{auth:i.auth,state:approvalResponseStatePatch(e.activity,i.auth)})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function approvalResponseStatePatch(e,t){if(t?.principalId===void 0||!isTeamsToolApprovalResponseActivity(e))return;let n=deriveTeamsInputResponses(e)[0]?.requestId,r=e.replyToId;return n===void 0||r===void 0?{approvalResponderAccounts:{[t.principalId]:e.from}}:{approvalResponderAccounts:{[t.principalId]:e.from},pendingApprovalCards:{[n]:{activityId:r,prompt:readTeamsToolApprovalPrompt(e)??`Tool approval`}}}}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,approvalResponderAccounts:{},pendingApprovalCards:{},pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function 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};
@@ -5,7 +5,7 @@
5
5
  * eve stores compact callback ids in durable channel state and remaps
6
6
  * them back to full input responses inside the channel deliver hook.
7
7
  */
8
- import type { InputRequest, InputResponse } from "#runtime/input/types.js";
8
+ import { type InputRequest, type InputResponse, type ValidatedInputResponse } from "#runtime/input/types.js";
9
9
  /** Prefix used in Telegram callback_data values generated by eve. */
10
10
  export declare const TELEGRAM_HITL_CALLBACK_PREFIX = "eve:";
11
11
  /** Synthetic request id prefix sent through `send()` for callback queries. */
@@ -47,13 +47,13 @@ export declare function registerTelegramFreeformPrompt(state: TelegramHitlState,
47
47
  * placeholder; {@link resolveTelegramInputResponses} resolves it back to the real
48
48
  * stored response.
49
49
  */
50
- export declare function telegramCallbackInputResponse(callbackData: string): InputResponse;
50
+ export declare function telegramCallbackInputResponse(callbackData: string): ValidatedInputResponse;
51
51
  /** Wraps a reply-to-message id in an `InputResponse` shape for delivery. */
52
52
  export declare function telegramReplyInputResponse(input: {
53
53
  readonly messageId: string;
54
54
  readonly text: string;
55
- }): InputResponse;
55
+ }): ValidatedInputResponse;
56
56
  /** True when an input response needs Telegram-specific durable-state remapping. */
57
57
  export declare function isTelegramSyntheticResponse(response: InputResponse): boolean;
58
58
  /** Remaps compact Telegram callback/reply ids into real eve input responses. */
59
- export declare function resolveTelegramInputResponses(state: TelegramHitlState, responses: readonly InputResponse[]): InputResponse[];
59
+ export declare function resolveTelegramInputResponses(state: TelegramHitlState, responses: readonly InputResponse[]): ValidatedInputResponse[];
@@ -1 +1 @@
1
- const TELEGRAM_HITL_CALLBACK_PREFIX=`eve:`,TELEGRAM_CALLBACK_RESPONSE_PREFIX=`telegram_callback:`,TELEGRAM_REPLY_RESPONSE_PREFIX=`telegram_reply:`,TELEGRAM_PROMPT_MAX_LENGTH=4e3;function renderTelegramInputRequest(e,t){let n=e.options;return n&&n.length>0?{replyMarkup:{inline_keyboard:chunk(n.map(n=>({callback_data:registerTelegramCallback(t,{optionId:n.id,requestId:e.requestId}),text:truncate(n.label,64)})),2)},text:truncate(e.prompt,TELEGRAM_PROMPT_MAX_LENGTH)}:{freeformRequestId:e.requestId,replyMarkup:{force_reply:!0,input_field_placeholder:truncate(`Type your answer`,64),selective:!0},text:truncate(e.prompt,TELEGRAM_PROMPT_MAX_LENGTH)}}function registerTelegramFreeformPrompt(e,t){e.pendingFreeformReplies={...e.pendingFreeformReplies,[t.messageId]:t.requestId}}function telegramCallbackInputResponse(e){return{optionId:`selected`,requestId:`${TELEGRAM_CALLBACK_RESPONSE_PREFIX}${e}`}}function telegramReplyInputResponse(e){return{requestId:`${TELEGRAM_REPLY_RESPONSE_PREFIX}${e.messageId}`,text:e.text}}function isTelegramSyntheticResponse(e){return e.requestId.startsWith(`telegram_callback:`)||e.requestId.startsWith(`telegram_reply:`)}function resolveTelegramInputResponses(e,t){let n=[];for(let r of t){if(r.requestId.startsWith(`telegram_callback:`)){let t=r.requestId.slice(18),i=e.hitlCallbacks?.[t];i!==void 0&&(n.push(i),delete e.hitlCallbacks?.[t]);continue}if(r.requestId.startsWith(`telegram_reply:`)){let t=r.requestId.slice(15),i=e.pendingFreeformReplies?.[t];i!==void 0&&r.text!==void 0&&(n.push({requestId:i,text:r.text}),delete e.pendingFreeformReplies?.[t]);continue}n.push(r)}return n}function registerTelegramCallback(t,n){let r=t.nextHitlCallbackId??0;t.nextHitlCallbackId=r+1;let i=`${TELEGRAM_HITL_CALLBACK_PREFIX}${r.toString(36)}`;return t.hitlCallbacks={...t.hitlCallbacks,[i]:n},i}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function chunk(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}export{TELEGRAM_CALLBACK_RESPONSE_PREFIX,TELEGRAM_HITL_CALLBACK_PREFIX,TELEGRAM_REPLY_RESPONSE_PREFIX,isTelegramSyntheticResponse,registerTelegramFreeformPrompt,renderTelegramInputRequest,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponse};
1
+ import{parseInputResponse,parseInputResponses}from"#runtime/input/types.js";const TELEGRAM_HITL_CALLBACK_PREFIX=`eve:`,TELEGRAM_CALLBACK_RESPONSE_PREFIX=`telegram_callback:`,TELEGRAM_REPLY_RESPONSE_PREFIX=`telegram_reply:`,TELEGRAM_PROMPT_MAX_LENGTH=4e3;function renderTelegramInputRequest(e,t){let n=e.options;return n&&n.length>0?{replyMarkup:{inline_keyboard:chunk(n.map(n=>({callback_data:registerTelegramCallback(t,{optionId:n.id,requestId:e.requestId}),text:truncate(n.label,64)})),2)},text:truncate(e.prompt,TELEGRAM_PROMPT_MAX_LENGTH)}:{freeformRequestId:e.requestId,replyMarkup:{force_reply:!0,input_field_placeholder:truncate(`Type your answer`,64),selective:!0},text:truncate(e.prompt,TELEGRAM_PROMPT_MAX_LENGTH)}}function registerTelegramFreeformPrompt(e,t){e.pendingFreeformReplies={...e.pendingFreeformReplies,[t.messageId]:t.requestId}}function telegramCallbackInputResponse(t){return parseInputResponse({optionId:`selected`,requestId:`${TELEGRAM_CALLBACK_RESPONSE_PREFIX}${t}`})}function telegramReplyInputResponse(t){return parseInputResponse({requestId:`${TELEGRAM_REPLY_RESPONSE_PREFIX}${t.messageId}`,text:t.text})}function isTelegramSyntheticResponse(e){return e.requestId.startsWith(`telegram_callback:`)||e.requestId.startsWith(`telegram_reply:`)}function resolveTelegramInputResponses(e,n){let r=[];for(let t of n){if(t.requestId.startsWith(`telegram_callback:`)){let n=t.requestId.slice(18),i=e.hitlCallbacks?.[n];i!==void 0&&(r.push(i),delete e.hitlCallbacks?.[n]);continue}if(t.requestId.startsWith(`telegram_reply:`)){let n=t.requestId.slice(15),i=e.pendingFreeformReplies?.[n];i!==void 0&&t.text!==void 0&&(r.push({requestId:i,text:t.text}),delete e.pendingFreeformReplies?.[n]);continue}r.push(t)}return[...parseInputResponses(r)]}function registerTelegramCallback(e,t){let r=e.nextHitlCallbackId??0;e.nextHitlCallbackId=r+1;let i=`${TELEGRAM_HITL_CALLBACK_PREFIX}${r.toString(36)}`;return e.hitlCallbacks={...e.hitlCallbacks,[i]:t},i}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}function chunk(e,t){let n=[];for(let r=0;r<e.length;r+=t)n.push(e.slice(r,r+t));return n}export{TELEGRAM_CALLBACK_RESPONSE_PREFIX,TELEGRAM_HITL_CALLBACK_PREFIX,TELEGRAM_REPLY_RESPONSE_PREFIX,isTelegramSyntheticResponse,registerTelegramFreeformPrompt,renderTelegramInputRequest,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponse};
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{inputRequestSchema}from"#runtime/input/types.js";const ASK_QUESTION_TOOL_NAME=`ask_question`,ASK_QUESTION_INPUT_SCHEMA=inputRequestSchema.omit({action:!0,display:!0,kind:!0,requestId:!0}),ASK_QUESTION_OUTPUT_SCHEMA=z.object({optionId:z.string().optional(),status:z.enum([`answered`,`ignored`]),text:z.string().optional()}).strict(),ASK_QUESTION_TOOL_DEFINITION={description:`Ask the user a question and wait for their response before continuing. Use this when you need clarification or a choice from the user.`,inputSchema:ASK_QUESTION_INPUT_SCHEMA,logicalPath:`eve:framework/ask-question`,name:ASK_QUESTION_TOOL_NAME,outputSchema:ASK_QUESTION_OUTPUT_SCHEMA,sourceId:`eve:ask-question-tool`,sourceKind:`module`};export{ASK_QUESTION_INPUT_SCHEMA,ASK_QUESTION_OUTPUT_SCHEMA,ASK_QUESTION_TOOL_DEFINITION,ASK_QUESTION_TOOL_NAME};
1
+ import{inputRequestSchema}from"#runtime/input/types.js";import{z}from"#compiled/zod/index.js";const ASK_QUESTION_TOOL_NAME=`ask_question`,ASK_QUESTION_INPUT_SCHEMA=inputRequestSchema.omit({action:!0,display:!0,kind:!0,requestId:!0}),ASK_QUESTION_OUTPUT_SCHEMA=z.object({optionId:z.string().optional(),status:z.enum([`answered`,`ignored`]),text:z.string().optional()}).strict(),ASK_QUESTION_TOOL_DEFINITION={description:`Ask the user a question and wait for their response before continuing. Use this when you need clarification or a choice from the user.`,inputSchema:ASK_QUESTION_INPUT_SCHEMA,logicalPath:`eve:framework/ask-question`,name:ASK_QUESTION_TOOL_NAME,outputSchema:ASK_QUESTION_OUTPUT_SCHEMA,sourceId:`eve:ask-question-tool`,sourceKind:`module`};export{ASK_QUESTION_INPUT_SCHEMA,ASK_QUESTION_OUTPUT_SCHEMA,ASK_QUESTION_TOOL_DEFINITION,ASK_QUESTION_TOOL_NAME};
@@ -6,13 +6,11 @@ import type { ResolvedToolDefinition } from "#runtime/types.js";
6
6
  *
7
7
  * With the flag on, subagent calls return a task receipt instead of
8
8
  * blocking the parent turn; these tools coordinate that delegated work.
9
- * `task_cancel` and `task_update` are
10
- * execute-less runtime actions — they need durable session state and
11
- * world access, so the runtime-action dispatch step executes them.
12
- * `task_sleep` only records a durable pause and executes in-loop.
9
+ * `task_cancel` and `task_update` are execute-less runtime actions —
10
+ * they need durable session state and world access, so the runtime-action
11
+ * dispatch step executes them.
13
12
  */
14
13
  export declare const TASK_CANCEL_TOOL_NAME = "task_cancel";
15
- export declare const TASK_SLEEP_TOOL_NAME = "task_sleep";
16
14
  export declare const TASK_UPDATE_TOOL_NAME = "task_update";
17
15
  /** Every model-visible task tool name, for gating and dispatch matching. */
18
16
  export declare const TASK_TOOL_NAMES: ReadonlySet<string>;
@@ -24,9 +22,6 @@ export declare const TASK_CANCEL_INPUT_SCHEMA: z.ZodObject<{
24
22
  export declare const TASK_UPDATE_INPUT_SCHEMA: z.ZodObject<{
25
23
  message: z.ZodString;
26
24
  }, z.core.$strict>;
27
- export declare const TASK_SLEEP_INPUT_SCHEMA: z.ZodObject<{
28
- seconds: z.ZodNumber;
29
- }, z.core.$strict>;
30
25
  export declare const TASK_VIEWS_OUTPUT_SCHEMA: z.ZodObject<{
31
26
  tasks: z.ZodArray<z.ZodObject<{
32
27
  inputRequests: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
@@ -56,9 +51,6 @@ export declare const TASK_VIEWS_OUTPUT_SCHEMA: z.ZodObject<{
56
51
  taskId: z.ZodString;
57
52
  }, z.core.$strip>>;
58
53
  }, z.core.$strip>;
59
- export declare const TASK_SLEEP_OUTPUT_SCHEMA: z.ZodObject<{
60
- waitedSeconds: z.ZodNumber;
61
- }, z.core.$strict>;
62
54
  /**
63
55
  * Builds the harness definitions injected when the root agent enables
64
56
  * `experimental.tasks`. Follows the implicit `agent` tool pattern:
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{requestTurnSleep}from"#harness/turn-sleep.js";const TASK_CANCEL_TOOL_NAME=`task_cancel`,TASK_SLEEP_TOOL_NAME=`task_sleep`,TASK_UPDATE_TOOL_NAME=`task_update`,TASK_TOOL_NAMES=new Set([TASK_CANCEL_TOOL_NAME,TASK_SLEEP_TOOL_NAME,TASK_UPDATE_TOOL_NAME]),TASK_CONTROL_TOOL_NAMES=new Set([TASK_CANCEL_TOOL_NAME,TASK_UPDATE_TOOL_NAME]),TASK_IDS_SCHEMA=z.array(z.string().min(1)).min(1).describe(`Task ids from earlier subagent task receipts.`),TASK_CANCEL_INPUT_SCHEMA=z.strictObject({taskIds:TASK_IDS_SCHEMA}),TASK_UPDATE_INPUT_SCHEMA=z.strictObject({message:z.string().min(1).describe(`Brief description of what this task is currently doing.`)}),MAX_SLEEP_SECONDS=Math.floor((2**53-1)/1e3),TASK_SLEEP_INPUT_SCHEMA=z.strictObject({seconds:z.number().positive().max(MAX_SLEEP_SECONDS).describe(`How long to wait, in seconds.`)}),TASK_VIEW_SCHEMA=z.object({inputRequests:z.array(z.unknown()).optional(),lastOutput:z.object({data:z.unknown(),type:z.enum([`result`,`error`])}).optional(),metadata:z.object({agentId:z.string(),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string()}),status:z.enum([`working`,`input_required`,`completed`,`failed`,`cancelled`]),taskId:z.string()}),TASK_VIEWS_OUTPUT_SCHEMA=z.object({tasks:z.array(TASK_VIEW_SCHEMA)}),TASK_SLEEP_OUTPUT_SCHEMA=z.strictObject({waitedSeconds:z.number().positive()}),TASK_CANCEL_DESCRIPTION=`Request cooperative cancellation of one or more background tasks. Cancellation is final: a task that finishes after you cancel it stays cancelled. Cancelling an already-finished task changes nothing.`,TASK_SLEEP_DESCRIPTION=`Pause durably before continuing while waiting for a background-task notification. Does not read or change any task.`,TASK_UPDATE_DESCRIPTION=`Briefly tell the parent agent what this background task is currently doing. Report activity, not preliminary findings or results.`;function createTaskToolHarnessDefinitions(){return[{description:TASK_CANCEL_DESCRIPTION,inputSchema:TASK_CANCEL_INPUT_SCHEMA,name:TASK_CANCEL_TOOL_NAME,outputSchema:TASK_VIEWS_OUTPUT_SCHEMA,runtimeAction:{kind:`task-control`}},{description:TASK_SLEEP_DESCRIPTION,execute:async e=>(requestTurnSleep(Math.ceil(e.seconds*1e3)),{waitedSeconds:e.seconds}),inputSchema:TASK_SLEEP_INPUT_SCHEMA,name:TASK_SLEEP_TOOL_NAME,outputSchema:TASK_SLEEP_OUTPUT_SCHEMA},{description:TASK_UPDATE_DESCRIPTION,inputSchema:TASK_UPDATE_INPUT_SCHEMA,name:TASK_UPDATE_TOOL_NAME,runtimeAction:{kind:`task-control`}}]}function isTaskToolAvailable(e){return e.tasksEnabled&&!e.disabledFrameworkTools.includes(e.toolName)&&!e.hasAuthoredTool}function createResolvedTaskToolStub(e){return{description:e.description,inputSchema:null,logicalPath:`eve:framework/${e.name}`,name:e.name,sourceId:`eve:${e.name}-tool`,sourceKind:`module`}}const TASK_TOOL_DEFINITIONS=[createResolvedTaskToolStub({description:TASK_CANCEL_DESCRIPTION,name:TASK_CANCEL_TOOL_NAME}),createResolvedTaskToolStub({description:TASK_SLEEP_DESCRIPTION,name:TASK_SLEEP_TOOL_NAME}),createResolvedTaskToolStub({description:TASK_UPDATE_DESCRIPTION,name:TASK_UPDATE_TOOL_NAME})];export{TASK_CANCEL_INPUT_SCHEMA,TASK_CANCEL_TOOL_NAME,TASK_CONTROL_TOOL_NAMES,TASK_SLEEP_INPUT_SCHEMA,TASK_SLEEP_OUTPUT_SCHEMA,TASK_SLEEP_TOOL_NAME,TASK_TOOL_DEFINITIONS,TASK_TOOL_NAMES,TASK_UPDATE_INPUT_SCHEMA,TASK_UPDATE_TOOL_NAME,TASK_VIEWS_OUTPUT_SCHEMA,createTaskToolHarnessDefinitions,isTaskToolAvailable};
1
+ import{z}from"#compiled/zod/index.js";const TASK_CANCEL_TOOL_NAME=`task_cancel`,TASK_UPDATE_TOOL_NAME=`task_update`,TASK_TOOL_NAMES=new Set([TASK_CANCEL_TOOL_NAME,TASK_UPDATE_TOOL_NAME]),TASK_CONTROL_TOOL_NAMES=new Set([TASK_CANCEL_TOOL_NAME,TASK_UPDATE_TOOL_NAME]),TASK_IDS_SCHEMA=z.array(z.string().min(1)).min(1).describe(`Task ids from earlier subagent task receipts.`),TASK_CANCEL_INPUT_SCHEMA=z.strictObject({taskIds:TASK_IDS_SCHEMA}),TASK_UPDATE_INPUT_SCHEMA=z.strictObject({message:z.string().min(1).describe(`Brief description of what this task is currently doing.`)}),TASK_VIEW_SCHEMA=z.object({inputRequests:z.array(z.unknown()).optional(),lastOutput:z.object({data:z.unknown(),type:z.enum([`result`,`error`])}).optional(),metadata:z.object({agentId:z.string(),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string()}),status:z.enum([`working`,`input_required`,`completed`,`failed`,`cancelled`]),taskId:z.string()}),TASK_VIEWS_OUTPUT_SCHEMA=z.object({tasks:z.array(TASK_VIEW_SCHEMA)}),TASK_CANCEL_DESCRIPTION=`Request cooperative cancellation of one or more background tasks. Cancellation is final: a task that finishes after you cancel it stays cancelled. Cancelling an already-finished task changes nothing.`,TASK_UPDATE_DESCRIPTION=`Briefly tell the parent agent what this background task is currently doing. Report activity, not preliminary findings or results.`;function createTaskToolHarnessDefinitions(){return[{description:TASK_CANCEL_DESCRIPTION,inputSchema:TASK_CANCEL_INPUT_SCHEMA,name:TASK_CANCEL_TOOL_NAME,outputSchema:TASK_VIEWS_OUTPUT_SCHEMA,runtimeAction:{kind:`task-control`}},{description:TASK_UPDATE_DESCRIPTION,inputSchema:TASK_UPDATE_INPUT_SCHEMA,name:TASK_UPDATE_TOOL_NAME,runtimeAction:{kind:`task-control`}}]}function isTaskToolAvailable(e){return e.tasksEnabled&&!e.disabledFrameworkTools.includes(e.toolName)&&!e.hasAuthoredTool}function createResolvedTaskToolStub(e){return{description:e.description,inputSchema:null,logicalPath:`eve:framework/${e.name}`,name:e.name,sourceId:`eve:${e.name}-tool`,sourceKind:`module`}}const TASK_TOOL_DEFINITIONS=[createResolvedTaskToolStub({description:TASK_CANCEL_DESCRIPTION,name:TASK_CANCEL_TOOL_NAME}),createResolvedTaskToolStub({description:TASK_UPDATE_DESCRIPTION,name:TASK_UPDATE_TOOL_NAME})];export{TASK_CANCEL_INPUT_SCHEMA,TASK_CANCEL_TOOL_NAME,TASK_CONTROL_TOOL_NAMES,TASK_TOOL_DEFINITIONS,TASK_TOOL_NAMES,TASK_UPDATE_INPUT_SCHEMA,TASK_UPDATE_TOOL_NAME,TASK_VIEWS_OUTPUT_SCHEMA,createTaskToolHarnessDefinitions,isTaskToolAvailable};
@@ -72,6 +72,11 @@ export declare const inputRequestSchema: z.ZodObject<{
72
72
  * Unified input response submitted by the client for a pending request.
73
73
  */
74
74
  export type InputResponse = z.infer<typeof inputResponseSchema>;
75
+ declare const validatedInputResponseBrand: unique symbol;
76
+ /** Input response proven to match the strict durable wire schema. */
77
+ export type ValidatedInputResponse = InputResponse & {
78
+ readonly [validatedInputResponseBrand]: true;
79
+ };
75
80
  /**
76
81
  * Zod schema for one input response.
77
82
  */
@@ -80,6 +85,18 @@ export declare const inputResponseSchema: z.ZodObject<{
80
85
  requestId: z.ZodString;
81
86
  text: z.ZodOptional<z.ZodString>;
82
87
  }, z.core.$strict>;
88
+ /** Parses one response and preserves schema validation in its static type. */
89
+ export declare function parseInputResponse(value: unknown): ValidatedInputResponse;
90
+ /** Parses response arrays whose element types were widened before delivery. */
91
+ export declare function parseInputResponses(value: unknown): readonly ValidatedInputResponse[];
92
+ type IsWidenedInputResponse<TResponse extends InputResponse> = keyof TResponse extends keyof InputResponse ? keyof InputResponse extends keyof TResponse ? InputResponse extends TResponse ? true : false : false : false;
93
+ type StrictInputResponse<TResponse extends InputResponse> = TResponse extends ValidatedInputResponse ? TResponse : IsWidenedInputResponse<TResponse> extends true ? never : TResponse & {
94
+ readonly [TKey in Exclude<keyof TResponse, keyof InputResponse>]: never;
95
+ };
96
+ /** Rejects extra response keys and imprecise arrays not proven by the strict schema. */
97
+ export type StrictInputResponses<TResponses extends readonly InputResponse[]> = TResponses & {
98
+ readonly [TIndex in keyof TResponses]: TResponses[TIndex] extends InputResponse ? StrictInputResponse<TResponses[TIndex]> : TResponses[TIndex];
99
+ };
83
100
  /**
84
101
  * Returns true when a value matches the input request contract.
85
102
  */
@@ -87,4 +104,5 @@ export declare function isInputRequest(value: unknown): value is InputRequest;
87
104
  /**
88
105
  * Returns true when a value matches the input response contract.
89
106
  */
90
- export declare function isInputResponse(value: unknown): value is InputResponse;
107
+ export declare function isInputResponse(value: unknown): value is ValidatedInputResponse;
108
+ export {};
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{runtimeToolCallActionRequestSchema}from"#runtime/actions/types.js";const inputOptionSchema=z.object({description:z.string().describe(`Optional additional context for this option.`).optional(),id:z.string().describe(`Stable identifier for the option.`),label:z.string().describe(`User-facing label for the option.`),style:z.enum([`primary`,`danger`,`default`]).describe(`Visual treatment hint for the option.`).optional()}).strict(),inputRequestKindSchema=z.enum([`question`,`session-limit`,`tool-approval`]),inputRequestSchema=z.object({action:runtimeToolCallActionRequestSchema,allowFreeform:z.boolean().describe(`Whether the user may answer with freeform text instead of selecting one of the provided options.`).optional(),display:z.enum([`confirmation`,`select`,`text`]).describe(`Rendering hint: the channel uses this to pick a UX treatment.`).optional(),kind:inputRequestKindSchema.describe(`Framework-owned request source used to resolve, route, and render the response.`),options:z.array(inputOptionSchema).describe(`Selectable answer options to present to the user.`).optional(),prompt:z.string().describe(`The prompt to present to the user.`),requestId:z.string().describe(`Stable identifier for this request.`)}).strict(),inputResponseSchema=z.object({optionId:z.string().optional(),requestId:z.string(),text:z.string().optional()}).strict();function isInputRequest(e){return inputRequestSchema.safeParse(e).success}function isInputResponse(e){return inputResponseSchema.safeParse(e).success}export{inputOptionSchema,inputRequestKindSchema,inputRequestSchema,inputResponseSchema,isInputRequest,isInputResponse};
1
+ import{z}from"#compiled/zod/index.js";import{runtimeToolCallActionRequestSchema}from"#runtime/actions/types.js";const inputOptionSchema=z.object({description:z.string().describe(`Optional additional context for this option.`).optional(),id:z.string().describe(`Stable identifier for the option.`),label:z.string().describe(`User-facing label for the option.`),style:z.enum([`primary`,`danger`,`default`]).describe(`Visual treatment hint for the option.`).optional()}).strict(),inputRequestKindSchema=z.enum([`question`,`session-limit`,`tool-approval`]),inputRequestSchema=z.object({action:runtimeToolCallActionRequestSchema,allowFreeform:z.boolean().describe(`Whether the user may answer with freeform text instead of selecting one of the provided options.`).optional(),display:z.enum([`confirmation`,`select`,`text`]).describe(`Rendering hint: the channel uses this to pick a UX treatment.`).optional(),kind:inputRequestKindSchema.describe(`Framework-owned request source used to resolve, route, and render the response.`),options:z.array(inputOptionSchema).describe(`Selectable answer options to present to the user.`).optional(),prompt:z.string().describe(`The prompt to present to the user.`),requestId:z.string().describe(`Stable identifier for this request.`)}).strict(),inputResponseSchema=z.object({optionId:z.string().optional(),requestId:z.string(),text:z.string().optional()}).strict();function parseInputResponse(e){return inputResponseSchema.parse(e)}function parseInputResponses(e){return inputResponseSchema.array().parse(e).map(e=>e)}function isInputRequest(e){return inputRequestSchema.safeParse(e).success}function isInputResponse(e){return inputResponseSchema.safeParse(e).success}export{inputOptionSchema,inputRequestKindSchema,inputRequestSchema,inputResponseSchema,isInputRequest,isInputResponse,parseInputResponse,parseInputResponses};
@@ -1,4 +1,4 @@
1
1
  import{formatAvailableSkillsSection}from"#execution/skills/instructions.js";import{createWorkspacePromptSection}from"#runtime/workspace/spec.js";import{formatConnectionsSection}from"#runtime/prompt/connections.js";function composeRuntimeBasePrompt(e){return[...createInstructionsPromptBlocks(e.instructions),...createWorkspacePromptBlocks(e.workspaceSpec),...e.toolsAvailable?[`Tool execution
2
- A single tool or subagent call runs as one serial action. If you call multiple independent tools or subagents in one response, eve treats that batch as parallel work. Only batch work that is independent and does not rely on another call in the same response.`]:[],...e.subagentsAvailable&&e.persistentSubagentSessions?[e.tasksEnabled?"Agent messaging\nSubagent calls start durable background tasks and return immediately with a task receipt. After delegating, continue helping the user or end your turn; do not wait with task_sleep unless the user explicitly asks you to wait or the task result is required before you can answer. The task will notify you when it completes, fails, needs input, or sends an update; completion and failure notifications include the task's result. Agents you have already delegated to remain visible in the framework-authored `<agents>` conversation note. `availability=busy` means the listed task still owns that agent session: wait for its notification or use task_cancel with its taskId instead of starting a continuation. `availability=available` means no nonterminal task owns the session, so you may pass agentId to the original subagent tool to continue it. Calling a subagent without agentId always starts a new agent session.":"Agent messaging\nAgents you have already delegated to stay available after they answer. eve injects the current `<agents>` list into the conversation as a note labeled `[Agents]`; it is added automatically by the framework, not written by the user, and never requires a reply. The list is only a record of those existing agents — their `agentId`, name, and latest status. It does not limit which subagent tools you can call: your tool list is the source of truth, and any subagent tool can always be called without `agentId` to start a new agent, including when the `<agents>` list is empty or absent. Pass `agentId` to the same subagent tool only to continue one of those existing agents' sessions."]:[],...createConnectionsPromptBlocks(e.connections),...createSkillsPromptBlocks(e.skills)]}function createInstructionsPromptBlocks(e){let t=(e??[]).filter(e=>e.role===`system`&&e.content.trim().length>0);if(t.length===0)return[];let n=t.length===1?t[0]:void 0;return[`Instructions (${n!==void 0&&!n.sourceId.startsWith(`ext:`)&&!n.sourceId.startsWith(`ext-override:`)?n.name:`instructions`})\n${t.map(e=>e.content).join(`
2
+ A single tool or subagent call runs as one serial action. If you call multiple independent tools or subagents in one response, eve treats that batch as parallel work. Only batch work that is independent and does not rely on another call in the same response.`]:[],...e.subagentsAvailable&&e.persistentSubagentSessions?[e.tasksEnabled?"Agent messaging\nSubagent calls start durable background tasks and return immediately with a task receipt. After delegating, continue helping the user or end your turn. The task will notify you when it completes, fails, needs input, or sends an update; completion and failure notifications include the task's result. Agents you have already delegated to remain visible in the framework-authored `<agents>` conversation note. `availability=busy` means the listed task still owns that agent session: wait for its notification or use task_cancel with its taskId instead of starting a continuation. `availability=available` means no nonterminal task owns the session, so you may pass agentId to the original subagent tool to continue it. Calling a subagent without agentId always starts a new agent session.":"Agent messaging\nAgents you have already delegated to stay available after they answer. eve injects the current `<agents>` list into the conversation as a note labeled `[Agents]`; it is added automatically by the framework, not written by the user, and never requires a reply. The list is only a record of those existing agents — their `agentId`, name, and latest status. It does not limit which subagent tools you can call: your tool list is the source of truth, and any subagent tool can always be called without `agentId` to start a new agent, including when the `<agents>` list is empty or absent. Pass `agentId` to the same subagent tool only to continue one of those existing agents' sessions."]:[],...createConnectionsPromptBlocks(e.connections),...createSkillsPromptBlocks(e.skills)]}function createInstructionsPromptBlocks(e){let t=(e??[]).filter(e=>e.role===`system`&&e.content.trim().length>0);if(t.length===0)return[];let n=t.length===1?t[0]:void 0;return[`Instructions (${n!==void 0&&!n.sourceId.startsWith(`ext:`)&&!n.sourceId.startsWith(`ext-override:`)?n.name:`instructions`})\n${t.map(e=>e.content).join(`
3
3
 
4
4
  `).trim()}`]}function createWorkspacePromptBlocks(e){if(e===void 0)return[];let n=createWorkspacePromptSection(e);return n===void 0?[]:[n]}function createConnectionsPromptBlocks(e){return!e||e.length===0?[]:[formatConnectionsSection(e)]}function createSkillsPromptBlocks(t){if(!t||t.length===0)return[];let n=formatAvailableSkillsSection(t);return n===null?[]:[n]}export{composeRuntimeBasePrompt};
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{isInputRequest}from"#runtime/input/types.js";import{jsonValueSchema}from"#shared/json-schemas.js";import{REMOTE_AGENT_FAILED}from"#harness/agent-handle-errors.js";import{readTaskIdFromInboxToken}from"#tasks/task-id.js";import{resumeHook}from"#internal/workflow/runtime.js";import{tokenUsageSchema}from"#shared/token-usage.js";import{agentTurnOutcomeSchema}from"#shared/agent-turn-outcome.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`],ZERO_TOKEN_USAGE={cacheReadTokens:0,cacheWriteTokens:0,inputTokens:0,outputTokens:0},eventCoordinateSchema=z.number().int().nonnegative(),authorizationChallengeSchema=z.looseObject({displayName:z.string().optional(),expiresAt:z.string().optional(),instructions:z.string().optional(),url:z.string().optional(),userCode:z.string().optional()}),taskInputEventSchema=z.looseObject({requests:z.array(jsonValueSchema.refine(isInputRequest)).min(1),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string()}),taskAuthorizationEventSchema=z.discriminatedUnion(`type`,[z.looseObject({data:z.looseObject({attemptId:z.string().optional(),authorization:authorizationChallengeSchema.optional(),description:z.string(),name:z.string(),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string(),webhookUrl:z.string().optional()}),type:z.literal(`authorization.required`)}),z.looseObject({data:z.looseObject({attemptId:z.string().optional(),authorization:authorizationChallengeSchema.optional(),name:z.string(),outcome:z.enum([`authorized`,`declined`,`failed`,`timed-out`]),reason:z.string().optional(),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string()}),type:z.literal(`authorization.completed`)})]),taskEventCallbackSchema=z.discriminatedUnion(`kind`,[z.object({callId:z.string(),childContinuationToken:z.string(),childSessionId:z.string(),event:taskInputEventSchema,kind:z.literal(`task.input-requested`),subagentName:z.string(),taskId:z.string()}),z.object({callId:z.string(),childContinuationToken:z.string(),childSessionId:z.string(),event:taskAuthorizationEventSchema,kind:z.literal(`task.authorization`),subagentName:z.string(),taskId:z.string()})]),taskTurnStartedCallbackSchema=z.object({kind:z.literal(`turn.started`),sessionId:z.string().min(1),taskId:z.string().min(1),turnId:z.string().min(1)}),taskUpdateCallbackSchema=z.object({callId:z.string().min(1),childStepIndex:eventCoordinateSchema,childTurnId:z.string().min(1),kind:z.literal(`task.update`),message:z.string().min(1),taskId:z.string().min(1)}),sessionResultCallbackSchema=z.discriminatedUnion(`kind`,[z.object({callId:z.string().min(1),kind:z.literal(`session.completed`),output:jsonValueSchema.optional(),subagentName:z.string().min(1),usage:z.unknown().optional()}),z.object({callId:z.string().min(1),error:jsonValueSchema.optional(),kind:z.literal(`session.failed`),subagentName:z.string().min(1),usage:z.unknown().optional()}),z.object({callId:z.string().min(1),kind:z.literal(`turn.completed`),outcome:agentTurnOutcomeSchema,output:jsonValueSchema.optional(),subagentName:z.string().min(1)}),z.object({callId:z.string().min(1),error:jsonValueSchema,kind:z.literal(`turn.failed`),outcome:agentTurnOutcomeSchema,subagentName:z.string().min(1)})]);function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(e){let n=channelNameForMethod(e);return{name:n,method:e,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${n}`,sourceId:`eve:framework:session-callback-${e.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,t){let n=t.params.token;if(typeof n!=`string`||n.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let r;try{r=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let i=projectTaskEvent(r,n);if(i instanceof Response)return i;if(i!==void 0){try{await resumeHook(n,i)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let a=projectTaskUpdate(r,n);if(a instanceof Response)return a;if(a!==void 0){try{await resumeHook(n,a)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let o=projectTaskTurnStarted(r,n);if(o instanceof Response)return o;if(o!==void 0){try{await resumeHook(n,o)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let s=projectSessionCallbackResult(r);if(s instanceof Response)return s;try{await resumeHook(n,{kind:`runtime-action-result`,results:[s]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function callbackKind(e){if(!(typeof e!=`object`||!e))return Reflect.get(e,`kind`)}function projectTaskEvent(e,t){let n=callbackKind(e);if(n!==`task.input-requested`&&n!==`task.authorization`)return;let r=taskEventCallbackSchema.safeParse(e);if(!r.success)return Response.json({error:`Invalid task event callback.`,ok:!1},{status:400});let i=r.data,a=rejectMismatchedTaskToken(t,i.taskId);return a===void 0?i.kind===`task.input-requested`?{callId:i.callId,childContinuationToken:i.childContinuationToken,childSessionId:i.childSessionId,event:i.event,kind:`subagent-input-request`,subagentName:i.subagentName}:{callId:i.callId,childSessionId:i.childSessionId,event:i.event,kind:`authorization-event`,subagentName:i.subagentName}:a}function projectTaskTurnStarted(e,t){if(callbackKind(e)!==`turn.started`)return;let n=taskTurnStartedCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid task turn-start callback.`,ok:!1},{status:400});let r=rejectMismatchedTaskToken(t,n.data.taskId);return r===void 0?{childSessionId:n.data.sessionId,childTurnId:n.data.turnId,kind:`turn-started`,taskId:n.data.taskId}:r}function projectTaskUpdate(e,t){if(callbackKind(e)!==`task.update`)return;let n=taskUpdateCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid task update callback.`,ok:!1},{status:400});let r=rejectMismatchedTaskToken(t,n.data.taskId);return r===void 0?{callId:n.data.callId,childStepIndex:n.data.childStepIndex,childTurnId:n.data.childTurnId,kind:`task-update`,message:n.data.message}:r}function rejectMismatchedTaskToken(e,t){return readTaskIdFromInboxToken(e)===t?void 0:Response.json({error:`Task callback token mismatch.`,ok:!1},{status:403})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=callbackKind(e);if(t!==`session.completed`&&t!==`session.failed`&&t!==`turn.completed`&&t!==`turn.failed`)return Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400});let n=sessionResultCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid session result callback.`,ok:!1},{status:400});let r=n.data;if(r.kind===`session.completed`){let e=r.output??``,t=parseCallbackUsage(r.usage),n={callId:r.callId,kind:`subagent-result`,origin:`child`,outcome:{kind:`terminal`,result:{kind:`succeeded`,output:e},usageDelta:t??ZERO_TOKEN_USAGE},output:e,subagentName:r.subagentName};return t===void 0?n:{...n,usage:t}}if(r.kind===`session.failed`){let e=r.error===void 0?{code:REMOTE_AGENT_FAILED,message:`Remote agent failed.`}:r.error,t=parseCallbackUsage(r.usage);return{callId:r.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:`terminal`,result:{error:e,kind:`failed`},usageDelta:t??ZERO_TOKEN_USAGE},output:e,subagentName:r.subagentName}}return r.kind===`turn.completed`?{callId:r.callId,kind:`subagent-result`,origin:`child`,outcome:r.outcome,output:r.output??``,subagentName:r.subagentName,usage:r.outcome.usageDelta}:{callId:r.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:r.outcome,output:r.error,subagentName:r.subagentName}}function parseCallbackUsage(e){if(e===void 0)return;let t=tokenUsageSchema.safeParse(e);return t.success?t.data:void 0}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
1
+ import{isInputRequest}from"#runtime/input/types.js";import{z}from"#compiled/zod/index.js";import{EVE_CALLBACK_ROUTE_PATTERN}from"#protocol/routes.js";import{jsonValueSchema}from"#shared/json-schemas.js";import{REMOTE_AGENT_FAILED}from"#harness/agent-handle-errors.js";import{readTaskIdFromInboxToken}from"#tasks/task-id.js";import{resumeHook}from"#internal/workflow/runtime.js";import{tokenUsageSchema}from"#shared/token-usage.js";import{agentTurnOutcomeSchema}from"#shared/agent-turn-outcome.js";const HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX=`eve/v1/callback`,HANDLED_METHODS=[`POST`],ZERO_TOKEN_USAGE={cacheReadTokens:0,cacheWriteTokens:0,inputTokens:0,outputTokens:0},eventCoordinateSchema=z.number().int().nonnegative(),authorizationChallengeSchema=z.looseObject({displayName:z.string().optional(),expiresAt:z.string().optional(),instructions:z.string().optional(),url:z.string().optional(),userCode:z.string().optional()}),taskInputEventSchema=z.looseObject({requests:z.array(jsonValueSchema.refine(isInputRequest)).min(1),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string()}),taskAuthorizationEventSchema=z.discriminatedUnion(`type`,[z.looseObject({data:z.looseObject({attemptId:z.string().optional(),authorization:authorizationChallengeSchema.optional(),description:z.string(),name:z.string(),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string(),webhookUrl:z.string().optional()}),type:z.literal(`authorization.required`)}),z.looseObject({data:z.looseObject({attemptId:z.string().optional(),authorization:authorizationChallengeSchema.optional(),name:z.string(),outcome:z.enum([`authorized`,`declined`,`failed`,`timed-out`]),reason:z.string().optional(),sequence:eventCoordinateSchema,stepIndex:eventCoordinateSchema,turnId:z.string()}),type:z.literal(`authorization.completed`)})]),taskEventCallbackSchema=z.discriminatedUnion(`kind`,[z.object({callId:z.string(),childContinuationToken:z.string(),childSessionId:z.string(),event:taskInputEventSchema,kind:z.literal(`task.input-requested`),subagentName:z.string(),taskId:z.string()}),z.object({callId:z.string(),childContinuationToken:z.string(),childSessionId:z.string(),event:taskAuthorizationEventSchema,kind:z.literal(`task.authorization`),subagentName:z.string(),taskId:z.string()})]),taskTurnStartedCallbackSchema=z.object({kind:z.literal(`turn.started`),sessionId:z.string().min(1),taskId:z.string().min(1),turnId:z.string().min(1)}),taskUpdateCallbackSchema=z.object({callId:z.string().min(1),childStepIndex:eventCoordinateSchema,childTurnId:z.string().min(1),kind:z.literal(`task.update`),message:z.string().min(1),taskId:z.string().min(1)}),sessionResultCallbackSchema=z.discriminatedUnion(`kind`,[z.object({callId:z.string().min(1),kind:z.literal(`session.completed`),output:jsonValueSchema.optional(),subagentName:z.string().min(1),usage:z.unknown().optional()}),z.object({callId:z.string().min(1),error:jsonValueSchema.optional(),kind:z.literal(`session.failed`),subagentName:z.string().min(1),usage:z.unknown().optional()}),z.object({callId:z.string().min(1),kind:z.literal(`turn.completed`),outcome:agentTurnOutcomeSchema,output:jsonValueSchema.optional(),subagentName:z.string().min(1)}),z.object({callId:z.string().min(1),error:jsonValueSchema,kind:z.literal(`turn.failed`),outcome:agentTurnOutcomeSchema,subagentName:z.string().min(1)})]);function getSessionCallbackChannelDefinitions(){return HANDLED_METHODS.map(e=>buildCallbackChannelDefinition(e))}function getSessionCallbackChannelNames(){return new Set(HANDLED_METHODS.map(channelNameForMethod))}function buildCallbackChannelDefinition(e){let t=channelNameForMethod(e);return{name:t,method:e,urlPath:EVE_CALLBACK_ROUTE_PATTERN,fetch:handleSessionCallbackRequest,logicalPath:`framework://channels/${t}`,sourceId:`eve:framework:session-callback-${e.toLowerCase()}`,sourceKind:`module`}}function channelNameForMethod(e){return`${HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX}/${e.toLowerCase()}`}async function handleSessionCallbackRequest(e,t){let n=t.params.token;if(typeof n!=`string`||n.length===0)return Response.json({error:`Missing callback token.`,ok:!1},{status:400});let r;try{r=await e.json()}catch{return Response.json({error:`Invalid JSON body.`,ok:!1},{status:400})}let i=projectTaskEvent(r,n);if(i instanceof Response)return i;if(i!==void 0){try{await resumeHook(n,i)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let a=projectTaskUpdate(r,n);if(a instanceof Response)return a;if(a!==void 0){try{await resumeHook(n,a)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let o=projectTaskTurnStarted(r,n);if(o instanceof Response)return o;if(o!==void 0){try{await resumeHook(n,o)}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}let s=projectSessionCallbackResult(r);if(s instanceof Response)return s;try{await resumeHook(n,{kind:`runtime-action-result`,results:[s]})}catch{return Response.json({error:`Session callback not pending.`,ok:!1},{status:404})}return Response.json({ok:!0},{status:202})}function callbackKind(e){if(!(typeof e!=`object`||!e))return Reflect.get(e,`kind`)}function projectTaskEvent(e,t){let n=callbackKind(e);if(n!==`task.input-requested`&&n!==`task.authorization`)return;let r=taskEventCallbackSchema.safeParse(e);if(!r.success)return Response.json({error:`Invalid task event callback.`,ok:!1},{status:400});let i=r.data,a=rejectMismatchedTaskToken(t,i.taskId);return a===void 0?i.kind===`task.input-requested`?{callId:i.callId,childContinuationToken:i.childContinuationToken,childSessionId:i.childSessionId,event:i.event,kind:`subagent-input-request`,subagentName:i.subagentName}:{callId:i.callId,childSessionId:i.childSessionId,event:i.event,kind:`authorization-event`,subagentName:i.subagentName}:a}function projectTaskTurnStarted(e,t){if(callbackKind(e)!==`turn.started`)return;let n=taskTurnStartedCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid task turn-start callback.`,ok:!1},{status:400});let r=rejectMismatchedTaskToken(t,n.data.taskId);return r===void 0?{childSessionId:n.data.sessionId,childTurnId:n.data.turnId,kind:`turn-started`,taskId:n.data.taskId}:r}function projectTaskUpdate(e,t){if(callbackKind(e)!==`task.update`)return;let n=taskUpdateCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid task update callback.`,ok:!1},{status:400});let r=rejectMismatchedTaskToken(t,n.data.taskId);return r===void 0?{callId:n.data.callId,childStepIndex:n.data.childStepIndex,childTurnId:n.data.childTurnId,kind:`task-update`,message:n.data.message}:r}function rejectMismatchedTaskToken(e,t){return readTaskIdFromInboxToken(e)===t?void 0:Response.json({error:`Task callback token mismatch.`,ok:!1},{status:403})}function projectSessionCallbackResult(e){if(typeof e!=`object`||!e)return Response.json({error:`Expected a JSON object.`,ok:!1},{status:400});let t=callbackKind(e);if(t!==`session.completed`&&t!==`session.failed`&&t!==`turn.completed`&&t!==`turn.failed`)return Response.json({error:`Unsupported callback kind.`,ok:!1},{status:400});let n=sessionResultCallbackSchema.safeParse(e);if(!n.success)return Response.json({error:`Invalid session result callback.`,ok:!1},{status:400});let r=n.data;if(r.kind===`session.completed`){let e=r.output??``,t=parseCallbackUsage(r.usage),n={callId:r.callId,kind:`subagent-result`,origin:`child`,outcome:{kind:`terminal`,result:{kind:`succeeded`,output:e},usageDelta:t??ZERO_TOKEN_USAGE},output:e,subagentName:r.subagentName};return t===void 0?n:{...n,usage:t}}if(r.kind===`session.failed`){let e=r.error===void 0?{code:REMOTE_AGENT_FAILED,message:`Remote agent failed.`}:r.error,t=parseCallbackUsage(r.usage);return{callId:r.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:{kind:`terminal`,result:{error:e,kind:`failed`},usageDelta:t??ZERO_TOKEN_USAGE},output:e,subagentName:r.subagentName}}return r.kind===`turn.completed`?{callId:r.callId,kind:`subagent-result`,origin:`child`,outcome:r.outcome,output:r.output??``,subagentName:r.subagentName,usage:r.outcome.usageDelta}:{callId:r.callId,isError:!0,kind:`subagent-result`,origin:`child`,outcome:r.outcome,output:r.error,subagentName:r.subagentName}}function parseCallbackUsage(e){if(e===void 0)return;let t=tokenUsageSchema.safeParse(e);return t.success?t.data:void 0}export{HTTP_SESSION_CALLBACK_CHANNEL_NAME_PREFIX,getSessionCallbackChannelDefinitions,getSessionCallbackChannelNames,handleSessionCallbackRequest};
@@ -0,0 +1,32 @@
1
+ import type { ChannelSetupLog } from "#setup/cli/index.js";
2
+ import type { VercelProjectReference } from "#setup/project-resolution.js";
3
+ import { runVercel, runVercelCaptureStdout } from "#setup/primitives/run-vercel.js";
4
+ export declare const LINQ_TRIGGER_PATH = "/eve/v1/linq";
5
+ export declare const LINQ_TRIGGER_EVENTS: string[];
6
+ export interface LinqConnectorRef {
7
+ id: string;
8
+ uid: string;
9
+ phoneNumber?: string;
10
+ }
11
+ export interface ProvisionLinqConnectorDeps {
12
+ runVercel: typeof runVercel;
13
+ runVercelCaptureStdout: typeof runVercelCaptureStdout;
14
+ }
15
+ /** Credentials for a connector backed by an existing Linq account. */
16
+ export interface LinqExistingAccountCredentials {
17
+ apiToken: string;
18
+ phoneNumbers: string[];
19
+ }
20
+ /** Parses Vercel Connect JSON for an app-scoped Linq connector. */
21
+ export declare function parseCreatedLinqConnector(stdout: string): LinqConnectorRef | undefined;
22
+ /** Creates a managed Linq connector and routes verified events to eve. */
23
+ export declare function provisionLinqConnector(input: {
24
+ /** When omitted, Connect opens Linq's managed browser flow to provision a line. */
25
+ existingAccount?: LinqExistingAccountCredentials;
26
+ log: ChannelSetupLog;
27
+ project: VercelProjectReference;
28
+ projectRoot: string;
29
+ slug: string;
30
+ signal?: AbortSignal;
31
+ deps?: ProvisionLinqConnectorDeps;
32
+ }): Promise<LinqConnectorRef>;