eve 0.41.0 → 0.43.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.
- package/CHANGELOG.md +30 -0
- package/dist/src/channel/channel-operations.d.ts +2 -2
- package/dist/src/channel/channel-operations.js +1 -1
- package/dist/src/channel/forwarded-principal.d.ts +4 -4
- package/dist/src/channel/session.d.ts +2 -2
- package/dist/src/channel/session.js +1 -1
- package/dist/src/cli/dev/tui/tool-presentation.js +1 -1
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/client/index.js +1 -1
- package/dist/src/compiler/extension-compatibility.d.ts +9 -7
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +3 -0
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-tool.js +1 -1
- package/dist/src/context/build-dynamic-tools.d.ts +5 -5
- package/dist/src/context/build-dynamic-tools.js +1 -1
- package/dist/src/context/dynamic-subagent-lifecycle.js +1 -1
- package/dist/src/context/dynamic-tool-lifecycle.d.ts +8 -27
- package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
- package/dist/src/context/keys.d.ts +10 -14
- package/dist/src/context/keys.js +1 -1
- package/dist/src/context/provider.d.ts +5 -1
- package/dist/src/context/run-step.d.ts +3 -2
- package/dist/src/context/run-step.js +1 -1
- package/dist/src/execution/agent-handle-dispatch.d.ts +3 -0
- package/dist/src/execution/agent-handle-dispatch.js +1 -1
- package/dist/src/execution/delegation-tool.d.ts +9 -1
- package/dist/src/execution/delegation-tool.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.d.ts +14 -1
- package/dist/src/execution/dispatch-runtime-actions-shared.js +1 -1
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
- package/dist/src/execution/history-view.d.ts +9 -0
- package/dist/src/execution/history-view.js +1 -0
- package/dist/src/execution/next-driver-action.d.ts +33 -1
- package/dist/src/execution/node-step.d.ts +5 -2
- package/dist/src/execution/node-step.js +1 -1
- package/dist/src/execution/remote-agent-dispatch.d.ts +2 -0
- package/dist/src/execution/remote-agent-dispatch.js +1 -1
- package/dist/src/execution/session-callback-step.d.ts +2 -2
- package/dist/src/execution/session-callback-step.js +1 -1
- package/dist/src/execution/tasks/child/steps.js +1 -1
- package/dist/src/execution/tasks/child/update.d.ts +2 -2
- package/dist/src/execution/tasks/child/update.js +1 -1
- package/dist/src/execution/tasks/child/workflow.js +1 -1
- package/dist/src/execution/tasks/parent/agent-views.d.ts +2 -1
- package/dist/src/execution/tasks/parent/agent-views.js +1 -1
- package/dist/src/execution/tasks/parent/continuation-dispatch.d.ts +6 -0
- package/dist/src/execution/tasks/parent/continuation-dispatch.js +1 -1
- package/dist/src/execution/tasks/parent/control-shared.d.ts +1 -1
- package/dist/src/execution/tasks/parent/control-shared.js +1 -1
- package/dist/src/execution/tasks/parent/delegate.d.ts +20 -6
- package/dist/src/execution/tasks/parent/delegate.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch-task-step.js +1 -1
- package/dist/src/execution/tasks/parent/dispatch.d.ts +13 -1
- package/dist/src/execution/tasks/parent/dispatch.js +1 -1
- package/dist/src/execution/tasks/parent/hitl-proxy-steps.js +1 -1
- package/dist/src/execution/tasks/parent/tool-execution.d.ts +46 -0
- package/dist/src/execution/tasks/parent/tool-execution.js +1 -0
- package/dist/src/execution/tool-auth.d.ts +12 -3
- package/dist/src/execution/tool-auth.js +1 -1
- package/dist/src/execution/turn-cancellation-control.js +1 -1
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/wire/session-inbox-wire.v1.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +1 -54
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/advertised-tools.js +1 -1
- package/dist/src/harness/background-tools.d.ts +37 -0
- package/dist/src/harness/background-tools.js +1 -0
- package/dist/src/harness/execute-tool.d.ts +10 -1
- package/dist/src/harness/handles/transitions.d.ts +36 -0
- package/dist/src/harness/handles/transitions.js +1 -1
- package/dist/src/harness/messages.d.ts +2 -0
- package/dist/src/harness/messages.js +1 -1
- package/dist/src/harness/tool-loop.js +2 -2
- package/dist/src/harness/tools.d.ts +5 -1
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/harness/types.d.ts +13 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/schema-backed.js +1 -1
- package/dist/src/internal/authored-module-loader.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-capability-transform-plugin.js +1 -1
- package/dist/src/internal/workflow-bundle/dynamic-tool-ast-references.d.ts +13 -0
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.d.ts +7 -31
- package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +4 -4
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/channels/discord/hitl.d.ts +3 -3
- package/dist/src/public/channels/discord/hitl.js +1 -1
- package/dist/src/public/channels/eve.d.ts +7 -7
- package/dist/src/public/channels/eve.js +1 -1
- package/dist/src/public/channels/mcp.js +1 -1
- package/dist/src/public/channels/slack/hitl.d.ts +4 -5
- package/dist/src/public/channels/slack/hitl.js +2 -2
- package/dist/src/public/channels/slack/interactions.js +1 -1
- package/dist/src/public/channels/slack/session-operations.d.ts +2 -2
- package/dist/src/public/channels/slack/slackChannel.d.ts +4 -4
- package/dist/src/public/channels/teams/hitl.d.ts +2 -2
- package/dist/src/public/channels/teams/hitl.js +1 -1
- package/dist/src/public/channels/telegram/hitl.d.ts +4 -4
- package/dist/src/public/channels/telegram/hitl.js +1 -1
- package/dist/src/public/definitions/remote-agent.d.ts +7 -5
- package/dist/src/public/definitions/tool.d.ts +23 -0
- package/dist/src/public/definitions/tool.js +1 -1
- package/dist/src/public/tools/approval/approval-helpers.js +1 -1
- package/dist/src/public/tools/index.d.ts +1 -1
- package/dist/src/runtime/framework-tools/ask-question.js +1 -1
- package/dist/src/runtime/framework-tools/connection-search-dynamic.js +2 -2
- package/dist/src/runtime/framework-tools/subagent/local.d.ts +41 -0
- package/dist/src/runtime/framework-tools/subagent/local.js +1 -0
- package/dist/src/runtime/framework-tools/subagent/remote.d.ts +23 -0
- package/dist/src/runtime/framework-tools/subagent/remote.js +1 -0
- package/dist/src/runtime/framework-tools/tasks.d.ts +13 -12
- package/dist/src/runtime/framework-tools/tasks.js +1 -1
- package/dist/src/runtime/input/types.d.ts +19 -1
- package/dist/src/runtime/input/types.js +1 -1
- package/dist/src/runtime/prompt/compose.js +1 -1
- package/dist/src/runtime/resolve-tool.js +1 -1
- package/dist/src/runtime/session-callback-route.js +1 -1
- package/dist/src/setup/integrations/linq/management.d.ts +5 -0
- package/dist/src/setup/integrations/linq/management.js +1 -0
- package/dist/src/setup/integrations/linq/setup.d.ts +5 -1
- package/dist/src/setup/integrations/linq/setup.js +3 -3
- package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +4 -10
- package/dist/src/setup/scaffold/create/web-template.d.ts +0 -1
- package/dist/src/setup/scaffold/create/web-template.js +1 -1
- package/dist/src/setup/scaffold/update/channels.d.ts +1 -1
- package/dist/src/setup/scaffold/update/channels.js +2 -2
- package/dist/src/setup/scaffold/update/package-json.d.ts +0 -2
- package/dist/src/setup/scaffold/update/package-json.js +1 -1
- package/dist/src/setup/scaffold/workspace-root.d.ts +0 -1
- package/dist/src/setup/scaffold/workspace-root.js +1 -1
- package/dist/src/shared/durable-dynamic-tool-callbacks.d.ts +34 -0
- package/dist/src/shared/durable-dynamic-tool-callbacks.js +1 -0
- package/dist/src/shared/dynamic-tool-definition.d.ts +2 -4
- package/dist/src/shared/empty-delivery.js +1 -1
- package/dist/src/shared/history-view.d.ts +22 -0
- package/dist/src/shared/history-view.js +1 -0
- package/dist/src/shared/json.d.ts +2 -0
- package/dist/src/shared/json.js +1 -1
- package/dist/src/shared/tool-definition.d.ts +4 -1
- package/dist/src/shared/tool-task.d.ts +107 -0
- package/dist/src/shared/tool-task.js +1 -0
- package/dist/src/tasks/delivery-context.d.ts +12 -0
- package/dist/src/tasks/delivery-context.js +17 -0
- package/dist/src/tasks/json.d.ts +25 -10
- package/dist/src/tasks/json.js +1 -1
- package/dist/src/tasks/session-index.d.ts +5 -3
- package/dist/src/tasks/session-index.js +1 -1
- package/dist/src/tasks/transitions.d.ts +40 -5
- package/dist/src/tasks/transitions.js +1 -1
- package/dist/src/tasks/types.d.ts +46 -4
- package/dist/src/tasks/types.js +1 -1
- package/docs/channels/custom.mdx +12 -0
- package/docs/channels/linq.mdx +1 -1
- package/docs/getting-started.mdx +36 -36
- package/docs/guides/auth-and-route-protection.md +6 -2
- package/docs/guides/dynamic-capabilities.md +12 -10
- package/docs/guides/remote-agents.md +10 -2
- package/docs/tools/overview.mdx +19 -0
- package/package.json +1 -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
|
|
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:
|
|
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
|
|
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
|
|
335
|
+
readonly inputResponses: readonly ValidatedInputResponse[];
|
|
336
336
|
readonly messageTs: string;
|
|
337
337
|
readonly user: SlackInteractionUser;
|
|
338
338
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Teams Adaptive Card rendering and decode helpers for eve HITL prompts.
|
|
3
3
|
*/
|
|
4
|
-
import type
|
|
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. */
|
|
@@ -48,7 +48,7 @@ export declare function readTeamsToolApprovalPrompt(activity: TeamsActivity): st
|
|
|
48
48
|
* acknowledgement), or an empty array when the activity has no recognizable
|
|
49
49
|
* HITL payload or requestId.
|
|
50
50
|
*/
|
|
51
|
-
export declare function deriveTeamsInputResponses(activity: TeamsActivity): readonly
|
|
51
|
+
export declare function deriveTeamsInputResponses(activity: TeamsActivity): readonly ValidatedInputResponse[];
|
|
52
52
|
/**
|
|
53
53
|
* Builds the HTTP body Teams expects after an Adaptive Card invoke action.
|
|
54
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`,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,
|
|
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};
|
|
@@ -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
|
|
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):
|
|
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
|
-
}):
|
|
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[]):
|
|
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(
|
|
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};
|
|
@@ -21,11 +21,13 @@ export interface RemoteAgentDefinition {
|
|
|
21
21
|
readonly description: string;
|
|
22
22
|
/**
|
|
23
23
|
* Forwards the dispatching turn's session principal to the remote
|
|
24
|
-
* deployment as the `forwardedPrincipal`
|
|
25
|
-
* remote
|
|
26
|
-
* Connect, local subagents, and further remote hops all see that
|
|
27
|
-
* principal).
|
|
28
|
-
*
|
|
24
|
+
* deployment as the `forwardedPrincipal` session-request body field, so
|
|
25
|
+
* each remote turn runs as the same end user as the parent (per-user
|
|
26
|
+
* Connect, local subagents, and further remote hops all see that active
|
|
27
|
+
* principal). Session creation forwards current and initiator identity;
|
|
28
|
+
* continuation forwards only the active caller and leaves the remote
|
|
29
|
+
* session's initiator pinned. Defaults to `false` — forwarding identity to
|
|
30
|
+
* another deployment is an explicit decision, never ambient.
|
|
29
31
|
*
|
|
30
32
|
* Only principal metadata crosses the wire, never tokens or credentials —
|
|
31
33
|
* {@link auth} keeps authenticating *this* deployment to the remote. The
|
|
@@ -3,12 +3,14 @@ import type { PublicToolDefinition, ToolModelOutput } from "#shared/tool-definit
|
|
|
3
3
|
import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
4
4
|
import type { Approval } from "#public/definitions/approval.js";
|
|
5
5
|
import type { JsonObject } from "#shared/json.js";
|
|
6
|
+
import type { TaskDelegated, TaskExec, TaskReceipt } from "#shared/tool-task.js";
|
|
6
7
|
import type { AuthorizationDefinition, ConnectionAuthorizationContext, NonInteractiveAuthorizationDefinition, TokenResult } from "#runtime/connections/types.js";
|
|
7
8
|
import { type DynamicEvents, type DynamicSentinel } from "#shared/dynamic-tool-definition.js";
|
|
8
9
|
type ApprovalContextInput<TInput> = unknown extends TInput ? Record<string, unknown> : TInput;
|
|
9
10
|
type DynamicEventMapHandler<TEvents extends DynamicEvents> = Extract<NonNullable<TEvents[keyof TEvents]>, (...args: never[]) => unknown>;
|
|
10
11
|
type DynamicEventMapResult<TEvents extends DynamicEvents> = Awaited<ReturnType<DynamicEventMapHandler<TEvents>>>;
|
|
11
12
|
export type { ToolModelOutput, ToolModelOutputPart } from "#shared/tool-definition.js";
|
|
13
|
+
export type { TaskBinding, TaskDelegated, TaskExec, TaskExecutorBinding, TaskReceipt, TaskSendCommand, } from "#shared/tool-task.js";
|
|
12
14
|
/**
|
|
13
15
|
* Authorization provider passed to {@link ToolContext.getToken} or
|
|
14
16
|
* {@link ToolContext.requireAuth}. Accepts the same shapes as a connection's
|
|
@@ -88,6 +90,7 @@ export type ToolContext = SessionContext & {
|
|
|
88
90
|
* Authored definitions have no `name` field; identity is path-derived.
|
|
89
91
|
*/
|
|
90
92
|
export interface ToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> {
|
|
93
|
+
readonly execution?: never;
|
|
91
94
|
execute(input: TInput, ctx: ToolContext): Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
|
|
92
95
|
/**
|
|
93
96
|
* Optional per-tool approval gate. The return value determines whether
|
|
@@ -110,10 +113,21 @@ export interface ToolDefinition<TInput = unknown, TOutput = unknown> extends Pub
|
|
|
110
113
|
*/
|
|
111
114
|
toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
|
|
112
115
|
}
|
|
116
|
+
/** A tool whose executor can outlive the model tool-call phase as a durable task. */
|
|
117
|
+
export interface BackgroundToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> {
|
|
118
|
+
readonly execution: "background";
|
|
119
|
+
execute(input: TInput, ctx: ToolContext, task: TaskExec): Promise<TaskDelegated | TOutput> | TaskDelegated | TOutput;
|
|
120
|
+
approval?: Approval<ApprovalContextInput<TInput>>;
|
|
121
|
+
toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
|
|
122
|
+
}
|
|
113
123
|
type ToolOutputFromExecuteReturn<TReturn> = TReturn extends Promise<infer TOutput> ? TOutput : TReturn extends AsyncIterable<infer TOutput> ? TOutput : TReturn;
|
|
124
|
+
type BackgroundToolOutputFromExecuteReturn<TReturn> = ToolOutputFromExecuteReturn<TReturn> extends infer TOutput ? TOutput extends TaskDelegated<infer TData> ? TaskReceipt<TData> : TOutput : never;
|
|
114
125
|
type ToolDefinitionWithExecuteReturn<TInput, TOutput, TReturn> = ToolDefinition<TInput, TOutput> & {
|
|
115
126
|
execute(input: TInput, ctx: ToolContext): TReturn;
|
|
116
127
|
};
|
|
128
|
+
type BackgroundToolDefinitionWithExecuteReturn<TInput, TOutput, TReturn> = BackgroundToolDefinition<TInput, TOutput> & {
|
|
129
|
+
execute(input: TInput, ctx: ToolContext, task: TaskExec): TReturn;
|
|
130
|
+
};
|
|
117
131
|
/**
|
|
118
132
|
* Defines a tool configuration, used both for static tools (default export
|
|
119
133
|
* from `agent/tools/*.ts`) and as the entry wrapper inside `defineDynamic`
|
|
@@ -122,6 +136,15 @@ type ToolDefinitionWithExecuteReturn<TInput, TOutput, TReturn> = ToolDefinition<
|
|
|
122
136
|
* For static tools, the runtime tool name is the filename slug. `defineTool`
|
|
123
137
|
* stamps a brand that lifecycle code validates; it rejects raw object literals.
|
|
124
138
|
*/
|
|
139
|
+
export declare function defineTool<TSchema extends StandardSchemaV1<unknown, unknown> | StandardJSONSchemaV1<unknown, unknown>, TReturn>(definition: {
|
|
140
|
+
description: BackgroundToolDefinition<unknown, unknown>["description"];
|
|
141
|
+
execution: "background";
|
|
142
|
+
inputSchema: TSchema;
|
|
143
|
+
outputSchema?: PublicToolDefinition<unknown, BackgroundToolOutputFromExecuteReturn<TReturn>>["outputSchema"];
|
|
144
|
+
execute(input: StandardSchemaV1.InferOutput<TSchema>, ctx: ToolContext, task: TaskExec): TReturn extends AsyncIterable<unknown> ? never : TReturn;
|
|
145
|
+
approval?: BackgroundToolDefinition<StandardSchemaV1.InferOutput<TSchema>, unknown>["approval"];
|
|
146
|
+
toModelOutput?: BackgroundToolDefinition<unknown, BackgroundToolOutputFromExecuteReturn<TReturn>>["toModelOutput"];
|
|
147
|
+
}): BackgroundToolDefinitionWithExecuteReturn<StandardSchemaV1.InferOutput<TSchema>, BackgroundToolOutputFromExecuteReturn<TReturn>, TReturn>;
|
|
125
148
|
export declare function defineTool<TInputSchema extends StandardSchemaV1<unknown, unknown> | StandardJSONSchemaV1<unknown, unknown>, TOutputSchema extends StandardJSONSchemaV1<unknown, unknown>, TReturn extends Promise<StandardJSONSchemaV1.InferOutput<TOutputSchema>> | StandardJSONSchemaV1.InferOutput<TOutputSchema> | AsyncIterable<StandardJSONSchemaV1.InferOutput<TOutputSchema>>>(definition: {
|
|
126
149
|
description: ToolDefinition<unknown, unknown>["description"];
|
|
127
150
|
inputSchema: TInputSchema;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DYNAMIC_SENTINEL_KIND,TOOL_BRAND}from"#shared/dynamic-tool-definition.js";import{stampDefinitionKey}from"#public/tool-result-narrowing.js";function defineTool(e){if(e.auth!==void 0)throw Error(`defineTool: The "auth" field is no longer supported. Pass auth providers inline to ctx.getToken(provider) or ctx.requireAuth(provider).`);return Object.assign(e,{[TOOL_BRAND]:!0}),stampDefinitionKey(e,`tool:${e.description}`),e}function defineDynamic(t){let n={kind:DYNAMIC_SENTINEL_KIND,events:t.events};return stampDefinitionKey(n,`dynamic:${Object.keys(t.events).join(`,`)}`),n}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}const EXPERIMENTAL_WORKFLOW_TOOL_KIND=`eve:enable-workflow-tool`;function experimental_workflow(e={}){let t={kind:EXPERIMENTAL_WORKFLOW_TOOL_KIND};return e.maxSubagents!==void 0&&(t.maxSubagents=e.maxSubagents),t}function isExperimentalWorkflowToolDefinition(e){return typeof e==`object`&&!!e&&e.kind===EXPERIMENTAL_WORKFLOW_TOOL_KIND}export{defineDynamic,defineTool,disableTool,experimental_workflow,isDisabledToolSentinel,isExperimentalWorkflowToolDefinition};
|
|
1
|
+
import{DYNAMIC_SENTINEL_KIND,TOOL_BRAND}from"#shared/dynamic-tool-definition.js";import{collectDurableDynamicToolCallbacks,stampDurableDynamicToolCallbacks}from"#shared/durable-dynamic-tool-callbacks.js";import{stampDefinitionKey}from"#public/tool-result-narrowing.js";function defineTool(e){if(e.auth!==void 0)throw Error(`defineTool: The "auth" field is no longer supported. Pass auth providers inline to ctx.getToken(provider) or ctx.requireAuth(provider).`);return Object.assign(e,{[TOOL_BRAND]:!0}),stampDurableDynamicToolCallbacks(e,collectDurableDynamicToolCallbacks({approval:e.approval,execute:e.execute,toModelOutput:e.toModelOutput})),stampDefinitionKey(e,`tool:${e.description}`),e}function defineDynamic(t){let n={kind:DYNAMIC_SENTINEL_KIND,events:t.events};return stampDefinitionKey(n,`dynamic:${Object.keys(t.events).join(`,`)}`),n}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}const EXPERIMENTAL_WORKFLOW_TOOL_KIND=`eve:enable-workflow-tool`;function experimental_workflow(e={}){let t={kind:EXPERIMENTAL_WORKFLOW_TOOL_KIND};return e.maxSubagents!==void 0&&(t.maxSubagents=e.maxSubagents),t}function isExperimentalWorkflowToolDefinition(e){return typeof e==`object`&&!!e&&e.kind===EXPERIMENTAL_WORKFLOW_TOOL_KIND}export{defineDynamic,defineTool,disableTool,experimental_workflow,isDisabledToolSentinel,isExperimentalWorkflowToolDefinition};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
function always(){return()=>`user-approval
|
|
1
|
+
import{registerDurableDynamicCallback,stampDurableDynamicCallback}from"#shared/durable-dynamic-tool-callbacks.js";const ALWAYS_STEP_ID=`eve:dynamic-tool-helper//approval/always/v1`,NEVER_STEP_ID=`eve:dynamic-tool-helper//approval/never/v1`,ONCE_STEP_ID=`eve:dynamic-tool-helper//approval/once/v1`;function alwaysApproval(e){return`user-approval`}function neverApproval(e){return`not-applicable`}function onceApproval(e,t){return t.approvedTools.has(t.toolName)?`not-applicable`:`user-approval`}registerDurableDynamicCallback(ALWAYS_STEP_ID,alwaysApproval),registerDurableDynamicCallback(NEVER_STEP_ID,neverApproval),registerDurableDynamicCallback(ONCE_STEP_ID,onceApproval);function always(){return stampDurableDynamicCallback(()=>`user-approval`,{closure:{},stepId:ALWAYS_STEP_ID})}function never(){return stampDurableDynamicCallback(()=>`not-applicable`,{closure:{},stepId:NEVER_STEP_ID})}function once(){return stampDurableDynamicCallback(({approvedTools:e,toolName:t})=>e.has(t)?`not-applicable`:`user-approval`,{closure:{},stepId:ONCE_STEP_ID})}export{always,never,once};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool authoring helpers for `agent/tools/*.ts` files.
|
|
3
3
|
*/
|
|
4
|
-
export { type DisabledToolSentinel, type ExperimentalWorkflowToolDefinition, type ExperimentalWorkflowToolInput, defineDynamic, defineTool, disableTool, experimental_workflow, isDisabledToolSentinel, isExperimentalWorkflowToolDefinition, type ToolAuthOptions, type ToolAuthProvider, type ToolDefinition, type ToolContext, type ToolModelOutput, type ToolModelOutputPart, } from "#public/definitions/tool.js";
|
|
4
|
+
export { type BackgroundToolDefinition, type DisabledToolSentinel, type ExperimentalWorkflowToolDefinition, type ExperimentalWorkflowToolInput, defineDynamic, defineTool, disableTool, experimental_workflow, isDisabledToolSentinel, isExperimentalWorkflowToolDefinition, type TaskBinding, type TaskDelegated, type TaskExec, type TaskExecutorBinding, type TaskReceipt, type ToolAuthOptions, type ToolAuthProvider, type ToolDefinition, type ToolContext, type ToolModelOutput, type ToolModelOutputPart, } from "#public/definitions/tool.js";
|
|
5
5
|
export { toolOutput, toolOutputPart } from "#public/tools/output-builders.js";
|
|
6
6
|
export type { Approval, ApprovalConfiguration, ApprovalContext, ApprovalPolicy, ApprovalRequest, ApprovalResponse, ApprovalResponseAuth, ApprovalResponseContext, ApprovalResponseDecision, ApprovalResponsePolicy, ApprovalResponseSession, ApprovalStatus, } from "#public/definitions/approval.js";
|
|
7
7
|
export type { DynamicToolEntry, DynamicEvents, DynamicToolEvents, DynamicResolveContext, DynamicSentinel, DynamicToolSet, DynamicToolResult, } from "#shared/dynamic-tool-definition.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
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};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{z}from"#compiled/zod/index.js";import{toError}from"#shared/errors.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{ConnectionRegistryKey}from"#context/providers/connection-key.js";import{
|
|
2
|
-
`));
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{z}from"#compiled/zod/index.js";import{toError}from"#shared/errors.js";import{loadContext}from"#context/container.js";import{ContextKey}from"#context/key.js";import{registerDurableDynamicCallback,stampDurableDynamicToolCallbacks}from"#shared/durable-dynamic-tool-callbacks.js";import{ConnectionRegistryKey}from"#context/providers/connection-key.js";import{consumeAuthorizationResult,createAuthorizationAttempt,requestAuthorization}from"#harness/authorization.js";import{ConnectionAuthorizationFailedError,isConnectionAuthorizationFailedError,isConnectionAuthorizationRequiredError}from"#public/connections/errors.js";import{supportsInteractiveAuthorization}from"#runtime/connections/types.js";import{resolveAuthorizationCallbackUrl,stampChallengeDisplayName}from"#runtime/connections/scoped-authorization.js";import{resolveApprovalPolicy}from"#public/definitions/approval.js";import{defineDynamic,defineTool}from"#public/definitions/tool.js";import{resolveConnectionAuthorization}from"#runtime/connections/resolve-authorization.js";import{writeCachedToken}from"#runtime/connections/authorization-tokens.js";import{principalKey,resolveConnectionPrincipal}from"#runtime/connections/principal.js";const logger=createLogger(`framework.connection-search-dynamic`),CONNECTION_SEARCH_INPUT_SCHEMA=z.strictObject({connection:z.string().describe(`Optional: limit search to a specific connection name.`).optional(),keywords:z.string().describe(`Search keywords and expanded aliases. Distill intent into keywords; avoid stop words like 'a', 'the', 'in'.`),limit:z.number().describe(`Max results to return. Default 10.`).optional()}),connectionSchema=z.looseObject({}),CONNECTION_SEARCH_RESULT_ITEM_SCHEMA=z.strictObject({connection:z.string(),description:z.string(),error:z.string().optional(),inputSchema:connectionSchema.optional(),needsAuthorization:z.boolean().optional(),outputSchema:connectionSchema.optional(),qualifiedName:z.string().optional(),tool:z.string().optional()}),CONNECTION_SEARCH_OUTPUT_SCHEMA=z.array(CONNECTION_SEARCH_RESULT_ITEM_SCHEMA),ConnectionSearchResultsKey=new ContextKey(`eve.connectionSearchResults`);function qualifiedConnectionToolName(e,t){return`${e}__${t}`}function tokenize(e){return e.toLowerCase().split(/[\s_\-./]+/).filter(e=>e.length>1)}function scoreMatch(e,t){let n=tokenize(t.name),r=tokenize(t.description),i=0;for(let t of e){for(let e of n)(e.includes(t)||t.includes(e))&&(i+=3);for(let e of r)(e.includes(t)||t.includes(e))&&(i+=1)}return i}async function resolveInteractiveAuth(e,t){let n=e.getConnections().find(e=>e.connectionName===t);if(n===void 0)return;let r=await resolveConnectionAuthorization(n);if(supportsInteractiveAuthorization(r))return r}async function completePendingAuthorizations(e,t){let n=loadContext(),i=new Set;for(let r of t){let t=consumeAuthorizationResult(r.connectionName);if(!t)continue;let a=await resolveInteractiveAuth(e,r.connectionName);if(!a)continue;let o=t.principal??resolveConnectionPrincipal(r.connectionName,a),s=await a.completeAuthorization({callbackUrl:t.hookUrl,connection:{url:r.url??``},principal:o,resume:t.resume,callback:t.callback});writeCachedToken(n,r.connectionName,principalKey(o),s),i.add(r.connectionName)}return i}async function executeConnectionSearch(e){let t=loadContext(),i=t.get(ConnectionRegistryKey);if(i===void 0)return[];let a=e.limit??10,o=tokenize(e.keywords),c=[],d=[],p=e.connection!==void 0&&e.connection!==``?i.getConnections().filter(t=>t.connectionName===e.connection):i.getConnections();if(e.connection&&p.length===0)throw Error(`Connection "${e.connection}" is not registered. Available connections: ${i.getConnectionNames().join(`, `)}.`);let m=await completePendingAuthorizations(i,p),h=[];for(let e of p){let t;try{t=await i.getClient(e.connectionName).getToolMetadata()}catch(t){if(isConnectionAuthorizationRequiredError(t)){if(m.has(e.connectionName)){logger.warn(`connection still unauthorized after authorization`,{connection:e.connectionName}),d.push({connection:e.connectionName,description:e.description,error:`Authorization for "${e.connectionName}" did not take effect; the token was rejected after sign-in.`});continue}let t=await resolveInteractiveAuth(i,e.connectionName);if(t){let r=createAuthorizationAttempt(e.connectionName);if(r){let i=resolveConnectionPrincipal(e.connectionName,t),a=resolveAuthorizationCallbackUrl({authorization:t,callbackUrl:r.hookUrl});try{let{challenge:n,resume:o}=await t.startAuthorization({callbackUrl:a,connection:{url:e.url??``},principal:i});h.push({attemptId:r.attemptId,name:e.connectionName,challenge:stampChallengeDisplayName(n,t),hookUrl:a,principal:i,resume:o})}catch(t){let r=toError(t);logger.warn(`startAuthorization failed`,{connection:e.connectionName,error:r}),d.push({connection:e.connectionName,description:e.description,error:`Failed to start authorization for "${e.connectionName}": ${r.message}`});continue}}}d.push({connection:e.connectionName,description:e.description,needsAuthorization:!0});continue}if(isConnectionAuthorizationFailedError(t)){logger.warn(`connection authorization failed`,{connection:e.connectionName,reason:t.reason,retryable:t.retryable,error:t}),d.push({connection:e.connectionName,description:e.description,error:`Authorization failed for ${e.connectionName}: ${t.message}`});continue}let r=toError(t);logger.warn(`failed to load connection tools`,{connection:e.connectionName,error:r}),d.push({connection:e.connectionName,description:e.description,error:`Failed to load tools for "${e.connectionName}": ${r.message}`});continue}for(let n of t){let t=scoreMatch(o,n);t>0&&c.push({item:{connection:e.connectionName,description:n.description,inputSchema:n.inputSchema,outputSchema:n.outputSchema,qualifiedName:qualifiedConnectionToolName(e.connectionName,n.name),tool:n.name},score:t})}}if(h.length>0)return requestAuthorization(h);let g=d.filter(e=>e.error!==void 0);if(p.length>0&&g.length===p.length)throw Error(g.map(e=>e.error).join(`
|
|
2
|
+
`));c.sort((e,t)=>t.score-e.score);let _=c.slice(0,a).map(e=>e.item);if(_.length>0){let e=[..._,...d],n=t.get(ConnectionSearchResultsKey)??[],r=new Map(n.map(e=>[e.qualifiedName,e]));for(let e of _)e.qualifiedName&&r.set(e.qualifiedName,e);return t.set(ConnectionSearchResultsKey,[...r.values()]),e}return p.map(e=>d.find(t=>t.connection===e.connectionName)||{connection:e.connectionName,description:e.description})}function extractDiscoveredTools(e){let t=new Map;for(let n of e){if(n.role!==`tool`)continue;let e=n.content;for(let n of e){if(n.type!==`tool-result`||n.toolName!==`connection_search`)continue;let e=n.output;if(e==null)continue;let r=typeof e==`object`&&`type`in e&&`value`in e?e.value:e;if(Array.isArray(r))for(let e of r)e.tool&&e.qualifiedName&&t.set(e.qualifiedName,e)}}return[...t.values()]}const CONNECTION_SEARCH_EXECUTE_STEP_ID=`eve:framework-dynamic//connection-search/execute/v1`,DISCOVERED_TOOL_EXECUTE_STEP_ID=`eve:framework-dynamic//connection-search/discovered-execute/v1`,DISCOVERED_TOOL_APPROVAL_REQUEST_STEP_ID=`eve:framework-dynamic//connection-search/discovered-approval-request/v1`,DISCOVERED_TOOL_APPROVAL_RESPONSE_STEP_ID=`eve:framework-dynamic//connection-search/discovered-approval-response/v1`;function readDiscoveredToolClosure(e){let t=e.connectionName,n=e.toolName;if(typeof t!=`string`||typeof n!=`string`)throw Error(`Discovered connection tool callback metadata is invalid.`);return{connectionName:t,toolName:n}}async function executeDiscoveredConnectionTool(e,t,n){let{connectionName:i,toolName:a}=readDiscoveredToolClosure(e),o=loadContext().get(ConnectionRegistryKey);if(o===void 0)throw Error(`Connection registry is unavailable while replaying a discovered tool.`);let f=o.getConnections().find(e=>e.connectionName===i),p=await resolveInteractiveAuth(o,i),m=!1;if(p){let e=consumeAuthorizationResult(i);if(e){m=!0;let t=loadContext(),n=e.principal??resolveConnectionPrincipal(i,p),a=await p.completeAuthorization({callbackUrl:e.hookUrl,connection:{url:f?.url??``},principal:n,resume:e.resume,callback:e.callback});writeCachedToken(t,i,principalKey(n),a)}}try{return await o.getClient(i).executeTool(a,t,{abortSignal:n.abortSignal})}catch(e){if(!isConnectionAuthorizationRequiredError(e)||!p)throw e;if(m)throw new ConnectionAuthorizationFailedError(i,{retryable:!1,reason:`token_rejected_after_authorization`,message:`Connection "${i}" rejected the token immediately after authorization.`});let t=createAuthorizationAttempt(i);if(!t)throw e;let n=resolveConnectionPrincipal(i,p),r=resolveAuthorizationCallbackUrl({authorization:p,callbackUrl:t.hookUrl}),{challenge:a,resume:o}=await p.startAuthorization({callbackUrl:r,connection:{url:f?.url??``},principal:n});return requestAuthorization([{attemptId:t.attemptId,name:i,challenge:stampChallengeDisplayName(a,p),hookUrl:r,principal:n,resume:o}])}}async function requestDiscoveredConnectionToolApproval(e,t){let{connectionName:n}=readDiscoveredToolClosure(e),i=loadContext().get(ConnectionRegistryKey)?.getConnectionApproval(n);return i===void 0?`not-applicable`:await resolveApprovalPolicy(i)(t)}async function authorizeDiscoveredConnectionToolApproval(e,t){let{connectionName:n}=readDiscoveredToolClosure(e),i=loadContext().get(ConnectionRegistryKey)?.getConnectionApproval(n),a=i===void 0||typeof i==`function`?void 0:i.response;return a===void 0?{reason:`Approval response authorization is unavailable.`,status:`rejected`}:await a(t)}registerDurableDynamicCallback(CONNECTION_SEARCH_EXECUTE_STEP_ID,(e,t)=>executeConnectionSearch(t)),registerDurableDynamicCallback(DISCOVERED_TOOL_EXECUTE_STEP_ID,executeDiscoveredConnectionTool),registerDurableDynamicCallback(DISCOVERED_TOOL_APPROVAL_REQUEST_STEP_ID,requestDiscoveredConnectionToolApproval),registerDurableDynamicCallback(DISCOVERED_TOOL_APPROVAL_RESPONSE_STEP_ID,authorizeDiscoveredConnectionToolApproval);const connectionSearchDynamicDefinition=defineDynamic({events:{"step.started":async(e,t)=>{let n=loadContext().get(ConnectionRegistryKey);if(!n||n.getConnections().length===0)return null;let i=n.getConnections().map(e=>e.connectionName),a=extractDiscoveredTools(t.messages),c=loadContext().get(ConnectionSearchResultsKey)??[],l=new Map;for(let e of c)e.qualifiedName&&l.set(e.qualifiedName,e);for(let e of a)e.qualifiedName&&l.set(e.qualifiedName,e);let u=[...l.values()],d={},f=defineTool({description:`Search for tools across your connections. Discovered tools become directly callable by their qualified name (e.g. \`linear__list_issues\`) in your next response. Available connections: ${i.join(`, `)}.`,inputSchema:CONNECTION_SEARCH_INPUT_SCHEMA,async execute(e){return executeConnectionSearch(e)},outputSchema:CONNECTION_SEARCH_OUTPUT_SCHEMA});stampDurableDynamicToolCallbacks(f,{execute:{closure:{},stepId:CONNECTION_SEARCH_EXECUTE_STEP_ID}}),d.connection_search=f;for(let e of u){let t=e.connection,r=e.tool,i=n.getConnectionApproval(t),a={connectionName:t,toolName:r},s=defineTool({description:e.description,inputSchema:e.inputSchema??{type:`object`},approval:i,outputSchema:e.outputSchema,async execute(e,t){return await executeDiscoveredConnectionTool(a,e,t)}});stampDurableDynamicToolCallbacks(s,{execute:{closure:a,stepId:DISCOVERED_TOOL_EXECUTE_STEP_ID},...i===void 0?{}:{approvalRequest:{closure:a,stepId:DISCOVERED_TOOL_APPROVAL_REQUEST_STEP_ID}},...i===void 0||typeof i==`function`||i.response===void 0?{}:{approvalResponse:{closure:a,stepId:DISCOVERED_TOOL_APPROVAL_RESPONSE_STEP_ID}}}),d[qualifiedConnectionToolName(t,r)]=s}return d}}});export{connectionSearchDynamicDefinition as default,extractDiscoveredTools};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type TaskExec, type ToolContext } from "#public/definitions/tool.js";
|
|
2
|
+
interface SubagentDefinitionInput {
|
|
3
|
+
readonly description: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly nodeId: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function defineSubagent(input: SubagentDefinitionInput): import("#public/definitions/tool.js").BackgroundToolDefinition<{
|
|
8
|
+
message: string;
|
|
9
|
+
outputSchema?: {
|
|
10
|
+
[x: string]: unknown;
|
|
11
|
+
} | undefined;
|
|
12
|
+
agentId?: string | null | undefined;
|
|
13
|
+
}, import("#public/definitions/tool.js").TaskReceipt<{
|
|
14
|
+
agentId: string;
|
|
15
|
+
}>> & {
|
|
16
|
+
execute(input: {
|
|
17
|
+
message: string;
|
|
18
|
+
outputSchema?: {
|
|
19
|
+
[x: string]: unknown;
|
|
20
|
+
} | undefined;
|
|
21
|
+
agentId?: string | null | undefined;
|
|
22
|
+
}, ctx: ToolContext, task: TaskExec): Promise<import("#public/definitions/tool.js").TaskDelegated<{
|
|
23
|
+
agentId: string;
|
|
24
|
+
}>>;
|
|
25
|
+
};
|
|
26
|
+
export declare function registerLocalSubagentExecutor(execute: object): void;
|
|
27
|
+
export declare function countLocalSubagentCalls(calls: readonly {
|
|
28
|
+
readonly definition: {
|
|
29
|
+
readonly execute: object;
|
|
30
|
+
};
|
|
31
|
+
}[]): number;
|
|
32
|
+
export declare function executeSubagentTool(input: {
|
|
33
|
+
readonly definition: SubagentDefinitionInput;
|
|
34
|
+
readonly kind: "local" | "remote";
|
|
35
|
+
readonly task: TaskExec;
|
|
36
|
+
readonly toolContext: ToolContext;
|
|
37
|
+
readonly toolInput: unknown;
|
|
38
|
+
}): Promise<import("#public/definitions/tool.js").TaskDelegated<{
|
|
39
|
+
agentId: string;
|
|
40
|
+
}>>;
|
|
41
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{HandleEventKey}from"#context/keys.js";import{createSubagentCalledEvent}from"#protocol/message.js";import{parseJsonObject}from"#shared/json.js";import{loadContext}from"#context/container.js";import{PERSISTENT_SUBAGENT_TOOL_INPUT_SCHEMA}from"#runtime/subagents/registry.js";import{getHarnessEmissionState}from"#harness/emission.js";import{workflowEntryReference}from"#execution/workflow-runtime.js";import{serializeContext}from"#context/serialize.js";import{createDurableSessionState}from"#execution/durable-session-store.js";import{SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA}from"#runtime/framework-tools/tasks.js";import{dispatchToTaskAgentAddress}from"#execution/agent-handle-dispatch.js";import{createAgentContinuationBundle}from"#execution/agent-continuation-bundle.js";import{prepareAgentActionDispatch,startSubagent}from"#execution/dispatch-runtime-actions-shared.js";import{activeTurnId}from"#harness/active-turn-id.js";import{createSubagentExecutorBinding}from"#tasks/types.js";import{findTaskAgentAddress}from"#execution/tasks/parent/control-shared.js";import{checkTaskContinuationAvailability,createTaskContinuationBusyResult,describeTaskDispatch}from"#execution/tasks/parent/continuation-dispatch.js";import{CallbackBaseUrlKey}from"#harness/authorization.js";import{defineTool}from"#public/definitions/tool.js";const localSubagentExecutors=new WeakSet,batchAgentClaims=new WeakMap,log=createLogger(`runtime.framework-tools.subagent`);function defineSubagent(e){return defineTool({description:e.description,execution:`background`,inputSchema:PERSISTENT_SUBAGENT_TOOL_INPUT_SCHEMA,outputSchema:SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA,execute:(t,n,r)=>executeSubagentTool({definition:e,kind:`local`,task:r,toolContext:n,toolInput:t})})}function registerLocalSubagentExecutor(e){localSubagentExecutors.add(e)}function countLocalSubagentCalls(e){return e.filter(e=>localSubagentExecutors.has(e.definition.execute)).length}async function executeSubagentTool(e){let t=loadContext(),{batch:n,session:r,task:o}=e.task,s=getHarnessEmissionState(r.state),c={callId:e.toolContext.callId,description:e.definition.description,input:parseJsonObject(PERSISTENT_SUBAGENT_TOOL_INPUT_SCHEMA.parse(e.toolInput)),name:e.definition.name,nodeId:e.definition.nodeId},l=await dispatchSubagent({action:e.kind===`remote`?{...c,kind:`remote-agent-call`,remoteAgentName:e.definition.name}:{...c,kind:`subagent-call`,subagentName:e.definition.name},batch:n,callbackBaseUrl:t.get(CallbackBaseUrlKey),ctx:t,event:{...s,turnId:activeTurnId(s)},localFanoutSize:countLocalSubagentCalls(n),serializedContext:serializeContext(t),sessionState:createDurableSessionState({session:r}),task:o}),u=findTaskAgentAddress(l.session,l.agentId);if(u===void 0)throw Error(`Subagent dispatch for "${l.agentId}" recorded no task agent address.`);let d=createSubagentExecutorBinding({address:u.address,identity:u.identity});await emitSubagentCalled$1({callId:e.toolContext.callId,childSessionId:l.address.sessionId,event:{...s,turnId:activeTurnId(s)},name:l.name,remote:l.remote,sessionId:r.sessionId,toolName:e.definition.name});let f=e.task.delegated({executor:d,receipt:{agentId:l.agentId}});return await emitSubagentCompleted({callId:e.toolContext.callId,output:JSON.stringify(f.receipt),subagentName:l.name,taskId:f.receipt.taskId}),f}async function dispatchSubagent(e){let t=await prepareAgentActionDispatch({action:e.action,ctx:e.ctx,event:e.event,localFanoutSize:e.localFanoutSize,serializedContext:e.serializedContext,sessionState:e.sessionState}),n=t.plan[0];if(n===void 0||n.kind===`task-control`)throw Error(`Subagent tool dispatch produced no executable plan entry.`);if(n.kind===`reject`)throw Error(JSON.stringify(n.result.output));if(n.kind===`resume`){let r=await checkTaskContinuationAvailability({action:n.action,agentId:n.agentId,parentStepIndex:e.event.stepIndex,parentTurnId:e.event.turnId,session:t.session});if(r!==void 0)throw Error(JSON.stringify(r.output));let i=claimBatchAgent(e.batch,n.agentId,e.task.taskId);if(i!==void 0){let e=createTaskContinuationBusyResult({action:n.action,agentId:n.agentId,status:`working`,taskId:i});throw Error(JSON.stringify(e.output))}}let r=n.kind===`resume`?await dispatchToTaskAgentAddress({action:n.action,agentId:n.agentId,auth:t.auth,bundle:createAgentContinuationBundle({action:n.action,bundle:t.bundle,dynamicRemoteAgent:n.dynamicRemoteAgent}),currentSession:t.session,parentToken:e.task.taskInboxToken}):await startSubagent({auth:t.auth,batchEvent:e.event,bundle:t.bundle,callbackBaseUrl:e.callbackBaseUrl,capabilities:t.capabilities,channelMetadata:t.channelMetadata,currentSession:t.session,fanoutSize:t.fanoutSize,initiatorAuth:t.initiatorAuth,parentContinuationToken:e.task.taskInboxToken,parentTraceContext:t.parentTraceContext,persistentSessions:!0,sandboxSessionId:t.sandboxSessionId,serializedContext:t.serializedContext,session:t.session,taskOwned:!0,target:n.target});if(r.kind===`error`)throw Error(JSON.stringify(r.result.output));let i=describeTaskDispatch({action:e.action,agentId:n.kind===`resume`?n.agentId:void 0,parentSessionId:t.session.sessionId,parentTurnId:e.event.turnId,session:r.session}),a=n.kind===`resume`?n.dynamicRemoteAgent:n.target.kind===`remote`?n.target.dynamicRemoteAgent:void 0;return{address:r.address,agentId:i.agentId,mode:i.mode,name:i.name,...r.address.kind===`agent/remote`?{remote:{resolverId:a?.credentialsStepId??e.action.nodeId,url:r.address.url}}:{},session:r.session}}function claimBatchAgent(e,t,n){let r=batchAgentClaims.get(e);r===void 0&&(r=new Map,batchAgentClaims.set(e,r));let i=r.get(t);if(i!==void 0)return i;r.set(t,n)}async function emitSubagentCalled$1(e){let i=loadContext().get(HandleEventKey);if(i!==void 0)try{await i(createSubagentCalledEvent({callId:e.callId,childSessionId:e.childSessionId,name:e.name,remote:e.remote,sequence:e.event.sequence,sessionId:e.sessionId,toolName:e.toolName,turnId:e.event.turnId,workflowId:workflowEntryReference.workflowId}))}catch(n){logError(log,`subagent.called emission failed`,n,{callId:e.callId,childSessionId:e.childSessionId,toolName:e.toolName})}}async function emitSubagentCompleted(e){let r=loadContext().get(HandleEventKey);if(r!==void 0)try{await r({data:{backgroundTask:{status:`working`,taskId:e.taskId},callId:e.callId,output:e.output,subagentName:e.subagentName},type:`subagent.completed`})}catch(n){logError(log,`subagent.completed emission failed`,n,{callId:e.callId,taskId:e.taskId})}}export{countLocalSubagentCalls,defineSubagent,executeSubagentTool,registerLocalSubagentExecutor};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export declare function defineRemoteSubagent(input: {
|
|
2
|
+
readonly description: string;
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly nodeId: string;
|
|
5
|
+
}): import("#public/definitions/tool.js").BackgroundToolDefinition<{
|
|
6
|
+
message: string;
|
|
7
|
+
outputSchema?: {
|
|
8
|
+
[x: string]: unknown;
|
|
9
|
+
} | undefined;
|
|
10
|
+
agentId?: string | null | undefined;
|
|
11
|
+
}, import("#public/definitions/tool.js").TaskReceipt<{
|
|
12
|
+
agentId: string;
|
|
13
|
+
}>> & {
|
|
14
|
+
execute(input: {
|
|
15
|
+
message: string;
|
|
16
|
+
outputSchema?: {
|
|
17
|
+
[x: string]: unknown;
|
|
18
|
+
} | undefined;
|
|
19
|
+
agentId?: string | null | undefined;
|
|
20
|
+
}, ctx: import("#public/definitions/tool.js").ToolContext, task: import("#public/definitions/tool.js").TaskExec): Promise<import("#public/definitions/tool.js").TaskDelegated<{
|
|
21
|
+
agentId: string;
|
|
22
|
+
}>>;
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{PERSISTENT_SUBAGENT_TOOL_INPUT_SCHEMA}from"#runtime/subagents/registry.js";import{SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA}from"#runtime/framework-tools/tasks.js";import{executeSubagentTool}from"#runtime/framework-tools/subagent/local.js";import{defineTool}from"#public/definitions/tool.js";function defineRemoteSubagent(r){return defineTool({description:r.description,execution:`background`,inputSchema:PERSISTENT_SUBAGENT_TOOL_INPUT_SCHEMA,outputSchema:SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA,execute:(e,t,n)=>executeSubagentTool({definition:r,kind:`remote`,task:n,toolContext:t,toolInput:e})})}export{defineRemoteSubagent};
|
|
@@ -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
|
-
*
|
|
11
|
-
*
|
|
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>>;
|
|
@@ -37,7 +32,7 @@ export declare const TASK_VIEWS_OUTPUT_SCHEMA: z.ZodObject<{
|
|
|
37
32
|
result: "result";
|
|
38
33
|
}>;
|
|
39
34
|
}, z.core.$strip>>;
|
|
40
|
-
metadata: z.ZodObject<{
|
|
35
|
+
metadata: z.ZodUnion<readonly [z.ZodObject<{
|
|
41
36
|
agentId: z.ZodString;
|
|
42
37
|
kind: z.ZodLiteral<"subagent">;
|
|
43
38
|
mode: z.ZodEnum<{
|
|
@@ -45,7 +40,11 @@ export declare const TASK_VIEWS_OUTPUT_SCHEMA: z.ZodObject<{
|
|
|
45
40
|
remote: "remote";
|
|
46
41
|
}>;
|
|
47
42
|
name: z.ZodString;
|
|
48
|
-
}, z.core.$strip
|
|
43
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
44
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
45
|
+
kind: z.ZodString;
|
|
46
|
+
name: z.ZodString;
|
|
47
|
+
}, z.core.$strip>]>;
|
|
49
48
|
status: z.ZodEnum<{
|
|
50
49
|
cancelled: "cancelled";
|
|
51
50
|
completed: "completed";
|
|
@@ -56,8 +55,10 @@ export declare const TASK_VIEWS_OUTPUT_SCHEMA: z.ZodObject<{
|
|
|
56
55
|
taskId: z.ZodString;
|
|
57
56
|
}, z.core.$strip>>;
|
|
58
57
|
}, z.core.$strip>;
|
|
59
|
-
export declare const
|
|
60
|
-
|
|
58
|
+
export declare const SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA: z.ZodObject<{
|
|
59
|
+
agentId: z.ZodString;
|
|
60
|
+
status: z.ZodLiteral<"working">;
|
|
61
|
+
taskId: z.ZodString;
|
|
61
62
|
}, z.core.$strict>;
|
|
62
63
|
/**
|
|
63
64
|
* Builds the harness definitions injected when the root agent enables
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{z}from"#compiled/zod/index.js";
|
|
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.union([z.object({agentId:z.string(),kind:z.literal(`subagent`),mode:z.enum([`local`,`remote`]),name:z.string()}),z.object({data:z.record(z.string(),z.unknown()).optional(),kind:z.string(),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)}),SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA=z.strictObject({agentId:z.string(),status:z.literal(`working`),taskId:z.string()}),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{SUBAGENT_TASK_RECEIPT_OUTPUT_SCHEMA,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
|
|
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};
|