@microsoft/agents-hosting 1.6.0-beta.8.g226709c215 → 1.6.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.
Files changed (94) hide show
  1. package/dist/package.json +4 -9
  2. package/dist/src/agent-client/agentClient.js +2 -2
  3. package/dist/src/agent-client/agentClient.js.map +1 -1
  4. package/dist/src/agent-client/agentResponseHandler.js +2 -2
  5. package/dist/src/agent-client/agentResponseHandler.js.map +1 -1
  6. package/dist/src/app/agentApplication.js +28 -2
  7. package/dist/src/app/agentApplication.js.map +1 -1
  8. package/dist/src/app/agentApplicationOptions.d.ts +10 -0
  9. package/dist/src/app/attachmentDownloader.js +5 -10
  10. package/dist/src/app/attachmentDownloader.js.map +1 -1
  11. package/dist/src/app/auth/authorizationManager.d.ts +4 -0
  12. package/dist/src/app/auth/authorizationManager.js +94 -67
  13. package/dist/src/app/auth/authorizationManager.js.map +1 -1
  14. package/dist/src/app/auth/handlers/azureBotAuthorization.js +2 -2
  15. package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
  16. package/dist/src/app/proactive/createConversationOptionsBuilder.js +10 -6
  17. package/dist/src/app/proactive/createConversationOptionsBuilder.js.map +1 -1
  18. package/dist/src/app/proactive/proactive.d.ts +1 -0
  19. package/dist/src/app/proactive/proactive.js +30 -15
  20. package/dist/src/app/proactive/proactive.js.map +1 -1
  21. package/dist/src/app/teamsAttachmentDownloader.js +6 -8
  22. package/dist/src/app/teamsAttachmentDownloader.js.map +1 -1
  23. package/dist/src/auth/authConfiguration.d.ts +2 -143
  24. package/dist/src/auth/authConfiguration.js +301 -257
  25. package/dist/src/auth/authConfiguration.js.map +1 -1
  26. package/dist/src/auth/jwt-middleware.js +2 -1
  27. package/dist/src/auth/jwt-middleware.js.map +1 -1
  28. package/dist/src/auth/msalConnectionManager.js +27 -14
  29. package/dist/src/auth/msalConnectionManager.js.map +1 -1
  30. package/dist/src/auth/msalTokenProvider.d.ts +7 -0
  31. package/dist/src/auth/msalTokenProvider.js +188 -44
  32. package/dist/src/auth/msalTokenProvider.js.map +1 -1
  33. package/dist/src/auth/settings.d.ts +327 -0
  34. package/dist/src/auth/settings.js +158 -0
  35. package/dist/src/auth/settings.js.map +1 -0
  36. package/dist/src/cloudAdapter.d.ts +58 -1
  37. package/dist/src/cloudAdapter.js +232 -52
  38. package/dist/src/cloudAdapter.js.map +1 -1
  39. package/dist/src/connector-client/connectorClient.d.ts +12 -8
  40. package/dist/src/connector-client/connectorClient.js +99 -82
  41. package/dist/src/connector-client/connectorClient.js.map +1 -1
  42. package/dist/src/errorHelper.js +85 -7
  43. package/dist/src/errorHelper.js.map +1 -1
  44. package/dist/src/getProductInfo.d.ts +23 -0
  45. package/dist/src/getProductInfo.js +71 -1
  46. package/dist/src/getProductInfo.js.map +1 -1
  47. package/dist/src/headerPropagation.d.ts +17 -2
  48. package/dist/src/headerPropagation.js +46 -24
  49. package/dist/src/headerPropagation.js.map +1 -1
  50. package/dist/src/httpClient.d.ts +60 -0
  51. package/dist/src/httpClient.js +173 -0
  52. package/dist/src/httpClient.js.map +1 -0
  53. package/dist/src/index.d.ts +2 -1
  54. package/dist/src/index.js +7 -2
  55. package/dist/src/index.js.map +1 -1
  56. package/dist/src/oauth/userTokenClient.d.ts +5 -4
  57. package/dist/src/oauth/userTokenClient.js +97 -78
  58. package/dist/src/oauth/userTokenClient.js.map +1 -1
  59. package/dist/src/observability/traces.d.ts +11 -4
  60. package/dist/src/observability/traces.js +39 -7
  61. package/dist/src/observability/traces.js.map +1 -1
  62. package/dist/src/utils/env.d.ts +50 -0
  63. package/dist/src/utils/env.js +113 -0
  64. package/dist/src/utils/env.js.map +1 -0
  65. package/dist/src/utils.d.ts +10 -0
  66. package/dist/src/utils.js +18 -0
  67. package/dist/src/utils.js.map +1 -0
  68. package/package.json +4 -9
  69. package/src/agent-client/agentClient.ts +2 -2
  70. package/src/agent-client/agentResponseHandler.ts +2 -2
  71. package/src/app/agentApplication.ts +30 -3
  72. package/src/app/agentApplicationOptions.ts +11 -0
  73. package/src/app/attachmentDownloader.ts +6 -8
  74. package/src/app/auth/authorizationManager.ts +84 -41
  75. package/src/app/auth/handlers/azureBotAuthorization.ts +2 -2
  76. package/src/app/proactive/createConversationOptionsBuilder.ts +8 -4
  77. package/src/app/proactive/proactive.ts +39 -23
  78. package/src/app/teamsAttachmentDownloader.ts +7 -6
  79. package/src/auth/authConfiguration.ts +317 -356
  80. package/src/auth/jwt-middleware.ts +1 -1
  81. package/src/auth/msalConnectionManager.ts +27 -10
  82. package/src/auth/msalTokenProvider.ts +180 -42
  83. package/src/auth/settings.ts +323 -0
  84. package/src/cloudAdapter.ts +291 -12
  85. package/src/connector-client/connectorClient.ts +116 -94
  86. package/src/errorHelper.ts +96 -7
  87. package/src/getProductInfo.ts +79 -1
  88. package/src/headerPropagation.ts +55 -23
  89. package/src/httpClient.ts +223 -0
  90. package/src/index.ts +5 -1
  91. package/src/oauth/userTokenClient.ts +103 -84
  92. package/src/observability/traces.ts +39 -8
  93. package/src/utils/env.ts +105 -0
  94. package/src/utils.ts +14 -0
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+ // Copyright (c) Microsoft Corporation. All rights reserved.
3
+ // Licensed under the MIT License.
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.parseBooleanEnv = parseBooleanEnv;
6
+ exports.parseIntEnv = parseIntEnv;
7
+ exports.suggestClosest = suggestClosest;
8
+ /**
9
+ * Internal helpers for parsing environment-variable strings into typed values.
10
+ *
11
+ * These helpers are intentionally NOT exported from the package's public
12
+ * `index.ts`; they are an internal utility shared between the adapter,
13
+ * authentication, and connector-client modules. Keeping them internal lets us
14
+ * normalize behavior across the package without growing the public API.
15
+ */
16
+ /**
17
+ * Parses an environment-variable string into a boolean.
18
+ *
19
+ * Recognized truthy values (case-insensitive, trimmed): `"true"`, `"1"`.
20
+ * Recognized falsy values (case-insensitive, trimmed): `"false"`, `"0"`.
21
+ * Returns `undefined` for unset (`undefined`), empty strings, or any other
22
+ * value, so callers can distinguish "not specified" from explicit `false`.
23
+ *
24
+ * @param value - The raw environment variable value (typically
25
+ * `process.env.X`).
26
+ * @returns `true`, `false`, or `undefined` when the value is unset or
27
+ * unrecognized.
28
+ */
29
+ function parseBooleanEnv(value) {
30
+ if (value === undefined)
31
+ return undefined;
32
+ const v = value.trim().toLowerCase();
33
+ if (v === 'true' || v === '1')
34
+ return true;
35
+ if (v === '')
36
+ return undefined;
37
+ if (v === 'false' || v === '0')
38
+ return false;
39
+ return undefined;
40
+ }
41
+ /**
42
+ * Parses an environment-variable string into an integer, returning the
43
+ * supplied fallback for unset, empty, or non-numeric values.
44
+ *
45
+ * @param value - The raw environment variable value.
46
+ * @param fallback - The value to return when the input is unset or invalid.
47
+ * @returns A finite integer, or `fallback` when the input cannot be parsed.
48
+ */
49
+ function parseIntEnv(value, fallback) {
50
+ if (value === undefined || value.trim() === '')
51
+ return fallback;
52
+ const parsed = parseInt(value, 10);
53
+ return Number.isNaN(parsed) ? fallback : parsed;
54
+ }
55
+ /**
56
+ * Returns the candidate from `candidates` that is closest to `input` by
57
+ * Levenshtein edit distance, provided the distance is no greater than
58
+ * `maxDistance`. Returns `undefined` when no candidate is close enough or the
59
+ * input is empty.
60
+ *
61
+ * Intended for "did you mean X?" hints on unknown configuration keys.
62
+ * Comparison is case-insensitive so casing differences alone never count as
63
+ * an edit. Ties are broken by the order in which candidates appear.
64
+ *
65
+ * In addition to `maxDistance`, the match must be within 50% of the input
66
+ * length (rounded up). This prevents confident-but-wrong suggestions on
67
+ * short inputs (e.g., a 4-char typo matching a 6-char canonical name).
68
+ *
69
+ * @param input - The unknown name supplied by the user.
70
+ * @param candidates - The set of known valid names.
71
+ * @param maxDistance - Maximum edit distance to consider a match (default 2).
72
+ */
73
+ function suggestClosest(input, candidates, maxDistance = 2) {
74
+ if (!input)
75
+ return undefined;
76
+ const a = input.toLowerCase();
77
+ const cutoff = Math.min(maxDistance, Math.max(1, Math.ceil(a.length / 2)));
78
+ let best;
79
+ for (const candidate of candidates) {
80
+ const d = levenshtein(a, candidate.toLowerCase());
81
+ if (d <= cutoff && (!best || d < best.distance)) {
82
+ best = { name: candidate, distance: d };
83
+ if (d === 0)
84
+ break;
85
+ }
86
+ }
87
+ return best === null || best === void 0 ? void 0 : best.name;
88
+ }
89
+ /** Standard Levenshtein edit distance using a single-row dynamic-programming table. */
90
+ function levenshtein(a, b) {
91
+ if (a === b)
92
+ return 0;
93
+ if (a.length === 0)
94
+ return b.length;
95
+ if (b.length === 0)
96
+ return a.length;
97
+ const row = new Array(b.length + 1);
98
+ for (let j = 0; j <= b.length; j++)
99
+ row[j] = j;
100
+ for (let i = 1; i <= a.length; i++) {
101
+ let prev = i - 1;
102
+ row[0] = i;
103
+ for (let j = 1; j <= b.length; j++) {
104
+ const temp = row[j];
105
+ row[j] = a[i - 1] === b[j - 1]
106
+ ? prev
107
+ : 1 + Math.min(prev, row[j - 1], row[j]);
108
+ prev = temp;
109
+ }
110
+ }
111
+ return row[b.length];
112
+ }
113
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/utils/env.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Copyright (c) Microsoft Corporation. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /**
6
+ * Utility function to prune undefined values from an object. This is useful for cleaning up configuration objects before logging or processing, ensuring that only defined values are included.
7
+ * @param obj The object to prune
8
+ * @returns A new object with all undefined values removed
9
+ */
10
+ export declare const prune: <T extends Record<string, any>>(obj: T) => T;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Microsoft Corporation. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.prune = void 0;
8
+ /**
9
+ * Utility function to prune undefined values from an object. This is useful for cleaning up configuration objects before logging or processing, ensuring that only defined values are included.
10
+ * @param obj The object to prune
11
+ * @returns A new object with all undefined values removed
12
+ */
13
+ const prune = (obj) => {
14
+ const entries = Object.entries(obj).filter(([, value]) => value !== undefined);
15
+ return Object.fromEntries(entries);
16
+ };
17
+ exports.prune = prune;
18
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH;;;;GAIG;AACI,MAAM,KAAK,GAAG,CAAgC,GAAM,EAAE,EAAE;IAC7D,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC,CAAA;IAC9E,OAAO,MAAM,CAAC,WAAW,CAAC,OAAO,CAAM,CAAA;AACzC,CAAC,CAAA;AAHY,QAAA,KAAK,SAGjB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@microsoft/agents-hosting",
4
- "version": "1.6.0-beta.8.g226709c215",
4
+ "version": "1.6.1",
5
5
  "homepage": "https://github.com/microsoft/Agents-for-js",
