@microsoft/agents-hosting 1.1.0-alpha.85 → 1.1.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/dist/package.json +4 -4
- package/dist/src/app/auth/handlers/agenticAuthorization.js +4 -4
- package/dist/src/app/auth/handlers/agenticAuthorization.js.map +1 -1
- package/dist/src/app/auth/handlers/azureBotAuthorization.d.ts +4 -0
- package/dist/src/app/auth/handlers/azureBotAuthorization.js +3 -2
- package/dist/src/app/auth/handlers/azureBotAuthorization.js.map +1 -1
- package/dist/src/auth/authProvider.d.ts +6 -3
- package/dist/src/auth/msalTokenProvider.d.ts +10 -3
- package/dist/src/auth/msalTokenProvider.js +30 -11
- package/dist/src/auth/msalTokenProvider.js.map +1 -1
- package/dist/src/cards/cardFactory.d.ts +2 -1
- package/dist/src/cards/cardFactory.js +3 -2
- package/dist/src/cards/cardFactory.js.map +1 -1
- package/dist/src/cloudAdapter.js +10 -8
- package/dist/src/cloudAdapter.js.map +1 -1
- package/dist/src/transcript/fileTranscriptLogger.d.ts +109 -0
- package/dist/src/transcript/fileTranscriptLogger.js +398 -0
- package/dist/src/transcript/fileTranscriptLogger.js.map +1 -0
- package/package.json +4 -4
- package/src/app/auth/handlers/agenticAuthorization.ts +1 -0
- package/src/app/auth/handlers/azureBotAuthorization.ts +9 -2
- package/src/auth/authProvider.ts +6 -3
- package/src/auth/msalTokenProvider.ts +30 -11
- package/src/cards/cardFactory.ts +3 -2
- package/src/cloudAdapter.ts +7 -6
- package/src/transcript/fileTranscriptLogger.ts +409 -0
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
* Licensed under the MIT License.
|
|
4
|
+
*/
|
|
5
|
+
import { PagedResult, TranscriptInfo } from './transcriptLogger';
|
|
6
|
+
import { TranscriptStore } from './transcriptStore';
|
|
7
|
+
import { Activity } from '@microsoft/agents-activity';
|
|
8
|
+
/**
|
|
9
|
+
* FileTranscriptLogger which creates a .transcript file for each conversationId.
|
|
10
|
+
* @remarks
|
|
11
|
+
* This is a useful class for unit tests.
|
|
12
|
+
*
|
|
13
|
+
* Concurrency Safety:
|
|
14
|
+
* - Uses an in-memory promise chain to serialize writes within the same Node.js process
|
|
15
|
+
* - Prevents race conditions and file corruption when multiple concurrent writes occur
|
|
16
|
+
* - Optimized for performance with minimal overhead (no file-based locking)
|
|
17
|
+
*
|
|
18
|
+
* Note: This implementation is designed for single-process scenarios. For multi-server
|
|
19
|
+
* deployments, consider using a database-backed transcript store.
|
|
20
|
+
*/
|
|
21
|
+
export declare class FileTranscriptLogger implements TranscriptStore {
|
|
22
|
+
private static readonly TRANSCRIPT_FILE_EXTENSION;
|
|
23
|
+
private static readonly MAX_FILE_NAME_SIZE;
|
|
24
|
+
private readonly _folder;
|
|
25
|
+
private readonly _fileLocks;
|
|
26
|
+
/**
|
|
27
|
+
* Initializes a new instance of the FileTranscriptLogger class.
|
|
28
|
+
* @param folder - Folder to place the transcript files (Default current directory).
|
|
29
|
+
*/
|
|
30
|
+
constructor(folder?: string);
|
|
31
|
+
/**
|
|
32
|
+
* Log an activity to the transcript.
|
|
33
|
+
* @param activity - The activity to transcribe.
|
|
34
|
+
* @returns A promise that represents the work queued to execute.
|
|
35
|
+
*/
|
|
36
|
+
logActivity(activity: Activity): Promise<void>;
|
|
37
|
+
/**
|
|
38
|
+
* Gets from the store activities that match a set of criteria.
|
|
39
|
+
* @param channelId - The ID of the channel the conversation is in.
|
|
40
|
+
* @param conversationId - The ID of the conversation.
|
|
41
|
+
* @param continuationToken - The continuation token (if available).
|
|
42
|
+
* @param startDate - A cutoff date. Activities older than this date are not included.
|
|
43
|
+
* @returns A promise that resolves with the matching activities.
|
|
44
|
+
*/
|
|
45
|
+
getTranscriptActivities(channelId: string, conversationId: string, continuationToken?: string, startDate?: Date): Promise<PagedResult<Activity>>;
|
|
46
|
+
/**
|
|
47
|
+
* Gets the conversations on a channel from the store.
|
|
48
|
+
* @param channelId - The ID of the channel.
|
|
49
|
+
* @param continuationToken - Continuation token (if available).
|
|
50
|
+
* @returns A promise that resolves with all transcripts for the given ChannelID.
|
|
51
|
+
*/
|
|
52
|
+
listTranscripts(channelId: string, continuationToken?: string): Promise<PagedResult<TranscriptInfo>>;
|
|
53
|
+
/**
|
|
54
|
+
* Deletes conversation data from the store.
|
|
55
|
+
* @param channelId - The ID of the channel the conversation is in.
|
|
56
|
+
* @param conversationId - The ID of the conversation to delete.
|
|
57
|
+
* @returns A promise that represents the work queued to execute.
|
|
58
|
+
*/
|
|
59
|
+
deleteTranscript(channelId: string, conversationId: string): Promise<void>;
|
|
60
|
+
/**
|
|
61
|
+
* Loads a transcript from a file.
|
|
62
|
+
*/
|
|
63
|
+
private loadTranscriptAsync;
|
|
64
|
+
/**
|
|
65
|
+
* Executes a file operation with exclusive locking per file.
|
|
66
|
+
* This ensures that concurrent writes to the same transcript file are serialized.
|
|
67
|
+
*/
|
|
68
|
+
private withFileLock;
|
|
69
|
+
/**
|
|
70
|
+
* Performs the actual write operation to the transcript file.
|
|
71
|
+
*/
|
|
72
|
+
private logActivityToFile;
|
|
73
|
+
/**
|
|
74
|
+
* Updates a message in the transcript.
|
|
75
|
+
*/
|
|
76
|
+
private messageUpdateAsync;
|
|
77
|
+
/**
|
|
78
|
+
* Deletes a message from the transcript (tombstones it).
|
|
79
|
+
*/
|
|
80
|
+
private messageDeleteAsync;
|
|
81
|
+
/**
|
|
82
|
+
* Sanitizes a string by removing invalid characters.
|
|
83
|
+
*/
|
|
84
|
+
private static sanitizeString;
|
|
85
|
+
/**
|
|
86
|
+
* Gets the transcript file path for a conversation.
|
|
87
|
+
*/
|
|
88
|
+
private getTranscriptFile;
|
|
89
|
+
/**
|
|
90
|
+
* Gets the channel folder path, creating it if necessary.
|
|
91
|
+
*/
|
|
92
|
+
private getChannelFolder;
|
|
93
|
+
/**
|
|
94
|
+
* Checks if a file or directory exists.
|
|
95
|
+
*/
|
|
96
|
+
private pathExists;
|
|
97
|
+
/**
|
|
98
|
+
* Gets invalid filename characters for the current platform.
|
|
99
|
+
*/
|
|
100
|
+
private getInvalidFileNameChars;
|
|
101
|
+
/**
|
|
102
|
+
* Gets invalid path characters for the current platform.
|
|
103
|
+
*/
|
|
104
|
+
private getInvalidPathChars;
|
|
105
|
+
/**
|
|
106
|
+
* Adds file:// protocol to a file path.
|
|
107
|
+
*/
|
|
108
|
+
private protocol;
|
|
109
|
+
}
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
* Licensed under the MIT License.
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.FileTranscriptLogger = void 0;
|
|
41
|
+
const logger_1 = require("@microsoft/agents-activity/logger");
|
|
42
|
+
const fs = __importStar(require("fs/promises"));
|
|
43
|
+
const path = __importStar(require("path"));
|
|
44
|
+
const os_1 = require("os");
|
|
45
|
+
const agents_activity_1 = require("@microsoft/agents-activity");
|
|
46
|
+
const logger = (0, logger_1.debug)('agents:file-transcript-logger');
|
|
47
|
+
/**
|
|
48
|
+
* FileTranscriptLogger which creates a .transcript file for each conversationId.
|
|
49
|
+
* @remarks
|
|
50
|
+
* This is a useful class for unit tests.
|
|
51
|
+
*
|
|
52
|
+
* Concurrency Safety:
|
|
53
|
+
* - Uses an in-memory promise chain to serialize writes within the same Node.js process
|
|
54
|
+
* - Prevents race conditions and file corruption when multiple concurrent writes occur
|
|
55
|
+
* - Optimized for performance with minimal overhead (no file-based locking)
|
|
56
|
+
*
|
|
57
|
+
* Note: This implementation is designed for single-process scenarios. For multi-server
|
|
58
|
+
* deployments, consider using a database-backed transcript store.
|
|
59
|
+
*/
|
|
60
|
+
class FileTranscriptLogger {
|
|
61
|
+
/**
|
|
62
|
+
* Initializes a new instance of the FileTranscriptLogger class.
|
|
63
|
+
* @param folder - Folder to place the transcript files (Default current directory).
|
|
64
|
+
*/
|
|
65
|
+
constructor(folder) {
|
|
66
|
+
this._fileLocks = new Map();
|
|
67
|
+
this._folder = path.normalize(folder !== null && folder !== void 0 ? folder : process.cwd());
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Log an activity to the transcript.
|
|
71
|
+
* @param activity - The activity to transcribe.
|
|
72
|
+
* @returns A promise that represents the work queued to execute.
|
|
73
|
+
*/
|
|
74
|
+
async logActivity(activity) {
|
|
75
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
|
|
76
|
+
if (!activity) {
|
|
77
|
+
throw new Error('activity is required.');
|
|
78
|
+
}
|
|
79
|
+
const transcriptFile = this.getTranscriptFile(activity.channelId, (_a = activity.conversation) === null || _a === void 0 ? void 0 : _a.id);
|
|
80
|
+
if (activity.type === agents_activity_1.ActivityTypes.Message) {
|
|
81
|
+
const sender = (_e = (_c = (_b = activity.from) === null || _b === void 0 ? void 0 : _b.name) !== null && _c !== void 0 ? _c : (_d = activity.from) === null || _d === void 0 ? void 0 : _d.id) !== null && _e !== void 0 ? _e : (_f = activity.from) === null || _f === void 0 ? void 0 : _f.role;
|
|
82
|
+
logger.debug(`${sender} [${activity.type}] ${activity.text}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
const sender = (_k = (_h = (_g = activity.from) === null || _g === void 0 ? void 0 : _g.name) !== null && _h !== void 0 ? _h : (_j = activity.from) === null || _j === void 0 ? void 0 : _j.id) !== null && _k !== void 0 ? _k : (_l = activity.from) === null || _l === void 0 ? void 0 : _l.role;
|
|
86
|
+
logger.debug(`${sender} [${activity.type}]`);
|
|
87
|
+
}
|
|
88
|
+
await this.withFileLock(transcriptFile, async () => {
|
|
89
|
+
const maxRetries = 3;
|
|
90
|
+
for (let i = 1; i <= maxRetries; i++) {
|
|
91
|
+
try {
|
|
92
|
+
switch (activity.type) {
|
|
93
|
+
case agents_activity_1.ActivityTypes.MessageDelete:
|
|
94
|
+
return await this.messageDeleteAsync(activity, transcriptFile);
|
|
95
|
+
case agents_activity_1.ActivityTypes.MessageUpdate:
|
|
96
|
+
return await this.messageUpdateAsync(activity, transcriptFile);
|
|
97
|
+
default: // Append activity
|
|
98
|
+
return await this.logActivityToFile(activity, transcriptFile);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
// Try again
|
|
103
|
+
logger.warn(`Try ${i} - Failed to log activity because:`, error);
|
|
104
|
+
if (i === maxRetries) {
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Gets from the store activities that match a set of criteria.
|
|
113
|
+
* @param channelId - The ID of the channel the conversation is in.
|
|
114
|
+
* @param conversationId - The ID of the conversation.
|
|
115
|
+
* @param continuationToken - The continuation token (if available).
|
|
116
|
+
* @param startDate - A cutoff date. Activities older than this date are not included.
|
|
117
|
+
* @returns A promise that resolves with the matching activities.
|
|
118
|
+
*/
|
|
119
|
+
async getTranscriptActivities(channelId, conversationId, continuationToken, startDate) {
|
|
120
|
+
const transcriptFile = this.getTranscriptFile(channelId, conversationId);
|
|
121
|
+
if (!await this.pathExists(transcriptFile)) {
|
|
122
|
+
logger.debug(`Transcript file does not exist: ${this.protocol(transcriptFile)}`);
|
|
123
|
+
return { items: [], continuationToken: undefined };
|
|
124
|
+
}
|
|
125
|
+
const transcript = await this.loadTranscriptAsync(transcriptFile);
|
|
126
|
+
const filterDate = startDate !== null && startDate !== void 0 ? startDate : new Date(0);
|
|
127
|
+
const items = transcript.filter(activity => {
|
|
128
|
+
const activityDate = activity.timestamp ? new Date(activity.timestamp) : new Date(0);
|
|
129
|
+
return activityDate >= filterDate;
|
|
130
|
+
});
|
|
131
|
+
return { items, continuationToken: undefined };
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Gets the conversations on a channel from the store.
|
|
135
|
+
* @param channelId - The ID of the channel.
|
|
136
|
+
* @param continuationToken - Continuation token (if available).
|
|
137
|
+
* @returns A promise that resolves with all transcripts for the given ChannelID.
|
|
138
|
+
*/
|
|
139
|
+
async listTranscripts(channelId, continuationToken) {
|
|
140
|
+
const channelFolder = this.getChannelFolder(channelId);
|
|
141
|
+
if (!await this.pathExists(channelFolder)) {
|
|
142
|
+
logger.debug(`Channel folder does not exist: ${this.protocol(channelFolder)}`);
|
|
143
|
+
return { items: [], continuationToken: undefined };
|
|
144
|
+
}
|
|
145
|
+
const files = await fs.readdir(channelFolder);
|
|
146
|
+
const items = [];
|
|
147
|
+
for (const file of files) {
|
|
148
|
+
if (!file.endsWith('.transcript')) {
|
|
149
|
+
continue;
|
|
150
|
+
}
|
|
151
|
+
const filePath = path.join(channelFolder, file);
|
|
152
|
+
const stats = await fs.stat(filePath);
|
|
153
|
+
items.push({
|
|
154
|
+
channelId,
|
|
155
|
+
id: path.parse(file).name,
|
|
156
|
+
created: stats.birthtime
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
return { items, continuationToken: undefined };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Deletes conversation data from the store.
|
|
163
|
+
* @param channelId - The ID of the channel the conversation is in.
|
|
164
|
+
* @param conversationId - The ID of the conversation to delete.
|
|
165
|
+
* @returns A promise that represents the work queued to execute.
|
|
166
|
+
*/
|
|
167
|
+
async deleteTranscript(channelId, conversationId) {
|
|
168
|
+
const file = this.getTranscriptFile(channelId, conversationId);
|
|
169
|
+
await this.withFileLock(file, async () => {
|
|
170
|
+
if (!await this.pathExists(file)) {
|
|
171
|
+
logger.debug(`Transcript file does not exist: ${this.protocol(file)}`);
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
await fs.unlink(file);
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Loads a transcript from a file.
|
|
179
|
+
*/
|
|
180
|
+
async loadTranscriptAsync(transcriptFile) {
|
|
181
|
+
if (!await this.pathExists(transcriptFile)) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const json = await fs.readFile(transcriptFile, 'utf-8');
|
|
185
|
+
const result = JSON.parse(json);
|
|
186
|
+
return result.map(agents_activity_1.Activity.fromObject);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Executes a file operation with exclusive locking per file.
|
|
190
|
+
* This ensures that concurrent writes to the same transcript file are serialized.
|
|
191
|
+
*/
|
|
192
|
+
async withFileLock(transcriptFile, operation) {
|
|
193
|
+
var _a;
|
|
194
|
+
// Get the current lock chain for this file
|
|
195
|
+
const existingLock = (_a = this._fileLocks.get(transcriptFile)) !== null && _a !== void 0 ? _a : Promise.resolve();
|
|
196
|
+
// Create a new lock that waits for the existing one and then performs the operation
|
|
197
|
+
const newLock = existingLock.then(async () => {
|
|
198
|
+
return await operation();
|
|
199
|
+
}).catch(error => {
|
|
200
|
+
logger.warn('Error in write chain:', error);
|
|
201
|
+
throw error;
|
|
202
|
+
});
|
|
203
|
+
// Update the lock chain
|
|
204
|
+
this._fileLocks.set(transcriptFile, newLock);
|
|
205
|
+
// Wait for this operation to complete
|
|
206
|
+
try {
|
|
207
|
+
return await newLock;
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
// Clean up if this was the last operation in the chain
|
|
211
|
+
if (this._fileLocks.get(transcriptFile) === newLock) {
|
|
212
|
+
this._fileLocks.delete(transcriptFile);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Performs the actual write operation to the transcript file.
|
|
218
|
+
*/
|
|
219
|
+
async logActivityToFile(activity, transcriptFile) {
|
|
220
|
+
const activityStr = JSON.stringify(activity);
|
|
221
|
+
if (!await this.pathExists(transcriptFile)) {
|
|
222
|
+
const folder = path.dirname(transcriptFile);
|
|
223
|
+
if (!await this.pathExists(folder)) {
|
|
224
|
+
await fs.mkdir(folder, { recursive: true });
|
|
225
|
+
}
|
|
226
|
+
await fs.writeFile(transcriptFile, `[${activityStr}]`, 'utf-8');
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
// Use file handle to append efficiently
|
|
230
|
+
const fileHandle = await fs.open(transcriptFile, 'r+');
|
|
231
|
+
try {
|
|
232
|
+
const stats = await fileHandle.stat();
|
|
233
|
+
// Seek to before the closing bracket
|
|
234
|
+
const position = Math.max(0, stats.size - 1);
|
|
235
|
+
// Write the comma, new activity, and closing bracket
|
|
236
|
+
const appendContent = `,${os_1.EOL}${activityStr}]`;
|
|
237
|
+
await fileHandle.write(appendContent, position);
|
|
238
|
+
// Truncate any remaining content (in case the file had trailing data)
|
|
239
|
+
await fileHandle.truncate(position + Buffer.byteLength(appendContent));
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
await fileHandle.close();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Updates a message in the transcript.
|
|
247
|
+
*/
|
|
248
|
+
async messageUpdateAsync(activity, transcriptFile) {
|
|
249
|
+
// Load all activities
|
|
250
|
+
const transcript = await this.loadTranscriptAsync(transcriptFile);
|
|
251
|
+
for (let i = 0; i < transcript.length; i++) {
|
|
252
|
+
const originalActivity = transcript[i];
|
|
253
|
+
if (originalActivity.id === activity.id) {
|
|
254
|
+
// Clone and update the activity
|
|
255
|
+
const updatedActivity = { ...activity };
|
|
256
|
+
updatedActivity.type = originalActivity.type; // Fixup original type (should be Message)
|
|
257
|
+
updatedActivity.localTimestamp = originalActivity.localTimestamp;
|
|
258
|
+
updatedActivity.timestamp = originalActivity.timestamp;
|
|
259
|
+
transcript[i] = updatedActivity;
|
|
260
|
+
const json = JSON.stringify(transcript);
|
|
261
|
+
await fs.writeFile(transcriptFile, json, 'utf-8');
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Deletes a message from the transcript (tombstones it).
|
|
268
|
+
*/
|
|
269
|
+
async messageDeleteAsync(activity, transcriptFile) {
|
|
270
|
+
var _a, _b;
|
|
271
|
+
// Load all activities
|
|
272
|
+
const transcript = await this.loadTranscriptAsync(transcriptFile);
|
|
273
|
+
// If message delete comes in, tombstone the message in the transcript
|
|
274
|
+
for (let index = 0; index < transcript.length; index++) {
|
|
275
|
+
const originalActivity = transcript[index];
|
|
276
|
+
if (originalActivity.id === activity.id) {
|
|
277
|
+
// Tombstone the original message
|
|
278
|
+
transcript[index] = {
|
|
279
|
+
type: agents_activity_1.ActivityTypes.MessageDelete,
|
|
280
|
+
id: originalActivity.id,
|
|
281
|
+
from: {
|
|
282
|
+
id: 'deleted',
|
|
283
|
+
role: (_a = originalActivity.from) === null || _a === void 0 ? void 0 : _a.role
|
|
284
|
+
},
|
|
285
|
+
recipient: {
|
|
286
|
+
id: 'deleted',
|
|
287
|
+
role: (_b = originalActivity.recipient) === null || _b === void 0 ? void 0 : _b.role
|
|
288
|
+
},
|
|
289
|
+
locale: originalActivity.locale,
|
|
290
|
+
localTimestamp: originalActivity.timestamp,
|
|
291
|
+
timestamp: originalActivity.timestamp,
|
|
292
|
+
channelId: originalActivity.channelId,
|
|
293
|
+
conversation: originalActivity.conversation,
|
|
294
|
+
serviceUrl: originalActivity.serviceUrl,
|
|
295
|
+
replyToId: originalActivity.replyToId
|
|
296
|
+
};
|
|
297
|
+
const json = JSON.stringify(transcript);
|
|
298
|
+
await fs.writeFile(transcriptFile, json, 'utf-8');
|
|
299
|
+
return;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Sanitizes a string by removing invalid characters.
|
|
305
|
+
*/
|
|
306
|
+
static sanitizeString(str, invalidChars) {
|
|
307
|
+
if (!(str === null || str === void 0 ? void 0 : str.trim())) {
|
|
308
|
+
return str;
|
|
309
|
+
}
|
|
310
|
+
// Preemptively check for : in string and replace with _
|
|
311
|
+
let result = str.replaceAll(':', '_');
|
|
312
|
+
// Remove invalid characters
|
|
313
|
+
for (const invalidChar of invalidChars) {
|
|
314
|
+
result = result.replaceAll(invalidChar, '');
|
|
315
|
+
}
|
|
316
|
+
return result;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Gets the transcript file path for a conversation.
|
|
320
|
+
*/
|
|
321
|
+
getTranscriptFile(channelId, conversationId) {
|
|
322
|
+
if (!(channelId === null || channelId === void 0 ? void 0 : channelId.trim())) {
|
|
323
|
+
throw new Error('channelId is required.');
|
|
324
|
+
}
|
|
325
|
+
if (!(conversationId === null || conversationId === void 0 ? void 0 : conversationId.trim())) {
|
|
326
|
+
throw new Error('conversationId is required.');
|
|
327
|
+
}
|
|
328
|
+
// Get invalid filename characters (cross-platform)
|
|
329
|
+
const invalidChars = this.getInvalidFileNameChars();
|
|
330
|
+
let fileName = FileTranscriptLogger.sanitizeString(conversationId, invalidChars);
|
|
331
|
+
const maxLength = FileTranscriptLogger.MAX_FILE_NAME_SIZE - FileTranscriptLogger.TRANSCRIPT_FILE_EXTENSION.length;
|
|
332
|
+
if (fileName && fileName.length > maxLength) {
|
|
333
|
+
fileName = fileName.substring(0, maxLength);
|
|
334
|
+
}
|
|
335
|
+
const channelFolder = this.getChannelFolder(channelId);
|
|
336
|
+
return path.join(channelFolder, fileName + FileTranscriptLogger.TRANSCRIPT_FILE_EXTENSION);
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Gets the channel folder path, creating it if necessary.
|
|
340
|
+
*/
|
|
341
|
+
getChannelFolder(channelId) {
|
|
342
|
+
if (!(channelId === null || channelId === void 0 ? void 0 : channelId.trim())) {
|
|
343
|
+
throw new Error('channelId is required.');
|
|
344
|
+
}
|
|
345
|
+
const invalidChars = this.getInvalidPathChars();
|
|
346
|
+
const folderName = FileTranscriptLogger.sanitizeString(channelId, invalidChars);
|
|
347
|
+
return path.join(this._folder, folderName);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Checks if a file or directory exists.
|
|
351
|
+
*/
|
|
352
|
+
async pathExists(path) {
|
|
353
|
+
try {
|
|
354
|
+
await fs.stat(path);
|
|
355
|
+
return true;
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
return false;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Gets invalid filename characters for the current platform.
|
|
363
|
+
*/
|
|
364
|
+
getInvalidFileNameChars() {
|
|
365
|
+
// Windows invalid filename chars: < > : " / \ | ? *
|
|
366
|
+
// Unix systems are more permissive, but / is always invalid
|
|
367
|
+
const invalid = this.getInvalidPathChars();
|
|
368
|
+
if (process.platform === 'win32') {
|
|
369
|
+
return [...invalid, '/', '\\'];
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
return [...invalid, '/'];
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* Gets invalid path characters for the current platform.
|
|
377
|
+
*/
|
|
378
|
+
getInvalidPathChars() {
|
|
379
|
+
// Similar to filename chars but allows directory separators in the middle
|
|
380
|
+
if (process.platform === 'win32') {
|
|
381
|
+
return ['<', '>', ':', '"', '|', '?', '*', '\0'];
|
|
382
|
+
}
|
|
383
|
+
else {
|
|
384
|
+
// Unix/Linux: only null byte is invalid in paths
|
|
385
|
+
return ['\0'];
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Adds file:// protocol to a file path.
|
|
390
|
+
*/
|
|
391
|
+
protocol(filePath) {
|
|
392
|
+
return `file://${filePath.replace(/\\/g, '/')}`;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
exports.FileTranscriptLogger = FileTranscriptLogger;
|
|
396
|
+
FileTranscriptLogger.TRANSCRIPT_FILE_EXTENSION = '.transcript';
|
|
397
|
+
FileTranscriptLogger.MAX_FILE_NAME_SIZE = 100;
|
|
398
|
+
//# sourceMappingURL=fileTranscriptLogger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fileTranscriptLogger.js","sourceRoot":"","sources":["../../../src/transcript/fileTranscriptLogger.ts"],"names":[],"mappings":"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"}
|
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.1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"homepage": "https://github.com/microsoft/Agents-for-js",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
"types": "dist/src/index.d.ts",
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@azure/core-auth": "^1.10.1",
|
|
23
|
-
"@azure/msal-node": "^3.8.
|
|
24
|
-
"@microsoft/agents-activity": "1.1.
|
|
25
|
-
"axios": "^1.13.
|
|
23
|
+
"@azure/msal-node": "^3.8.2",
|
|
24
|
+
"@microsoft/agents-activity": "1.1.1",
|
|
25
|
+
"axios": "^1.13.2",
|
|
26
26
|
"jsonwebtoken": "^9.0.2",
|
|
27
27
|
"jwks-rsa": "^3.2.0",
|
|
28
28
|
"object-path": "^0.11.8"
|
|
@@ -113,6 +113,7 @@ export class AgenticAuthorization implements AuthorizationHandler {
|
|
|
113
113
|
}
|
|
114
114
|
|
|
115
115
|
const token = await connection.getAgenticUserToken(
|
|
116
|
+
context.activity.getAgenticTenantId() ?? '',
|
|
116
117
|
context.activity.getAgenticInstanceId() ?? '',
|
|
117
118
|
context.activity.getAgenticUser() ?? '',
|
|
118
119
|
options?.scopes || this._options.scopes!
|
|
@@ -126,6 +126,11 @@ export interface AzureBotAuthorizationOptions {
|
|
|
126
126
|
* - `${authHandlerId}_obo_scopes` (comma-separated values, e.g. `scope1,scope2`)
|
|
127
127
|
*/
|
|
128
128
|
obo?: AzureBotAuthorizationOptionsOBO
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Option to enable SSO when authenticating using Azure Active Directory (AAD). Defaults to true.
|
|
132
|
+
*/
|
|
133
|
+
enableSso?: boolean
|
|
129
134
|
}
|
|
130
135
|
|
|
131
136
|
/**
|
|
@@ -191,7 +196,8 @@ export class AzureBotAuthorization implements AuthorizationHandler {
|
|
|
191
196
|
obo: {
|
|
192
197
|
connection: settings.obo?.connection ?? process.env[`${this.id}_obo_connection`],
|
|
193
198
|
scopes: settings.obo?.scopes ?? this.loadScopes(process.env[`${this.id}_obo_scopes`]),
|
|
194
|
-
}
|
|
199
|
+
},
|
|
200
|
+
enableSso: process.env[`${this.id}_enableSso`] !== 'false' // default value is true
|
|
195
201
|
}
|
|
196
202
|
|
|
197
203
|
if (!result.name) {
|
|
@@ -393,7 +399,8 @@ export class AzureBotAuthorization implements AuthorizationHandler {
|
|
|
393
399
|
|
|
394
400
|
if (!tokenResponse) {
|
|
395
401
|
logger.debug(this.prefix('Cannot find token. Sending sign-in card'), activity)
|
|
396
|
-
|
|
402
|
+
|
|
403
|
+
const oCard = CardFactory.oauthCard(this._options.name!, this._options.title!, this._options.text!, signInResource, this._options.enableSso)
|
|
397
404
|
await context.sendActivity(MessageFactory.attachment(oCard))
|
|
398
405
|
await storage.write({ activity, id: this.id, ...(active ?? {}), attemptsLeft: this.maxAttempts })
|
|
399
406
|
return AuthorizationHandlerStatus.PENDING
|
package/src/auth/authProvider.ts
CHANGED
|
@@ -19,26 +19,29 @@ export interface AuthProvider {
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Get an access token for the agentic application
|
|
22
|
+
* @param tenantId
|
|
22
23
|
* @param agentAppInstanceId
|
|
23
24
|
* @returns a promise that resolves to the access token.
|
|
24
25
|
*/
|
|
25
|
-
getAgenticApplicationToken: (agentAppInstanceId: string) => Promise<string>
|
|
26
|
+
getAgenticApplicationToken: (tenantId: string, agentAppInstanceId: string) => Promise<string>
|
|
26
27
|
|
|
27
28
|
/**
|
|
28
29
|
* Get an access token for the agentic instance
|
|
30
|
+
* @param tenantId
|
|
29
31
|
* @param agentAppInstanceId
|
|
30
32
|
* @returns a promise that resolves to the access token.
|
|
31
33
|
*/
|
|
32
|
-
getAgenticInstanceToken: (agentAppInstanceId: string) => Promise<string>
|
|
34
|
+
getAgenticInstanceToken: (tenantId: string, agentAppInstanceId: string) => Promise<string>
|
|
33
35
|
|
|
34
36
|
/**
|
|
35
37
|
* Get an access token for the agentic user
|
|
38
|
+
* @param tenantId
|
|
36
39
|
* @param agentAppInstanceId
|
|
37
40
|
* @param upn
|
|
38
41
|
* @param scopes
|
|
39
42
|
* @returns a promise that resolves to the access token.
|
|
40
43
|
*/
|
|
41
|
-
getAgenticUserToken: (agentAppInstanceId: string, upn: string, scopes: string[]) => Promise<string>
|
|
44
|
+
getAgenticUserToken: (tenantId: string, agentAppInstanceId: string, upn: string, scopes: string[]) => Promise<string>
|
|
42
45
|
|
|
43
46
|
acquireTokenOnBehalfOf (scopes: string[], oboAssertion: string): Promise<string>
|
|
44
47
|
acquireTokenOnBehalfOf (authConfig: AuthConfiguration, scopes: string[], oboAssertion: string): Promise<string>
|