@@ -177,10 +177,220 @@ client.Administration.DeleteAgent(agentId: agent.Id);
177
177
178
178
::: zone-end
179
179
180
- :::zone pivot="javascript "
180
+ :::zone pivot="typescript "
181
181
182
- ``` javascript
183
- TBD
182
+ > [ !NOTE]
183
+ > You need the latest preview version of the ` @azure/ai-projects ` package.
184
+
185
+ ``` typescript
186
+ import type {
187
+ MessageTextContent ,
188
+ ThreadMessage ,
189
+ DeepResearchToolDefinition ,
190
+ MessageTextUrlCitationAnnotation ,
191
+ } from " @azure/ai-agents" ;
192
+ import { AgentsClient , isOutputOfType } from " @azure/ai-agents" ;
193
+ import { DefaultAzureCredential } from " @azure/identity" ;
194
+
195
+ import " dotenv/config" ;
196
+
197
+ const projectEndpoint = process .env [" PROJECT_ENDPOINT" ] || " <project endpoint>" ;
198
+ const modelDeploymentName = process .env [" MODEL_DEPLOYMENT_NAME" ] || " gpt-4o" ;
199
+ const deepResearchModelDeploymentName =
200
+ process .env [" DEEP_RESEARCH_MODEL_DEPLOYMENT_NAME" ] || " gpt-4o" ;
201
+ const bingConnectionId = process .env [" AZURE_BING_CONNECTION_ID" ] || " <connection-id>" ;
202
+
203
+ /**
204
+ * Fetches and prints new agent response from the thread
205
+ * @param threadId - The thread ID
206
+ * @param client - The AgentsClient instance
207
+ * @param lastMessageId - The ID of the last message processed
208
+ * @returns The ID of the newest message, or undefined if no new message
209
+ */
210
+ async function fetchAndPrintNewAgentResponse(
211
+ threadId : string ,
212
+ client : AgentsClient ,
213
+ lastMessageId ? : string ,
214
+ ): Promise <string | undefined > {
215
+ const messages = client .messages .list (threadId );
216
+ let latestMessage: ThreadMessage | undefined ;
217
+ for await (const msg of messages ) {
218
+ if (msg .role === " assistant" ) {
219
+ latestMessage = msg ;
220
+ break ;
221
+ }
222
+ }
223
+
224
+ if (! latestMessage || latestMessage .id === lastMessageId ) {
225
+ return lastMessageId ;
226
+ }
227
+
228
+ console .log (" \n Agent response:" );
229
+
230
+ // Print text content
231
+ for (const content of latestMessage .content ) {
232
+ if (isOutputOfType <MessageTextContent >(content , " text" )) {
233
+ console .log (content .text .value );
234
+ }
235
+ }
236
+
237
+ const urlCitations = getUrlCitationsFromMessage (latestMessage );
238
+ if (urlCitations .length > 0 ) {
239
+ console .log (" \n URL Citations:" );
240
+ for (const citation of urlCitations ) {
241
+ console .log (` URL Citations: [${citation .title }](${citation .url }) ` );
242
+ }
243
+ }
244
+
245
+ return latestMessage .id ;
246
+ }
247
+
248
+ /**
249
+ * Extracts URL citations from a thread message
250
+ * @param message - The thread message
251
+ * @returns Array of URL citations
252
+ */
253
+ function getUrlCitationsFromMessage(message : ThreadMessage ): Array <{ title: string ; url: string }> {
254
+ const citations: Array <{ title: string ; url: string }> = [];
255
+
256
+ for (const content of message .content ) {
257
+ if (isOutputOfType <MessageTextContent >(content , " text" )) {
258
+ for (const annotation of content .text .annotations ) {
259
+ if (isOutputOfType <MessageTextUrlCitationAnnotation >(annotation , " url_citation" )) {
260
+ citations .push ({
261
+ title: annotation .urlCitation .title || annotation .urlCitation .url ,
262
+ url: annotation .urlCitation .url ,
263
+ });
264
+ }
265
+ }
266
+ }
267
+ }
268
+
269
+ return citations ;
270
+ }
271
+
272
+ /**
273
+ * Creates a research summary from the final message
274
+ * @param message - The thread message containing the research results
275
+ * @param filepath - The file path to write the summary to
276
+ */
277
+ function createResearchSummary(message : ThreadMessage ): void {
278
+ if (! message ) {
279
+ console .log (" No message content provided, cannot create research summary." );
280
+ return ;
281
+ }
282
+
283
+ let content = " " ;
284
+
285
+ // Write text summary
286
+ const textSummaries: string [] = [];
287
+ for (const contentItem of message .content ) {
288
+ if (isOutputOfType <MessageTextContent >(contentItem , " text" )) {
289
+ textSummaries .push (contentItem .text .value .trim ());
290
+ }
291
+ }
292
+ content += textSummaries .join (" \n\n " );
293
+
294
+ // Write unique URL citations, if present
295
+ const urlCitations = getUrlCitationsFromMessage (message );
296
+ if (urlCitations .length > 0 ) {
297
+ content += " \n\n ## References\n " ;
298
+ const seenUrls = new Set <string >();
299
+ for (const citation of urlCitations ) {
300
+ if (! seenUrls .has (citation .url )) {
301
+ content += ` - [${citation .title }](${citation .url })\n ` ;
302
+ seenUrls .add (citation .url );
303
+ }
304
+ }
305
+ }
306
+
307
+ // writeFileSync(filepath, content, "utf-8");
308
+ console .log (` Research summary created:\n ${content } ` );
309
+ // console.log(`Research summary written to '${filepath}'.`);
310
+ }
311
+
312
+ export async function main(): Promise <void > {
313
+ // Create an Azure AI Client
314
+ const client = new AgentsClient (projectEndpoint , new DefaultAzureCredential ());
315
+
316
+ // Create Deep Research tool definition
317
+ const deepResearchTool: DeepResearchToolDefinition = {
318
+ type: " deep_research" ,
319
+ deepResearch: {
320
+ deepResearchModel: deepResearchModelDeploymentName ,
321
+ deepResearchBingGroundingConnections: [
322
+ {
323
+ connectionId: bingConnectionId ,
324
+ },
325
+ ],
326
+ },
327
+ };
328
+
329
+ // Create agent with the Deep Research tool
330
+ const agent = await client .createAgent (modelDeploymentName , {
331
+ name: " my-agent" ,
332
+ instructions: " You are a helpful Agent that assists in researching scientific topics." ,
333
+ tools: [deepResearchTool ],
334
+ });
335
+ console .log (` Created agent, ID: ${agent .id } ` );
336
+
337
+ // Create thread for communication
338
+ const thread = await client .threads .create ();
339
+ console .log (` Created thread, ID: ${thread .id } ` );
340
+
341
+ // Create message to thread
342
+ const message = await client .messages .create (
343
+ thread .id ,
344
+ " user" ,
345
+ " Research the current scientific understanding of orca intelligence and communication, focusing on recent (preferably past 5 years) peer-reviewed studies, comparisons with other intelligent species such as dolphins or primates, specific cognitive abilities like problem-solving and social learning, and detailed analyses of vocal and non-vocal communication systems—please include notable authors or landmark papers if applicable." ,
346
+ );
347
+ console .log (` Created message, ID: ${message .id } ` );
348
+
349
+ console .log (" Start processing the message... this may take a few minutes to finish. Be patient!" );
350
+
351
+ // Create and poll the run
352
+ const run = await client .runs .create (thread .id , agent .id );
353
+ let lastMessageId: string | undefined ;
354
+
355
+ // Poll the run status
356
+ let currentRun = run ;
357
+ while (currentRun .status === " queued" || currentRun .status === " in_progress" ) {
358
+ await new Promise ((resolve ) => setTimeout (resolve , 1000 )); // Wait 1 second
359
+ currentRun = await client .runs .get (thread .id , run .id );
360
+
361
+ lastMessageId = await fetchAndPrintNewAgentResponse (thread .id , client , lastMessageId );
362
+ console .log (` Run status: ${currentRun .status } ` );
363
+ }
364
+
365
+ console .log (` Run finished with status: ${currentRun .status }, ID: ${currentRun .id } ` );
366
+
367
+ if (currentRun .status === " failed" ) {
368
+ console .log (` Run failed: ${currentRun .lastError } ` );
369
+ }
370
+
371
+ // Fetch the final message from the agent and create a research summary
372
+ const messages = client .messages .list (thread .id , { order: " desc" , limit: 10 });
373
+ let finalMessage: ThreadMessage | undefined ;
374
+
375
+ for await (const msg of messages ) {
376
+ if (msg .role === " assistant" ) {
377
+ finalMessage = msg ;
378
+ break ;
379
+ }
380
+ }
381
+
382
+ if (finalMessage ) {
383
+ createResearchSummary (finalMessage );
384
+ }
385
+
386
+ // Clean-up and delete the agent once the run is finished
387
+ await client .deleteAgent (agent .id );
388
+ console .log (" Deleted agent" );
389
+ }
390
+
391
+ main ().catch ((err ) => {
392
+ console .error (" The sample encountered an error:" , err );
393
+ });
184
394
```
185
395
186
396
::: zone-end
0 commit comments