6
6
  "repository": {
7
7
  "type": "git",
@@ -20,13 +20,11 @@
20
20
  "types": "dist/src/index.d.ts",
21
21
  "dependencies": {
22
22
  "@azure/core-auth": "1.10.1",
23
- "@azure/msal-node": "5.0.6",
24
- "@microsoft/agents-activity": "1.6.0-beta.8.g226709c215",
25
- "@microsoft/agents-telemetry": "1.6.0-beta.8.g226709c215",
26
- "axios": "1.15.0",
23
+ "@azure/msal-node": "5.1.5",
24
+ "@microsoft/agents-activity": "1.6.1",
25
+ "@microsoft/agents-telemetry": "1.6.1",
27
26
  "jsonwebtoken": "9.0.3",
28
27
  "jwks-rsa": "4.0.1",
29
- "object-path": "0.11.8",
30
28
  "zod": "3.25.75"
31
29
  },
32
30
  "license": "MIT",
@@ -46,8 +44,5 @@
46
44
  },
47
45
  "engines": {
48
46
  "node": ">=20.0.0"
49
- },
50
- "devDependencies": {
51
- "@types/object-path": "0.11.4"
52
47
  }
53
48
  }
@@ -1,6 +1,6 @@
1
1
  import { AuthConfiguration, MsalTokenProvider } from '../auth'
