eve 0.40.0 → 0.41.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 +13 -0
- package/dist/src/chunks/{use-eve-agent-CTI9fHaO.js → use-eve-agent-C0SG1Ttk.js} +4 -1
- package/dist/src/chunks/{use-eve-agent-DlkXRQVo.js → use-eve-agent-D71oDil7.js} +4 -1
- package/dist/src/client/session.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +2 -1
- package/dist/src/compiled/@linqapp/chat-sdk-adapter/LICENSE +201 -0
- package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.d.ts +3 -0
- package/dist/src/compiled/@linqapp/chat-sdk-adapter/index.js +8 -0
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/packages/eve-catalog/src/index.js +1 -1
- package/dist/src/public/channels/linq/inboundContent.d.ts +4 -0
- package/dist/src/public/channels/linq/inboundContent.js +1 -0
- package/dist/src/public/channels/linq/index.d.ts +1 -0
- package/dist/src/public/channels/linq/index.js +1 -0
- package/dist/src/public/channels/linq/linqChannel.d.ts +66 -0
- package/dist/src/public/channels/linq/linqChannel.js +1 -0
- package/dist/src/public/channels/teams/api.js +2 -2
- package/dist/src/public/channels/teams/defaults.js +1 -1
- package/dist/src/public/channels/teams/hitl.d.ts +9 -0
- package/dist/src/public/channels/teams/hitl.js +1 -1
- package/dist/src/public/channels/teams/index.d.ts +1 -1
- package/dist/src/public/channels/teams/index.js +1 -1
- package/dist/src/public/channels/teams/teamsChannel.d.ts +8 -0
- package/dist/src/public/channels/teams/teamsChannel.js +1 -1
- package/dist/src/setup/integrations/linq/connect.d.ts +32 -0
- package/dist/src/setup/integrations/linq/connect.js +1 -0
- package/dist/src/setup/integrations/linq/setup.d.ts +22 -0
- package/dist/src/setup/integrations/linq/setup.js +15 -0
- package/dist/src/setup/integrations/registry.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +2 -2
- package/dist/src/setup/scaffold/create/web-template.js +74 -50
- package/dist/src/svelte/index.js +1 -1
- package/dist/src/svelte/use-eve-agent.js +1 -1
- package/dist/src/vue/index.js +1 -1
- package/dist/src/vue/use-eve-agent.js +1 -1
- package/docs/channels/linq.mdx +67 -0
- package/docs/channels/meta.json +1 -0
- package/docs/channels/overview.mdx +3 -2
- package/docs/channels/teams.mdx +2 -0
- package/docs/guides/client/streaming.mdx +1 -1
- package/package.json +7 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { linqChannel, type LinqChannel, type LinqChannelConfig, type LinqChannelCredentials, type LinqCredentialValue, type LinqInboundMessageContext, type LinqInboundResult, type LinqInboundResultOrPromise, } from "#public/channels/linq/linqChannel.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{linqChannel}from"#public/channels/linq/linqChannel.js";export{linqChannel};
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { SessionAuthContext, TurnPolicy } from "#channel/types.js";
|
|
2
|
+
import { type ChatSdkChannelEvents, type ChatSdkChannelState, type ChatSdkInstrumentationMetadata, type ChatSdkReceiveTarget } from "#public/channels/chat-sdk/index.js";
|
|
3
|
+
import type { Channel } from "#public/definitions/channel.js";
|
|
4
|
+
import { createLinqAdapter, type LinqWebhookVerifier } from "#compiled/@linqapp/chat-sdk-adapter/index.js";
|
|
5
|
+
import type { Message, Thread } from "#compiled/chat/index.js";
|
|
6
|
+
/** Context passed to {@link LinqChannelConfig.onMessage}. */
|
|
7
|
+
export interface LinqInboundMessageContext {
|
|
8
|
+
/** Low-level Chat SDK thread for Linq-specific operations. */
|
|
9
|
+
readonly thread: Thread;
|
|
10
|
+
}
|
|
11
|
+
/** Result of {@link LinqChannelConfig.onMessage}. Return `null` to drop the message. */
|
|
12
|
+
export type LinqInboundResult = {
|
|
13
|
+
readonly auth: SessionAuthContext | null;
|
|
14
|
+
readonly context?: readonly string[];
|
|
15
|
+
/** Overrides the workflow run title without changing the message sent to the model. */
|
|
16
|
+
readonly title?: string;
|
|
17
|
+
} | null;
|
|
18
|
+
/** Sync or async {@link LinqInboundResult}. */
|
|
19
|
+
export type LinqInboundResultOrPromise = LinqInboundResult | Promise<LinqInboundResult>;
|
|
20
|
+
/** A direct value or lazy resolver for a Linq credential. */
|
|
21
|
+
export type LinqCredentialValue = string | (() => string | Promise<string>);
|
|
22
|
+
/** Linq credentials for outbound API calls and inbound webhook verification. */
|
|
23
|
+
export interface LinqChannelCredentials {
|
|
24
|
+
/** API key for outbound Linq API calls. */
|
|
25
|
+
readonly apiKey?: LinqCredentialValue;
|
|
26
|
+
/** Signing secret for direct Linq webhook delivery. */
|
|
27
|
+
readonly signingSecret?: LinqCredentialValue;
|
|
28
|
+
/** Trusted verifier for webhooks forwarded by a provider such as Vercel Connect. */
|
|
29
|
+
readonly webhookVerifier?: LinqWebhookVerifier;
|
|
30
|
+
}
|
|
31
|
+
/** Configuration for {@link linqChannel}. */
|
|
32
|
+
export interface LinqChannelConfig {
|
|
33
|
+
/** Optional Linq API base URL, for example a sandbox endpoint. */
|
|
34
|
+
readonly baseURL?: string;
|
|
35
|
+
/** Outbound credentials and inbound webhook verification. */
|
|
36
|
+
readonly credentials?: LinqChannelCredentials;
|
|
37
|
+
/** Per-event overrides for the underlying Chat SDK channel. */
|
|
38
|
+
readonly events?: ChatSdkChannelEvents<{
|
|
39
|
+
linq: ReturnType<typeof createLinqAdapter>;
|
|
40
|
+
}>;
|
|
41
|
+
/** Inbound message policy. Defaults to dispatching every message with no user auth. */
|
|
42
|
+
readonly onMessage?: (ctx: LinqInboundMessageContext, message: Message) => LinqInboundResultOrPromise;
|
|
43
|
+
/** Override the default webhook route (`/eve/v1/linq`). */
|
|
44
|
+
readonly route?: string;
|
|
45
|
+
/** Policy for accepted messages that arrive while a turn is active. */
|
|
46
|
+
readonly turnPolicy?: TurnPolicy;
|
|
47
|
+
/** Display name used by the Chat SDK runtime. Defaults to `"eve"`. */
|
|
48
|
+
readonly userName?: string;
|
|
49
|
+
}
|
|
50
|
+
/** First-class eve channel backed by Linq iMessage and SMS. */
|
|
51
|
+
export interface LinqChannel extends Channel<ChatSdkChannelState, ChatSdkReceiveTarget, ChatSdkInstrumentationMetadata> {
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Creates an eve channel for Linq-powered iMessage and SMS conversations.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```ts
|
|
58
|
+
* import { connectLinqCredentials } from "@vercel/connect/eve";
|
|
59
|
+
* import { linqChannel } from "eve/channels/linq";
|
|
60
|
+
*
|
|
61
|
+
* export default linqChannel({
|
|
62
|
+
* credentials: connectLinqCredentials("linq/my-agent"),
|
|
63
|
+
* });
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export declare function linqChannel(config: LinqChannelConfig): LinqChannel;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{vercelOidc}from"#public/channels/auth.js";import{chatSdkChannel}from"#public/channels/chat-sdk/index.js";import{createMemoryState}from"#compiled/@chat-adapter/state-memory/index.js";import{createLinqAdapter}from"#compiled/@linqapp/chat-sdk-adapter/index.js";import{linqInboundContent}from"#public/channels/linq/inboundContent.js";function linqChannel(e){let i=normalizeCredentials(e.credentials);e.baseURL!==void 0&&(i.baseURL=e.baseURL);let a=chatSdkChannel({adapters:{linq:createLinqAdapter(i)},concurrency:`concurrent`,events:e.events,routes:{linq:e.route??`/eve/v1/linq`},state:createMemoryState(),streaming:!1,turnPolicy:e.turnPolicy,userName:e.userName??`eve`}),o=e.onMessage??defaultOnMessage;return a.bot.onDirectMessage(async(e,t)=>{await dispatchMessage(a,o,e,t)}),a.bot.onNewMessage(/[\s\S]*/,async(e,t)=>{await dispatchMessage(a,o,e,t)}),a.channel}function normalizeCredentials(t){let{apiKey:n,signingSecret:r,webhookVerifier:i}=t??{},a={};return n!==void 0&&(a.credentials=createCredentialProvider(n,r)),i===void 0?r===void 0&&(a.webhookVerifier=vercelOidc()):a.webhookVerifier=i,a}function createCredentialProvider(e,t){return async()=>{let n={apiKey:await resolveCredentialValue(e)};return t!==void 0&&(n.signingSecret=await resolveCredentialValue(t)),n}}async function resolveCredentialValue(e){return typeof e==`function`?await e():e}async function defaultOnMessage(){return{auth:null}}async function dispatchMessage(e,t,n,r){let a=await t({thread:n},r);if(a===null)return;await markReadBestEffort(e.bot.getAdapter(`linq`),n,r);let o=linqInboundContent(r);o!==void 0&&await e.send({context:[...a.context??[]],message:o},{auth:a.auth,thread:n,title:a.title})}async function markReadBestEffort(e,t,n){try{await e.markRead(t.id,n.id)}catch{}}export{linqChannel};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){let t=normalizeTeamsContinuationAddress(e);return[e.tenantId??`_`,t.conversationId,t.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}function normalizeTeamsContinuationAddress(e){let t=e.conversationId.lastIndexOf(`;messageid=`);return t<0?{conversationId:e.conversationId,replyToActivityId:e.replyToActivityId??null}:{conversationId:e.conversationId.slice(0,t),replyToActivityId:e.conversationId.slice(t+11)||e.replyToActivityId||null}}async function resolveTeamsAppId(e){let t=e??process.env.MICROSOFT_APP_ID??process.env.TEAMS_APP_ID;if(!t)throw Error(`MICROSOFT_APP_ID or TEAMS_APP_ID is required.`);return typeof t==`function`?await t():t}async function resolveTeamsAppPassword(e){let t=e??process.env.MICROSOFT_APP_PASSWORD??process.env.TEAMS_APP_PASSWORD;if(!t)throw Error(`MICROSOFT_APP_PASSWORD or TEAMS_APP_PASSWORD is required.`);return typeof t==`function`?await t():t}async function resolveTeamsTenantId(e){let t=e??process.env.MICROSOFT_TENANT_ID??process.env.TEAMS_TENANT_ID;if(t)return typeof t==`function`?await t():t}async function resolveTeamsAccessToken(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let a=await resolveTeamsAppId(n?.appId),o=await resolveTeamsAppPassword(n?.appPassword),s=await resolveTeamsTenantId(n?.tenantId),c=trimTrailingSlash(t.loginBaseUrl??`https://login.microsoftonline.com`),l=`${c}:${s??BOT_FRAMEWORK_TENANT}:${a}`,u=accessTokenCache.get(l),d=Date.now();if(u!==void 0&&u.expiresAt-6e4>d)return u.accessToken;let f=`${c}/${encodeURIComponent(s??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,p=new URLSearchParams({client_id:a,client_secret:o,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),m=await(t.fetch??fetch)(f,{body:p,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),h=await parseResponseBody(m);if(!m.ok)throw Error(`Teams access-token request failed with HTTP ${m.status}.`);let g=isObject(h)?h:{},_=typeof g.access_token==`string`?g.access_token:``;if(!_)throw Error(`Teams access-token response did not include access_token.`);let v=typeof g.expires_in==`number`?g.expires_in:3600;return accessTokenCache.set(l,{accessToken:_,expiresAt:d+v*1e3}),_}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status}
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";const TEAMS_MESSAGE_TEXT_MAX_LENGTH=80*1024,BOT_FRAMEWORK_TENANT=`botframework.com`,accessTokenCache=new Map;function teamsContinuationToken(e){let t=normalizeTeamsContinuationAddress(e);return[e.tenantId??`_`,t.conversationId,t.replyToActivityId??``].map(e=>encodeURIComponent(e)).join(`:`)}function normalizeTeamsContinuationAddress(e){let t=e.conversationId.lastIndexOf(`;messageid=`);return t<0?{conversationId:e.conversationId,replyToActivityId:e.replyToActivityId??null}:{conversationId:e.conversationId.slice(0,t),replyToActivityId:e.conversationId.slice(t+11)||e.replyToActivityId||null}}async function resolveTeamsAppId(e){let t=e??process.env.MICROSOFT_APP_ID??process.env.TEAMS_APP_ID;if(!t)throw Error(`MICROSOFT_APP_ID or TEAMS_APP_ID is required.`);return typeof t==`function`?await t():t}async function resolveTeamsAppPassword(e){let t=e??process.env.MICROSOFT_APP_PASSWORD??process.env.TEAMS_APP_PASSWORD;if(!t)throw Error(`MICROSOFT_APP_PASSWORD or TEAMS_APP_PASSWORD is required.`);return typeof t==`function`?await t():t}async function resolveTeamsTenantId(e){let t=e??process.env.MICROSOFT_TENANT_ID??process.env.TEAMS_TENANT_ID;if(t)return typeof t==`function`?await t():t}async function resolveTeamsAccessToken(t={}){let n=t.credentials;if(n?.tokenProvider!==void 0)return normalizeAccessTokenResult(await n.tokenProvider()).accessToken;let a=await resolveTeamsAppId(n?.appId),o=await resolveTeamsAppPassword(n?.appPassword),s=await resolveTeamsTenantId(n?.tenantId),c=trimTrailingSlash(t.loginBaseUrl??`https://login.microsoftonline.com`),l=`${c}:${s??BOT_FRAMEWORK_TENANT}:${a}`,u=accessTokenCache.get(l),d=Date.now();if(u!==void 0&&u.expiresAt-6e4>d)return u.accessToken;let f=`${c}/${encodeURIComponent(s??BOT_FRAMEWORK_TENANT)}/oauth2/v2.0/token`,p=new URLSearchParams({client_id:a,client_secret:o,grant_type:`client_credentials`,scope:`https://api.botframework.com/.default`}),m=await(t.fetch??fetch)(f,{body:p,headers:{"content-type":`application/x-www-form-urlencoded`},method:`POST`}),h=await parseResponseBody(m);if(!m.ok)throw Error(`Teams access-token request failed with HTTP ${m.status}.`);let g=isObject(h)?h:{},_=typeof g.access_token==`string`?g.access_token:``;if(!_)throw Error(`Teams access-token response did not include access_token.`);let v=typeof g.expires_in==`number`?g.expires_in:3600;return accessTokenCache.set(l,{accessToken:_,expiresAt:d+v*1e3}),_}async function callTeamsConnectorApi(e){let n=e.fetch??fetch,r=new Headers;r.set(`authorization`,`Bearer ${await resolveTeamsAccessToken(e)}`),r.set(`content-type`,`application/json; charset=utf-8`);let i={headers:r,method:e.method??`POST`};e.body!==void 0&&(i.body=JSON.stringify(parseJsonObject(e.body)));let a=await n(`${trimTrailingSlash(e.serviceUrl)}${e.path}`,i);return{body:await parseResponseBody(a),ok:a.ok,status:a.status}}async function sendTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams send activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function replyToTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams reply activity failed with HTTP ${t.status}.`);return toPostedActivity(t.body)}async function updateTeamsActivity(e){let t=await callTeamsConnectorApi({...e,body:e.body,method:`PUT`,path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities/${encodeURIComponent(e.activityId)}`});if(!t.ok)throw Error(`Teams update activity failed with HTTP ${t.status} for conversation "${e.conversationId}" activity "${e.activityId}": ${formatConnectorErrorBody(t.body)}`);return toPostedActivity(t.body)}async function triggerTeamsTypingIndicator(e){let t=await callTeamsConnectorApi({...e,body:{type:`typing`},path:`/v3/conversations/${encodeURIComponent(e.conversationId)}/activities`});if(!t.ok)throw Error(`Teams typing indicator failed with HTTP ${t.status}.`)}function splitTeamsMessageText(e){if(e.length<=81920)return[e];let t=[],r=e;for(;r.length>TEAMS_MESSAGE_TEXT_MAX_LENGTH;){let e=r.lastIndexOf(`
|
|
2
2
|
|
|
3
3
|
`,TEAMS_MESSAGE_TEXT_MAX_LENGTH);e<=0&&(e=r.lastIndexOf(`
|
|
4
|
-
`,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=r.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(r.slice(0,e).trimEnd()),r=r.slice(e).trimStart()}return t.push(r),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(t){let n=isObject(t)?t:{};return{id:typeof n.id==`string`?n.id:``,raw:t}}function trimTrailingSlash(e){return e.replace(/\/+$/,``)}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};
|
|
4
|
+
`,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=r.lastIndexOf(` `,TEAMS_MESSAGE_TEXT_MAX_LENGTH)),e<=0&&(e=TEAMS_MESSAGE_TEXT_MAX_LENGTH),t.push(r.slice(0,e).trimEnd()),r=r.slice(e).trimStart()}return t.push(r),t}function normalizeTeamsPostInput(e){return typeof e==`string`?{text:e,textFormat:`markdown`}:e}function normalizeAccessTokenResult(e){if(typeof e==`string`)return{accessToken:e};let t=e.expiresAt instanceof Date?e.expiresAt.getTime():e.expiresAt;return{accessToken:e.accessToken,expiresAt:t}}function toPostedActivity(t){let n=isObject(t)?t:{};return{id:typeof n.id==`string`?n.id:``,raw:t}}function formatConnectorErrorBody(e){let t=typeof e==`string`?e:JSON.stringify(e);return t===void 0||t.length===0?`empty response body`:t.length<=1e3?t:`${t.slice(0,997)}...`}function trimTrailingSlash(e){return e.replace(/\/+$/,``)}async function parseResponseBody(e){let t=await e.text();if(!t)return null;try{return JSON.parse(t)}catch{return t}}export{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}const defaultEvents={async"turn.started"(e,t,n){await t.thread.startTyping()},async"actions.requested"(e,t,n){await t.thread.startTyping()},async"input.requested"(e,t,n){for(let n of e.requests)await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion,replyToActivityId:t.teams.replyToActivityId}))},async"message.completed"(e,t,n){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
|
|
1
|
+
import{extractErrorId,formatErrorHint}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{splitTeamsMessageText}from"#public/channels/teams/api.js";import{renderAnsweredInputRequestMessage,renderInputRequestMessage}from"#public/channels/teams/hitl.js";function defaultTeamsAuth(e){let t=e.tenantId,n={activity_id:e.id,conversation_id:e.conversation.id,scope:e.scope,user_id:e.from.id};e.from.name!==void 0&&(n.user_name=e.from.name),e.from.aadObjectId!==void 0&&(n.aad_object_id=e.from.aadObjectId),t!==void 0&&(n.tenant_id=t),e.teamId!==void 0&&(n.team_id=e.teamId),e.teamsChannelId!==void 0&&(n.channel_id=e.teamsChannelId);let r=t?`teams:${t}:${e.from.id}`:`teams:${e.from.id}`;return{attributes:n,authenticator:`teams-activity`,issuer:t?`teams:${t}`:`teams`,principalId:r,principalType:e.from.role===`bot`?`service`:`user`,subject:e.from.aadObjectId}}async function defaultOnMessage(e,t){return t.from.role===`bot`||t.from.id===t.recipient.id||t.scope!==`personal`&&!t.isBotMentioned?null:(await e.thread.startTyping(),{auth:defaultTeamsAuth(t)})}const defaultEvents={async"turn.started"(e,t,n){await t.thread.startTyping()},async"actions.requested"(e,t,n){await t.thread.startTyping()},async"input.requested"(e,t,n){for(let n of e.requests){let e=await t.thread.post(renderInputRequestMessage(n,{adaptiveCardVersion:t.adaptiveCardVersion,replyToActivityId:t.teams.replyToActivityId}));n.kind===`tool-approval`&&e.id&&(t.state.pendingApprovalCards={...t.state.pendingApprovalCards,[n.requestId]:{activityId:e.id,prompt:n.prompt}})}},async"approval.settled"(e,t,n){let r=t.state.pendingApprovalCards??{},a=r[e.requestId];if(a===void 0)return;let o=t.state.approvalResponderAccounts?.[e.responderPrincipalId],s=e.outcome===`approved`?`Approved`:`Cancelled`,c=o?.name??o?.id;await t.thread.update(a.activityId,renderAnsweredInputRequestMessage({includeText:!1,label:c===void 0?s:`${s} by ${c}`,prompt:a.prompt}));let l={...r};delete l[e.requestId],t.state.pendingApprovalCards=l},async"message.completed"(e,t,n){if(!(e.finishReason===`tool-calls`||!e.message))for(let n of splitTeamsMessageText(e.message))await t.thread.post(n)},async"session.failed"(n,r){let i=formatErrorHint(n),a=extractErrorId(n.details);await r.thread.post([`This session could not recover from an error${i}.`,``,`Start a new Teams conversation to continue.`,...a?[``,`Error id: ${a}`]:[]].join(`
|
|
2
2
|
`))},async"turn.failed"(n,r,i){let a=formatErrorHint(n),o=extractErrorId(n.details);await r.thread.post([`I hit an error while handling your request${a}.`,``,`Please try again, rephrase, or reach out if it keeps failing.`,...o?[``,`Error id: ${o}`]:[]].join(`
|
|
3
3
|
`))},async"authorization.required"(e,t,r){let i=e.authorization?.displayName??formatConnectionDisplayName(e.name),a=e.authorization?.url,o=a?`Authorization required for ${i}: ${a}`:`Authorization required for ${i}.`,s=await t.thread.post({attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:a?[{title:`Sign in with ${i}`,type:`Action.OpenUrl`,url:a}]:[],body:[{text:`Authorization required for ${i}`,type:`TextBlock`,weight:`Bolder`,wrap:!0},{text:t.state.triggeringUser?`Requested by ${t.state.triggeringUser.name??t.state.triggeringUser.id}.`:`No triggering user is available for a private prompt.`,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:t.adaptiveCardVersion}),contentType:`application/vnd.microsoft.card.adaptive`}],text:o});s.id&&(t.state.pendingAuthActivityId=s.id)},async"authorization.completed"(e,t,n){e.outcome===`authorized`&&await t.thread.startTyping();let r=t.state.pendingAuthActivityId;if(!r)return;let a=buildAuthCompletedText({displayName:e.authorization?.displayName??formatConnectionDisplayName(e.name),outcome:e.outcome,reason:e.reason});await t.thread.update(r,renderAnsweredInputRequestMessage({prompt:a})),t.state.pendingAuthActivityId=null}};function formatConnectionDisplayName(e){return e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1)}function buildAuthCompletedText(e){if(e.outcome===`authorized`)return`${e.displayName} connected.`;let t=e.reason===void 0?``:` (${e.reason})`;return`${e.displayName} authorization ${e.outcome}${t}.`}function teamsMentionUser(e){let t=e.name??e.id;return{mentioned:{id:e.id,name:e.name},text:`<at>${t}</at>`,type:`mention`}}export{buildAuthCompletedText,defaultEvents,defaultOnMessage,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser};
|
|
@@ -12,6 +12,10 @@ export declare const TEAMS_HITL_DATA_KEY = "eve_input";
|
|
|
12
12
|
export declare const TEAMS_HITL_CHOICE_INPUT_ID = "eve_option";
|
|
13
13
|
/** Text input id used for freeform HITL requests. */
|
|
14
14
|
export declare const TEAMS_HITL_FREEFORM_INPUT_ID = "eve_freeform_text";
|
|
15
|
+
/** Request kind carried on approval actions so lifecycle handling can distinguish them from questions. */
|
|
16
|
+
export declare const TEAMS_HITL_REQUEST_KIND_KEY = "kind";
|
|
17
|
+
/** Prompt carried on approval actions so a response can recover its card record. */
|
|
18
|
+
export declare const TEAMS_HITL_PROMPT_KEY = "prompt";
|
|
15
19
|
/** Renders one input request as a Teams message body containing an Adaptive Card. */
|
|
16
20
|
export declare function renderInputRequestMessage(request: InputRequest, options?: {
|
|
17
21
|
readonly adaptiveCardVersion?: string;
|
|
@@ -28,11 +32,16 @@ export declare function renderInputRequestAttachment(request: InputRequest, opti
|
|
|
28
32
|
}): TeamsAttachment;
|
|
29
33
|
/** Renders an answered Teams card that replaces a pending HITL prompt. */
|
|
30
34
|
export declare function renderAnsweredInputRequestMessage(input: {
|
|
35
|
+
readonly includeText?: boolean;
|
|
31
36
|
readonly label?: string;
|
|
32
37
|
readonly prompt: string;
|
|
33
38
|
}): TeamsMessageBody;
|
|
34
39
|
/** Returns true when a Teams activity carries an eve HITL submit payload. */
|
|
35
40
|
export declare function isTeamsInputResponseActivity(activity: TeamsActivity): boolean;
|
|
41
|
+
/** Returns whether an eve HITL activity answers a tool approval. */
|
|
42
|
+
export declare function isTeamsToolApprovalResponseActivity(activity: TeamsActivity): boolean;
|
|
43
|
+
/** Reads the original prompt from a tool-approval submit activity. */
|
|
44
|
+
export declare function readTeamsToolApprovalPrompt(activity: TeamsActivity): string | undefined;
|
|
36
45
|
/**
|
|
37
46
|
* Decodes the eve HITL submit payload from a Teams activity. Returns a single
|
|
38
47
|
* `InputResponse` (option selection, freeform text, or a bare requestId
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";const TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`eve_input`,TEAMS_HITL_CHOICE_INPUT_ID=`eve_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`eve_freeform_text`;function renderInputRequestMessage(e,t={}){let n=formatApprovalInput(e),r=n?truncate(n,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH):null;return{attachments:[renderInputRequestAttachment(e,t)],text:r?`${e.prompt}\n\nTool input:\n${r}`:e.prompt}}function renderInputRequestAttachment(e,n={}){let r=formatApprovalInput(e);return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e,n.replyToActivityId),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...r?[{fontType:`Monospace`,text:truncate(r,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0}]:[],...renderInputs(e)],type:`AdaptiveCard`,version:n.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){
|
|
1
|
+
import{isObject}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{TEAMS_ADAPTIVE_CARD_ACTION_LIMIT,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH}from"#public/channels/teams/limits.js";const TEAMS_ADAPTIVE_CARD_CONTENT_TYPE=`application/vnd.microsoft.card.adaptive`,TEAMS_HITL_DATA_KEY=`eve_input`,TEAMS_HITL_CHOICE_INPUT_ID=`eve_option`,TEAMS_HITL_FREEFORM_INPUT_ID=`eve_freeform_text`,TEAMS_HITL_REQUEST_KIND_KEY=`kind`,TEAMS_HITL_PROMPT_KEY=`prompt`;function renderInputRequestMessage(e,t={}){let n=formatApprovalInput(e),r=n?truncate(n,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH):null;return{attachments:[renderInputRequestAttachment(e,t)],text:r?`${e.prompt}\n\nTool input:\n${r}`:e.prompt}}function renderInputRequestAttachment(e,n={}){let r=formatApprovalInput(e);return{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,actions:renderActions(e,n.replyToActivityId),body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},...r?[{fontType:`Monospace`,text:truncate(r,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0}]:[],...renderInputs(e)],type:`AdaptiveCard`,version:n.adaptiveCardVersion??`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}}function renderAnsweredInputRequestMessage(e){let n=e.label?`Answered: ${e.label}`:`Answered`,r={attachments:[{content:parseJsonObject({$schema:`http://adaptivecards.io/schemas/adaptive-card.json`,body:[{text:truncate(e.prompt,TEAMS_ADAPTIVE_CARD_TEXT_MAX_LENGTH),type:`TextBlock`,wrap:!0},{color:`good`,text:n,type:`TextBlock`,wrap:!0}],type:`AdaptiveCard`,version:`1.5`}),contentType:TEAMS_ADAPTIVE_CARD_CONTENT_TYPE}]};return e.includeText===!1?r:{...r,text:n}}function isTeamsInputResponseActivity(e){return deriveTeamsInputResponses(e).length>0}function isTeamsToolApprovalResponseActivity(e){let t=readActivityValue(e);return(t&&readHitlPayload(t))?.[TEAMS_HITL_REQUEST_KIND_KEY]===`tool-approval`}function readTeamsToolApprovalPrompt(e){let t=readActivityValue(e),n=(t&&readHitlPayload(t))?.[TEAMS_HITL_PROMPT_KEY];return typeof n==`string`&&n.length>0?n:void 0}function deriveTeamsInputResponses(e){let t=readActivityValue(e);if(!t)return[];let n=readHitlPayload(t);if(!n)return[];let r=typeof n.requestId==`string`?n.requestId:``;if(!r)return[];let i=typeof n.optionId==`string`?n.optionId:typeof t.eve_option==`string`?t[TEAMS_HITL_CHOICE_INPUT_ID]:void 0,a=typeof t.eve_freeform_text==`string`?t[TEAMS_HITL_FREEFORM_INPUT_ID]:void 0;return i===void 0?a===void 0?[{requestId:r}]:[{requestId:r,text:a}]:[{optionId:i,requestId:r}]}function readTeamsInputReplyToActivityId(e){let t=readActivityValue(e);if(!t)return null;let n=readHitlPayload(t);return n&&typeof n.replyToActivityId==`string`?n.replyToActivityId:null}function teamsInvokeResponse(e={}){return{statusCode:e.statusCode??200,type:`application/vnd.microsoft.activity.message`,value:e.message??`Answer received.`}}function renderInputs(e){return e.display===`select`&&e.options&&e.options.length>0?[{choices:e.options.map(e=>({title:truncate(e.label,TEAMS_ADAPTIVE_CARD_CHOICE_TITLE_MAX_LENGTH),value:e.id})),id:TEAMS_HITL_CHOICE_INPUT_ID,isMultiSelect:!1,style:`compact`,type:`Input.ChoiceSet`}]:e.allowFreeform===!0||!e.options||e.options.length===0?[{id:TEAMS_HITL_FREEFORM_INPUT_ID,isMultiline:!0,placeholder:`Type your answer`,type:`Input.Text`}]:[]}function renderActions(e,t){let payload=n=>{let r={requestId:e.requestId};return e.kind===`tool-approval`&&(r[TEAMS_HITL_REQUEST_KIND_KEY]=`tool-approval`,r[TEAMS_HITL_PROMPT_KEY]=e.prompt),t!==void 0&&(r.replyToActivityId=t),n!==void 0&&(r.optionId=n),r},i=e.options;return i&&i.length>0&&e.display!==`select`?i.slice(0,TEAMS_ADAPTIVE_CARD_ACTION_LIMIT).map(e=>({data:{[TEAMS_HITL_DATA_KEY]:payload(e.id)},title:truncate(e.label,TEAMS_ADAPTIVE_CARD_ACTION_TITLE_MAX_LENGTH),type:`Action.Submit`})):[{data:{[TEAMS_HITL_DATA_KEY]:payload()},title:`Submit`,type:`Action.Submit`}]}function readActivityValue(e){return e.type===`message`?readMessageValue(e):e.type===`invoke`?readInvokeValue(e):null}function readMessageValue(e){return e.value??null}function readInvokeValue(t){let n=t.value;if(!n)return null;let r=isObject(n.action)?n.action:null;return(r&&isObject(r.data)?r.data:null)??n}function readHitlPayload(t){let n=t[TEAMS_HITL_DATA_KEY];if(isObject(n))return n;let r=isObject(t.action)?t.action:null,i=(r&&isObject(r.data)?r.data:null)?.[TEAMS_HITL_DATA_KEY];return isObject(i)?i:null}function formatApprovalInput(e){if(e.kind!==`tool-approval`)return null;let t=JSON.stringify(e.action.input,null,2);return t===`{}`?null:t}function truncate(e,t){if(e.length<=t)return e;let n=Math.max(0,t-3);return`${e.slice(0,n).trimEnd()}...`}export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse};
|
|
@@ -13,7 +13,7 @@ export interface TeamsInstrumentationMetadata extends Record<string, unknown> {
|
|
|
13
13
|
export { teamsChannel, type TeamsChannel, type TeamsChannelConfig, type TeamsChannelCredentials, type TeamsChannelEvents, type TeamsChannelState, type TeamsContext, type TeamsEventContext, type TeamsHandle, type TeamsInboundMessageContext, type TeamsInboundResult, type TeamsInboundResultOrPromise, type TeamsInputResponseResult, type TeamsInvokeResult, type TeamsInvokeResultOrPromise, type TeamsReceiveTarget, type TeamsRequestOptions, type TeamsThread, } from "#public/channels/teams/teamsChannel.js";
|
|
14
14
|
export { callTeamsConnectorApi, normalizeTeamsPostInput, replyToTeamsActivity, resolveTeamsAccessToken, resolveTeamsAppId, resolveTeamsAppPassword, resolveTeamsTenantId, sendTeamsActivity, splitTeamsMessageText, teamsContinuationToken, triggerTeamsTypingIndicator, updateTeamsActivity, TEAMS_MESSAGE_TEXT_MAX_LENGTH, type TeamsAccessTokenResult, type TeamsApiOptions, type TeamsApiResponse, type TeamsAppId, type TeamsAppPassword, type TeamsAttachment, type TeamsChannelAccount, type TeamsCredentials, type TeamsFetch, type TeamsMention, type TeamsMessageBody, type TeamsOutboundActivity, type TeamsPostedActivity, type TeamsTenantId, type TeamsTokenProvider, } from "#public/channels/teams/api.js";
|
|
15
15
|
export { formatTeamsContextBlock, isTeamsPersonalMessage, parseTeamsActivity, teamsThreadRootActivityId, type TeamsActivity, type TeamsActivityBase, type TeamsConversationAccount, type TeamsConversationScope, type TeamsConversationUpdateActivity, type TeamsInboundContext, type TeamsInvokeActivity, type TeamsMessageActivity, } from "#public/channels/teams/inbound.js";
|
|
16
|
-
export { deriveTeamsInputResponses, isTeamsInputResponseActivity, renderAnsweredInputRequestMessage, renderInputRequestAttachment, renderInputRequestMessage, teamsInvokeResponse, TEAMS_ADAPTIVE_CARD_CONTENT_TYPE, TEAMS_HITL_CHOICE_INPUT_ID, TEAMS_HITL_DATA_KEY, TEAMS_HITL_FREEFORM_INPUT_ID, } from "#public/channels/teams/hitl.js";
|
|
16
|
+
export { deriveTeamsInputResponses, isTeamsInputResponseActivity, isTeamsToolApprovalResponseActivity, readTeamsToolApprovalPrompt, renderAnsweredInputRequestMessage, renderInputRequestAttachment, renderInputRequestMessage, teamsInvokeResponse, TEAMS_ADAPTIVE_CARD_CONTENT_TYPE, TEAMS_HITL_CHOICE_INPUT_ID, TEAMS_HITL_DATA_KEY, TEAMS_HITL_FREEFORM_INPUT_ID, TEAMS_HITL_REQUEST_KIND_KEY, TEAMS_HITL_PROMPT_KEY, } from "#public/channels/teams/hitl.js";
|
|
17
17
|
export { collectTeamsFileParts, buildTeamsTurnMessage, createTeamsFetchFile, normalizeTeamsFilesPolicy, type TeamsFilesConfig, type TeamsFilesPolicy, } from "#public/channels/teams/attachments.js";
|
|
18
18
|
export { buildAuthCompletedText, defaultTeamsAuth, formatConnectionDisplayName, teamsMentionUser, } from "#public/channels/teams/defaults.js";
|
|
19
19
|
export { verifyTeamsJwt, verifyTeamsRequest, type TeamsJwtVerifyOptions, type TeamsVerifyOptions, type TeamsWebhookVerifier, } from "#public/channels/teams/verify.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,deriveTeamsInputResponses,isTeamsInputResponseActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{teamsChannel}from"#public/channels/teams/teamsChannel.js";import{formatTeamsContextBlock,isTeamsPersonalMessage,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{buildAuthCompletedText,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsJwt,verifyTeamsRequest}from"#public/channels/teams/verify.js";export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_MESSAGE_TEXT_MAX_LENGTH,buildAuthCompletedText,buildTeamsTurnMessage,callTeamsConnectorApi,collectTeamsFileParts,createTeamsFetchFile,defaultTeamsAuth,deriveTeamsInputResponses,formatConnectionDisplayName,formatTeamsContextBlock,isTeamsInputResponseActivity,isTeamsPersonalMessage,normalizeTeamsFilesPolicy,normalizeTeamsPostInput,parseTeamsActivity,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsChannel,teamsContinuationToken,teamsInvokeResponse,teamsMentionUser,teamsThreadRootActivityId,triggerTeamsTypingIndicator,updateTeamsActivity,verifyTeamsJwt,verifyTeamsRequest};
|
|
1
|
+
import{TEAMS_MESSAGE_TEXT_MAX_LENGTH,callTeamsConnectorApi,normalizeTeamsPostInput,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{teamsChannel}from"#public/channels/teams/teamsChannel.js";import{formatTeamsContextBlock,isTeamsPersonalMessage,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{buildAuthCompletedText,defaultTeamsAuth,formatConnectionDisplayName,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsJwt,verifyTeamsRequest}from"#public/channels/teams/verify.js";export{TEAMS_ADAPTIVE_CARD_CONTENT_TYPE,TEAMS_HITL_CHOICE_INPUT_ID,TEAMS_HITL_DATA_KEY,TEAMS_HITL_FREEFORM_INPUT_ID,TEAMS_HITL_PROMPT_KEY,TEAMS_HITL_REQUEST_KIND_KEY,TEAMS_MESSAGE_TEXT_MAX_LENGTH,buildAuthCompletedText,buildTeamsTurnMessage,callTeamsConnectorApi,collectTeamsFileParts,createTeamsFetchFile,defaultTeamsAuth,deriveTeamsInputResponses,formatConnectionDisplayName,formatTeamsContextBlock,isTeamsInputResponseActivity,isTeamsPersonalMessage,isTeamsToolApprovalResponseActivity,normalizeTeamsFilesPolicy,normalizeTeamsPostInput,parseTeamsActivity,readTeamsToolApprovalPrompt,renderAnsweredInputRequestMessage,renderInputRequestAttachment,renderInputRequestMessage,replyToTeamsActivity,resolveTeamsAccessToken,resolveTeamsAppId,resolveTeamsAppPassword,resolveTeamsTenantId,sendTeamsActivity,splitTeamsMessageText,teamsChannel,teamsContinuationToken,teamsInvokeResponse,teamsMentionUser,teamsThreadRootActivityId,triggerTeamsTypingIndicator,updateTeamsActivity,verifyTeamsJwt,verifyTeamsRequest};
|
|
@@ -33,6 +33,10 @@ export interface TeamsChannelContext extends TeamsContext {
|
|
|
33
33
|
export interface TeamsEventContext extends TeamsChannelContext, ChannelContinuationOps {
|
|
34
34
|
}
|
|
35
35
|
/** JSON-serializable Teams channel state. */
|
|
36
|
+
export interface TeamsPendingApprovalCard {
|
|
37
|
+
readonly activityId: string;
|
|
38
|
+
readonly prompt: string;
|
|
39
|
+
}
|
|
36
40
|
export interface TeamsChannelState {
|
|
37
41
|
/** Bot account captured from the inbound activity recipient. */
|
|
38
42
|
bot: TeamsChannelAccount | null;
|
|
@@ -49,6 +53,8 @@ export interface TeamsChannelState {
|
|
|
49
53
|
triggeringUser: TeamsChannelAccount | null;
|
|
50
54
|
/** Activity id for the default connection-auth card, when posted. */
|
|
51
55
|
pendingAuthActivityId?: string | null;
|
|
56
|
+
pendingApprovalCards?: Record<string, TeamsPendingApprovalCard>;
|
|
57
|
+
approvalResponderAccounts?: Record<string, TeamsChannelAccount>;
|
|
52
58
|
}
|
|
53
59
|
/** Teams channel credentials. */
|
|
54
60
|
export interface TeamsChannelCredentials extends TeamsCredentials {
|
|
@@ -98,6 +104,8 @@ type TeamsEventHandler<T extends UnstampedMessageStreamEvent["type"]> = (data: E
|
|
|
98
104
|
type TeamsSessionFailedHandler = (data: EventData<"session.failed">, channel: TeamsEventContext) => void | Promise<void>;
|
|
99
105
|
/** Event handlers supported by `teamsChannel({ events })`. */
|
|
100
106
|
export interface TeamsChannelEvents {
|
|
107
|
+
readonly "approval.candidate"?: TeamsEventHandler<"approval.candidate">;
|
|
108
|
+
readonly "approval.settled"?: TeamsEventHandler<"approval.settled">;
|
|
101
109
|
readonly "turn.started"?: TeamsEventHandler<"turn.started">;
|
|
102
110
|
readonly "actions.requested"?: TeamsEventHandler<"actions.requested">;
|
|
103
111
|
readonly "action.partial"?: TeamsEventHandler<"action.partial">;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,readTeamsInputReplyToActivityId,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),o=e.onMessage??defaultOnMessage,s=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),c={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,turnPolicy:e.turnPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},routes:[POST(e.route??`/eve/v1/teams`,async(n,{from:i,resolveSession:a,waitUntil:c})=>{let l=await verifyInbound(n,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(c(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,from:i,onInputResponse:s}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:o,from:i,resolveSession:a})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:s,waitUntil:c,from:i}):teamsOk()})],async receive(t,{from:r}){let i=t.target,a=readNonEmptyString(i.serviceUrl),o=readNonEmptyString(i.conversationId);if(!a||!o)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let s=readNonEmptyString(i.conversationType)??null,c=readNonEmptyString(i.replyToActivityId)??null,l=i.initialMessage;if(l!==void 0&&c!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readNonEmptyString(i.channelId)??null,conversationId:o,conversationType:s,replyToActivityId:c,serviceUrl:a,teamId:readNonEmptyString(i.teamId)??null,tenantId:readNonEmptyString(i.tenantId)??null};if(l!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(l);s!==`personal`&&t.id&&(c=t.id,u.replyToActivityId=t.id)}return r(teamsContinuationToken({conversationId:o,replyToActivityId:c,tenantId:u.tenantId})).send(t.message,{auth:t.auth,state:u})},events:c})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.rekey(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildOutboundActivity(t,i),credentials:r,activityId:e,conversationId:a.conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveSession(r)!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,from:e.from})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.from(resolveInputContinuationToken(e.activity,n)).respond(t,{auth:i.auth})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{defaultDeliverResult}from"#channel/adapter.js";import{readNonEmptyString}from"#shared/guards.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/channel.js";import{callTeamsConnectorApi,normalizeTeamsContinuationAddress,normalizeTeamsPostInput,replyToTeamsActivity,sendTeamsActivity,teamsContinuationToken,triggerTeamsTypingIndicator,updateTeamsActivity}from"#public/channels/teams/api.js";import{deriveTeamsInputResponses,isTeamsInputResponseActivity,isTeamsToolApprovalResponseActivity,readTeamsInputReplyToActivityId,readTeamsToolApprovalPrompt,teamsInvokeResponse}from"#public/channels/teams/hitl.js";import{formatTeamsContextBlock,parseTeamsActivity,teamsThreadRootActivityId}from"#public/channels/teams/inbound.js";import{buildTeamsTurnMessage,collectTeamsFileParts,createTeamsFetchFile,normalizeTeamsFilesPolicy}from"#public/channels/teams/attachments.js";import{defaultEvents,defaultOnMessage,defaultTeamsAuth,teamsMentionUser}from"#public/channels/teams/defaults.js";import{verifyTeamsRequest}from"#public/channels/teams/verify.js";const log=createLogger(`teams.channel`);function teamsChannel(e={}){let t=normalizeTeamsFilesPolicy(e.files),s=e.onMessage??defaultOnMessage,c=e.onInputResponse??(e.onMessage===void 0?defaultOnInputResponse:rejectInput),l={...defaultEvents,...e.events};return defineChannel({kindHint:`teams`,turnPolicy:e.turnPolicy,state:initialTeamsState(),fetchFile:createTeamsFetchFile(t),metadata:e=>({channelId:e.channelId,conversationType:e.conversationType,teamId:e.teamId}),context(t,n){return rebuildTeamsContext(t,n,e)},deliver(e,t){let r=e.state,i=r?.pendingApprovalCards;i!==void 0&&(t.state.pendingApprovalCards={...i,...t.state.pendingApprovalCards});let a=r?.approvalResponderAccounts;return a!==void 0&&(t.state.approvalResponderAccounts={...t.state.approvalResponderAccounts,...a}),defaultDeliverResult(e)},routes:[POST(e.route??`/eve/v1/teams`,async(n,{from:r,resolveSession:a,waitUntil:o})=>{let l=await verifyInbound(n,e.credentials);if(l===null)return new Response(`unauthorized`,{status:401});let u;try{u=parseJsonObject(JSON.parse(l))}catch(e){return log.warn(`inbound Teams body is not valid JSON`,{error:e}),teamsOk()}let d=parseTeamsActivity(u);return d===null?teamsOk():d.type===`message`?(o(isTeamsInputResponseActivity(d)?dispatchInputResponses({activity:d,config:e,from:r,onInputResponse:c}):dispatchMessage({activity:d,config:e,filesPolicy:t,onMessage:s,from:r,resolveSession:a})),teamsOk()):d.type===`invoke`?handleInvoke({activity:d,config:e,onInputResponse:c,waitUntil:o,from:r}):teamsOk()})],async receive(t,{from:n}){let i=t.target,a=readNonEmptyString(i.serviceUrl),o=readNonEmptyString(i.conversationId);if(!a||!o)throw Error(`teamsChannel().receive requires target.serviceUrl and target.conversationId.`);let s=readNonEmptyString(i.conversationType)??null,c=readNonEmptyString(i.replyToActivityId)??null,l=i.initialMessage;if(l!==void 0&&c!==null)throw Error("teamsChannel().receive: `replyToActivityId` and `initialMessage` are mutually exclusive.");let u={...initialTeamsState(),channelId:readNonEmptyString(i.channelId)??null,conversationId:o,conversationType:s,replyToActivityId:c,serviceUrl:a,teamId:readNonEmptyString(i.teamId)??null,tenantId:readNonEmptyString(i.tenantId)??null};if(l!==void 0){let t=await buildTeamsBinding({config:e,state:u}).thread.post(l);s!==`personal`&&t.id&&(c=t.id,u.replyToActivityId=t.id)}return n(teamsContinuationToken({conversationId:o,replyToActivityId:c,tenantId:u.tenantId})).send(t.message,{auth:t.auth,state:u})},events:l})}function rebuildTeamsContext(e,t,n){return{...buildTeamsBinding({config:n,session:t,state:e}),adaptiveCardVersion:n.adaptiveCardVersion??`1.5`,state:e}}function buildTeamsBinding(e){let n=buildTeamsHandle(e);return{teams:n,thread:{mentionUser:teamsMentionUser,post(e){return n.sendActivity(e)},async startTyping(){try{await n.startTyping()}catch(e){logError(log,`Teams typing indicator failed — swallowed`,e)}},update(e,t){return n.updateActivity(e,t)}}}}function buildTeamsHandle(e){let t=e.state,n=e.config.api,r=e.config.credentials;function requireAddress(){let e=t.conversationId??``,n=t.serviceUrl??``;if(!e||!n)throw Error(`teamsChannel: missing serviceUrl or conversationId for outbound message.`);return{conversationId:e,serviceUrl:n}}function anchor(n){if(!n.id||t.replyToActivityId||t.conversationType===`personal`)return;t.replyToActivityId=n.id;let r=t.conversationId;r&&e.session?.continuation?.rekey(teamsContinuationToken({conversationId:r,replyToActivityId:n.id,tenantId:t.tenantId}))}async function send(e){let i=requireAddress(),a=buildOutboundActivity(t,e),o=t.replyToActivityId===null?await sendTeamsActivity({...n,body:a,credentials:r,conversationId:i.conversationId,serviceUrl:i.serviceUrl}):await replyToTeamsActivity({...n,body:a,credentials:r,activityId:t.replyToActivityId,conversationId:i.conversationId,serviceUrl:i.serviceUrl});return anchor(o),o}return{channelId:t.channelId??void 0,conversationId:t.conversationId??``,conversationType:t.conversationType??void 0,replyToActivityId:t.replyToActivityId??void 0,serviceUrl:t.serviceUrl??``,teamId:t.teamId??void 0,tenantId:t.tenantId??void 0,request(e,t,i){let a=requireAddress();return callTeamsConnectorApi({...n,body:t,credentials:r,method:i?.method,path:e,serviceUrl:a.serviceUrl})},sendActivity:send,replyToActivity(e){let i=requireAddress(),a=t.replyToActivityId??``;if(!a)throw Error(`teamsChannel: missing reply activity id.`);return replyToTeamsActivity({...n,body:buildOutboundActivity(t,e),credentials:r,activityId:a,conversationId:i.conversationId,serviceUrl:i.serviceUrl})},updateActivity(e,i){let a=requireAddress();return updateTeamsActivity({...n,body:buildUpdateActivity(t,i),credentials:r,activityId:e,conversationId:normalizeTeamsContinuationAddress({conversationId:a.conversationId}).conversationId,serviceUrl:a.serviceUrl})},async startTyping(){let e=requireAddress();await triggerTeamsTypingIndicator({...n,credentials:r,conversationId:e.conversationId,serviceUrl:e.serviceUrl})}}}async function verifyInbound(e,t){try{return await verifyTeamsRequest(e,{appId:t?.webhookVerifier?void 0:t?.appId,webhookVerifier:t?.webhookVerifier})}catch(e){return log.warn(`teams inbound verification failed`,{error:e}),null}}async function dispatchMessage(e){let t=stateFromActivity(e.activity),n=buildTeamsBinding({config:e.config,state:t}),r=stateToken(t),i={...n,isSubscribed:async()=>await e.resolveSession(r)!==void 0},a;try{a=await e.onMessage(i,e.activity)}catch(e){log.error(`Teams message handler failed`,{error:e});return}if(a==null)return;let o=collectTeamsFileParts(e.activity.attachments,e.filesPolicy),s=buildTeamsTurnMessage(e.activity.text,o),c={activityId:e.activity.id,channelId:e.activity.teamsChannelId,conversationId:e.activity.conversation.id,conversationType:e.activity.conversationType,scope:e.activity.scope,teamId:e.activity.teamId,tenantId:e.activity.tenantId,userId:e.activity.from.id,userName:e.activity.from.name},l=a.context??[];try{await e.from(r).send(s,{auth:a.auth,context:[formatTeamsContextBlock(c),...l],state:t,title:a.title})}catch(e){log.error(`Teams message delivery failed`,{error:e})}}async function handleInvoke(e){if(isTeamsInputResponseActivity(e.activity))return e.waitUntil(dispatchInputResponses({activity:e.activity,config:e.config,onInputResponse:e.onInputResponse,from:e.from})),Response.json(teamsInvokeResponse());if(e.config.onInvoke===void 0)return teamsOk();let t=buildTeamsBinding({config:e.config,state:stateFromActivity(e.activity)}),n=await e.config.onInvoke(t,e.activity);return n instanceof Response?n:n&&typeof n==`object`?Response.json(n):teamsOk()}async function dispatchInputResponses(e){let t=deriveTeamsInputResponses(e.activity);if(t.length===0)return;let n=stateFromActivity(e.activity),r=buildTeamsBinding({config:e.config,state:n}),i;try{i=await e.onInputResponse(r,e.activity)}catch(e){log.error(`Teams input response authorization failed`,{error:e});return}if(i!==null)try{await e.from(resolveInputContinuationToken(e.activity,n)).respond(t,{auth:i.auth,state:approvalResponseStatePatch(e.activity,i.auth)})}catch(e){log.error(`Teams input response delivery failed`,{error:e})}}function stateFromActivity(e){let t=normalizeTeamsContinuationAddress({conversationId:e.conversation.id,replyToActivityId:teamsThreadRootActivityId(e)});return{bot:e.recipient,channelId:e.teamsChannelId??null,conversationId:e.conversation.id,conversationType:e.conversationType??e.scope,pendingAuthActivityId:null,replyToActivityId:t.replyToActivityId,serviceUrl:e.serviceUrl,teamId:e.teamId??null,tenantId:e.tenantId??null,triggeringUser:e.from}}function resolveInputContinuationToken(e,t){let n=readTeamsInputReplyToActivityId(e);return n===null?stateToken(t):teamsContinuationToken({conversationId:e.conversation.id,replyToActivityId:n,tenantId:e.tenantId})}function approvalResponseStatePatch(e,t){if(t?.principalId===void 0||!isTeamsToolApprovalResponseActivity(e))return;let n=deriveTeamsInputResponses(e)[0]?.requestId,r=e.replyToId;return n===void 0||r===void 0?{approvalResponderAccounts:{[t.principalId]:e.from}}:{approvalResponderAccounts:{[t.principalId]:e.from},pendingApprovalCards:{[n]:{activityId:r,prompt:readTeamsToolApprovalPrompt(e)??`Tool approval`}}}}function defaultOnInputResponse(e,t){return{auth:defaultTeamsAuth(t)}}function rejectInput(){return null}function initialTeamsState(){return{bot:null,channelId:null,conversationId:null,conversationType:null,approvalResponderAccounts:{},pendingApprovalCards:{},pendingAuthActivityId:null,replyToActivityId:null,serviceUrl:null,teamId:null,tenantId:null,triggeringUser:null}}function stateToken(e){let t=e.conversationId??``;if(!t)throw Error(`teamsChannel: missing conversation id.`);return teamsContinuationToken({conversationId:t,replyToActivityId:e.replyToActivityId,tenantId:e.tenantId})}function buildOutboundActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)return t;let n=normalizeTeamsPostInput(t),r=mergeChannelData(e,n.channelData);return{...n,channelData:r,conversation:e.conversationId?{id:e.conversationId}:void 0,from:e.bot??void 0,replyToId:e.replyToActivityId??void 0,type:`message`}}function buildUpdateActivity(e,t){if(typeof t!=`string`&&`type`in t&&t.type===`typing`)throw Error(`teamsChannel: cannot replace an activity with a typing indicator.`);let{channelData:n,conversation:r,from:i,recipient:a,replyToId:o,type:s,...c}=normalizeTeamsPostInput(t);return{...c,type:`message`}}function mergeChannelData(e,t){let n={...t};return e.tenantId&&(n.tenant={id:e.tenantId}),e.teamId&&(n.team={id:e.teamId}),e.channelId&&(n.channel={id:e.channelId}),Object.keys(n).length>0?parseJsonObject(n):void 0}function teamsOk(){return new Response(`ok`,{status:200})}export{teamsChannel};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { ChannelSetupLog } from "#setup/cli/index.js";
|
|
2
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
3
|
+
import { runVercel, runVercelCaptureStdout } from "#setup/primitives/run-vercel.js";
|
|
4
|
+
export declare const LINQ_TRIGGER_PATH = "/eve/v1/linq";
|
|
5
|
+
export declare const LINQ_TRIGGER_EVENTS: string[];
|
|
6
|
+
export interface LinqConnectorRef {
|
|
7
|
+
id: string;
|
|
8
|
+
uid: string;
|
|
9
|
+
phoneNumber?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ProvisionLinqConnectorDeps {
|
|
12
|
+
runVercel: typeof runVercel;
|
|
13
|
+
runVercelCaptureStdout: typeof runVercelCaptureStdout;
|
|
14
|
+
}
|
|
15
|
+
/** Credentials for a connector backed by an existing Linq account. */
|
|
16
|
+
export interface LinqExistingAccountCredentials {
|
|
17
|
+
apiToken: string;
|
|
18
|
+
phoneNumbers: string[];
|
|
19
|
+
}
|
|
20
|
+
/** Parses Vercel Connect JSON for an app-scoped Linq connector. */
|
|
21
|
+
export declare function parseCreatedLinqConnector(stdout: string): LinqConnectorRef | undefined;
|
|
22
|
+
/** Creates a managed Linq connector and routes verified events to eve. */
|
|
23
|
+
export declare function provisionLinqConnector(input: {
|
|
24
|
+
/** When omitted, Connect opens Linq's managed browser flow to provision a line. */
|
|
25
|
+
existingAccount?: LinqExistingAccountCredentials;
|
|
26
|
+
log: ChannelSetupLog;
|
|
27
|
+
project: VercelProjectReference;
|
|
28
|
+
projectRoot: string;
|
|
29
|
+
slug: string;
|
|
30
|
+
signal?: AbortSignal;
|
|
31
|
+
deps?: ProvisionLinqConnectorDeps;
|
|
32
|
+
}): Promise<LinqConnectorRef>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{array,object,string}from"../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/schemas.js";import"../../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/index.js";import{runVercel,runVercelCaptureStdout}from"#setup/primitives/run-vercel.js";import{createPromptCommandOutput,withPhase}from"#setup/cli/index.js";import{replaceConnectTrigger}from"#setup/connect-provisioning.js";const LINQ_TRIGGER_PATH=`/eve/v1/linq`,LINQ_TRIGGER_EVENTS=[`message.received`,`reaction.added`,`reaction.removed`],ConnectorSchema=object({id:string().min(1),uid:string().min(1),supportedSubjectTypes:array(string()).refine(e=>e.includes(`app`)),data:object({phoneNumbers:array(string().min(1)).optional()}).optional()});function parseCreatedLinqConnector(e){try{let t=ConnectorSchema.safeParse(JSON.parse(e));if(!t.success)return;let n=t.data.data?.phoneNumbers?.[0],r={id:t.data.id,uid:t.data.uid};return n!==void 0&&(r.phoneNumber=n),r}catch{return}}function requireCreatedConnector(e){if(!e.ok){let t=[e.stderr,e.stdout].find(e=>e!==void 0&&e.trim().length>0);throw Error(t?`Linq connector creation failed:\n${t}`:`Linq connector creation failed.`)}let t=parseCreatedLinqConnector(e.stdout);if(t===void 0)throw Error(`Vercel returned an invalid Linq connector.`);return t}async function provisionLinqConnector(e){let t=e.deps??{runVercel,runVercelCaptureStdout},n=createPromptCommandOutput(e.log),onOutput=e=>{URL.parse(e.text)===null&&n(e)},i=[`connect`,`create`,`linq`,`--name`,e.slug],a=e.existingAccount===void 0?void 0:JSON.stringify({apiToken:e.existingAccount.apiToken,phoneNumbers:e.existingAccount.phoneNumbers});a!==void 0&&i.push(`--connector-type`,`linq`,`--data`,`@-`),i.push(`--triggers`,...LINQ_TRIGGER_EVENTS.flatMap(e=>[`--trigger-event`,e]),`-F`,`json`,`--scope`,e.project.orgId);let o=await withPhase(e.log,`Creating Linq connector...`,()=>t.runVercelCaptureStdout(i,{cwd:e.projectRoot,nonInteractive:!0,onOutput,signal:e.signal,stdin:a}));e.signal?.throwIfAborted();let s=await readLinqConnector({connector:requireCreatedConnector(o),projectRoot:e.projectRoot,orgId:e.project.orgId,signal:e.signal,deps:t});if((await withPhase(e.log,`Connecting Linq credentials...`,()=>replaceConnectTrigger({connectorUid:s.uid,projectRoot:e.projectRoot,projectId:e.project.projectId,orgId:e.project.orgId,environment:`production`,triggerPath:LINQ_TRIGGER_PATH,onOutput,signal:e.signal,deps:t}))).state!==`attached`)throw Error(`Linq connector was created, but its trigger could not be attached. Run \`vercel connect attach ${s.uid} --project ${e.project.projectId} --environment production --triggers --trigger-path ${LINQ_TRIGGER_PATH} --yes --scope ${e.project.orgId}\`.`);return s}async function readLinqConnector(e){let t=await e.deps.runVercelCaptureStdout([`api`,`/v1/connect/connectors/${encodeURIComponent(e.connector.id)}`,`--scope`,e.orgId],{cwd:e.projectRoot,nonInteractive:!0,signal:e.signal});if(!t.ok)return e.connector;let n=parseCreatedLinqConnector(t.stdout);return n?.phoneNumber===void 0?e.connector:{...e.connector,phoneNumber:n.phoneNumber}}export{LINQ_TRIGGER_EVENTS,LINQ_TRIGGER_PATH,parseCreatedLinqConnector,provisionLinqConnector};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { VercelProjectReference } from "#setup/project-resolution.js";
|
|
2
|
+
import { type LinqExistingAccountCredentials } from "./connect.js";
|
|
3
|
+
import { type SetupApplyContext, type SetupPrepareContext } from "../types.js";
|
|
4
|
+
interface LinqSetupPlan {
|
|
5
|
+
credentials: "connect" | "portable";
|
|
6
|
+
connectorSlug?: string;
|
|
7
|
+
existingAccount?: LinqExistingAccountCredentials;
|
|
8
|
+
project?: VercelProjectReference;
|
|
9
|
+
apiKey?: string;
|
|
10
|
+
signingSecret?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function prepareLinqSetup(context: SetupPrepareContext): Promise<LinqSetupPlan>;
|
|
13
|
+
export declare function applyLinqSetup(plan: LinqSetupPlan, context: SetupApplyContext): Promise<{
|
|
14
|
+
facts: {
|
|
15
|
+
label: string;
|
|
16
|
+
value: string;
|
|
17
|
+
kind: "phone";
|
|
18
|
+
}[];
|
|
19
|
+
deploymentRequired: true;
|
|
20
|
+
}>;
|
|
21
|
+
export declare const LINQ_SETUP: import("../types.js").SetupIntegration;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import{defineSetupIntegration}from"../types.js";import{provisionLinqConnector}from"./connect.js";import{join}from"node:path";import{deriveSlackConnectorSlug}from"#setup/scaffold/index.js";import{select,text}from"#setup/ask.js";import{writeTextFile}from"#setup/scaffold/files.js";import{appendEnv}from"#setup/append-env.js";function validatePhoneNumbers(e){let t=e.split(`,`).map(e=>e.trim()).filter(Boolean);return t.length===0?`Enter at least one phone number.`:t.every(e=>/^\+[1-9]\d{1,14}$/.test(e))?null:`Use comma-separated E.164 numbers, for example +14155550123.`}function connectTemplate(e){return`import { connectLinqCredentials } from "@vercel/connect/eve";
|
|
2
|
+
import { linqChannel } from "eve/channels/linq";
|
|
3
|
+
|
|
4
|
+
export default linqChannel({
|
|
5
|
+
credentials: connectLinqCredentials(${JSON.stringify(e)}),
|
|
6
|
+
});
|
|
7
|
+
`}async function prepareLinqSetup(e){let t=await e.asker.ask(select({key:`linq-credentials`,message:`How would you like to configure Linq?`,options:[{id:`connect`,value:`connect`,label:`Set up Vercel Connect`,hint:`Provision a managed Linq line`},{id:`portable`,value:`portable`,label:`Use portable credentials`,hint:`Register the webhook in Linq`}],recommended:e.environment.vercel.kind===`available`?`connect`:`portable`,required:!0}));if(t===`connect`){if(e.environment.vercel.kind===`unavailable`)throw Error("Vercel Connect requires an authenticated Vercel CLI. Run `vercel login`, then retry Linq setup.");let n=await e.resolveVercelProject(`Linq`),o=await e.asker.ask(text({key:`linq-connector-name`,message:`Name your Linq agent`,recommended:await deriveSlackConnectorSlug(e.appRoot),required:!0}));if(await e.asker.ask(select({key:`linq-account`,message:`Which Linq account would you like to use?`,options:[{id:`new`,value:`new`,label:`Create a new Linq account`,hint:`Provision a new managed Linq line`},{id:`existing`,value:`existing`,label:`Use an existing Linq account`,hint:`Connect a Linq partner API token and phone numbers`}],recommended:`new`,required:!0}))===`new`)return{credentials:t,connectorSlug:o.trim(),project:n};let s=await e.asker.ask(text({key:`linq-existing-api-token`,message:`Linq partner API token`,required:!0,sensitive:!0,environment:`LINQ_API_KEY`})),c=await e.asker.ask(text({key:`linq-existing-phone-numbers`,message:`Linq phone numbers`,placeholder:`+14155550123, +14155550124`,required:!0,validate:validatePhoneNumbers}));return{credentials:t,connectorSlug:o.trim(),existingAccount:{apiToken:s.trim(),phoneNumbers:c.split(`,`).map(e=>e.trim()).filter(Boolean)},project:n}}let n=await e.asker.ask(text({key:`linq-api-key`,message:`Linq API key`,required:!0,sensitive:!0,environment:`LINQ_API_KEY`})),o=await e.asker.ask(text({key:`linq-signing-secret`,message:`Linq webhook signing secret`,required:!0,sensitive:!0,environment:`LINQ_WEBHOOK_SECRET`}));return{credentials:t,apiKey:n.trim(),signingSecret:o.trim()}}async function applyLinqSetup(e,r){let i=join(r.appRoot,`agent/channels/linq.ts`),a;if(e.credentials===`connect`){let n={log:r.presenter.log,project:e.project,projectRoot:r.appRoot,slug:e.connectorSlug,signal:r.signal};e.existingAccount!==void 0&&(n.existingAccount=e.existingAccount);let s=await provisionLinqConnector(n);a=s.phoneNumber,await writeTextFile(i,connectTemplate(s.uid),{force:r.force}),a!==void 0&&r.presenter.note(a,`Text your agent`,{tone:`success`})}else await appendEnv(join(r.appRoot,`.env.local`),{LINQ_API_KEY:e.apiKey,LINQ_WEBHOOK_SECRET:e.signingSecret}),await writeTextFile(i,`import { linqChannel } from "eve/channels/linq";
|
|
8
|
+
|
|
9
|
+
export default linqChannel({
|
|
10
|
+
credentials: {
|
|
11
|
+
apiKey: process.env.LINQ_API_KEY!,
|
|
12
|
+
signingSecret: process.env.LINQ_WEBHOOK_SECRET!,
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
`,{force:r.force}),r.presenter.nextSteps([`Deploy the agent, then create a Linq webhook subscription for https://<your-host>/eve/v1/linq with message.received, reaction.added, and reaction.removed events.`]);return r.presenter.log.success(`Scaffolded channel: linq`),{facts:a===void 0?[]:[{label:`Agent phone number`,value:a,kind:`phone`}],deploymentRequired:!0}}const LINQ_SETUP=defineSetupIntegration({kind:`linq`,label:`Linq`,hint:`iMessage and SMS through Linq`,prepare:prepareLinqSetup,apply:applyLinqSetup});export{LINQ_SETUP,applyLinqSetup,prepareLinqSetup};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{DISCORD_SETUP}from"./discord/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,PHOTON_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
|
|
1
|
+
import{DISCORD_SETUP}from"./discord/setup.js";import{GITHUB_SETUP}from"./github/setup.js";import{LINEAR_SETUP}from"./linear/setup.js";import{LINQ_SETUP}from"./linq/setup.js";import{PHOTON_SETUP}from"./photon/setup.js";import{SLACK_SETUP}from"./slack/setup.js";import{WEB_SETUP}from"./web/setup.js";import{createSetupContexts,createSetupPresenter}from"./shared/ui.js";const SETUP_INTEGRATIONS=[WEB_SETUP,SLACK_SETUP,DISCORD_SETUP,GITHUB_SETUP,LINEAR_SETUP,LINQ_SETUP,PHOTON_SETUP];function setupIntegration(e){let t=SETUP_INTEGRATIONS.find(t=>t.kind===e);if(t===void 0)throw Error(`Integration setup "${e}" is not available in this version of eve. Upgrade eve and try again.`);return t}export{SETUP_INTEGRATIONS,createSetupContexts,createSetupPresenter,setupIntegration};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.
|
|
1
|
+
import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.58`,DEFAULT_CONNECT_PACKAGE_VERSION=`0.4.3`,DEFAULT_ZOD_PACKAGE_VERSION=`4.4.3`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.41.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.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__",
|