experimental-ash 0.51.0 → 0.52.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 +8 -0
- package/dist/docs/public/advanced/instrumentation.md +87 -119
- package/dist/docs/public/advanced/typescript-api.md +4 -2
- package/dist/docs/public/channels/discord.mdx +2 -2
- package/dist/docs/public/channels/index.md +4 -4
- package/dist/docs/public/channels/teams.mdx +1 -1
- package/dist/docs/public/channels/telegram.mdx +2 -2
- package/dist/docs/public/meta.json +1 -0
- package/dist/docs/public/onboarding.md +119 -0
- package/dist/docs/public/schedules.mdx +4 -4
- package/dist/src/channel/compiled-channel.d.ts +2 -2
- package/dist/src/channel/cross-channel-receive.d.ts +6 -6
- package/dist/src/channel/cross-channel-receive.js +1 -1
- package/dist/src/channel/receive-target.d.ts +17 -0
- package/dist/src/cli/commands/channels.d.ts +2 -0
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/info.d.ts +46 -1
- package/dist/src/cli/commands/info.js +2 -2
- package/dist/src/cli/run.d.ts +3 -1
- package/dist/src/cli/run.js +2 -2
- package/dist/src/harness/{instrumentation-metadata.d.ts → instrumentation-runtime-context.d.ts} +2 -2
- package/dist/src/harness/instrumentation-runtime-context.js +1 -0
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/instrumentation.d.ts +8 -7
- package/dist/src/internal/instrumentation.js +1 -1
- package/dist/src/packages/ash-scaffold/src/channels.js +2 -2
- package/dist/src/packages/ash-scaffold/src/human-action.js +1 -0
- package/dist/src/packages/ash-scaffold/src/index.js +1 -1
- package/dist/src/packages/ash-scaffold/src/steps/run-add-to-agent.js +1 -1
- package/dist/src/packages/ash-scaffold/src/steps/setup-slackbot.js +1 -1
- package/dist/src/public/channels/discord/discordChannel.d.ts +3 -3
- package/dist/src/public/channels/discord/discordChannel.js +1 -1
- package/dist/src/public/channels/discord/index.d.ts +1 -1
- package/dist/src/public/channels/slack/index.d.ts +1 -1
- package/dist/src/public/channels/slack/slackChannel.d.ts +4 -3
- package/dist/src/public/channels/slack/slackChannel.js +1 -1
- package/dist/src/public/channels/teams/index.d.ts +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -3
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/public/channels/telegram/index.d.ts +1 -1
- package/dist/src/public/channels/telegram/telegramChannel.d.ts +3 -3
- package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
- package/dist/src/public/channels/twilio/index.d.ts +1 -1
- package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -3
- package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
- package/dist/src/public/definitions/defineChannel.d.ts +8 -8
- package/dist/src/public/definitions/schedule.d.ts +2 -2
- package/dist/src/public/instrumentation/index.d.ts +21 -11
- package/dist/src/public/schedules/index.d.ts +1 -1
- package/package.json +1 -1
- package/dist/src/channel/receive-args.d.ts +0 -17
- package/dist/src/harness/instrumentation-metadata.js +0 -1
- /package/dist/src/channel/{receive-args.js → receive-target.js} +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ModelMessage } from "ai";
|
|
2
|
-
export { slackChannel, type SlackApiResponse, type SlackBotToken, type SlackChannel, type SlackChannelConfig, type SlackChannelCredentials, type SlackChannelEvents, type SlackChannelState, type SlackContext, type SlackEventContext, type SlackHandle, type SlackInboundResult, type SlackInboundResultOrPromise, type SlackInstrumentationMetadata, type SlackInitialMessage, type SlackInteractionAction, type SlackMentionResult, type SlackMentionResultOrPromise, type
|
|
2
|
+
export { slackChannel, type SlackApiResponse, type SlackBotToken, type SlackChannel, type SlackChannelConfig, type SlackChannelCredentials, type SlackChannelEvents, type SlackChannelState, type SlackContext, type SlackEventContext, type SlackHandle, type SlackInboundResult, type SlackInboundResultOrPromise, type SlackInstrumentationMetadata, type SlackInitialMessage, type SlackInteractionAction, type SlackMentionResult, type SlackMentionResultOrPromise, type SlackReceiveTarget, type SlackThread, type SlackWebhookVerifier, } from "#public/channels/slack/slackChannel.js";
|
|
3
3
|
export type { SlackAttachment, SlackAuthor, SlackInboundContext, SlackMessage, } from "#public/channels/slack/inbound.js";
|
|
4
4
|
export { slackContinuationToken, type SlackPostInput, type SlackPostedMessage, type SlackThreadMessage, type SlackUploadFilesOptions, type SlackUploadFilesResult, } from "#public/channels/slack/api.js";
|
|
5
5
|
export { defaultSlackAuth } from "#public/channels/slack/defaults.js";
|
|
@@ -99,7 +99,8 @@ export interface SlackChannelCredentials {
|
|
|
99
99
|
*/
|
|
100
100
|
readonly webhookVerifier?: SlackWebhookVerifier;
|
|
101
101
|
}
|
|
102
|
-
|
|
102
|
+
/** Target accepted by `receive(slack, { target })` for proactive sessions. */
|
|
103
|
+
export interface SlackReceiveTarget {
|
|
103
104
|
readonly channelId: string;
|
|
104
105
|
readonly threadTs?: string;
|
|
105
106
|
/**
|
|
@@ -113,7 +114,7 @@ export interface SlackReceiveArgs {
|
|
|
113
114
|
}
|
|
114
115
|
/**
|
|
115
116
|
* Pre-agent post issued by `slackChannel().receive` when the caller
|
|
116
|
-
* provides `
|
|
117
|
+
* provides `target.initialMessage`. The shape mirrors `ctx.thread.post`'s
|
|
117
118
|
* card variant so the same `Card({...})` construction can be reused.
|
|
118
119
|
*/
|
|
119
120
|
export interface SlackInitialMessage {
|
|
@@ -288,7 +289,7 @@ export interface SlackChannelConfig {
|
|
|
288
289
|
* default-export a `slackChannel(...)` call under `declaration: true`
|
|
289
290
|
* without TypeScript falling back to an internal path for `Channel`.
|
|
290
291
|
*/
|
|
291
|
-
export interface SlackChannel extends Channel<SlackChannelState,
|
|
292
|
+
export interface SlackChannel extends Channel<SlackChannelState, SlackReceiveTarget, SlackInstrumentationMetadata> {
|
|
292
293
|
}
|
|
293
294
|
/**
|
|
294
295
|
* Slack channel factory. Wires up the Slack webhook route, mention
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{formatSlackContextBlock,parseAppMentionEvent,parseDirectMessageEvent}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),l=createSlackFetchFile({botToken:e.credentials?.botToken}),u=e.onAppMention??defaultOnAppMention,d=e.onDirectMessage??defaultOnDirectMessage,f={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler()};return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,pendingAuthMessageTs:{}},fetchFile:l,metadata(e){return{channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);return a===null?new Response(`unauthorized`,{status:401}):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(a,{send:r,waitUntil:i},{config:e}):handleEventPost({body:a,send:r,waitUntil:i,onAppMention:u,onDirectMessage:d,uploadPolicy:t,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{buildSlackBinding,slackContinuationToken}from"#public/channels/slack/api.js";import{defaultEvents,defaultInputRequestedHandler,defaultOnAppMention,defaultOnDirectMessage}from"#public/channels/slack/defaults.js";import{buildSlackTurnMessage,collectInboundFileParts,createSlackFetchFile}from"#public/channels/slack/attachments.js";import{formatSlackContextBlock,parseAppMentionEvent,parseDirectMessageEvent}from"#public/channels/slack/inbound.js";import{SLACK_CHANNEL_DEFAULT_ROUTE}from"#public/channels/slack/constants.js";import{handleInteractionPost}from"#public/channels/slack/interactions.js";import{verifySlackRequest}from"#public/channels/slack/verify.js";const log=createLogger(`slack.channel`);function rebuildSlackContext(e,t,n){let{thread:r,slack:i}=buildSlackBinding({botToken:n?.botToken,channelId:e.channelId??``,threadTs:e.threadTs??``,teamId:e.teamId??void 0,onThreadTsChanged(n){e.threadTs=n,e.channelId&&t.setContinuationToken(slackContinuationToken(e.channelId,n))}});return{thread:r,slack:i,state:e}}function slackChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),l=createSlackFetchFile({botToken:e.credentials?.botToken}),u=e.onAppMention??defaultOnAppMention,d=e.onDirectMessage??defaultOnDirectMessage,f={...defaultEvents,...e.events,"input.requested":e.events?.[`input.requested`]??defaultInputRequestedHandler()};return defineChannel({kindHint:`slack`,state:{channelId:null,threadTs:null,teamId:null,triggeringUserId:null,pendingToolCallMessage:null,pendingAuthMessageTs:{}},fetchFile:l,metadata(e){return{channelId:e.channelId,teamId:e.teamId,threadTs:e.threadTs,triggeringUserId:e.triggeringUserId??null}},context(t,n){return rebuildSlackContext(t,n,e.credentials)},routes:[POST(e.route??SLACK_CHANNEL_DEFAULT_ROUTE,async(n,{send:r,waitUntil:i})=>{let a=await verifyInbound(n,e.credentials);return a===null?new Response(`unauthorized`,{status:401}):(n.headers.get(`content-type`)??``).includes(`application/x-www-form-urlencoded`)?handleInteractionPost(a,{send:r,waitUntil:i},{config:e}):handleEventPost({body:a,send:r,waitUntil:i,onAppMention:u,onDirectMessage:d,uploadPolicy:t,credentials:e.credentials})})],async receive(t,{send:n}){let r=t.target,i=r.channelId;if(!i||typeof i!=`string`)throw Error(`slackChannel().receive requires target.channelId.`);let o=typeof r.threadTs==`string`?r.threadTs:``,s=r.initialMessage;if(s&&o.length>0)throw Error("slackChannel().receive: `threadTs` and `initialMessage` are mutually exclusive.");let c=o;if(s){let{thread:t}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:i,threadTs:``,teamId:void 0}),n={card:s.card};s.fallbackText!==void 0&&(n.fallbackText=s.fallbackText),c=(await t.post(n)).id}return n(t.message,{auth:t.auth,continuationToken:slackContinuationToken(i,c),state:{channelId:i,threadTs:c||null,teamId:null,triggeringUserId:null}})},events:f})}async function handleEventPost(e){let t;try{t=JSON.parse(e.body)}catch(e){return log.warn(`inbound webhook body is not valid JSON`,{error:e}),new Response(`ok`)}if(typeof t.challenge==`string`)return new Response(t.challenge,{status:200,headers:{"content-type":`text/plain`}});let n=parseAppMentionEvent(t);if(n)return e.waitUntil(dispatchInboundMessage({kind:`app_mention`,message:n,handler:e.onAppMention,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`);let r=parseDirectMessageEvent(t);return r&&e.waitUntil(dispatchInboundMessage({kind:`direct_message`,message:r,handler:e.onDirectMessage,send:e.send,uploadPolicy:e.uploadPolicy,credentials:e.credentials})),new Response(`ok`)}async function verifyInbound(e,t){try{return await verifySlackRequest(e,{signingSecret:t?.signingSecret??(t?.webhookVerifier?void 0:process.env.SLACK_SIGNING_SECRET),webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`slack inbound verification failed`,{error:e}),null}}async function dispatchInboundMessage(e){let{message:n,kind:r}=e,{thread:i,slack:o}=buildSlackBinding({botToken:e.credentials?.botToken,channelId:n.channelId,threadTs:n.threadTs,teamId:n.teamId}),s={thread:i,slack:o},c;try{c=await e.handler(s,n)}catch(e){logError(log,`${r} handler failed`,e,{channelId:n.channelId});return}if(c!=null)try{let t=await collectInboundFileParts({mention:n,thread:i,policy:e.uploadPolicy}),r=buildSlackTurnMessage(n.markdown,t),a={channelId:n.channelId,fullName:n.author?.fullName,teamId:n.teamId,threadTs:n.threadTs,userId:n.author?.userId??``,userName:n.author?.userName},o=c.context??[];await e.send({message:r,context:[formatSlackContextBlock(a),...o]},{auth:c.auth,continuationToken:slackContinuationToken(n.channelId,n.threadTs),state:{channelId:n.channelId,threadTs:n.threadTs,teamId:n.teamId??null,triggeringUserId:a.userId||null}})}catch(e){logError(log,`${r} delivery failed`,e,{channelId:n.channelId})}}export{slackChannel};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ModelMessage } from "ai";
|
|
2
|
-
export { teamsChannel, type TeamsChannel, type TeamsChannelConfig, type TeamsChannelCredentials, type TeamsChannelEvents, type TeamsChannelState, type TeamsContext, type TeamsEventContext, type TeamsHandle, type TeamsInboundResult, type TeamsInboundResultOrPromise, type TeamsInvokeResult, type TeamsInvokeResultOrPromise, type
|
|
2
|
+
export { teamsChannel, type TeamsChannel, type TeamsChannelConfig, type TeamsChannelCredentials, type TeamsChannelEvents, type TeamsChannelState, type TeamsContext, type TeamsEventContext, type TeamsHandle, type TeamsInboundResult, type TeamsInboundResultOrPromise, type TeamsInvokeResult, type TeamsInvokeResultOrPromise, type TeamsReceiveTarget, type TeamsRequestOptions, type TeamsThread, } from "#public/channels/teams/teamsChannel.js";
|
|
3
3
|
export { callTeamsConnectorApi, normalizeTeamsPostInput, replyToTeamsActivity, resolveTeamsAccessToken, resolveTeamsAppId, resolveTeamsAppPassword, resolveTeamsTenantId, sendTeamsActivity, splitTeamsMessageText, teamsContinuationToken, triggerTeamsTypingIndicator, updateTeamsActivity, TEAMS_MESSAGE_TEXT_MAX_LENGTH, type TeamsAccessTokenResult, type TeamsApiOptions, type TeamsApiResponse, type TeamsAppId, type TeamsAppPassword, type TeamsAttachment, type TeamsChannelAccount, type TeamsCredentials, type TeamsFetch, type TeamsMention, type TeamsMessageBody, type TeamsOutboundActivity, type TeamsPostedActivity, type TeamsTenantId, type TeamsTokenProvider, } from "#public/channels/teams/api.js";
|
|
4
4
|
export { formatTeamsContextBlock, isTeamsPersonalMessage, parseTeamsActivity, teamsThreadRootActivityId, type TeamsActivity, type TeamsActivityBase, type TeamsConversationAccount, type TeamsConversationScope, type TeamsConversationUpdateActivity, type TeamsInboundContext, type TeamsInvokeActivity, type TeamsMessageActivity, } from "#public/channels/teams/inbound.js";
|
|
5
5
|
export { deriveTeamsInputResponses, isTeamsInputResponseActivity, renderAnsweredInputRequestMessage, renderInputRequestAttachment, renderInputRequestMessage, teamsInvokeResponse, TEAMS_ADAPTIVE_CARD_CONTENT_TYPE, TEAMS_HITL_CHOICE_INPUT_ID, TEAMS_HITL_DATA_KEY, TEAMS_HITL_FREEFORM_INPUT_ID, } from "#public/channels/teams/hitl.js";
|
|
@@ -57,8 +57,8 @@ export interface TeamsChannelCredentials extends TeamsCredentials {
|
|
|
57
57
|
*/
|
|
58
58
|
readonly webhookVerifier?: TeamsWebhookVerifier;
|
|
59
59
|
}
|
|
60
|
-
/**
|
|
61
|
-
export interface
|
|
60
|
+
/** Target accepted by `receive(teams, { target })` for proactive sessions. */
|
|
61
|
+
export interface TeamsReceiveTarget {
|
|
62
62
|
readonly channelId?: string;
|
|
63
63
|
readonly conversationId: string;
|
|
64
64
|
readonly conversationType?: string;
|
|
@@ -156,7 +156,7 @@ export interface TeamsRequestOptions {
|
|
|
156
156
|
readonly method?: "DELETE" | "GET" | "POST" | "PUT";
|
|
157
157
|
}
|
|
158
158
|
/** Concrete return type of {@link teamsChannel}. */
|
|
159
|
-
export interface TeamsChannel extends Channel<TeamsChannelState,
|
|
159
|
+
export interface TeamsChannel extends Channel<TeamsChannelState, TeamsReceiveTarget> {
|
|
160
160
|
}
|
|
161
161
|
/** Teams channel factory for Bot Framework Activities and proactive messages. */
|
|
162
162
|
export declare function teamsChannel(config?: TeamsChannelConfig): TeamsChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),a=e.onMessage??defaultOnMessage,o={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/ash/v1/teams`,async(r,{send:i,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let l=parseTeamsActivity(c);return l===null?teamsOk():l.type===`message`?(o(dispatchMessage({activity:l,config:e,filesPolicy:t,onMessage:a,send:i})),teamsOk()):l.type===`invoke`?handleInvoke({activity:l,config:e,send:i,waitUntil:o}):teamsOk()})],async receive(t,{send:n}){let r=t.
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),a=e.onMessage??defaultOnMessage,o={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/ash/v1/teams`,async(r,{send:i,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let l=parseTeamsActivity(c);return l===null?teamsOk():l.type===`message`?(o(dispatchMessage({activity:l,config:e,filesPolicy:t,onMessage:a,send:i})),teamsOk()):l.type===`invoke`?handleInvoke({activity:l,config:e,send:i,waitUntil:o}):teamsOk()})],async receive(t,{send:n}){let r=t.target,i=readString(r.serviceUrl),a=readString(r.conversationId);if(!i||!a)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let o=readString(r.conversationType)??null,s=readString(r.replyToActivityId)??null,c=r.initialMessage;if(c!==void 0&&s!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readString(r.channelId)??null,conversationId:a,conversationType:o,replyToActivityId:s,serviceUrl:i,teamId:readString(r.teamId)??null,tenantId:readString(r.tenantId)??null};if(c!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(c);o!==`personal`&&t.id&&(s=t.id,u.replyToActivityId=t.id)}return n(t.message,{auth:t.auth,continuationToken:teamsContinuationToken({conversationId:a,replyToActivityId:s,tenantId:u.tenantId}),state:u})},events:o})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.setContinuationToken(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let o=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:o.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildOutboundActivity(t,i),credentials:r,activityId:e,conversationId:a.conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r;try{r=await e.onMessage(n,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(r==null)return;let i=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),a=buildTeamsTurnMessage(e.activity.text,i),o={activityId:e.activity.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},s=r.context??[];try{await e.send({message:a,context:[formatTeamsContextBlock(o),...s]},{auth:r.auth,continuationToken:stateToken(t),state:t})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,send:e.send})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity);try{await e.send({inputResponses:t},{auth:null,continuationToken:stateToken(n),state:n})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:teamsThreadRootActivityId(e),serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function mergeChannelData(e,t){let r={...t};return e.tenantId&&(r.tenant={id:e.tenantId}),e.teamId&&(r.team={id:e.teamId}),e.channelId&&(r.channel={id:e.channelId}),Object.keys(r).length>0?parseJsonObject(r):void 0}function teamsOk(){return new Response(`ok`,{status:200})}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{teamsChannel};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export type { ModelMessage } from "ai";
|
|
2
|
-
export { telegramChannel, type TelegramChannel, type TelegramChannelConfig, type TelegramChannelCredentials, type TelegramChannelEvents, type TelegramChannelState, type TelegramContext, type TelegramEventContext, type TelegramHandle, type TelegramInboundResult, type TelegramInboundResultOrPromise, type
|
|
2
|
+
export { telegramChannel, type TelegramChannel, type TelegramChannelConfig, type TelegramChannelCredentials, type TelegramChannelEvents, type TelegramChannelState, type TelegramContext, type TelegramEventContext, type TelegramHandle, type TelegramInboundResult, type TelegramInboundResultOrPromise, type TelegramReceiveTarget, } from "#public/channels/telegram/telegramChannel.js";
|
|
3
3
|
export { callTelegramApi, answerTelegramCallbackQuery, downloadTelegramFile, editTelegramMessageReplyMarkup, getTelegramFile, resolveTelegramBotToken, sendTelegramChatAction, sendTelegramMessage, splitTelegramMessageText, telegramContinuationToken, TELEGRAM_MESSAGE_TEXT_MAX_LENGTH, type TelegramApiOptions, type TelegramApiResponse, type TelegramBotToken, type TelegramCredentials, type TelegramFetch, type TelegramMessageBody, type TelegramMessageResult, } from "#public/channels/telegram/api.js";
|
|
4
4
|
export { formatTelegramContextBlock, parseTelegramUpdate, type TelegramAttachment, type TelegramCallbackQuery, type TelegramChat, type TelegramChatType, type TelegramInboundContext, type TelegramMessage, type TelegramMessageReference, type TelegramUpdate, type TelegramUser, } from "#public/channels/telegram/inbound.js";
|
|
5
5
|
export { TELEGRAM_CALLBACK_RESPONSE_PREFIX, TELEGRAM_HITL_CALLBACK_PREFIX, TELEGRAM_REPLY_RESPONSE_PREFIX, isTelegramSyntheticResponse, registerTelegramFreeformPrompt, renderTelegramInputRequest, resolveTelegramInputResponses, telegramCallbackInputResponse, telegramReplyInputResponse, type TelegramHitlState, type TelegramInputRequestMessage, } from "#public/channels/telegram/hitl.js";
|
|
@@ -51,8 +51,8 @@ export interface TelegramChannelCredentials extends TelegramCredentials {
|
|
|
51
51
|
/** Custom inbound webhook verifier for forwarded webhooks. */
|
|
52
52
|
readonly webhookVerifier?: TelegramWebhookVerifier;
|
|
53
53
|
}
|
|
54
|
-
/**
|
|
55
|
-
export interface
|
|
54
|
+
/** Target accepted by `receive(telegram, { target })` for proactive sessions. */
|
|
55
|
+
export interface TelegramReceiveTarget {
|
|
56
56
|
readonly chatId: number | string;
|
|
57
57
|
readonly conversationId?: number | string;
|
|
58
58
|
readonly initialMessage?: string | TelegramMessageBody;
|
|
@@ -120,7 +120,7 @@ export interface TelegramHandle {
|
|
|
120
120
|
}): Promise<TelegramApiResponse>;
|
|
121
121
|
}
|
|
122
122
|
/** Concrete return type of {@link telegramChannel}. */
|
|
123
|
-
export interface TelegramChannel extends Channel<TelegramChannelState,
|
|
123
|
+
export interface TelegramChannel extends Channel<TelegramChannelState, TelegramReceiveTarget> {
|
|
124
124
|
}
|
|
125
125
|
/** Telegram channel factory for webhook updates and proactive messages. */
|
|
126
126
|
export declare function telegramChannel(config?: TelegramChannelConfig): TelegramChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponse}from"#public/channels/telegram/hitl.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{defaultEvents,defaultOnMessage}from"#public/channels/telegram/defaults.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},c=defineChannel({kindHint:`telegram`,state:initialTelegramState(e.botUsername),fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/ash/v1/telegram`,async(r,{send:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,send:a,uploadPolicy:t})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,send:a})),new Response(`ok`))})],async receive(t,{send:n}){let r=t.
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{isCompiledChannel}from"#channel/compiled-channel.js";import{defaultDeliverResult}from"#channel/adapter.js";import{parseJsonObject}from"#shared/json.js";import{mergeUploadPolicy}from"#public/channels/upload-policy.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{answerTelegramCallbackQuery,callTelegramApi,editTelegramMessageReplyMarkup,sendTelegramChatAction,sendTelegramMessage,splitTelegramMessageText,telegramContinuationToken}from"#public/channels/telegram/api.js";import{TELEGRAM_HITL_CALLBACK_PREFIX,isTelegramSyntheticResponse,resolveTelegramInputResponses,telegramCallbackInputResponse,telegramReplyInputResponse}from"#public/channels/telegram/hitl.js";import{formatTelegramContextBlock,parseTelegramUpdate}from"#public/channels/telegram/inbound.js";import{buildTelegramTurnMessage,collectTelegramFileParts,createTelegramFetchFile}from"#public/channels/telegram/attachments.js";import{defaultEvents,defaultOnMessage}from"#public/channels/telegram/defaults.js";import{verifyTelegramRequest}from"#public/channels/telegram/verify.js";const log=createLogger(`telegram.channel`);function telegramChannel(e={}){let t=mergeUploadPolicy(e.uploadPolicy),n=e.onMessage??defaultOnMessage,r={...defaultEvents,...e.events},c=defineChannel({kindHint:`telegram`,state:initialTelegramState(e.botUsername),fetchFile:createTelegramFetchFile({api:e.api,credentials:e.credentials,policy:t}),context(t,n){return rebuildTelegramContext(t,n,e)},routes:[POST(e.route??`/ash/v1/telegram`,async(r,{send:a,waitUntil:o})=>{let s=await verifyInbound(r,e.credentials);if(s===null)return new Response(`unauthorized`,{status:401});let c;try{c=parseJsonObject(JSON.parse(s))}catch(e){return log.warn(`inbound Telegram body is not valid JSON`,{error:e}),new Response(`ok`)}let l=parseTelegramUpdate(c);return l===null?new Response(`ok`):l.kind===`message`?(o(dispatchMessage({config:e,message:l.message,onMessage:n,send:a,uploadPolicy:t})),new Response(`ok`)):(o(dispatchCallbackQuery({config:e,query:l.callbackQuery,send:a})),new Response(`ok`))})],async receive(t,{send:n}){let r=t.target,i=readChatId(r.chatId);if(i===void 0)throw Error(`telegramChannel().receive requires target.chatId.`);let a=typeof r.messageThreadId==`number`?r.messageThreadId:void 0,o=readOptionalString(r.conversationId),s=r.initialMessage;if(s!==void 0&&o!==void 0)throw Error("telegramChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=o;return s!==void 0&&(c=(await buildTelegramHandle({config:e,state:{...initialTelegramState(e.botUsername),chatId:i,messageThreadId:a??null}}).sendMessage(s)).id||void 0),n(t.message,{auth:t.auth,continuationToken:telegramContinuationToken({chatId:i,conversationId:c,messageThreadId:a}),state:{...initialTelegramState(e.botUsername),chatId:i,conversationId:c??null,messageThreadId:a??null}})},events:r});return attachTelegramDeliver(c),c}function rebuildTelegramContext(e,t,n){return{state:e,telegram:buildTelegramHandle({config:n,session:t,state:e})}}function buildTelegramHandle(e){let n=e.config.api,r=e.state,i=e.config.credentials;function anchor(t){!t.id||r.chatType===`private`||(r.conversationId=t.id,r.chatId&&e.session?.setContinuationToken(telegramContinuationToken({chatId:r.chatId,conversationId:t.id,messageThreadId:r.messageThreadId??void 0})))}async function sendOne(e){let t=r.chatId??``;if(!t)throw Error(`telegramChannel: missing chat id for outbound message.`);let a=await sendTelegramMessage({apiBaseUrl:n?.apiBaseUrl,body:{...e,message_thread_id:e.message_thread_id??r.messageThreadId??void 0},credentials:i,fetch:n?.fetch,fileBaseUrl:n?.fileBaseUrl,chatId:t});return anchor(a),a}return{botUsername:r.botUsername??e.config.botUsername,chatId:r.chatId??``,chatType:r.chatType??void 0,conversationId:r.conversationId??void 0,messageThreadId:r.messageThreadId??void 0,answerCallbackQuery(e){return answerTelegramCallbackQuery({apiBaseUrl:n?.apiBaseUrl,callbackQueryId:e.callbackQueryId,credentials:i,fetch:n?.fetch,showAlert:e.showAlert,text:e.text})},editMessageReplyMarkup(e){let t=r.chatId??``;if(!t)throw Error(`telegramChannel: missing chat id for reply-markup edit.`);return editTelegramMessageReplyMarkup({apiBaseUrl:n?.apiBaseUrl,chatId:t,credentials:i,fetch:n?.fetch,messageId:e.messageId,replyMarkup:e.replyMarkup})},post(e){return postTelegramMessage(e,sendOne)},request(e,t){return callTelegramApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:i?.botToken,fetch:n?.fetch,method:e})},sendMessage(e){return postTelegramMessage(e,sendOne)},async startTyping(e=`typing`){let a=r.chatId??``;if(a)try{await sendTelegramChatAction({action:e,apiBaseUrl:n?.apiBaseUrl,chatId:a,credentials:i,fetch:n?.fetch,messageThreadId:r.messageThreadId??void 0})}catch(e){logError(log,`Telegram typing indicator failed — swallowed`,e,{chatId:a})}}}}async function postTelegramMessage(e,t){let n=typeof e==`string`?{text:e}:e,r=splitTelegramMessageText(n.text),i;for(let[e,a]of r.entries()){let r=await t(e===0?{...n,text:a}:{text:a});i===void 0&&(i=r)}return i??{id:``,raw:null}}async function verifyInbound(e,t){try{return await verifyTelegramRequest(e,{secretToken:t?.webhookVerifier?void 0:t?.webhookSecretToken,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`telegram inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){if(e.message.from?.isBot===!0)return;let t=stateFromMessage(e.message,e.config),n={telegram:buildTelegramHandle({config:e.config,state:t})},r;try{r=await e.onMessage(n,e.message)}catch(e){log.error(`message handler failed`,{error:e});return}if(r==null)return;let i=collectTelegramFileParts(e.message.attachments,e.uploadPolicy),a=buildTelegramTurnMessage(e.message,i),o=formatTelegramContextBlock({botUsername:e.config.botUsername,chatId:e.message.chat.id,chatTitle:e.message.chat.title,chatType:e.message.chat.type,messageId:e.message.messageId,messageThreadId:e.message.messageThreadId,userId:e.message.from?.id,username:e.message.from?.username}),s=r.context??[],c=e.message.text||e.message.caption,l=e.message.replyToMessage?.from?.isBot===!0&&c.trim().length>0?[telegramReplyInputResponse({messageId:e.message.replyToMessage.messageId,text:c})]:void 0;try{await e.send({inputResponses:l,message:a,context:[o,...s]},{auth:r.auth,continuationToken:continuationTokenFromState(t),state:t})}catch(e){log.error(`message delivery failed`,{error:e})}}async function dispatchCallbackQuery(e){let t=stateFromCallbackQuery(e.query,e.config),n={telegram:buildTelegramHandle({config:e.config,state:t})};if(e.query.data?.startsWith(TELEGRAM_HITL_CALLBACK_PREFIX)===!0){try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Answer received.`})}catch(e){log.warn(`Telegram callback-query acknowledgement failed`,{error:e})}if(!e.query.message||!t.chatId)return;try{await e.send({inputResponses:[telegramCallbackInputResponse(e.query.data)]},{auth:null,continuationToken:continuationTokenFromState(t),state:t})}catch(e){log.error(`callback query delivery failed`,{error:e})}return}if(e.config.onCallbackQuery!==void 0){try{await e.config.onCallbackQuery(n,e.query)}catch(e){log.error(`custom callback-query handler failed`,{error:e})}return}try{await n.telegram.answerCallbackQuery({callbackQueryId:e.query.id,text:`Unsupported action.`})}catch(e){log.warn(`Telegram unsupported callback-query acknowledgement failed`,{error:e})}}function attachTelegramDeliver(e){if(!isCompiledChannel(e))return;let t=e.adapter;t.deliver=(e,t)=>{let n=e.inputResponses??[];if(n.some(isTelegramSyntheticResponse)){let r=resolveTelegramInputResponses(t.state,n);return r.length>0?{inputResponses:r,context:e.context}:e.message===void 0?void 0:{message:e.message,context:e.context}}return defaultDeliverResult(e)}}function stateFromMessage(e,t){let n=e.chat.type===`private`;return{...initialTelegramState(t.botUsername),chatId:e.chat.id,chatType:e.chat.type,conversationId:n?null:conversationIdForMessage(e),messageThreadId:e.messageThreadId??null,triggeringUserId:e.from?.id??null}}function stateFromCallbackQuery(e,t){let n=e.message;if(!n)return{...initialTelegramState(t.botUsername),triggeringUserId:e.from.id};let r=n.chat.type===`private`;return{...initialTelegramState(t.botUsername),chatId:n.chat.id,chatType:n.chat.type,conversationId:r?null:n.messageId,messageThreadId:n.messageThreadId??null,triggeringUserId:e.from.id}}function conversationIdForMessage(e){return e.replyToMessage?.from?.isBot===!0?e.replyToMessage.messageId:e.messageId}function continuationTokenFromState(e){return telegramContinuationToken({chatId:e.chatId??``,conversationId:e.chatType===`private`?void 0:e.conversationId??void 0,messageThreadId:e.messageThreadId??void 0})}function initialTelegramState(e){return{botUsername:e??null,chatId:null,chatType:null,conversationId:null,hitlCallbacks:{},messageThreadId:null,nextHitlCallbackId:0,pendingFreeformReplies:{},triggeringUserId:null}}function readChatId(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}function readOptionalString(e){if(typeof e==`string`&&e.length>0)return e;if(typeof e==`number`&&Number.isFinite(e))return String(e)}export{telegramChannel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { twilioChannel, type TwilioAllowFrom, type TwilioChannel, type TwilioChannelConfig, type TwilioChannelCredentials, type TwilioChannelEvents, type TwilioChannelState, type TwilioContext, type TwilioEventContext, type TwilioHandle, type TwilioInboundResult, type TwilioInboundResultOrPromise, type TwilioInstrumentationMetadata, type TwilioMessagingConfig, type
|
|
1
|
+
export { twilioChannel, type TwilioAllowFrom, type TwilioChannel, type TwilioChannelConfig, type TwilioChannelCredentials, type TwilioChannelEvents, type TwilioChannelState, type TwilioContext, type TwilioEventContext, type TwilioHandle, type TwilioInboundResult, type TwilioInboundResultOrPromise, type TwilioInstrumentationMetadata, type TwilioMessagingConfig, type TwilioReceiveTarget, type TwilioSendMessageOptions, type TwilioVoiceConfig, type TwilioVoiceResult, type TwilioVoiceResultOrPromise, } from "#public/channels/twilio/twilioChannel.js";
|
|
2
2
|
export { callTwilioApi, resolveTwilioAccountSid, sendTwilioMessage, twilioContinuationToken, updateTwilioCall, type TwilioAccountSid, type TwilioApiOptions, type TwilioApiResponse, type TwilioCredentials, type TwilioFetch, type TwilioSendMessageInput, type TwilioUpdateCallInput, } from "#public/channels/twilio/api.js";
|
|
3
3
|
export type { TwilioInboundContext, TwilioTextMessage, TwilioVoiceCall, TwilioVoiceTranscription, } from "#public/channels/twilio/inbound.js";
|
|
4
4
|
export { emptyTwilioResponse, escapeXml, gatherSpeechTwilioResponse, sayTwilioResponse, twimlResponse, type TwilioGatherTwimlOptions, } from "#public/channels/twilio/twiml.js";
|
|
@@ -43,8 +43,8 @@ export interface TwilioInstrumentationMetadata extends Record<string, unknown> {
|
|
|
43
43
|
export interface TwilioChannelCredentials extends TwilioCredentials {
|
|
44
44
|
readonly authToken?: TwilioAuthToken;
|
|
45
45
|
}
|
|
46
|
-
/**
|
|
47
|
-
export interface
|
|
46
|
+
/** Target accepted by `receive(twilio, { target })` for proactive phone-number sessions. */
|
|
47
|
+
export interface TwilioReceiveTarget {
|
|
48
48
|
readonly phoneNumber: string;
|
|
49
49
|
/** Twilio sender included in the phone-pair continuation token. */
|
|
50
50
|
readonly from?: string;
|
|
@@ -183,7 +183,7 @@ export interface TwilioSendMessageOptions {
|
|
|
183
183
|
readonly statusCallbackUrl?: string;
|
|
184
184
|
}
|
|
185
185
|
/** Concrete return type of {@link twilioChannel}. */
|
|
186
|
-
export interface TwilioChannel extends Channel<TwilioChannelState,
|
|
186
|
+
export interface TwilioChannel extends Channel<TwilioChannelState, TwilioReceiveTarget, TwilioInstrumentationMetadata> {
|
|
187
187
|
}
|
|
188
188
|
/** Twilio channel factory for SMS and speech-transcribed inbound calls. */
|
|
189
189
|
export declare function twilioChannel(config: TwilioChannelConfig): TwilioChannel;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{verifyTwilioRequest}from"#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";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let r=buildRoutes(e.route??`/ash/v1/twilio`),i=e.onText??defaultOnText,a=e.onVoice??defaultOnVoice,s=e.onVoiceTranscription??defaultOnVoiceTranscription,l={...defaultEvents,...e.events};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:[POST(r.messages,async(t,{send:n,waitUntil:r})=>{let a=await verifyInbound(t,e);if(a===null)return new Response(`unauthorized`,{status:401});let o=parseTwilioTextMessage(a.params);return o?await isAllowed(o.from,e.allowFrom)?(r(dispatchText({config:e,message:o,onText:i,send:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}),POST(r.voice,async t=>{let n=await verifyInbound(t,e);if(n===null)return new Response(`unauthorized`,{status:401});let i=parseTwilioVoiceCall(n.params);if(!i)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(i.from,e.allowFrom))return new Response(`forbidden`,{status:403});let o=await acceptVoiceCall({call:i,config:e,onVoice:a});if(o===null)return new Response(`forbidden`,{status:403});let s=o??{};return gatherSpeechTwilioResponse({actionUrl:await buildActionUrl(t,e,r.transcription),hints:s.hints??e.voice?.hints,language:s.language??e.voice?.language,profanityFilter:s.profanityFilter??e.voice?.profanityFilter,prompt:s.prompt??e.voice?.prompt??`Please say your message after the tone.`,speechModel:s.speechModel??e.voice?.speechModel,speechTimeout:s.speechTimeout??e.voice?.speechTimeout??`auto`,timeoutSeconds:s.timeoutSeconds??e.voice?.timeoutSeconds,voice:s.voice??e.voice?.voice})}),POST(r.transcription,async(t,{send:n,waitUntil:i})=>{let a=await verifyInbound(t,e);if(a===null)return new Response(`unauthorized`,{status:401});let o=parseTwilioVoiceTranscription(a.params);return o?await isAllowed(o.from,e.allowFrom)?(i(dispatchVoiceTranscription({config:e,onVoiceTranscription:s,send:n,transcription:o})),sayTwilioResponse(e.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildActionUrl(t,e,r.transcription),language:e.voice?.language,prompt:e.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.voice?.speechTimeout??`auto`,timeoutSeconds:e.voice?.timeoutSeconds})})],async receive(t,{send:n}){let r=readString(t.
|
|
1
|
+
import{createLogger}from"#internal/logging.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import{verifyTwilioRequest}from"#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";const log=createLogger(`twilio.channel`);function twilioChannel(e){assertAllowFromConfigured(e);let r=buildRoutes(e.route??`/ash/v1/twilio`),i=e.onText??defaultOnText,a=e.onVoice??defaultOnVoice,s=e.onVoiceTranscription??defaultOnVoiceTranscription,l={...defaultEvents,...e.events};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:[POST(r.messages,async(t,{send:n,waitUntil:r})=>{let a=await verifyInbound(t,e);if(a===null)return new Response(`unauthorized`,{status:401});let o=parseTwilioTextMessage(a.params);return o?await isAllowed(o.from,e.allowFrom)?(r(dispatchText({config:e,message:o,onText:i,send:n})),emptyTwilioResponse()):new Response(`forbidden`,{status:403}):emptyTwilioResponse()}),POST(r.voice,async t=>{let n=await verifyInbound(t,e);if(n===null)return new Response(`unauthorized`,{status:401});let i=parseTwilioVoiceCall(n.params);if(!i)return sayTwilioResponse(`Missing caller information.`);if(!await isAllowed(i.from,e.allowFrom))return new Response(`forbidden`,{status:403});let o=await acceptVoiceCall({call:i,config:e,onVoice:a});if(o===null)return new Response(`forbidden`,{status:403});let s=o??{};return gatherSpeechTwilioResponse({actionUrl:await buildActionUrl(t,e,r.transcription),hints:s.hints??e.voice?.hints,language:s.language??e.voice?.language,profanityFilter:s.profanityFilter??e.voice?.profanityFilter,prompt:s.prompt??e.voice?.prompt??`Please say your message after the tone.`,speechModel:s.speechModel??e.voice?.speechModel,speechTimeout:s.speechTimeout??e.voice?.speechTimeout??`auto`,timeoutSeconds:s.timeoutSeconds??e.voice?.timeoutSeconds,voice:s.voice??e.voice?.voice})}),POST(r.transcription,async(t,{send:n,waitUntil:i})=>{let a=await verifyInbound(t,e);if(a===null)return new Response(`unauthorized`,{status:401});let o=parseTwilioVoiceTranscription(a.params);return o?await isAllowed(o.from,e.allowFrom)?(i(dispatchVoiceTranscription({config:e,onVoiceTranscription:s,send:n,transcription:o})),sayTwilioResponse(e.voice?.acknowledgement??`Thanks. I'll follow up by text.`)):new Response(`forbidden`,{status:403}):gatherSpeechTwilioResponse({actionUrl:await buildActionUrl(t,e,r.transcription),language:e.voice?.language,prompt:e.voice?.prompt??`Please say your message after the tone.`,speechTimeout:e.voice?.speechTimeout??`auto`,timeoutSeconds:e.voice?.timeoutSeconds})})],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 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 buildRoutes(e){let t=e.endsWith(`/`)?e.slice(0,-1):e;return{messages:`${t}/messages`,transcription:`${t}/voice/transcription`,voice:`${t}/voice`}}function assertAllowFromConfigured(e){if(e?.allowFrom===void 0)throw Error(`twilioChannel requires allowFrom. Use allowFrom: "*" to allow all numbers.`)}async function verifyInbound(e,t){try{return await verifyTwilioRequest(e,{authToken:t.credentials?.authToken,webhookUrl:t.webhookUrl})}catch(e){return log.warn(`twilio inbound verification failed`,{error:e}),null}}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)}async function buildActionUrl(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}/`}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{twilioChannel};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { FetchFileResult } from "#channel/adapter.js";
|
|
2
2
|
import { CHANNEL_SENTINEL } from "#channel/compiled-channel.js";
|
|
3
|
-
import type {
|
|
3
|
+
import type { TypedReceiveTarget } from "#channel/receive-target.js";
|
|
4
4
|
import type { SessionAuthContext } from "#channel/types.js";
|
|
5
5
|
import type { HandleMessageStreamEvent } from "#protocol/message.js";
|
|
6
6
|
import type { SessionContext } from "#public/definitions/callback-context.js";
|
|
@@ -49,12 +49,12 @@ export interface ChannelEvents<TCtx = void> {
|
|
|
49
49
|
* Input passed to a channel's `receive` callback when another channel or
|
|
50
50
|
* schedule proactively routes a message to it.
|
|
51
51
|
*/
|
|
52
|
-
export interface ReceiveInput<
|
|
52
|
+
export interface ReceiveInput<TReceiveTarget = Record<string, unknown>> {
|
|
53
53
|
readonly message: string;
|
|
54
|
-
readonly
|
|
54
|
+
readonly target: Readonly<TReceiveTarget>;
|
|
55
55
|
readonly auth: SessionAuthContext | null;
|
|
56
56
|
}
|
|
57
|
-
export interface ChannelDefinition<TState = undefined, TCtx = void,
|
|
57
|
+
export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> {
|
|
58
58
|
readonly state?: TState;
|
|
59
59
|
/**
|
|
60
60
|
* Builds the per-step channel context handed to `events` and
|
|
@@ -71,7 +71,7 @@ export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveArgs
|
|
|
71
71
|
*/
|
|
72
72
|
context?(state: NonNullable<TState>, session: SessionHandle): TCtx;
|
|
73
73
|
readonly routes: readonly RouteDefinition<TState>[];
|
|
74
|
-
receive?(input: ReceiveInput<
|
|
74
|
+
receive?(input: ReceiveInput<TReceiveTarget>, args: {
|
|
75
75
|
send: SendFn<TState>;
|
|
76
76
|
}): Promise<Session>;
|
|
77
77
|
readonly events?: ChannelEvents<TCtx>;
|
|
@@ -108,16 +108,16 @@ export interface ChannelDefinition<TState = undefined, TCtx = void, TReceiveArgs
|
|
|
108
108
|
*/
|
|
109
109
|
readonly kindHint?: string;
|
|
110
110
|
}
|
|
111
|
-
export interface Channel<TState = undefined,
|
|
111
|
+
export interface Channel<TState = undefined, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>> extends TypedReceiveTarget<TReceiveTarget> {
|
|
112
112
|
readonly __kind: typeof CHANNEL_SENTINEL;
|
|
113
113
|
readonly [CHANNEL_METADATA_TYPE]?: TMetadata;
|
|
114
114
|
readonly routes: readonly {
|
|
115
115
|
method: string;
|
|
116
116
|
path: string;
|
|
117
117
|
}[];
|
|
118
|
-
readonly receive?: (input: ReceiveInput<
|
|
118
|
+
readonly receive?: (input: ReceiveInput<TReceiveTarget>, args: {
|
|
119
119
|
send: SendFn<TState>;
|
|
120
120
|
}) => Promise<Session>;
|
|
121
121
|
}
|
|
122
122
|
export type InferChannelMetadata<TChannel> = TChannel extends Channel<any, any, infer TMetadata> ? TMetadata : Record<string, unknown>;
|
|
123
|
-
export declare function defineChannel<TState = undefined, TCtx = void,
|
|
123
|
+
export declare function defineChannel<TState = undefined, TCtx = void, TReceiveTarget = Record<string, unknown>, TMetadata extends Record<string, unknown> = Record<string, unknown>>(definition: ChannelDefinition<TState, TCtx, TReceiveTarget, TMetadata>): Channel<TState, TReceiveTarget, TMetadata>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { CrossChannelReceiveFn } from "#channel/cross-channel-receive.js";
|
|
2
2
|
import type { SessionAuthContext } from "#channel/types.js";
|
|
3
3
|
import type { ExactDefinition } from "#public/definitions/exact.js";
|
|
4
|
-
export type {
|
|
4
|
+
export type { InferReceiveTarget, TypedReceiveTarget } from "#channel/receive-target.js";
|
|
5
5
|
/**
|
|
6
6
|
* Arguments handed to {@link ScheduleDefinition.run}. Tight subset of
|
|
7
7
|
* `RouteHandlerArgs` — schedules can hand work off to a channel via
|
|
@@ -72,7 +72,7 @@ export type ScheduleDefinition = {
|
|
|
72
72
|
* async run({ receive, waitUntil, appAuth }) {
|
|
73
73
|
* waitUntil(receive(slack, {
|
|
74
74
|
* message: "Post the daily standup summary.",
|
|
75
|
-
*
|
|
75
|
+
* target: { channelId: "C0123ABC" },
|
|
76
76
|
* auth: appAuth,
|
|
77
77
|
* }));
|
|
78
78
|
* },
|
|
@@ -5,6 +5,7 @@ import type { ExactDefinition } from "#public/definitions/exact.js";
|
|
|
5
5
|
import type { ModelMessage, SystemModelMessage } from "ai";
|
|
6
6
|
import type { SessionAuthContext, SessionParent } from "#channel/types.js";
|
|
7
7
|
import type { Channel } from "#public/definitions/defineChannel.js";
|
|
8
|
+
import type { JsonObject } from "#shared/json.js";
|
|
8
9
|
/**
|
|
9
10
|
* Context passed to the {@link InstrumentationDefinition.setup} callback.
|
|
10
11
|
*/
|
|
@@ -18,12 +19,12 @@ export interface InstrumentationSetupContext {
|
|
|
18
19
|
readonly agentName: string;
|
|
19
20
|
}
|
|
20
21
|
/**
|
|
21
|
-
* User-authored
|
|
22
|
+
* User-authored runtime context values attached to AI SDK telemetry spans.
|
|
22
23
|
*
|
|
23
|
-
* Keys beginning with `ash.` are reserved for framework-owned
|
|
24
|
+
* Keys beginning with `ash.` are reserved for framework-owned context
|
|
24
25
|
* and are ignored when returned from authored instrumentation.
|
|
25
26
|
*/
|
|
26
|
-
export type
|
|
27
|
+
export type InstrumentationRuntimeContext = JsonObject;
|
|
27
28
|
/**
|
|
28
29
|
* Base channel metadata shape used by framework channel kinds.
|
|
29
30
|
*/
|
|
@@ -91,12 +92,12 @@ export interface InstrumentationModelInput {
|
|
|
91
92
|
readonly messages: readonly ModelMessage[];
|
|
92
93
|
}
|
|
93
94
|
/**
|
|
94
|
-
* Input passed to `
|
|
95
|
+
* Input passed to `events["step.started"]`.
|
|
95
96
|
*
|
|
96
97
|
* The callback runs after Ash has built the final model input for this
|
|
97
98
|
* model-call attempt and before the AI SDK model call is constructed.
|
|
98
99
|
*/
|
|
99
|
-
export interface
|
|
100
|
+
export interface InstrumentationStepStartedEventInput {
|
|
100
101
|
readonly channel: InstrumentationChannel;
|
|
101
102
|
readonly modelInput: InstrumentationModelInput;
|
|
102
103
|
readonly session: InstrumentationSession;
|
|
@@ -104,14 +105,23 @@ export interface InstrumentationStepStartedMetadataInput {
|
|
|
104
105
|
readonly turn: InstrumentationTurn;
|
|
105
106
|
}
|
|
106
107
|
/**
|
|
107
|
-
*
|
|
108
|
+
* Result returned by `events["step.started"]`.
|
|
108
109
|
*/
|
|
109
|
-
export interface
|
|
110
|
+
export interface InstrumentationStepStartedEventResult {
|
|
110
111
|
/**
|
|
111
|
-
*
|
|
112
|
+
* Additional runtime context merged into AI SDK telemetry spans.
|
|
113
|
+
*/
|
|
114
|
+
readonly runtimeContext: InstrumentationRuntimeContext;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Event hooks accepted by {@link defineInstrumentation}.
|
|
118
|
+
*/
|
|
119
|
+
export interface InstrumentationEvents {
|
|
120
|
+
/**
|
|
121
|
+
* Per-attempt runtime context resolved before the model call so child spans
|
|
112
122
|
* created by the AI SDK inherit the returned values.
|
|
113
123
|
*/
|
|
114
|
-
readonly "step.started"?: (input:
|
|
124
|
+
readonly "step.started"?: (input: InstrumentationStepStartedEventInput) => InstrumentationStepStartedEventResult | undefined;
|
|
115
125
|
}
|
|
116
126
|
/**
|
|
117
127
|
* Authored instrumentation settings accepted by `defineInstrumentation`.
|
|
@@ -127,9 +137,9 @@ export interface InstrumentationDefinition {
|
|
|
127
137
|
*/
|
|
128
138
|
readonly functionId?: string;
|
|
129
139
|
/**
|
|
130
|
-
*
|
|
140
|
+
* Instrumentation event hooks.
|
|
131
141
|
*/
|
|
132
|
-
readonly
|
|
142
|
+
readonly events?: InstrumentationEvents;
|
|
133
143
|
/**
|
|
134
144
|
* Whether to record full model inputs in telemetry spans.
|
|
135
145
|
*
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Schedule authoring helpers for `agent/schedules/*` files.
|
|
3
3
|
*/
|
|
4
|
-
export { defineSchedule, type ScheduleDefinition, type ScheduleHandlerArgs, type ScheduleRunHandler, type
|
|
4
|
+
export { defineSchedule, type ScheduleDefinition, type ScheduleHandlerArgs, type ScheduleRunHandler, type TypedReceiveTarget, } from "#public/definitions/schedule.js";
|
package/package.json
CHANGED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
declare const receiveArgsMarker: unique symbol;
|
|
2
|
-
/**
|
|
3
|
-
* Structural marker attached by channel factories (e.g. `slackChannel`,
|
|
4
|
-
* `twilioChannel`) to advertise the args type their `receive()` accepts.
|
|
5
|
-
* `receive(channel, args)` helpers and the route-handler
|
|
6
|
-
* `args.receive(channel, ...)` use this marker to infer typed args
|
|
7
|
-
* from a plain channel import.
|
|
8
|
-
*/
|
|
9
|
-
export interface TypedReceiveRoute<TArgs = Record<string, unknown>> {
|
|
10
|
-
readonly [receiveArgsMarker]?: TArgs;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* Extracts the receive-args type from a channel value, falling back to
|
|
14
|
-
* `Record<string, unknown>` when the channel does not advertise one.
|
|
15
|
-
*/
|
|
16
|
-
export type InferReceiveArgs<TChannel> = TChannel extends TypedReceiveRoute<infer TArgs> ? TArgs : Record<string, unknown>;
|
|
17
|
-
export {};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{createLogger,formatError}from"#internal/logging.js";import{normalizeInstrumentationChannelKind,resolveInstrumentationProjection}from"#internal/instrumentation.js";import{AuthKey,ChannelInstrumentationKey,InitiatorAuthKey,ParentSessionKey}from"#context/keys.js";import{parseJsonValue}from"#shared/json.js";import{contextStorage}from"#context/container.js";const log=createLogger(`harness.instrumentation-metadata`);function buildTelemetryRuntimeContext(e){if(e.authored===void 0)return;let t=resolveStepStartedMetadata(e),r=contextStorage.getStore()?.get(ChannelInstrumentationKey);return{...t,"ash.channel.kind":normalizeInstrumentationChannelKind(r?.kind),"ash.environment":e.environment,"ash.session.id":e.session.sessionId,"ash.step.index":String(e.emissionState.stepIndex),"ash.turn.id":e.emissionState.turnId,"ash.turn.sequence":String(e.emissionState.sequence),"ash.version":e.ashVersion}}function buildInstrumentationStepStartedInput(e){let t=contextStorage.getStore(),r=t?.get(ChannelInstrumentationKey);return{channel:{kind:normalizeInstrumentationChannelKind(r?.kind),metadata:snapshotForInstrumentation(r?.metadata,`channel.metadata`)??{}},modelInput:snapshotForInstrumentation(e.modelInput,`modelInput`)??{instructions:void 0,messages:[]},session:{auth:projectSessionAuth(t),id:e.session.sessionId,parent:snapshotForInstrumentation(t?.get(ParentSessionKey),`session.parent`)},step:{index:e.emissionState.stepIndex},turn:{id:e.emissionState.turnId,sequence:e.emissionState.sequence}}}function filterAuthoredMetadata(e,t){let n={};for(let[r,i]of Object.entries(e)){if(r.startsWith(`ash.`)){log.warn(`ignoring reserved instrumentation metadata key`,{key:r,source:t});continue}if(typeof i!=`string`){log.warn(`ignoring non-string instrumentation metadata value`,{key:r,source:t,valueType:typeof i});continue}n[r]=i}return Object.keys(n).length>0?n:void 0}function resolveStepStartedMetadata(e){let t=e.authored?.metadata?.[`step.started`];if(t===void 0)return;let n=`metadata["step.started"]`,i=resolveInstrumentationProjection({invoke:()=>t(buildInstrumentationStepStartedInput(e)),log,source:n});return i===void 0?void 0:filterAuthoredMetadata(i,n)}function projectSessionAuth(e){let t=e?.get(AuthKey)??null,n=e?.get(InitiatorAuthKey)??t;return{current:snapshotForInstrumentation(t,`session.auth.current`)??null,initiator:snapshotForInstrumentation(n,`session.auth.initiator`)??null}}function snapshotForInstrumentation(e,n){if(e!==void 0)try{return parseJsonValue(e)}catch(e){log.warn(`dropping non-serializable instrumentation snapshot`,{error:formatError(e),source:n});return}}export{buildTelemetryRuntimeContext};
|
|
File without changes
|