2
2
  import { Activity, ConversationReference, RoleTypes } from '@microsoft/agents-activity'
3
- import { v4 } from 'uuid'
3
+ import { randomUUID } from 'crypto'
4
4
  import { debug } from '@microsoft/agents-telemetry'
5
5
  import { ConversationState } from '../state'
6
6
  import { TurnContext } from '../turnContext'
@@ -88,7 +88,7 @@ export class AgentClient {
88
88
  ...activityCopy.conversation
89
89
  }
90
90
  }
91
- activityCopy.conversation!.id = v4()
91
+ activityCopy.conversation!.id = randomUUID()
92
92
 
93
93
  const conversationDataAccessor = conversationState.createProperty<ConversationData>(activityCopy.conversation!.id)
94
94
  const convRef = await conversationDataAccessor.set(context,
@@ -3,7 +3,7 @@ import { ActivityHandler } from '../activityHandler'
3
3
  import { CloudAdapter } from '../cloudAdapter'
4
4
  import { Request, Response, Application } from 'express'
5
5
  import { TurnContext } from '../turnContext'
6
- import { v4 } from 'uuid'
6
+ import { randomUUID } from 'crypto'
7
7
  import { normalizeIncomingActivity } from '../activityWireCompat'
8
8
  import { debug } from '@microsoft/agents-telemetry'
9
9
  import { ConversationState } from '../state'
@@ -78,7 +78,7 @@ const handleResponse = (adapter: CloudAdapter, handler: ActivityHandler, convers
78
78
  applyActivityToTurnContext(turnContext, activity)
79
79
  await handler.run(turnContext)
80
80
 
81
- response = v4().replace(/-/g, '')
81
+ response = randomUUID().replace(/-/g, '')
82
82
  } else {
83
83
  response = await turnContext.sendActivity(activity)
84
84
  }
@@ -21,7 +21,7 @@ import { CloudAdapter } from '../cloudAdapter'
21
21
  import { Authorization, UserAuthorization, AuthorizationManager } from './auth'
22
22
  import { Proactive } from './proactive'
23
23
  import { JwtPayload } from 'jsonwebtoken'
24
- import { trace, debug } from '@microsoft/agents-telemetry'
24
+ import { trace, debug, redactString } from '@microsoft/agents-telemetry'
25
25
  import { AgentApplicationTraceDefinitions } from '../observability'
26
26
  import { Errors } from '../errorHelper'
27
27
 
@@ -144,6 +144,8 @@ export class AgentApplication<TState extends TurnState> {
144
144
  this._adapter = new CloudAdapter()
145
145
  }
146
146
 
147
+ this._adapter.setAgentName(this._options.agentName)
148
+
147
149
  // Create Proactive whenever proactive options are explicitly configured or a storage
148
150
  // backend is available — no explicit `proactive` option is required.
149
151
  if (this._options.proactive !== undefined || this._options.storage !== undefined) {
@@ -164,10 +166,35 @@ export class AgentApplication<TState extends TurnState> {
164
166
  }
165
167
  }
166
168
 
167
- logger.debug('AgentApplication created with options:', this._options)
168
-
169
169
  this._authorizationManager = new AuthorizationManager(this, this._adapter.connectionManager)
170
170
  this._authorization = new UserAuthorization(this._authorizationManager)
171
+
172
+ const className = (obj: any) => obj?.constructor?.name ?? (obj ? 'custom' : undefined)
173
+ logger.info('AgentApplication settings loaded', {
174
+ agentAppId: redactString(this._options.agentAppId, true),
175
+ adapter: {
176
+ className: className(this._adapter),
177
+ source: this._options.adapter ? 'consumed' : 'created',
178
+ },
179
+ storage: className(this._options.storage),
180
+ authorization: this._authorizationManager.handlers.map(e => e.id),
181
+ proactive: {
182
+ ...this.options.proactive,
183
+ storage: className(this._options.proactive?.storage ?? this._options.storage),
184
+ source: this._options.proactive ? 'options' : 'storage',
185
+ },
186
+ transcriptLogger: className(this._options.transcriptLogger),
187
+ typing: {
188
+ startTimer: this._options.startTypingTimer,
189
+ options: this._options.typing,
190
+ },
191
+ longRunningMessages: this._options.longRunningMessages,
192
+ removeRecipientMention: this._options.removeRecipientMention,
193
+ normalizeMentions: this._options.normalizeMentions,
194
+ fileDownloaders: this._options.fileDownloaders ? 'configured' : undefined,
195
+ turnStateFactory: options?.turnStateFactory ? 'custom' : 'default',
196
+ adaptiveCardsOptions: this._options.adaptiveCardsOptions,
197
+ })
171
198
  }
