Skip to content

Commit 7caccfa

Browse files
committed
adding js package
1 parent bd616bd commit 7caccfa

File tree

2 files changed

+215
-7
lines changed

2 files changed

+215
-7
lines changed

articles/ai-foundry/agents/how-to/tools/deep-research-samples.md

Lines changed: 213 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -177,10 +177,220 @@ client.Administration.DeleteAgent(agentId: agent.Id);
177177

178178
:::zone-end
179179

180-
:::zone pivot="javascript"
180+
:::zone pivot="typescript"
181181

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("\nAgent 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("\nURL 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+
});
184394
```
185395

186396
:::zone-end

zone-pivots/zone-pivot-groups.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,12 +1102,10 @@ groups:
11021102
title: Selections
11031103
prompt: What would you like to see?
11041104
pivots:
1105-
- id: portal
1106-
title: Azure AI Foundry portal
11071105
- id: csharp
11081106
title: C#
1109-
- id: javascript
1110-
title: JavaScript
1107+
- id: typescript
1108+
title: TypeScript
11111109
- id: python
11121110
title: Python
11131111
# owner: aahi

0 commit comments

Comments
 (0)