eve 0.18.1 → 0.19.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 +20 -0
- package/dist/src/compiled/.vendor-stamp.json +2 -1
- package/dist/src/compiled/@chat-adapter/slack/index.js +29 -32
- package/dist/src/compiled/@chat-adapter/twilio/LICENSE +9 -0
- package/dist/src/compiled/@chat-adapter/twilio/api.d.ts +108 -0
- package/dist/src/compiled/@chat-adapter/twilio/api.js +1 -0
- package/dist/src/compiled/@chat-adapter/twilio/format.d.ts +12 -0
- package/dist/src/compiled/@chat-adapter/twilio/format.js +1 -0
- package/dist/src/compiled/@chat-adapter/twilio/index.d.ts +84 -0
- package/dist/src/compiled/@chat-adapter/twilio/index.js +1 -0
- package/dist/src/compiled/@chat-adapter/twilio/voice.d.ts +44 -0
- package/dist/src/compiled/@chat-adapter/twilio/voice.js +1 -0
- package/dist/src/compiled/@chat-adapter/twilio/webhook.d.ts +18 -0
- package/dist/src/compiled/@chat-adapter/twilio/webhook.js +1 -0
- package/dist/src/compiled/_chunks/node/chunk-5OX2R7AJ-CxVV-owP.js +1 -0
- package/dist/src/compiled/_chunks/node/chunk-PFJ2G64A-B79fSABi.js +1 -0
- package/dist/src/compiled/_chunks/node/chunk-QZV7YRVM-Dzw4WEBv.js +1 -0
- package/dist/src/compiled/_chunks/node/dist-RHRJZ03Q.js +4 -0
- package/dist/src/execution/sandbox/bindings/vercel-create-sdk.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-credentials.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-user-agent.d.ts +6 -0
- package/dist/src/execution/sandbox/bindings/vercel-user-agent.js +1 -0
- package/dist/src/harness/action-result-helpers.d.ts +11 -1
- package/dist/src/harness/action-result-helpers.js +1 -1
- package/dist/src/harness/emission.d.ts +1 -0
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/step-hooks.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/dev-runtime-source-snapshot-copy.js +1 -1
- package/dist/src/internal/nitro/host/configure-nitro-routes.js +1 -1
- package/dist/src/internal/nitro/host/dev-authored-source-watcher.js +1 -1
- package/dist/src/internal/nitro/routes/index.d.ts +7 -2
- package/dist/src/internal/nitro/routes/index.js +78 -48
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +141 -0
- package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +3 -0
- package/dist/src/public/channels/chat-sdk/index.d.ts +1 -0
- package/dist/src/public/channels/chat-sdk/index.js +1 -0
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/index.d.ts +2 -0
- package/dist/src/public/channels/slack/api.js +1 -1
- package/dist/src/public/channels/twilio/api.d.ts +8 -29
- package/dist/src/public/channels/twilio/api.js +1 -1
- package/dist/src/public/channels/twilio/inbound.d.ts +10 -19
- package/dist/src/public/channels/twilio/inbound.js +2 -2
- package/dist/src/public/channels/twilio/routing.d.ts +13 -0
- package/dist/src/public/channels/twilio/routing.js +1 -0
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/channels/twilio/twiml.d.ts +5 -36
- package/dist/src/public/channels/twilio/twiml.js +1 -1
- package/dist/src/public/channels/twilio/verify.d.ts +12 -33
- package/dist/src/public/channels/twilio/verify.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/package.json +7 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";const log=createLogger(`discord.channel`);function discordChannel(e={}){let t=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),metadata:e=>({channelId:e.channelId,guildId:e.guildId}),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/eve/v1/discord`,async(r,{send:i,waitUntil:a})=>{let o=await verifyDiscordInbound(r,e.credentials);if(o===null)return new Response(`unauthorized`,{status:401});let s;try{s=parseJsonObject(JSON.parse(o))}catch(e){return log.warn(`inbound Discord body is not valid JSON`,{error:e}),discordJson({content:`invalid request`,ephemeral:!0})}if(s.type===DISCORD_INTERACTION_TYPE.PING)return discordJson({type:DISCORD_INTERACTION_RESPONSE_TYPE.PONG});let c=parseDiscordInteraction(s);return c===null?discordJson({content:`Unsupported Discord interaction.`,ephemeral:!0}):handleInteraction({config:e,interaction:c,onCommand:t,send:i,waitUntil:a})})],async receive(t,{send:n}){let r=t.target,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires target.channelId.`);let a=readString(r.conversationId),o=r.initialMessage;if(o!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(o!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(o);c=t.id,l=t.id.length>0}return n(t.message,{auth:t.auth,continuationToken:discordContinuationToken(i,c),state:{applicationId:null,channelId:i,conversationId:c||null,guildId:null,hasMessageAnchor:l,initialResponseSent:!0,interactionToken:null}})},events:a})}function rebuildDiscordContext(e,t,n){return{discord:buildDiscordHandle({config:n,session:t,state:e}),state:e}}function buildDiscordHandle(e){let n=e.config.api,r=e.state,i=mergeCredentials(e.config.credentials,r);function anchor(t){!t.id||r.hasMessageAnchor||(r.conversationId=t.id,r.hasMessageAnchor=!0,r.channelId&&e.session?.setContinuationToken(discordContinuationToken(r.channelId,t.id)))}async function sendViaChannel(e){let t=r.channelId??``;if(!t)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,channelId:t});return anchor(a),a}async function editOriginal(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return r.initialResponseSent=!0,anchor(a),a}async function followup(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for followup message.`);let a=await createDiscordFollowupMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return anchor(a),a}async function startTyping(){let e=r.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:n?.apiBaseUrl,credentials:i,fetch:n?.fetch,channelId:e})}catch(n){logError(log,`Discord typing indicator failed — swallowed`,n,{channelId:e})}}return{applicationId:r.applicationId??void 0,channelId:r.channelId??``,conversationId:r.conversationId??``,guildId:r.guildId??void 0,interactionToken:r.interactionToken??void 0,request(e,t,r){return callDiscordApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:r?.botAuth===!0?i.botToken:void 0,fetch:n?.fetch,method:r?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),n;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:r});n===void 0&&(n=t)}return n??{id:``,raw:null}},editOriginalResponse:editOriginal,followup,sendChannelMessage:sendViaChannel,startTyping}}async function postOne(e){if(e.state.interactionToken&&e.state.applicationId)try{return e.state.initialResponseSent?await e.followup(e.body):await e.editOriginal(e.body)}catch(e){log.warn(`Discord interaction-token delivery failed, falling back to channel message`,{error:e})}return e.sendViaChannel(e.body)}async function handleInteraction(e){return e.interaction.type===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?handleCommandInteraction({config:e.config,interaction:e.interaction,onCommand:e.onCommand,send:e.send,waitUntil:e.waitUntil}):e.interaction.type===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?handleComponentInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil}):handleModalSubmitInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil})}async function handleCommandInteraction(e){let t=stateFromInteraction(e.interaction,{conversationId:e.interaction.id,hasMessageAnchor:!1,initialResponseSent:!1}),n={discord:buildDiscordHandle({config:e.config,state:t})},r;try{r=await e.onCommand(n,e.interaction)}catch(e){return log.error(`command handler failed`,{error:e}),discordJson({content:`The Discord command handler failed.`,ephemeral:!0})}return r==null?discordJson({content:`Command ignored.`,ephemeral:!0}):(e.waitUntil(dispatchCommand({interaction:e.interaction,result:r,send:e.send,state:t})),discordDeferredJson(r.ephemeral===!0))}function handleComponentInteraction(e){if(isDiscordFreeformComponent(e.interaction.customId)){let t=readMessageContent(e.interaction.raw);return discordJsonBody(buildFreeformModalResponse({customId:e.interaction.customId,prompt:t}))}let t=deriveComponentInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId,inputResponses:t,interaction:e.interaction,send:e.send})),discordJsonBody({type:DISCORD_INTERACTION_RESPONSE_TYPE.DEFERRED_UPDATE_MESSAGE})}function handleModalSubmitInteraction(e){let t=deriveModalInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId??e.interaction.id,inputResponses:t,interaction:e.interaction,send:e.send})),discordJson({content:`Answer received.`,ephemeral:!0})}async function dispatchCommand(e){let t=commandInteractionMessage(e.interaction),n=formatDiscordContextBlock({channelId:e.interaction.channelId,commandName:e.interaction.commandName,guildId:e.interaction.guildId,interactionId:e.interaction.id,userId:e.interaction.user.id,username:e.interaction.user.username}),r=e.result.context??[];try{await e.send({message:t,context:[n,...r]},{auth:e.result.auth,continuationToken:discordContinuationToken(e.interaction.channelId,e.interaction.id),state:e.state})}catch(e){log.error(`command delivery failed`,{error:e})}}async function dispatchInputResponses(e){try{await e.send({inputResponses:e.inputResponses},{auth:null,continuationToken:discordContinuationToken(e.interaction.channelId,e.conversationId),state:stateFromInteraction(e.interaction,{conversationId:e.conversationId,hasMessageAnchor:!0,initialResponseSent:!0})})}catch(e){log.error(`interaction response delivery failed`,{error:e})}}function stateFromInteraction(e,t){return{applicationId:e.applicationId,channelId:e.channelId,conversationId:t.conversationId,guildId:e.guildId??null,hasMessageAnchor:t.hasMessageAnchor,initialResponseSent:t.initialResponseSent,interactionToken:e.token}}function initialDiscordState(){return{applicationId:null,channelId:null,conversationId:null,guildId:null,hasMessageAnchor:!1,initialResponseSent:!1,interactionToken:null}}function mergeCredentials(e,t){return{applicationId:t.applicationId??e?.applicationId,botToken:e?.botToken,publicKey:e?.publicKey,webhookVerifier:e?.webhookVerifier}}function normalizePostInput(e){return typeof e==`string`?{content:e}:e}function expandPostBodies(e){return typeof e.content==`string`?splitDiscordMessageContent(e.content).map((t,n)=>n===0?{...e,content:t}:{allowed_mentions:e.allowed_mentions,content:t}):[e]}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{discordChannel};
|
|
@@ -18,6 +18,7 @@ export interface ChannelMetadataMap {
|
|
|
18
18
|
readonly subagent: InstrumentationChannelMetadata;
|
|
19
19
|
readonly unknown: InstrumentationChannelMetadata;
|
|
20
20
|
readonly "channel:slack": import("#public/channels/slack/slackChannel.js").SlackInstrumentationMetadata;
|
|
21
|
+
readonly "channel:chat-sdk": import("#public/channels/chat-sdk/chatSdkChannel.js").ChatSdkInstrumentationMetadata;
|
|
21
22
|
readonly "channel:discord": import("#public/channels/discord/index.js").DiscordInstrumentationMetadata;
|
|
22
23
|
readonly "channel:twilio": import("#public/channels/twilio/twilioChannel.js").TwilioInstrumentationMetadata;
|
|
23
24
|
readonly "channel:teams": import("#public/channels/teams/index.js").TeamsInstrumentationMetadata;
|
|
@@ -40,6 +41,7 @@ export type InstrumentationChannelKind = keyof ChannelMetadataMap;
|
|
|
40
41
|
*/
|
|
41
42
|
export interface ChannelReferenceMap {
|
|
42
43
|
readonly "channel:slack": import("#public/channels/slack/slackChannel.js").SlackChannel;
|
|
44
|
+
readonly "channel:chat-sdk": import("#public/channels/chat-sdk/chatSdkChannel.js").ChatSdkChannel;
|
|
43
45
|
readonly "channel:discord": import("#public/channels/discord/discordChannel.js").DiscordChannel;
|
|
44
46
|
readonly "channel:twilio": import("#public/channels/twilio/twilioChannel.js").TwilioChannel;
|
|
45
47
|
readonly "channel:teams": import("#public/channels/teams/teamsChannel.js").TeamsChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{callSlackApi as callSlackApi$1,fetchSlackThreadReplies,postSlackEphemeral,postSlackMessage,resolveSlackBotToken as resolveSlackBotToken$1,uploadSlackFiles}from"#compiled/@chat-adapter/slack/api.js";import{
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{isCardElement}from"#compiled/chat/index.js";import{callSlackApi as callSlackApi$1,fetchSlackThreadReplies,postSlackEphemeral,postSlackMessage,resolveSlackBotToken as resolveSlackBotToken$1,uploadSlackFiles}from"#compiled/@chat-adapter/slack/api.js";import{cardToBlocks,cardToFallbackText}from"#public/channels/slack/blocks.js";import{truncateTypingStatus}from"#public/channels/slack/limits.js";import{gfmToSlackMrkdwn,rewriteBareMentions,slackMrkdwnToGfm}from"#public/channels/slack/mrkdwn.js";const log=createLogger(`slack.api`);function slackContinuationToken(e,t){return`${e}:${t}`}async function resolveSlackBotToken(e){let t=e??process.env.SLACK_BOT_TOKEN;if(!t)throw Error(`SLACK_BOT_TOKEN is required.`);return resolveSlackBotToken$1(t)}async function callSlackApi(e){return callSlackApi$1(e.operation,normalizeSlackApiBody(e.body),createSlackApiOptions(e.botToken))}function createSlackRequester(e){return(t,n)=>callSlackApi({botToken:e,operation:t,body:n})}function buildSlackBinding(e){let n=createSlackRequester(e.botToken),r=[],s=e.threadTs;function handleMessageTs(t){s||t===s||(s=t,e.onThreadTsChanged?.(t))}async function uploadFiles(t,n){let r=n?.channelId??e.channelId,i=n?.threadTs??s;return uploadSlackFiles(t.map(toSlackFileUpload),{...createSlackApiOptions(e.botToken),channelId:r||void 0,initialComment:n?.initialComment,threadTs:i||void 0})}return{thread:{recentMessages:r,async post(t){let n=normalizePostInput(t),r=n.files??[],i=`blocks`in n||`card`in n;if(r.length>0&&!i){let e=await uploadFiles(r,{initialComment:`markdown`in n?rewriteBareMentions(gfmToSlackMrkdwn(n.markdown)):`text`in n?rewriteBareMentions(n.text):void 0});return{id:Array.isArray(e.raw.files)&&e.raw.files.length>0?String(e.raw.files[0].id??``):``,raw:e.raw}}let a=await postSlackMessage(buildPostMessageOptions(n,e.channelId,s,e.botToken)),c=a.id;if(handleMessageTs(c),r.length>0&&i)try{await uploadFiles(r)}catch(e){log.warn(`file upload after structured post failed`,{error:e})}return{id:c,raw:a.raw}},async postEphemeral(t,n){let r=await postSlackEphemeral({...buildPostMessageOptions(normalizePostInput(n),e.channelId,s,e.botToken),user:t});return{id:r.id,raw:r.raw}},async postDirectMessage(t,r){let i=await n(`conversations.open`,{users:t}),a=i.ok===!0?i.channel?.id:void 0;if(typeof a!=`string`||a.length===0)throw Error(`Slack conversations.open failed: ${i.error??`unknown_error`}`);let s=await postSlackMessage(buildPostMessageOptions(normalizePostInput(r),a,``,e.botToken));return{id:s.id,raw:s.raw}},async startTyping(r){if(!(!e.channelId||!s))try{let t=r===void 0?``:truncateTypingStatus(r),i={channel_id:e.channelId,thread_ts:s,status:t};t.length>0&&(i.loading_messages=[t]);let a=await n(`assistant.threads.setStatus`,i);a.ok!==!0&&log.warn(`assistant.threads.setStatus returned not-ok`,{error:a.error})}catch(n){logError(log,`startTyping threw — swallowed`,n,{channelId:e.channelId})}},async refresh(){if(r.length=0,!(!e.channelId||!s))try{let t=await fetchSlackThreadReplies({...createSlackApiOptions(e.botToken),channel:e.channelId,limit:50,ts:s});for(let e of t.messages)r.push(parseThreadMessage(e,s))}catch(n){logError(log,`refresh threw — swallowed`,n,{channelId:e.channelId})}},mentionUser(e){return`<@${e}>`}},slack:{channelId:e.channelId,get threadTs(){return s},teamId:e.teamId,request:n,uploadFiles}}}function normalizePostInput(e){return typeof e==`string`?{markdown:e}:isCardElement(e)?{card:e}:e}function buildPostMessageOptions(e,t,n,r){let i={...createSlackApiOptions(r),channel:t,threadTs:n||void 0,unfurlLinks:!1,unfurlMedia:!1};return`card`in e?(i.blocks=cardToBlocks(e.card),i.text=e.fallbackText??cardToFallbackText(e.card),i):`blocks`in e?(i.blocks=[...e.blocks],e.text!==void 0&&(i.text=e.text),i):`markdown`in e?(i.markdownText=rewriteBareMentions(e.markdown),i):(i.text=rewriteBareMentions(e.text),i)}function createSlackApiOptions(e){return{token:()=>resolveSlackBotToken(e)}}function normalizeSlackApiBody(e){return e&&typeof e==`object`&&!Array.isArray(e)?e:{}}function toSlackFileUpload(e){return{data:normalizeFileData(e.data),filename:e.filename}}function normalizeFileData(e){if(e instanceof ArrayBuffer||typeof Blob<`u`&&e instanceof Blob)return e;if(ArrayBuffer.isView(e)){let t=e;return new Uint8Array(t.buffer,t.byteOffset,t.byteLength)}return e}function parseThreadMessage(e,t){let n=typeof e.text==`string`?e.text:``,r=typeof e.ts==`string`?e.ts:``,i=typeof e.thread_ts==`string`?e.thread_ts:t,a=typeof e.user==`string`?e.user:void 0,o=typeof e.bot_id==`string`?e.bot_id:void 0;return{text:n,markdown:slackMrkdwnToGfm(n),user:a,botId:o,ts:r,threadTs:i,isMe:o!==void 0,raw:e}}export{buildSlackBinding,callSlackApi,resolveSlackBotToken,slackContinuationToken};
|
|
@@ -1,25 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
* Minimal Twilio REST API wrapper used by the Twilio channel.
|
|
3
|
-
*
|
|
4
|
-
* Requests use Twilio's normal `application/x-www-form-urlencoded`
|
|
5
|
-
* body encoding and HTTP Basic auth. No Twilio SDK dependency is
|
|
6
|
-
* required or exposed through eve public APIs.
|
|
7
|
-
*/
|
|
1
|
+
import { type TwilioApiResponse, type TwilioCredential, type TwilioFetch } from "#compiled/@chat-adapter/twilio/api.js";
|
|
8
2
|
import { type TwilioAuthToken } from "#public/channels/twilio/verify.js";
|
|
9
3
|
/**
|
|
10
|
-
* Builds the Twilio channel-local continuation token
|
|
11
|
-
*
|
|
12
|
-
* name before passing it to the runtime (`twilio:<from>:<to>`), so
|
|
13
|
-
* Twilio routes should pass the raw channel-local form returned
|
|
14
|
-
* here. `to` may be empty for proactive sessions that don't yet know
|
|
15
|
-
* the Twilio sender number.
|
|
4
|
+
* Builds the Twilio channel-local continuation token (`<from>:<to>`).
|
|
5
|
+
* Eve namespaces this with the channel name before handing it to the runtime.
|
|
16
6
|
*/
|
|
17
7
|
export declare function twilioContinuationToken(from: string, to: string | undefined): string;
|
|
18
8
|
/** Twilio Account SID, materialized directly or from an async secret provider. */
|
|
19
|
-
export type TwilioAccountSid =
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
/** Credentials required for Twilio REST API calls and webhook verification. */
|
|
9
|
+
export type TwilioAccountSid = TwilioCredential;
|
|
10
|
+
export type { TwilioApiResponse, TwilioFetch };
|
|
11
|
+
/** Credentials used for Twilio REST API calls and webhook verification. */
|
|
23
12
|
export interface TwilioCredentials {
|
|
24
13
|
readonly accountSid?: TwilioAccountSid;
|
|
25
14
|
readonly authToken?: TwilioAuthToken;
|
|
@@ -30,16 +19,6 @@ export interface TwilioApiOptions {
|
|
|
30
19
|
readonly apiBaseUrl?: string;
|
|
31
20
|
readonly fetch?: TwilioFetch;
|
|
32
21
|
}
|
|
33
|
-
/**
|
|
34
|
-
* Result of a Twilio REST call: HTTP `status`, an `ok` flag, and `body`.
|
|
35
|
-
* `body` holds parsed JSON for a JSON response, the raw text string
|
|
36
|
-
* otherwise, or `null` when empty.
|
|
37
|
-
*/
|
|
38
|
-
export interface TwilioApiResponse {
|
|
39
|
-
readonly status: number;
|
|
40
|
-
readonly ok: boolean;
|
|
41
|
-
readonly body: unknown;
|
|
42
|
-
}
|
|
43
22
|
/** Parameters for creating an outbound Twilio message. */
|
|
44
23
|
export interface TwilioSendMessageInput extends TwilioApiOptions {
|
|
45
24
|
readonly to: string;
|
|
@@ -58,8 +37,8 @@ export declare function resolveTwilioAccountSid(accountSid?: TwilioAccountSid):
|
|
|
58
37
|
/**
|
|
59
38
|
* Calls Twilio's REST API with Basic auth and form-encoded body fields.
|
|
60
39
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
40
|
+
* The return shape intentionally preserves Eve's previous non-throwing HTTP
|
|
41
|
+
* behavior: non-2xx Twilio responses become `{ ok: false, status, body }`.
|
|
63
42
|
*/
|
|
64
43
|
export declare function callTwilioApi(input: {
|
|
65
44
|
readonly credentials?: TwilioCredentials;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolveTwilioAuthToken}from"#public/channels/twilio/verify.js";function twilioContinuationToken(e,t){return`${e}:${t??``}`}async function resolveTwilioAccountSid(
|
|
1
|
+
import{TwilioApiError,callTwilioApi as callTwilioApi$1,encodeTwilioForm,resolveTwilioCredential}from"#compiled/@chat-adapter/twilio/api.js";import{resolveTwilioAuthToken}from"#public/channels/twilio/verify.js";function twilioContinuationToken(e,t){return`${e}:${t??``}`}async function resolveTwilioAccountSid(t){try{return await resolveTwilioCredential(t,`TWILIO_ACCOUNT_SID`)}catch(t){throw t instanceof TwilioApiError&&t.status===0?Error(`TWILIO_ACCOUNT_SID is required.`):t}}async function callTwilioApi(e){let n=await resolveCredentials(e.credentials);return preserveTwilioApiResponse(callTwilioApi$1({apiBaseUrl:e.apiBaseUrl,body:encodeTwilioForm(e.body),credentials:n,fetch:e.fetch,path:e.path}))}async function sendTwilioMessage(e){if(!e.from&&!e.messagingServiceSid)throw Error(`twilioChannel: sending a message requires from or messagingServiceSid.`);let n=await resolveTwilioAccountSid(e.credentials?.accountSid),r=await resolveCredentials(e.credentials);return preserveTwilioApiResponse(callTwilioApi$1({apiBaseUrl:e.apiBaseUrl,body:encodeTwilioForm({Body:e.body,From:e.from,MessagingServiceSid:e.messagingServiceSid,StatusCallback:e.statusCallbackUrl,To:e.to}),credentials:r,fetch:e.fetch,path:`/2010-04-01/Accounts/${encodeURIComponent(n)}/Messages.json`}))}async function updateTwilioCall(e){let n=await resolveTwilioAccountSid(e.credentials?.accountSid),r=await resolveCredentials(e.credentials);return preserveTwilioApiResponse(callTwilioApi$1({apiBaseUrl:e.apiBaseUrl,body:encodeTwilioForm({Twiml:e.twiml}),credentials:r,fetch:e.fetch,path:`/2010-04-01/Accounts/${encodeURIComponent(n)}/Calls/${encodeURIComponent(e.callSid)}.json`}))}async function resolveCredentials(e){return{accountSid:await resolveTwilioAccountSid(e?.accountSid),authToken:await resolveTwilioAuthToken(e?.authToken)}}async function preserveTwilioApiResponse(t){try{return await t}catch(t){if(t instanceof TwilioApiError&&t.status!==0)return{body:t.body,ok:!1,status:t.status};throw t}}export{callTwilioApi,resolveTwilioAccountSid,sendTwilioMessage,twilioContinuationToken,updateTwilioCall};
|
|
@@ -1,16 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*
|
|
4
|
-
* The channel owns these small data shapes instead of exposing raw
|
|
5
|
-
* Twilio webhook payloads as the public API surface.
|
|
6
|
-
*/
|
|
7
|
-
/** Channel-owned representation of one inbound Twilio text message. */
|
|
1
|
+
import { type TwilioMediaPayload } from "#compiled/@chat-adapter/twilio/webhook.js";
|
|
2
|
+
/** Channel-owned representation of one inbound Twilio text or media message. */
|
|
8
3
|
export interface TwilioTextMessage {
|
|
9
4
|
readonly from: string;
|
|
10
5
|
readonly to: string | undefined;
|
|
11
6
|
readonly body: string;
|
|
12
7
|
readonly messageSid: string | undefined;
|
|
13
8
|
readonly accountSid: string | undefined;
|
|
9
|
+
/** MMS media metadata parsed from Twilio's `MediaUrl*` webhook fields. */
|
|
10
|
+
readonly media?: readonly TwilioMediaPayload[];
|
|
14
11
|
readonly raw: URLSearchParams;
|
|
15
12
|
}
|
|
16
13
|
/** Channel-owned representation of one inbound Twilio voice call. */
|
|
@@ -31,11 +28,7 @@ export interface TwilioVoiceTranscription {
|
|
|
31
28
|
readonly transcriptionSid: string | undefined;
|
|
32
29
|
readonly raw: URLSearchParams;
|
|
33
30
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Inbound identity fields for the model-visible `<twilio_context>` block.
|
|
36
|
-
* Stores the caller and receiver numbers, the originating SID, and the turn
|
|
37
|
-
* medium (text or voice).
|
|
38
|
-
*/
|
|
31
|
+
/** Inbound identity fields for the model-visible `<twilio_context>` block. */
|
|
39
32
|
export interface TwilioInboundContext {
|
|
40
33
|
readonly from: string;
|
|
41
34
|
readonly to?: string;
|
|
@@ -43,17 +36,15 @@ export interface TwilioInboundContext {
|
|
|
43
36
|
readonly callSid?: string;
|
|
44
37
|
readonly channel: "text" | "voice";
|
|
45
38
|
}
|
|
46
|
-
/** Parses Twilio's incoming-message webhook fields. */
|
|
39
|
+
/** Parses Twilio's incoming-message webhook fields into Eve's text payload. */
|
|
47
40
|
export declare function parseTwilioTextMessage(params: URLSearchParams): TwilioTextMessage | null;
|
|
48
|
-
/** Parses Twilio's incoming-call webhook fields. */
|
|
41
|
+
/** Parses Twilio's incoming-call webhook fields into Eve's voice payload. */
|
|
49
42
|
export declare function parseTwilioVoiceCall(params: URLSearchParams): TwilioVoiceCall | null;
|
|
50
43
|
/**
|
|
51
|
-
* Parses Twilio
|
|
44
|
+
* Parses Twilio speech callbacks.
|
|
52
45
|
*
|
|
53
|
-
* Supports `<Gather input="speech"
|
|
54
|
-
* transcription callbacks
|
|
55
|
-
* transcription callbacks (`TranscriptionData` JSON). Real-time partial
|
|
56
|
-
* results are ignored until Twilio marks them final.
|
|
46
|
+
* Supports `<Gather input="speech">`, recording transcription callbacks, and
|
|
47
|
+
* real-time transcription callbacks. Real-time partial results are ignored.
|
|
57
48
|
*/
|
|
58
49
|
export declare function parseTwilioVoiceTranscription(params: URLSearchParams): TwilioVoiceTranscription | null;
|
|
59
50
|
/** Renders a deterministic `<twilio_context>` block for the model. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
function parseTwilioTextMessage(
|
|
2
|
-
`)}
|
|
1
|
+
import{parseTwilioWebhookBody}from"#compiled/@chat-adapter/twilio/webhook.js";import{parseTwilioVoiceCall as parseTwilioVoiceCall$1,parseTwilioVoiceTranscription as parseTwilioVoiceTranscription$1}from"#compiled/@chat-adapter/twilio/voice.js";function parseTwilioTextMessage(t){let n=parseTwilioWebhookBody(t);return n.kind===`text`?{accountSid:n.accountSid,body:n.body,from:n.from,media:n.media,messageSid:n.messageSid,raw:n.raw,to:n.to}:null}function parseTwilioVoiceCall(e){let n=parseTwilioVoiceCall$1(e);return n?{accountSid:n.accountSid,callSid:n.callSid,from:n.from,raw:n.raw,to:n.to}:null}function parseTwilioVoiceTranscription(e){let t=parseTwilioVoiceTranscription$1(e);return t?.from?{callSid:t.callSid,confidence:t.confidence,from:t.from,raw:t.raw,text:t.text,to:t.to,transcriptionSid:t.transcriptionSid}:null}function formatTwilioContextBlock(e){return[`<twilio_context>`,`channel: ${e.channel}`,`response_medium: sms`,`response_instructions: Reply for SMS in plain text. Keep the response concise and avoid Markdown formatting, tables, headings, code fences, and long lists. Ask at most one short follow-up question when more information is needed.`,`from: ${e.from}`,...e.to?[`to: ${e.to}`]:[],...e.messageSid?[`message_sid: ${e.messageSid}`]:[],...e.callSid?[`call_sid: ${e.callSid}`]:[],`</twilio_context>`].join(`
|
|
2
|
+
`)}export{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TwilioChannelConfig } from "#public/channels/twilio/twilioChannel.js";
|
|
2
|
+
export interface TwilioRoutes {
|
|
3
|
+
readonly messages: string;
|
|
4
|
+
readonly transcription: string;
|
|
5
|
+
readonly voice: string;
|
|
6
|
+
}
|
|
7
|
+
export type TwilioVerifyResult = {
|
|
8
|
+
readonly body: string;
|
|
9
|
+
readonly params: URLSearchParams;
|
|
10
|
+
} | null;
|
|
11
|
+
export declare function buildTwilioRoutes(baseRoute: string): TwilioRoutes;
|
|
12
|
+
export declare function verifyTwilioInbound(req: Request, config: TwilioChannelConfig): Promise<TwilioVerifyResult>;
|
|
13
|
+
export declare function buildTwilioActionUrl(request: Request, config: TwilioChannelConfig, route: string): Promise<string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{verifyTwilioRequest}from"#public/channels/twilio/verify.js";const log=createLogger(`twilio.channel`);function buildTwilioRoutes(e){let t=e.endsWith(`/`)?e.slice(0,-1):e;return{messages:`${t}/messages`,transcription:`${t}/voice/transcription`,voice:`${t}/voice`}}async function verifyTwilioInbound(e,r){try{return await verifyTwilioRequest(e,{authToken:r.credentials?.authToken,webhookUrl:r.webhookUrl})}catch(e){return log.warn(`twilio inbound verification failed`,{error:e}),null}}async function buildTwilioActionUrl(e,t,n){let r=typeof t.publicBaseUrl==`function`?await t.publicBaseUrl(e):t.publicBaseUrl;if(r)return new URL(n,ensureTrailingSlash(r)).toString();let i=new URL(e.url);return i.pathname=n,i.search=``,i.toString()}function ensureTrailingSlash(e){return e.endsWith(`/`)?e:`${e}/`}export{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{GET,POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/twilio/verify.js";import{callTwilioApi,sendTwilioMessage,twilioContinuationToken,updateTwilioCall}from"#public/channels/twilio/api.js";import{emptyTwilioResponse,gatherSpeechTwilioResponse,sayTwilioResponse}from"#public/channels/twilio/twiml.js";import{defaultEvents,defaultOnText,defaultOnVoice,defaultOnVoiceTranscription}from"#public/channels/twilio/defaults.js";import{formatTwilioContextBlock,parseTwilioTextMessage,parseTwilioVoiceCall,parseTwilioVoiceTranscription}from"#public/channels/twilio/inbound.js";import{buildTwilioActionUrl,buildTwilioRoutes,verifyTwilioInbound}from"#public/channels/twilio/routing.js";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let i=buildTwilioRoutes(e.route??`/eve/v1/twilio`),a=e.onText??defaultOnText,s=e.onVoice??defaultOnVoice,c=e.onVoiceTranscription??defaultOnVoiceTranscription,l={...defaultEvents,...e.events},u=handleTwilioMessages({config:e,onText:a}),d=handleTwilioVoice({config:e,onVoice:s,routes:i}),f=handleTwilioTranscription({config:e,onVoiceTranscription:c,routes:i});return defineChannel({kindHint:`twilio`,state:{from:null,to:null,lastCallSid:null,lastMessageSid:null},metadata(e){return{from:e.from,lastCallSid:e.lastCallSid??null,lastMessageSid:e.lastMessageSid??null,to:e.to}},context(t,n){return rebuildTwilioContext(t,n,e)},routes:[GET(i.messages,u),POST(i.messages,u),GET(i.voice,d),POST(i.voice,d),GET(i.transcription,f),POST(i.transcription,f)],async receive(t,{send:n}){let r=readString(t.target.phoneNumber);if(!r)throw Error(`twilioChannel().receive requires target.phoneNumber.`);let i=readString(t.target.from)??e.messaging?.from??null;return n(t.message,{auth:t.auth,continuationToken:twilioContinuationToken(r,i??void 0),state:{from:r,lastCallSid:null,lastMessageSid:null,to:i}})},events:l})}function handleTwilioMessages(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioTextMessage(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchText({config:e.config,message:a,onText:e.onText,send:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}}function handleTwilioVoice(e){return async t=>{let n=await verifyTwilioInbound(t,e.config);if(n===null)return new Response(`unauthorized`,{status:401});let r=parseTwilioVoiceCall(n.params);if(!r)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(r.from,e.config.allowFrom))return new Response(`forbidden`,{status:403});let i=await acceptVoiceCall({call:r,config:e.config,onVoice:e.onVoice});if(i===null)return new Response(`forbidden`,{status:403});let a=i??{};return gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),hints:a.hints??e.config.voice?.hints,language:a.language??e.config.voice?.language,profanityFilter:a.profanityFilter??e.config.voice?.profanityFilter,prompt:a.prompt??e.config.voice?.prompt??`Please say your message after the tone.`,speechModel:a.speechModel??e.config.voice?.speechModel,speechTimeout:a.speechTimeout??e.config.voice?.speechTimeout??`auto`,timeoutSeconds:a.timeoutSeconds??e.config.voice?.timeoutSeconds,voice:a.voice??e.config.voice?.voice})}}function handleTwilioTranscription(e){return async(t,{send:n,waitUntil:r})=>{let i=await verifyTwilioInbound(t,e.config);if(i===null)return new Response(`unauthorized`,{status:401});let a=parseTwilioVoiceTranscription(i.params);return a?await isAllowed(a.from,e.config.allowFrom)?(r(dispatchVoiceTranscription({config:e.config,onVoiceTranscription:e.onVoiceTranscription,send:n,transcription:a})),sayTwilioResponse(e.config.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildTwilioActionUrl(t,e.config,e.routes.transcription),language:e.config.voice?.language,prompt:e.config.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.config.voice?.speechTimeout??`auto`,timeoutSeconds:e.config.voice?.timeoutSeconds})}}function rebuildTwilioContext(e,t,n){return{state:e,twilio:buildTwilioHandle({callSid:e.lastCallSid??void 0,config:n,from:e.from??``,to:e.to??void 0})}}function buildTwilioHandle(e){let t=e.config.api,n=e.config.credentials,r=e.config.messaging?.from??e.to,o=e.config.messaging?.messagingServiceSid,c=e.config.messaging?.statusCallbackUrl;return{callSid:e.callSid,from:e.from,to:e.to,request(e,r){return callTwilioApi({apiBaseUrl:t?.apiBaseUrl,body:r,credentials:n,fetch:t?.fetch,path:e})},sendMessage(i,s){return sendTwilioMessage({apiBaseUrl:t?.apiBaseUrl,body:i,credentials:n,fetch:t?.fetch,from:s?.from??r,messagingServiceSid:s?.messagingServiceSid??o,statusCallbackUrl:s?.statusCallbackUrl??c,to:s?.to??e.from})},updateCall(e,r){return updateTwilioCall({apiBaseUrl:t?.apiBaseUrl,callSid:e,credentials:n,fetch:t?.fetch,twiml:r})}}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function dispatchText(e){let{message:t}=e,n={twilio:buildTwilioHandle({callSid:void 0,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onText(n,t)}catch(e){log.error(`text handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({channel:`text`,from:t.from,messageSid:t.messageSid,to:t.to});try{await e.send({message:t.body,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:null,lastMessageSid:t.messageSid??null,to:t.to??null}})}catch(e){log.error(`text delivery failed`,{error:e})}}async function acceptVoiceCall(e){let{call:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})};try{return await e.onVoice(n,t)}catch(e){return log.error(`voice handler failed`,{error:e}),null}}async function dispatchVoiceTranscription(e){let{transcription:t}=e,n={twilio:buildTwilioHandle({callSid:t.callSid,config:e.config,from:t.from,to:t.to})},r;try{r=await e.onVoiceTranscription(n,t)}catch(e){log.error(`voice transcription handler failed`,{error:e});return}if(r==null)return;let i=formatTwilioContextBlock({callSid:t.callSid,channel:`voice`,from:t.from,to:t.to});try{await e.send({message:t.text,context:[i]},{auth:r.auth,continuationToken:twilioContinuationToken(t.from,t.to),state:{from:t.from,lastCallSid:t.callSid??null,lastMessageSid:null,to:t.to??null}})}catch(e){log.error(`voice transcription delivery failed`,{error:e})}}async function isAllowed(e,t){let n=typeof t==`function`?await t():t;return n===`*`?!0:typeof n==`string`?n===e:n.includes(e)}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{twilioChannel};
|
|
@@ -1,37 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
*/
|
|
7
|
-
/** Options for rendering a voice `<Gather input="speech">` response. */
|
|
8
|
-
export interface TwilioGatherTwimlOptions {
|
|
9
|
-
/** Absolute callback URL that receives the speech result. */
|
|
10
|
-
readonly actionUrl: string;
|
|
11
|
-
/** Prompt spoken before Twilio starts speech recognition. */
|
|
12
|
-
readonly prompt: string;
|
|
13
|
-
/** Twilio `<Say voice>` used for the prompt, e.g. `Polly.Joanna-Neural`. */
|
|
14
|
-
readonly voice?: string;
|
|
15
|
-
/** BCP 47 language used for speech recognition and the nested `<Say>` prompt. */
|
|
16
|
-
readonly language?: string;
|
|
17
|
-
/** Twilio `<Gather speechModel>` used for speech recognition. */
|
|
18
|
-
readonly speechModel?: string;
|
|
19
|
-
/** Twilio `<Gather timeout>` in seconds. */
|
|
20
|
-
readonly timeoutSeconds?: number;
|
|
21
|
-
/** Twilio `<Gather speechTimeout>`, such as `"auto"` or a second count string. */
|
|
22
|
-
readonly speechTimeout?: string;
|
|
23
|
-
/** Twilio `<Gather hints>` for expected words or phrases. */
|
|
24
|
-
readonly hints?: string | readonly string[];
|
|
25
|
-
/** Twilio `<Gather profanityFilter>` toggle. */
|
|
26
|
-
readonly profanityFilter?: boolean;
|
|
27
|
-
}
|
|
28
|
-
/** Returns an empty TwiML response, useful for acknowledging inbound SMS without replying. */
|
|
29
|
-
export declare function emptyTwilioResponse(): Response;
|
|
30
|
-
/** Returns a TwiML response that speaks `message` and then ends the call. */
|
|
31
|
-
export declare function sayTwilioResponse(message: string): Response;
|
|
32
|
-
/** Returns a TwiML response that asks the caller to speak and posts the transcript to `actionUrl`. */
|
|
33
|
-
export declare function gatherSpeechTwilioResponse(options: TwilioGatherTwimlOptions): Response;
|
|
34
|
-
/** Wraps a TwiML string in a Twilio-compatible XML response. */
|
|
1
|
+
import { emptyTwilioResponse, escapeXml, gatherSpeechTwilioResponse, sayTwilioResponse, type TwilioGatherSpeechResponseOptions } from "#compiled/@chat-adapter/twilio/voice.js";
|
|
2
|
+
/** Options for rendering a Twilio `<Gather input="speech">` TwiML response. */
|
|
3
|
+
export type TwilioGatherTwimlOptions = TwilioGatherSpeechResponseOptions;
|
|
4
|
+
export { emptyTwilioResponse, escapeXml, gatherSpeechTwilioResponse, sayTwilioResponse };
|
|
5
|
+
/** Wraps a TwiML string in an XML `Response`. */
|
|
35
6
|
export declare function twimlResponse(twiml: string): Response;
|
|
36
|
-
/** Escapes the five XML predefined entities (`&`, `<`, `>`, `"`, `'`) for safe use in TwiML element content or attribute values. Note that `'` becomes `'`. */
|
|
37
|
-
export declare function escapeXml(value: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
import{emptyTwilioResponse,escapeXml,gatherSpeechTwilioResponse,sayTwilioResponse,twilioResponse}from"#compiled/@chat-adapter/twilio/voice.js";function twimlResponse(e){return twilioResponse(e)}export{emptyTwilioResponse,escapeXml,gatherSpeechTwilioResponse,sayTwilioResponse,twimlResponse};
|
|
@@ -1,43 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*/
|
|
8
|
-
/** Auth token, materialized either directly or from an async secret provider. */
|
|
9
|
-
export type TwilioAuthToken = string | (() => string | Promise<string>);
|
|
10
|
-
/** Public URL resolver used when the runtime request URL differs from Twilio's configured URL. */
|
|
11
|
-
export type TwilioWebhookUrl = string | ((request: Request) => string | Promise<string>);
|
|
12
|
-
/**
|
|
13
|
-
* Parsed and verified Twilio webhook body.
|
|
14
|
-
*
|
|
15
|
-
* `params` contains every form parameter Twilio sent. Signature
|
|
16
|
-
* validation happens before the channel reads any business fields.
|
|
17
|
-
*/
|
|
18
|
-
export interface TwilioVerifiedRequest {
|
|
19
|
-
readonly body: string;
|
|
20
|
-
readonly params: URLSearchParams;
|
|
21
|
-
}
|
|
22
|
-
/** Options for {@link verifyTwilioRequest}. */
|
|
1
|
+
import { type TwilioCredential } from "#compiled/@chat-adapter/twilio/api.js";
|
|
2
|
+
import { type TwilioVerifiedRequest, type TwilioWebhookUrl } from "#compiled/@chat-adapter/twilio/webhook.js";
|
|
3
|
+
/** Twilio auth token, materialized directly or from an async secret provider. */
|
|
4
|
+
export type TwilioAuthToken = TwilioCredential;
|
|
5
|
+
export type { TwilioVerifiedRequest, TwilioWebhookUrl };
|
|
6
|
+
/** Options for verifying Twilio inbound webhooks. */
|
|
23
7
|
export interface TwilioVerifyOptions {
|
|
24
|
-
/** Auth token used to verify the signature.
|
|
8
|
+
/** Auth token used to verify the signature. Defaults to `TWILIO_AUTH_TOKEN`. */
|
|
25
9
|
readonly authToken: TwilioAuthToken | undefined;
|
|
26
|
-
/** Public URL Twilio signed.
|
|
10
|
+
/** Public URL Twilio signed. Set this when a proxy or tunnel rewrites `request.url`. */
|
|
27
11
|
readonly webhookUrl?: TwilioWebhookUrl;
|
|
28
12
|
}
|
|
29
13
|
/** Resolves a Twilio auth token, falling back to `TWILIO_AUTH_TOKEN`. */
|
|
30
14
|
export declare function resolveTwilioAuthToken(authToken?: TwilioAuthToken): Promise<string>;
|
|
31
15
|
/**
|
|
32
|
-
* Verifies an inbound Twilio webhook and returns the raw body plus parsed
|
|
33
|
-
*
|
|
34
|
-
* Consumes the request body, so the passed `Request` cannot be re-read afterward.
|
|
35
|
-
* The signed URL comes from `options.webhookUrl` (falling back to `request.url`).
|
|
36
|
-
* Set `webhookUrl` when a proxy or tunnel rewrites the URL. A rewritten URL causes
|
|
37
|
-
* the signed payload to differ, so the signature check fails.
|
|
16
|
+
* Verifies an inbound Twilio webhook and returns the raw body plus parsed params.
|
|
38
17
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
18
|
+
* This preserves Eve's existing error messages while delegating signature
|
|
19
|
+
* semantics to the Chat SDK Twilio primitive.
|
|
41
20
|
*/
|
|
42
21
|
export declare function verifyTwilioRequest(request: Request, options: TwilioVerifyOptions): Promise<TwilioVerifiedRequest>;
|
|
43
22
|
/** Computes Twilio's HMAC-SHA1 request signature. */
|
|
@@ -46,5 +25,5 @@ export declare function signTwilioRequest(input: {
|
|
|
46
25
|
readonly url: string;
|
|
47
26
|
readonly params: URLSearchParams;
|
|
48
27
|
}): string;
|
|
49
|
-
/** Builds the string Twilio signs for a
|
|
28
|
+
/** Builds the string Twilio signs for a webhook request. */
|
|
50
29
|
export declare function buildTwilioSignatureBase(url: string, params: URLSearchParams): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{createHmac}from"node:crypto";import{TwilioApiError,resolveTwilioCredential}from"#compiled/@chat-adapter/twilio/api.js";import{TwilioWebhookVerificationError,twilioSignatureBase,verifyTwilioRequest as verifyTwilioRequest$1}from"#compiled/@chat-adapter/twilio/webhook.js";async function resolveTwilioAuthToken(e){try{return await resolveTwilioCredential(e,`TWILIO_AUTH_TOKEN`)}catch(e){throw e instanceof TwilioApiError&&e.status===0?Error(`TWILIO_AUTH_TOKEN is required.`):e}}async function verifyTwilioRequest(e,t){if(!e.headers.get(`x-twilio-signature`))throw Error(`twilioChannel: inbound request missing X-Twilio-Signature.`);let n=await resolveTwilioAuthToken(t.authToken);try{return await verifyTwilioRequest$1(e,{authToken:n,webhookUrl:t.webhookUrl})}catch(e){throw e instanceof TwilioWebhookVerificationError?Error(`twilioChannel: inbound request signature mismatch.`):e}}function signTwilioRequest(t){let n=buildTwilioSignatureBase(t.url,t.params);return createHmac(`sha1`,t.authToken).update(n).digest(`base64`)}function buildTwilioSignatureBase(e,t){return twilioSignatureBase(e,t)}export{buildTwilioSignatureBase,resolveTwilioAuthToken,signTwilioRequest,verifyTwilioRequest};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{pathExists,writeTextFile}from"../files.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{basename,join,resolve}from"node:path";import{mkdir,readdir,stat}from"node:fs/promises";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,ALLOWED_CREATE_IN_PLACE_ENTRIES=new Set([`.DS_Store`,`.git`,`.gitkeep`,`.hg`]),DEFAULT_AI_PACKAGE_VERSION=`^7.0.0`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.2.2`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.19.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e){return{"agent/agent.ts":BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
|
|
2
2
|
|
|
3
3
|
export default defineAgent({
|
|
4
4
|
model: "__EVE_INIT_MODEL__",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
|
|
6
6
|
"keywords": [
|
|
@@ -216,6 +216,11 @@
|
|
|
216
216
|
"import": "./dist/src/public/channels/slack/index.js",
|
|
217
217
|
"default": "./dist/src/public/channels/slack/index.js"
|
|
218
218
|
},
|
|
219
|
+
"./channels/chat-sdk": {
|
|
220
|
+
"types": "./dist/src/public/channels/chat-sdk/index.d.ts",
|
|
221
|
+
"import": "./dist/src/public/channels/chat-sdk/index.js",
|
|
222
|
+
"default": "./dist/src/public/channels/chat-sdk/index.js"
|
|
223
|
+
},
|
|
219
224
|
"./channels/github": {
|
|
220
225
|
"types": "./dist/src/public/channels/github/index.d.ts",
|
|
221
226
|
"import": "./dist/src/public/channels/github/index.js",
|
|
@@ -276,6 +281,7 @@
|
|
|
276
281
|
"@ai-sdk/provider-utils": "^5.0.0",
|
|
277
282
|
"@chat-adapter/slack": "4.31.0",
|
|
278
283
|
"@chat-adapter/state-memory": "4.31.0",
|
|
284
|
+
"@chat-adapter/twilio": "4.31.0",
|
|
279
285
|
"@clack/core": "1.3.1",
|
|
280
286
|
"@nuxt/kit": "^4.0.0",
|
|
281
287
|
"@standard-schema/spec": "1.1.0",
|