172
199
 
173
200
  /**
@@ -178,6 +178,17 @@ export interface AgentApplicationOptions<TState extends TurnState> {
178
178
  */
179
179
  headerPropagation?: HeaderPropagationDefinition
180
180
 
181
+ /**
182
+ * Optional. Human-friendly agent name sent in the `AgentName` header for
183
+ * SDK-managed outbound requests created during inbound turn processing.
184
+ *
185
+ * @remarks
186
+ * When omitted, the SDK uses the default value `Agent-SDK-JS`.
187
+ * The resolved value is trimmed and validated by the SDK. Only letters,
188
+ * numbers, spaces, hyphen, and underscore are allowed.
189
+ */
190
+ agentName?: string
191
+
181
192
  /**
182
193
  * Optional. Configuration for managing multiple authentication connections within the agent.
183
194
  * This allows the agent to handle authentication across different services or
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- import axios, { AxiosInstance } from 'axios'
6
+ import { HttpClient } from '../httpClient'
7
7
  import { InputFile, InputFileDownloader } from './inputFileDownloader'
8
8
  import { TurnState } from './turnState'
9
9
  import { TurnContext } from '../turnContext'
@@ -25,7 +25,7 @@ const logger = debug('agents:attachmentDownloader')
25
25
  *
26
26
  */
