@microsoft/agents-hosting 1.7.0-beta.1.g8bcd4f11a7 → 1.7.1
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/README.md +16 -0
- package/dist/package.json +3 -3
- package/dist/src/agent-client/agentClient.js +4 -3
- package/dist/src/agent-client/agentClient.js.map +1 -1
- package/dist/src/agent-client/agentResponseHandler.d.ts +25 -6
- package/dist/src/agent-client/agentResponseHandler.js +16 -55
- package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
- package/dist/src/agent-client/createAgentResponseHandler.d.ts +48 -0
- package/dist/src/agent-client/createAgentResponseHandler.js +92 -0
- package/dist/src/agent-client/createAgentResponseHandler.js.map +1 -0
- package/dist/src/agent-client/index.d.ts +1 -0
- package/dist/src/agent-client/index.js +1 -0
- package/dist/src/agent-client/index.js.map +1 -1
- package/dist/src/app/adaptiveCards/activityValueParsers.js +2 -1
- package/dist/src/app/adaptiveCards/activityValueParsers.js.map +1 -1
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js +13 -12
- package/dist/src/app/adaptiveCards/adaptiveCardsActions.js.map +1 -1
- package/dist/src/app/agentApplication.js +8 -8
- package/dist/src/app/agentApplication.js.map +1 -1
- package/dist/src/app/streaming/streamingResponse.js +2 -2
- package/dist/src/app/streaming/streamingResponse.js.map +1 -1
- package/dist/src/app/turnState.d.ts +0 -1
- package/dist/src/app/turnState.js +15 -14
- package/dist/src/app/turnState.js.map +1 -1
- package/dist/src/app/turnStateProperty.js +4 -2
- package/dist/src/app/turnStateProperty.js.map +1 -1
- package/dist/src/auth/authConfiguration.js +5 -3
- package/dist/src/auth/authConfiguration.js.map +1 -1
- package/dist/src/auth/jwt-middleware.d.ts +2 -2
- package/dist/src/auth/jwt-middleware.js +84 -6
- package/dist/src/auth/jwt-middleware.js.map +1 -1
- package/dist/src/auth/msal/msalTokenProvider.js +16 -16
- package/dist/src/auth/msal/msalTokenProvider.js.map +1 -1
- package/dist/src/baseAdapter.js +3 -1
- package/dist/src/baseAdapter.js.map +1 -1
- package/dist/src/cloudAdapter.d.ts +2 -2
- package/dist/src/cloudAdapter.js +10 -10
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/createCloudAdapter.d.ts +40 -0
- package/dist/src/createCloudAdapter.js +44 -0
- package/dist/src/createCloudAdapter.js.map +1 -0
- package/dist/src/errorHelper.js +206 -79
- package/dist/src/errorHelper.js.map +1 -1
- package/dist/src/headerPropagation.js +3 -1
- package/dist/src/headerPropagation.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/interfaces/index.d.ts +5 -0
- package/dist/src/interfaces/index.js +22 -0
- package/dist/src/interfaces/index.js.map +1 -0
- package/dist/src/interfaces/webResponse.d.ts +41 -0
- package/dist/src/interfaces/webResponse.js +7 -0
- package/dist/src/interfaces/webResponse.js.map +1 -0
- package/dist/src/middlewareSet.d.ts +0 -1
- package/dist/src/middlewareSet.js +4 -1
- package/dist/src/middlewareSet.js.map +1 -1
- package/dist/src/oauth/userTokenClient.js +2 -1
- package/dist/src/oauth/userTokenClient.js.map +1 -1
- package/dist/src/state/conversationState.js +4 -2
- package/dist/src/state/conversationState.js.map +1 -1
- package/dist/src/state/userState.js +4 -2
- package/dist/src/state/userState.js.map +1 -1
- package/dist/src/storage/memoryStorage.js +5 -3
- package/dist/src/storage/memoryStorage.js.map +1 -1
- package/dist/src/transcript/consoleTranscriptLogger.js +3 -1
- package/dist/src/transcript/consoleTranscriptLogger.js.map +1 -1
- package/dist/src/transcript/fileTranscriptLogger.js +5 -4
- package/dist/src/transcript/fileTranscriptLogger.js.map +1 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js +2 -1
- package/dist/src/transcript/transcriptLoggerMiddleware.js.map +1 -1
- package/dist/src/turnContext.js +2 -1
- package/dist/src/turnContext.js.map +1 -1
- package/package.json +3 -3
- package/src/agent-client/agentClient.ts +5 -4
- package/src/agent-client/agentResponseHandler.ts +43 -67
- package/src/agent-client/createAgentResponseHandler.ts +133 -0
- package/src/agent-client/index.ts +1 -0
- package/src/app/adaptiveCards/activityValueParsers.ts +3 -2
- package/src/app/adaptiveCards/adaptiveCardsActions.ts +5 -5
- package/src/app/agentApplication.ts +8 -16
- package/src/app/streaming/streamingResponse.ts +2 -2
- package/src/app/turnState.ts +15 -14
- package/src/app/turnStateProperty.ts +4 -2
- package/src/auth/authConfiguration.ts +5 -3
- package/src/auth/jwt-middleware.ts +87 -8
- package/src/auth/msal/msalTokenProvider.ts +16 -16
- package/src/baseAdapter.ts +3 -2
- package/src/cloudAdapter.ts +12 -12
- package/src/createCloudAdapter.ts +56 -0
- package/src/errorHelper.ts +244 -89
- package/src/headerPropagation.ts +4 -1
- package/src/index.ts +2 -0
- package/src/interfaces/index.ts +6 -0
- package/src/interfaces/webResponse.ts +44 -0
- package/src/middlewareSet.ts +3 -1
- package/src/oauth/userTokenClient.ts +3 -2
- package/src/state/conversationState.ts +4 -3
- package/src/state/userState.ts +4 -3
- package/src/storage/memoryStorage.ts +5 -3
- package/src/transcript/consoleTranscriptLogger.ts +3 -2
- package/src/transcript/fileTranscriptLogger.ts +6 -5
- package/src/transcript/transcriptLoggerMiddleware.ts +3 -2
- package/src/turnContext.ts +3 -2
|
@@ -4,8 +4,10 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
import { AuthConfiguration, resolveAuthority } from './authConfiguration'
|
|
7
|
-
import { Response, NextFunction } from 'express'
|
|
8
7
|
import { Request } from './request'
|
|
8
|
+
import { WebResponse, NextFunction } from '../interfaces/webResponse'
|
|
9
|
+
import { Errors } from '../errorHelper'
|
|
10
|
+
import { ExceptionHelper } from '@microsoft/agents-activity'
|
|
9
11
|
import jwksRsa, { JwksClient, SigningKey } from 'jwks-rsa'
|
|
10
12
|
import jwt, { JwtHeader, JwtPayload, SignCallback, GetPublicKeyOrSecret } from 'jsonwebtoken'
|
|
11
13
|
import { debug } from '@microsoft/agents-telemetry'
|
|
@@ -64,7 +66,7 @@ const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtP
|
|
|
64
66
|
logger.debug('jwt.decode ', JSON.stringify(payload))
|
|
65
67
|
|
|
66
68
|
if (!payload) {
|
|
67
|
-
throw
|
|
69
|
+
throw ExceptionHelper.generateException(Error, Errors.InvalidJwtToken)
|
|
68
70
|
}
|
|
69
71
|
const audience = payload.aud
|
|
70
72
|
|
|
@@ -73,7 +75,7 @@ const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtP
|
|
|
73
75
|
: undefined
|
|
74
76
|
|
|
75
77
|
if (!matchingEntry) {
|
|
76
|
-
const err =
|
|
78
|
+
const err = ExceptionHelper.generateException(Error, Errors.JwtAudienceMismatch)
|
|
77
79
|
logger.error(err.message, audience)
|
|
78
80
|
throw err
|
|
79
81
|
}
|
|
@@ -119,13 +121,78 @@ const verifyToken = async (raw: string, config: AuthConfiguration): Promise<JwtP
|
|
|
119
121
|
})
|
|
120
122
|
}
|
|
121
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Determines whether an `Authorization` header value is present (non-empty).
|
|
126
|
+
*
|
|
127
|
+
* The {@link Request} contract allows `string | string[] | undefined` because
|
|
128
|
+
* different web frameworks surface headers differently. This treats an empty
|
|
129
|
+
* string or empty array as "absent" so callers can distinguish a missing header
|
|
130
|
+
* (anonymous / 401) from a present-but-malformed one (always 401).
|
|
131
|
+
* @param authorization The raw `Authorization` header value.
|
|
132
|
+
* @returns `true` when a non-empty header value is present.
|
|
133
|
+
*/
|
|
134
|
+
function hasAuthorizationHeader (authorization: string | string[] | undefined): boolean {
|
|
135
|
+
if (Array.isArray(authorization)) {
|
|
136
|
+
return authorization.some((value) => typeof value === 'string' && value.trim().length > 0)
|
|
137
|
+
}
|
|
138
|
+
return typeof authorization === 'string' && authorization.trim().length > 0
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Parses a single `Authorization` header value and returns its bearer token.
|
|
143
|
+
*
|
|
144
|
+
* Validates the `Bearer <token>` scheme, returning `undefined` for anything
|
|
145
|
+
* malformed (wrong scheme, missing token, or extra whitespace-delimited parts).
|
|
146
|
+
* @param headerValue A single `Authorization` header value.
|
|
147
|
+
* @returns The bearer token, or `undefined` if the value is absent or malformed.
|
|
148
|
+
*/
|
|
149
|
+
function parseBearerValue (headerValue: string | undefined): string | undefined {
|
|
150
|
+
if (typeof headerValue !== 'string') {
|
|
151
|
+
return undefined
|
|
152
|
+
}
|
|
153
|
+
const parts = headerValue.trim().split(/\s+/)
|
|
154
|
+
if (parts.length !== 2) {
|
|
155
|
+
return undefined
|
|
156
|
+
}
|
|
157
|
+
const [scheme, token] = parts
|
|
158
|
+
if (scheme.toLowerCase() !== 'bearer' || !token) {
|
|
159
|
+
return undefined
|
|
160
|
+
}
|
|
161
|
+
return token
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Extracts the bearer token from a raw `Authorization` header value.
|
|
166
|
+
*
|
|
167
|
+
* On Node's core HTTP parser (which both Express and Fastify use) `Authorization`
|
|
168
|
+
* is always surfaced as a single string holding the *first* header line —
|
|
169
|
+
* duplicate `Authorization` headers are discarded, not comma-joined. The
|
|
170
|
+
* `string[]` case is handled only because the {@link Request} contract permits
|
|
171
|
+
* it for non-Node frameworks; when an array is supplied, every entry is inspected
|
|
172
|
+
* and the first valid `Bearer <token>` is returned (the bearer value is not
|
|
173
|
+
* assumed to be first). Returns `undefined` for anything malformed so the caller
|
|
174
|
+
* can emit a consistent 401 instead of throwing.
|
|
175
|
+
* @param authorization The raw `Authorization` header value.
|
|
176
|
+
* @returns The bearer token, or `undefined` if the header is absent or malformed.
|
|
177
|
+
*/
|
|
178
|
+
function extractBearerToken (authorization: string | string[] | undefined): string | undefined {
|
|
179
|
+
const values = Array.isArray(authorization) ? authorization : [authorization]
|
|
180
|
+
for (const value of values) {
|
|
181
|
+
const token = parseBearerValue(value)
|
|
182
|
+
if (token) {
|
|
183
|
+
return token
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return undefined
|
|
187
|
+
}
|
|
188
|
+
|
|
122
189
|
/**
|
|
123
190
|
* Middleware to authorize JWT tokens.
|
|
124
191
|
* @param authConfig The authentication configuration.
|
|
125
192
|
* @returns An Express middleware function.
|
|
126
193
|
*/
|
|
127
194
|
export const authorizeJWT = (authConfig: AuthConfiguration) => {
|
|
128
|
-
return async function (req: Request, res:
|
|
195
|
+
return async function (req: Request, res: WebResponse, next: NextFunction) {
|
|
129
196
|
let failed = false
|
|
130
197
|
logger.debug('authorizing jwt')
|
|
131
198
|
if (req.method !== 'POST' && req.method !== 'GET') {
|
|
@@ -133,9 +200,8 @@ export const authorizeJWT = (authConfig: AuthConfiguration) => {
|
|
|
133
200
|
logger.warn('Method not allowed', req.method)
|
|
134
201
|
res.status(405).send({ 'jwt-auth-error': 'Method not allowed' })
|
|
135
202
|
} else {
|
|
136
|
-
const
|
|
137
|
-
if (
|
|
138
|
-
const token: string = authHeader.split(' ')[1] // Extract the token from the Bearer string
|
|
203
|
+
const token = extractBearerToken(req.headers.authorization)
|
|
204
|
+
if (token) {
|
|
139
205
|
try {
|
|
140
206
|
const user = await verifyToken(token, authConfig)
|
|
141
207
|
logger.debug('token verified for ', user)
|
|
@@ -143,8 +209,21 @@ export const authorizeJWT = (authConfig: AuthConfiguration) => {
|
|
|
143
209
|
} catch (err: Error | any) {
|
|
144
210
|
failed = true
|
|
145
211
|
logger.error(err)
|
|
146
|
-
|
|
212
|
+
// Emit only the human-readable description rather than the
|
|
213
|
+
// ExceptionHelper-formatted "[code] - description - helplink" string,
|
|
214
|
+
// so the wire format does not leak internal error codes or help links.
|
|
215
|
+
// Fall back to a stable string so a thrown non-Error (no description/
|
|
216
|
+
// message) never serializes to an empty `{}` and drops the detail.
|
|
217
|
+
const wireMessage: string = err?.description ?? err?.message ?? 'unauthorized'
|
|
218
|
+
res.status(401).send({ 'jwt-auth-error': wireMessage })
|
|
147
219
|
}
|
|
220
|
+
} else if (hasAuthorizationHeader(req.headers.authorization)) {
|
|
221
|
+
// Header is present but not a well-formed `Bearer <token>` (e.g. wrong
|
|
222
|
+
// scheme, missing token, or an array value). Respond with a consistent
|
|
223
|
+
// 401 rather than letting malformed input throw before authorization.
|
|
224
|
+
failed = true
|
|
225
|
+
logger.warn('malformed authorization header')
|
|
226
|
+
res.status(401).send({ 'jwt-auth-error': 'invalid authorization header' })
|
|
148
227
|
} else {
|
|
149
228
|
if (!authConfig.clientId && process.env.NODE_ENV !== 'production') {
|
|
150
229
|
logger.info('using anonymous auth')
|
|
@@ -284,7 +284,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
284
284
|
if (typeof authConfigOrScope === 'string') {
|
|
285
285
|
// Called as getAccessToken(scope)
|
|
286
286
|
if (!this.connectionSettings) {
|
|
287
|
-
throw
|
|
287
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForGetAccessTokenScope)
|
|
288
288
|
}
|
|
289
289
|
authConfig = this.connectionSettings
|
|
290
290
|
actualScope = authConfigOrScope
|
|
@@ -378,7 +378,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
378
378
|
if (Array.isArray(authConfigOrScopes)) {
|
|
379
379
|
// Called as acquireTokenOnBehalfOf(scopes, oboAssertion)
|
|
380
380
|
if (!this.connectionSettings) {
|
|
381
|
-
throw
|
|
381
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForAcquireTokenOnBehalfOf)
|
|
382
382
|
}
|
|
383
383
|
authConfig = this.connectionSettings
|
|
384
384
|
actualScopes = authConfigOrScopes
|
|
@@ -399,7 +399,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
399
399
|
scopes: actualScopes
|
|
400
400
|
})
|
|
401
401
|
if (!token?.accessToken) {
|
|
402
|
-
throw
|
|
402
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenOnBehalfOf)
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
return token.accessToken
|
|
@@ -412,7 +412,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
412
412
|
record({ agenticInstanceId: agentAppInstanceId })
|
|
413
413
|
|
|
414
414
|
if (!this.connectionSettings) {
|
|
415
|
-
throw
|
|
415
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForGetAgenticInstanceToken)
|
|
416
416
|
}
|
|
417
417
|
|
|
418
418
|
const instanceTokenCacheKey = MsalTokenProvider.cacheKey(
|
|
@@ -444,7 +444,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
444
444
|
})
|
|
445
445
|
|
|
446
446
|
if (!token?.accessToken) {
|
|
447
|
-
throw
|
|
447
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireInstanceTokenForAgentInstance, undefined, { agentAppInstanceId })
|
|
448
448
|
}
|
|
449
449
|
|
|
450
450
|
this.cacheAgenticAuthenticationResult(instanceTokenCacheKey, token)
|
|
@@ -494,7 +494,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
494
494
|
*/
|
|
495
495
|
private async acquireTokenForAgenticScenarios (tenantId: string, clientId: string, clientAssertion: string | undefined, scopes: string[], tokenBodyParameters: { [key: string]: any }): Promise<string | null> {
|
|
496
496
|
if (!this.connectionSettings) {
|
|
497
|
-
throw
|
|
497
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForGetAgenticInstanceToken)
|
|
498
498
|
}
|
|
499
499
|
|
|
500
500
|
logger.debug('acquireTokenForAgenticScenarios clientId=%s tenantId=%s scopes=%o grant_type=%s', clientId, tenantId, scopes, tokenBodyParameters.grant_type)
|
|
@@ -585,7 +585,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
585
585
|
})
|
|
586
586
|
|
|
587
587
|
if (!token) {
|
|
588
|
-
throw
|
|
588
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireInstanceTokenForUserToken, undefined, { agentAppInstanceId })
|
|
589
589
|
}
|
|
590
590
|
|
|
591
591
|
return token
|
|
@@ -594,7 +594,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
594
594
|
|
|
595
595
|
public async getAgenticApplicationToken (tenantId: string, agentAppInstanceId: string): Promise<string> {
|
|
596
596
|
if (!this.connectionSettings?.clientId) {
|
|
597
|
-
throw
|
|
597
|
+
throw ExceptionHelper.generateException(Error, Errors.ConnectionSettingsRequiredForGetAgenticApplicationToken)
|
|
598
598
|
}
|
|
599
599
|
logger.debug('getAgenticApplicationToken clientId=%s tenantId=%s agentAppInstanceId=%s', this.connectionSettings.clientId, tenantId, agentAppInstanceId)
|
|
600
600
|
|
|
@@ -605,7 +605,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
605
605
|
if (!this.connectionSettings.idpmResource) {
|
|
606
606
|
resource = 'api://AzureAdTokenExchange/.default'
|
|
607
607
|
} else if (!URL.canParse(this.connectionSettings.idpmResource)) {
|
|
608
|
-
throw
|
|
608
|
+
throw ExceptionHelper.generateException(Error, Errors.IdpmResourceAbsoluteUriRequired)
|
|
609
609
|
} else {
|
|
610
610
|
resource = this.connectionSettings.idpmResource
|
|
611
611
|
}
|
|
@@ -617,7 +617,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
617
617
|
})
|
|
618
618
|
const tokenResult = await msiApp.acquireToken({ resource })
|
|
619
619
|
if (!tokenResult?.accessToken) {
|
|
620
|
-
throw
|
|
620
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenViaIdentityProxyManagerForAgentInstance, undefined, { agentAppInstanceId })
|
|
621
621
|
}
|
|
622
622
|
logger.debug('getAgenticApplicationToken via IdentityProxyManager clientId=%s resource=%s', this.connectionSettings.clientId, resource)
|
|
623
623
|
return tokenResult.accessToken
|
|
@@ -655,7 +655,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
655
655
|
})
|
|
656
656
|
|
|
657
657
|
if (!token) {
|
|
658
|
-
throw
|
|
658
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireInstanceTokenForAgentInstance, undefined, { agentAppInstanceId })
|
|
659
659
|
}
|
|
660
660
|
|
|
661
661
|
return token
|
|
@@ -780,7 +780,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
780
780
|
azureRegion: authConfig.azureRegion
|
|
781
781
|
})
|
|
782
782
|
if (!token?.accessToken) {
|
|
783
|
-
throw
|
|
783
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenUsingCertificate)
|
|
784
784
|
}
|
|
785
785
|
return token.accessToken
|
|
786
786
|
}
|
|
@@ -799,7 +799,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
799
799
|
azureRegion: authConfig.azureRegion
|
|
800
800
|
})
|
|
801
801
|
if (!token?.accessToken) {
|
|
802
|
-
throw
|
|
802
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenUsingClientSecret)
|
|
803
803
|
}
|
|
804
804
|
return token.accessToken
|
|
805
805
|
}
|
|
@@ -824,7 +824,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
824
824
|
const token = await cca.acquireTokenByClientCredential({ scopes, azureRegion: authConfig.azureRegion })
|
|
825
825
|
logger.debug('got token using FIC client assertion')
|
|
826
826
|
if (!token?.accessToken) {
|
|
827
|
-
throw
|
|
827
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenUsingFICClientAssertion)
|
|
828
828
|
}
|
|
829
829
|
return token.accessToken
|
|
830
830
|
}
|
|
@@ -850,7 +850,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
850
850
|
const token = await cca.acquireTokenByClientCredential({ scopes, azureRegion: authConfig.azureRegion })
|
|
851
851
|
logger.debug('got token using WID client assertion')
|
|
852
852
|
if (!token?.accessToken) {
|
|
853
|
-
throw
|
|
853
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireTokenUsingWIDClientAssertion)
|
|
854
854
|
}
|
|
855
855
|
return token.accessToken
|
|
856
856
|
}
|
|
@@ -874,7 +874,7 @@ export class MsalTokenProvider implements AuthProvider {
|
|
|
874
874
|
})
|
|
875
875
|
logger.debug('got token for FIC')
|
|
876
876
|
if (!response?.accessToken) {
|
|
877
|
-
throw
|
|
877
|
+
throw ExceptionHelper.generateException(Error, Errors.FailedToAcquireExternalTokenForFICClientAssertion)
|
|
878
878
|
}
|
|
879
879
|
return response.accessToken
|
|
880
880
|
}
|
package/src/baseAdapter.ts
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
import { Middleware, MiddlewareHandler, MiddlewareSet } from './middlewareSet'
|
|
7
7
|
import { TurnContext } from './turnContext'
|
|
8
8
|
import { debug } from '@microsoft/agents-telemetry'
|
|
9
|
-
import { Activity, ConversationReference } from '@microsoft/agents-activity'
|
|
9
|
+
import { Activity, ConversationReference, ExceptionHelper } from '@microsoft/agents-activity'
|
|
10
10
|
import { ResourceResponse } from './connector-client/resourceResponse'
|
|
11
11
|
import { AttachmentData } from './connector-client/attachmentData'
|
|
12
12
|
import { AttachmentInfo } from './connector-client/attachmentInfo'
|
|
13
13
|
import { JwtPayload } from 'jsonwebtoken'
|
|
14
|
+
import { Errors } from './errorHelper'
|
|
14
15
|
|
|
15
16
|
const logger = debug('agents:base-adapter')
|
|
16
17
|
|
|
@@ -202,7 +203,7 @@ export abstract class BaseAdapter {
|
|
|
202
203
|
if (err instanceof Error) {
|
|
203
204
|
await this.onTurnError(pContext.proxy, err)
|
|
204
205
|
} else {
|
|
205
|
-
throw
|
|
206
|
+
throw ExceptionHelper.generateException(Error, Errors.UnknownErrorType, undefined, { errorMessage: err.message })
|
|
206
207
|
}
|
|
207
208
|
} else {
|
|
208
209
|
throw err
|
package/src/cloudAdapter.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
import { AgentHandler, INVOKE_RESPONSE_KEY } from './activityHandler'
|
|
7
7
|
import { BaseAdapter } from './baseAdapter'
|
|
8
8
|
import { TurnContext } from './turnContext'
|
|
9
|
-
import { Response } from 'express'
|
|
10
9
|
import { Request } from './auth/request'
|
|
10
|
+
import { WebResponse } from './interfaces/webResponse'
|
|
11
11
|
import { ConnectorClient } from './connector-client/connectorClient'
|
|
12
12
|
import { AuthConfiguration, getAuthConfigWithDefaults } from './auth/authConfiguration'
|
|
13
13
|
import { AuthProvider } from './auth/authProvider'
|
|
@@ -289,7 +289,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
289
289
|
*/
|
|
290
290
|
protected resolveIfConnectorClientIsNeeded (activity: Activity): boolean {
|
|
291
291
|
if (!activity) {
|
|
292
|
-
throw
|
|
292
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ActivityParameterRequired)
|
|
293
293
|
}
|
|
294
294
|
|
|
295
295
|
switch (activity.deliveryMode) {
|
|
@@ -392,7 +392,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
392
392
|
headers
|
|
393
393
|
)
|
|
394
394
|
} else {
|
|
395
|
-
throw
|
|
395
|
+
throw ExceptionHelper.generateException(Error, Errors.CannotCreateConnectorClientForAgenticUser)
|
|
396
396
|
}
|
|
397
397
|
} else {
|
|
398
398
|
// ABS tokens will not have an azp/appid so use the botframework scope.
|
|
@@ -580,7 +580,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
580
580
|
*/
|
|
581
581
|
public async process (
|
|
582
582
|
request: Request,
|
|
583
|
-
res:
|
|
583
|
+
res: WebResponse,
|
|
584
584
|
logic: (context: TurnContext) => Promise<void>,
|
|
585
585
|
headerPropagation?: HeaderPropagationDefinition): Promise<void> {
|
|
586
586
|
return trace(AdapterTraceDefinitions.process, async ({ record }) => {
|
|
@@ -609,7 +609,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
609
609
|
res.end()
|
|
610
610
|
}
|
|
611
611
|
if (!request.body) {
|
|
612
|
-
throw
|
|
612
|
+
throw ExceptionHelper.generateException(TypeError, Errors.MissingRequestBody)
|
|
613
613
|
}
|
|
614
614
|
const incoming = normalizeIncomingActivity(request.body!)
|
|
615
615
|
const activity = Activity.fromObject(incoming)
|
|
@@ -726,11 +726,11 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
726
726
|
async updateActivity (context: TurnContext, activity: Activity): Promise<ResourceResponse | void> {
|
|
727
727
|
return trace(AdapterTraceDefinitions.updateActivity, async ({ record }) => {
|
|
728
728
|
if (!context) {
|
|
729
|
-
throw
|
|
729
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ContextParameterRequired)
|
|
730
730
|
}
|
|
731
731
|
|
|
732
732
|
if (!activity) {
|
|
733
|
-
throw
|
|
733
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ActivityParameterRequired)
|
|
734
734
|
}
|
|
735
735
|
|
|
736
736
|
record({ activity })
|
|
@@ -758,7 +758,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
758
758
|
async deleteActivity (context: TurnContext, reference: Partial<ConversationReference>): Promise<void> {
|
|
759
759
|
return trace(AdapterTraceDefinitions.deleteActivity, async ({ record }) => {
|
|
760
760
|
if (!context) {
|
|
761
|
-
throw
|
|
761
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ContextParameterRequired)
|
|
762
762
|
}
|
|
763
763
|
|
|
764
764
|
if (!reference || !reference.serviceUrl || (reference.conversation == null) || !reference.conversation.id || !reference.activityId) {
|
|
@@ -791,7 +791,7 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
791
791
|
}
|
|
792
792
|
|
|
793
793
|
if (!botAppIdOrIdentity) {
|
|
794
|
-
throw
|
|
794
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ContinueConversationBotAppIdOrIdentityRequired)
|
|
795
795
|
}
|
|
796
796
|
const botAppId = typeof botAppIdOrIdentity === 'string' ? botAppIdOrIdentity : botAppIdOrIdentity.aud as string
|
|
797
797
|
|
|
@@ -911,10 +911,10 @@ export class CloudAdapter extends BaseAdapter {
|
|
|
911
911
|
logic: (context: TurnContext) => Promise<void>
|
|
912
912
|
): Promise<void> {
|
|
913
913
|
if (typeof serviceUrl !== 'string' || !serviceUrl) {
|
|
914
|
-
throw
|
|
914
|
+
throw ExceptionHelper.generateException(TypeError, Errors.ServiceUrlRequired)
|
|
915
915
|
}
|
|
916
|
-
if (!conversationParameters) throw
|
|
917
|
-
if (!logic) throw
|
|
916
|
+
if (!conversationParameters) throw ExceptionHelper.generateException(TypeError, Errors.ConversationParametersRequired)
|
|
917
|
+
if (!logic) throw ExceptionHelper.generateException(TypeError, Errors.LogicParameterRequired)
|
|
918
918
|
|
|
919
919
|
const identity = CloudAdapter.createIdentity(audience)
|
|
920
920
|
const restClient = await this.createConnectorClient(serviceUrl, audience, identity)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { ActivityHandler } from './activityHandler'
|
|
7
|
+
import { AgentApplication } from './app/agentApplication'
|
|
8
|
+
import { AuthConfiguration } from './auth/authConfiguration'
|
|
9
|
+
import { CloudAdapter } from './cloudAdapter'
|
|
10
|
+
import { HeaderPropagationDefinition } from './headerPropagation'
|
|
11
|
+
import { TurnState } from './app/turnState'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Result of creating a CloudAdapter from an agent.
|
|
15
|
+
*/
|
|
16
|
+
export interface CloudAdapterResult {
|
|
17
|
+
adapter: CloudAdapter
|
|
18
|
+
headerPropagation: HeaderPropagationDefinition | undefined
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Creates a CloudAdapter for the given agent.
|
|
23
|
+
*
|
|
24
|
+
* If the agent is an AgentApplication with a pre-configured adapter, that adapter is reused.
|
|
25
|
+
* Otherwise, a new CloudAdapter is created.
|
|
26
|
+
*
|
|
27
|
+
* @param agent - The AgentApplication or ActivityHandler instance.
|
|
28
|
+
* @param authConfig - Optional auth configuration used when creating a new CloudAdapter.
|
|
29
|
+
* If the agent already has an adapter, that adapter is reused and this value is ignored.
|
|
30
|
+
* @returns An object containing the CloudAdapter and optional header propagation configuration.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* import { AgentApplication, TurnState, createCloudAdapter } from '@microsoft/agents-hosting';
|
|
35
|
+
*
|
|
36
|
+
* const app = new AgentApplication<TurnState>();
|
|
37
|
+
* const { adapter, headerPropagation } = createCloudAdapter(app, { clientId: process.env.CLIENT_ID });
|
|
38
|
+
*
|
|
39
|
+
* // Use the adapter directly with request/response objects compatible with CloudAdapter.process
|
|
40
|
+
* adapter.process(req, res, (context) => app.run(context), headerPropagation);
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export const createCloudAdapter = (
|
|
44
|
+
agent: AgentApplication<TurnState<any, any>> | ActivityHandler,
|
|
45
|
+
authConfig?: AuthConfiguration
|
|
46
|
+
): CloudAdapterResult => {
|
|
47
|
+
if (agent instanceof ActivityHandler) {
|
|
48
|
+
return { adapter: new CloudAdapter(authConfig), headerPropagation: undefined }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// AgentApplication: reuse its pre-configured adapter when present, otherwise create one.
|
|
52
|
+
// headerPropagation is an application-level option, so read it regardless of adapter source.
|
|
53
|
+
const headerPropagation = agent.options?.headerPropagation
|
|
54
|
+
const adapter = agent.adapter ?? new CloudAdapter(authConfig)
|
|
55
|
+
return { adapter, headerPropagation }
|
|
56
|
+
}
|