27
27
  export class AttachmentDownloader<TState extends TurnState = TurnState> implements InputFileDownloader<TState> {
28
- private _httpClient: AxiosInstance
28
+ private _httpClient: HttpClient
29
29
  private _stateKey: string
30
30
 
31
31
  /**
@@ -35,7 +35,7 @@ export class AttachmentDownloader<TState extends TurnState = TurnState> implemen
35
35
  * @param stateKey The key to store files in state. Defaults to 'inputFiles'.
36
36
  */
37
37
  public constructor (stateKey: string = 'inputFiles') {
38
- this._httpClient = axios.create()
38
+ this._httpClient = new HttpClient()
39
39
  this._stateKey = stateKey
40
40
  }
41
41
 
@@ -86,18 +86,16 @@ export class AttachmentDownloader<TState extends TurnState = TurnState> implemen
86
86
  (attachment.contentUrl && attachment.contentUrl.startsWith('https://')) ||
87
87
  (attachment.contentUrl && attachment.contentUrl.startsWith('http://localhost'))
88
88
  ) {
89
- let headers
89
+ const headers: Record<string, string> = {}
90
90
  if (accessToken.length > 0) {
91
- headers = {
92
- Authorization: `Bearer ${accessToken}`
93
- }
91
+ headers.Authorization = `Bearer ${accessToken}`
94
92
  }
95
93
  const response = await this._httpClient.get(attachment.contentUrl, {
96
94
  headers,
97
95
  responseType: 'arraybuffer'
98
96
  })
99
97
 
100
- const content = Buffer.from(response.data, 'binary')
98
+ const content = Buffer.from(response.data as ArrayBuffer)
101
99
 
102
100
  let contentType = attachment.contentType
103
101
  if (contentType === 'image/*') {
@@ -4,7 +4,7 @@
4
4
  */
5
5
 
6
6
  import { Activity, ExceptionHelper } from '@microsoft/agents-activity'
7
- import { debug } from '@microsoft/agents-telemetry'
7
+ import { debug, redactScopes } from '@microsoft/agents-telemetry'
8
8
  import { AgentApplication } from '../agentApplication'
9
9
  import { AgenticAuthorization, AzureBotAuthorization } from './handlers'
10
10
  import { TurnContext } from '../../turnContext'
@@ -13,7 +13,8 @@ import { Errors } from '../../errorHelper'
13
13
  import { ActiveAuthorizationHandler, AuthorizationHandlerStatus, AuthorizationHandler, AuthorizationHandlerSettings, AuthorizationOptions } from './types'
14
14
  import { Connections } from '../../auth/connections'
15
15
  import { sendInvokeResponse } from './utils'
16
- import { envParser, envParserUtils } from '../../auth'
16
+ import { envParser, envParserUtils } from '../../auth/settings'
17
+ import { prune } from '../../utils'
17
18
 
18
19
  const logger = debug('agents:authorization:manager')
19
20
 
@@ -155,10 +156,6 @@ export class AuthorizationManager {
155
156
  if (this.handlers.length === 0 && app.options.authorization !== undefined) {
156
157
  throw ExceptionHelper.generateException(Error, Errors.NoAuthHandlersConfigured)
157
158
  }
158
-
159
- for (const [id, handler] of Object.entries(this._handlers)) {
160
- logger.debug('auth handler "%s" type=%s scopes=%o', id, handler.type, handler.scopes)
161
- }
162
159
  }
163
160
 
164
161
  /**
@@ -320,7 +317,7 @@ export class AuthorizationManager {
320
317
  private createHandlers () {
321
318
  let legacyMessage = ''
322
319
  const settings: AuthorizationHandlerSettings = { storage: this.app.options.storage!, connections: this.connections }
323
- let runtimeEntries = Object.entries(this.app.options.authorization ?? {})
320
+ const runtimeOptionEntries = Object.entries(this.app.options.authorization ?? {})
324
321
  const result = { latest: {}, legacy: {} } as {
325
322
  latest: Record<string, Record<string, any> | undefined>;
326
323
  legacy: Record<string, Record<string, any> | undefined>;
@@ -335,7 +332,7 @@ export class AuthorizationManager {
335
332
 
336
333
  // Legacy: extract handler ID, handler options key and its value, and assign it to the correct runtime handler ID.
337
334
  if (!upperEnvKey.startsWith(this._envLatest.key.prefix.toUpperCase())) {
338
- const [id] = runtimeEntries.find(([id]) => upperEnvKey.startsWith(`${id.toUpperCase()}${this._envLegacy.key.separator}`)) ?? []
335
+ const [id] = runtimeOptionEntries.find(([id]) => upperEnvKey.startsWith(`${id.toUpperCase()}${this._envLegacy.key.separator}`)) ?? []
339
336
  if (!id) {
340
337
  continue
341
338
  }
@@ -386,7 +383,7 @@ export class AuthorizationManager {
386
383
  const fixTypes = (entries: [string, any][]) => entries
387
384
  .map(([id, options]) => [id, { ...options, type: this.fixType(id, options?.type) }] as [string, AuthorizationOptions[string]])
388
385
 
389
- runtimeEntries = fixTypes(runtimeEntries)
386
+ const runtimeEntries = fixTypes(runtimeOptionEntries)
390
387
  const latestEntries = fixTypes(Object.entries(result.latest))
391
388
  const legacyEntries = fixTypes(Object.entries(result.legacy))
392
389
 
@@ -396,39 +393,27 @@ export class AuthorizationManager {
396
393
  continue
397
394
  }
398
395
 
399
- // Find entries case-insensitively for later processing
400
- const [, runtime] = runtimeEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
401
- const [, latest] = latestEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
402
- const [, legacy] = legacyEntries.find(([key]) => key.toLowerCase() === id.toLowerCase()) ?? []
396
+ const { options, format } = this.resolveHandlerConfiguration(id, runtimeEntries, latestEntries, legacyEntries)
403
397
 
404
- if (runtime !== undefined && latest !== undefined) {
405
- logger.warn(this.prefix(id, 'Both runtime and latest environment variable configurations detected. Runtime configuration will take precedence over latest environment variables.'))
398
+ if (options.type === AZURE_BOT) {
399
+ // Set default values if not provided
400
+ options.title ||= 'Sign-in'
401
+ options.text ||= 'Please sign-in to continue'
402
+ options.oboScopes ??= []
403
+ options.enableSso = options.enableSso !== false // default value is true if undefined.
406
404
  }
407
405
 
408
- // Normalize runtime legacy options to latest format
409
- if (runtime?.type === AZURE_BOT) {
410
- runtime.azureBotOAuthConnectionName ??= runtime.name
411
- runtime.invalidSignInRetryMax ??= runtime.maxAttempts
412
- runtime.invalidSignInRetryMessage ??= runtime.messages?.invalidCode
413
- runtime.invalidSignInRetryMessageFormat ??= runtime.messages?.invalidCodeFormat
414
- runtime.invalidSignInRetryMaxExceededMessage ??= runtime.messages?.maxAttemptsExceeded
415
- runtime.oboConnectionName ??= runtime.obo?.connection
416
- runtime.oboScopes ??= runtime.obo?.scopes
417
- delete runtime.name
418
- delete runtime.maxAttempts
419
- delete runtime.messages
420
- delete runtime.obo
406
+ const maskedOptions: any = {}
407
+
408
+ if ('oboScopes' in options && options.oboScopes && options.oboScopes.length > 0) {
409
+ maskedOptions.oboScopes = redactScopes(options.oboScopes)
421
410
  }
422
411
 
423
- // Helper to remove undefined options
424
- const prune = <T extends Record<string, any>>(obj: T) => {
425
- const entries = Object.entries(obj).filter(([, e]) => e !== undefined)
426
- return Object.fromEntries(entries) as T
412
+ if ('scopes' in options && options.scopes && options.scopes.length > 0) {
413
+ maskedOptions.scopes = redactScopes(options.scopes)
427
414
  }
428
415
 
429
- // Priority: runtime > latest > legacy
430
- // Pruning done individually to avoid overwriting with undefined when merging.
431
- const options: AuthorizationOptions[string] = runtime ? { ...prune(legacy || {}), ...prune(runtime) } : prune(latest || {})
416
+ logger.info(this.prefix(id, 'settings loaded from \'%s\''), format, { ...options, ...maskedOptions })
432
417
 
433
418
  if (!settings.storage) {
434
419
  throw ExceptionHelper.generateException(Error, Errors.StorageRequiredForAuthorization)
@@ -437,12 +422,6 @@ export class AuthorizationManager {
437
422
  if (options.type === AGENTIC) {
438
423
  this._handlers[id] = new AgenticAuthorization(id, options, settings)
439
424
  } else if (options.type === AZURE_BOT) {
440
- // Set default values if not provided
441
- options.title ||= 'Sign-in'
442
- options.text ||= 'Please sign-in to continue'
443
- options.oboScopes ??= []
444
- options.enableSso = options.enableSso !== false // default value is true if undefined.
445
-
446
425
  this._handlers[id] = new AzureBotAuthorization(id, options, settings)
447
426
  }
448
427
 
@@ -473,4 +452,68 @@ export class AuthorizationManager {
473
452
 
474
453
  throw ExceptionHelper.generateException(Error, Errors.UnsupportedAuthHandlerType, undefined, { handlerType: type })
475
454
  }
455
+
456
+ /**
457
+ * Resolves the effective handler configuration for a given handler ID.
458
+ */
459
+ private resolveHandlerConfiguration (
460
+ id: string,
461
+ runtimeEntries: Array<[string, AuthorizationOptions[string]]>,
462
+ latestEntries: Array<[string, AuthorizationOptions[string]]>,
463
+ legacyEntries: Array<[string, AuthorizationOptions[string]]>
464
+ ): {
465
+ options: AuthorizationOptions[string];
466
+ format: string;
467
+ } {
468
+ const matchesId = ([_id]: [string, AuthorizationOptions[string]]) => _id.toLowerCase() === id.toLowerCase()
469
+
470
+ // Find entries case-insensitively for later processing
471
+ const [, runtime] = runtimeEntries.find(matchesId) ?? []
472
+ const [, latest] = latestEntries.find(matchesId) ?? []
473
+ const [, legacy] = legacyEntries.find(matchesId) ?? []
474
+
475
+ if (runtime !== undefined && latest !== undefined) {
476
+ logger.warn(this.prefix(id, 'Both runtime options and latest environment variable configurations detected. Runtime configuration will take precedence over latest environment variables.'))
477
+ }
478
+
479
+ const runtimeLegacyKeys = ['name', 'maxAttempts', 'messages', 'obo']
480
+ const isRuntimeLegacy = runtime !== undefined && Object.keys(runtime).some(key => runtimeLegacyKeys.includes(key))
481
+
482
+ let runtimeLegacyFormat = ''
483
+ if (isRuntimeLegacy && runtime.type === AZURE_BOT) {
484
+ runtime.azureBotOAuthConnectionName ??= runtime.name
485
+ runtime.invalidSignInRetryMax ??= runtime.maxAttempts
486
+ runtime.invalidSignInRetryMessage ??= runtime.messages?.invalidCode
487
+ runtime.invalidSignInRetryMessageFormat ??= runtime.messages?.invalidCodeFormat
488
+ runtime.invalidSignInRetryMaxExceededMessage ??= runtime.messages?.maxAttemptsExceeded
489
+ runtime.oboConnectionName ??= runtime.obo?.connection
490
+ runtime.oboScopes ??= runtime.obo?.scopes
491
+ delete runtime.name
492
+ delete runtime.maxAttempts
493
+ delete runtime.messages
494
+ delete runtime.obo
495
+ runtimeLegacyFormat = 'runtime options (legacy)'
496
+ }
497
+
498
+ if (runtime !== undefined && legacy !== undefined) {
499
+ return { format: `${runtimeLegacyFormat || 'runtime options'} + .env variables (legacy)`, options: { ...prune(legacy), ...prune(runtime) } }
500
+ }
501
+
502
+ if (runtime !== undefined) {
503
+ return { format: runtimeLegacyFormat || 'runtime options', options: prune(runtime) }
504
+ }
505
+
506
+ if (latest !== undefined) {
507
+ return { format: '.env variables', options: prune(latest) }
508
+ }
509
+
510
+ if (legacy !== undefined) {
511
+ // Note: this should never happen, as legacy requires runtime to be present.
512
+ // However, we show a warning just in case to detect if something goes wrong.
513
+ logger.warn(this.prefix(id, 'Legacy environment variable configuration detected without a corresponding runtime options configuration.'))
514
+ return { format: '.env variables (legacy)', options: prune(legacy) }
515
+ }
516
+
517
+ return { format: 'empty options', options: {} }
518
+ }
476
519
  }
@@ -334,7 +334,7 @@ export class AzureBotAuthorization implements AuthorizationHandler {
334
334
  const { activity } = context
335
335
  const userTokenClient = await this.getUserTokenClient(context)
336
336
  // Using getTokenOrSignInResource instead of getUserToken to avoid HTTP 404 errors.
337
- const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, '')
337
+ const { tokenResponse } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference({ forceBaseChannel: true }), activity.relatesTo!, '')
338
338
  return tokenResponse?.token
339
339
  }
340
340
 
@@ -399,7 +399,7 @@ export class AzureBotAuthorization implements AuthorizationHandler {
399
399
  const { activity } = context
400
400
 
401
401
  const userTokenClient = await this.getUserTokenClient(context)
402
- const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference(), activity.relatesTo!, code ?? '')
402
+ const { tokenResponse, signInResource } = await userTokenClient.getTokenOrSignInResource(activity.from?.id!, this.options.azureBotOAuthConnectionName!, activity.channelId!, activity.getConversationReference({ forceBaseChannel: true }), activity.relatesTo!, code ?? '')
403
403
 
404
404
  if (!tokenResponse && active && code) {
405
405
  reason.message = 'Invalid code entered. Restarting sign-in flow'
@@ -66,6 +66,9 @@ export class CreateConversationOptionsBuilder {
66
66
  const builder = new CreateConversationOptionsBuilder(claims, channelId, serviceUrl)
67
67
  if (parameters) {
68
68
  builder._parameters = { ...builder._parameters, ...parameters }
69
+ if (parameters.activity) {
70
+ builder._activity = parameters.activity
71
+ }
69
72
  }
70
73
 
71
74
  // Set parameters.agent if not already provided — matches C# behavior
@@ -161,9 +164,10 @@ export class CreateConversationOptionsBuilder {
161
164
  throw ExceptionHelper.generateException(Error, Errors.CreateConversationBuilderMembersRequired)
162
165
  }
163
166
 
164
- const activity: Partial<Activity> = {
165
- type: 'message',
166
- ...this._activity,
167
+ const isTeamsChannel = this._channelId === Channels.Msteams &&
168
+ Boolean((this._parameters.channelData as Record<string, any>)?.channel?.id)
169
+ if (isTeamsChannel && !this._activity) {
170
+ throw ExceptionHelper.generateException(Error, Errors.CreateConversationBuilderChannelActivityRequired)
167
171
  }
168
172
 
169
173
  return {
@@ -174,7 +178,7 @@ export class CreateConversationOptionsBuilder {
174
178
  storeConversation: this._storeConversation,
175
179
  parameters: {
176
180
  ...this._parameters,
177
- activity: activity as Activity,
181
+ activity: this._activity ? { type: 'message', ...this._activity } as Activity : undefined,
178
182
  },
179
183
  }
180
184
  }