Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/ai/azure-ai-projects/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* Added OpenAPI tool sample. See `sample_agent_openapi.py`.
* Added OpenAPI with Project Connection sample. See `sample_agent_openapi_with_project_connection.py`.
* Added SharePoint grounding tool sample. See `sample_agent_sharepoint.py`.

* Improved MCP client sample showing direct MCP tool invocation. See `samples/mcp_client/sample_mcp_tool_async.py`.

## 2.0.0b2 (2025-11-14)

Expand Down
101 changes: 0 additions & 101 deletions sdk/ai/azure-ai-projects/samples/agents/sample_mcp_tool_async_.py

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@
3) AI_SEARCH_PROJECT_CONNECTION_ID - The AI Search project connection ID,
as found in the "Connections" tab in your Microsoft Foundry project.
4) AI_SEARCH_INDEX_NAME - The name of the AI Search index to use for searching.
5) AI_SEARCH_USER_INPUT - (Optional) The question to ask. If not set, you will be prompted.
"""

import os
from typing import Optional
from dotenv import load_dotenv
from azure.identity import DefaultAzureCredential
from azure.ai.projects import AIProjectClient
Expand All @@ -36,76 +38,101 @@
AzureAISearchToolResource,
AISearchIndexResource,
AzureAISearchQueryType,
AgentVersionObject,
)

# Global variables to be asserted after main execution
output: Optional[str] = None

load_dotenv()

endpoint = os.environ["AZURE_AI_PROJECT_ENDPOINT"]

with (
DefaultAzureCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
project_client.get_openai_client() as openai_client,
):

# [START tool_declaration]
tool = AzureAISearchAgentTool(
azure_ai_search=AzureAISearchToolResource(
indexes=[
AISearchIndexResource(
project_connection_id=os.environ["AI_SEARCH_PROJECT_CONNECTION_ID"],
index_name=os.environ["AI_SEARCH_INDEX_NAME"],
query_type=AzureAISearchQueryType.SIMPLE,

def main() -> None:
global output
agent: Optional[AgentVersionObject] = None

with (
DefaultAzureCredential() as credential,
AIProjectClient(endpoint=endpoint, credential=credential) as project_client,
project_client.get_openai_client() as openai_client,
):
try:
# [START tool_declaration]
tool = AzureAISearchAgentTool(
azure_ai_search=AzureAISearchToolResource(
indexes=[
AISearchIndexResource(
project_connection_id=os.environ["AI_SEARCH_PROJECT_CONNECTION_ID"],
index_name=os.environ["AI_SEARCH_INDEX_NAME"],
query_type=AzureAISearchQueryType.SIMPLE,
),
]
)
)
# [END tool_declaration]

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you need to refresh code snippets in package README.md?

agent = project_client.agents.create_version(
agent_name="MyAgent",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="""You are a helpful assistant. You must always provide citations for
answers using the tool and render them as: `\u3010message_idx:search_idx\u2020source\u3011`.""",
tools=[tool],
),
]
)
)
# [END tool_declaration]

agent = project_client.agents.create_version(
agent_name="MyAgent",
definition=PromptAgentDefinition(
model=os.environ["AZURE_AI_MODEL_DEPLOYMENT_NAME"],
instructions="""You are a helpful assistant. You must always provide citations for
answers using the tool and render them as: `\u3010message_idx:search_idx\u2020source\u3011`.""",
tools=[tool],
),
description="You are a helpful agent.",
)
print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")

user_input = input("Enter your question (e.g., 'Tell me about mental health services'): \n")

stream_response = openai_client.responses.create(
stream=True,
tool_choice="required",
input=user_input,
extra_body={"agent": {"name": agent.name, "type": "agent_reference"}},
)

for event in stream_response:
if event.type == "response.created":
print(f"Follow-up response created with ID: {event.response.id}")
elif event.type == "response.output_text.delta":
print(f"Delta: {event.delta}")
elif event.type == "response.text.done":
print(f"\nFollow-up response done!")
elif event.type == "response.output_item.done":
if event.item.type == "message":
item = event.item
if item.content[-1].type == "output_text":
text_content = item.content[-1]
for annotation in text_content.annotations:
if annotation.type == "url_citation":
print(
f"URL Citation: {annotation.url}, "
f"Start index: {annotation.start_index}, "
f"End index: {annotation.end_index}"
)
elif event.type == "response.completed":
print(f"\nFollow-up completed!")
print(f"Full response: {event.response.output_text}")

print("\nCleaning up...")
project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version)
print("Agent deleted")
description="You are a helpful agent.",
)
print(f"Agent created (id: {agent.id}, name: {agent.name}, version: {agent.version})")

# Get user input from environment variable or prompt
user_input = os.environ.get("AI_SEARCH_USER_INPUT")
if not user_input:
user_input = input("Enter your question (e.g., 'Tell me about mental health services'): \n")

print(f"Question: {user_input}\n")

stream_response = openai_client.responses.create(
stream=True,
tool_choice="required",
input=user_input,
extra_body={"agent": {"name": agent.name, "type": "agent_reference"}},
)

output = None
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The output variable is assigned to None on line 102 but then conditionally assigned within the event loop. If the loop completes without encountering a response.completed event, output will remain None, causing the assertion on line 138 to fail.

This initialization should be removed since output is already initialized as None at the module level (line 45), and the code should ensure the assertion message is more descriptive about what went wrong.

Copilot uses AI. Check for mistakes.
for event in stream_response:
if event.type == "response.created":
print(f"Follow-up response created with ID: {event.response.id}")
elif event.type == "response.output_text.delta":
print(f"Delta: {event.delta}")
elif event.type == "response.text.done":
print(f"\nFollow-up response done!")
elif event.type == "response.output_item.done":
if event.item.type == "message":
item = event.item
if item.content[-1].type == "output_text":
text_content = item.content[-1]
for annotation in text_content.annotations:
if annotation.type == "url_citation":
print(
f"URL Citation: {annotation.url}, "
f"Start index: {annotation.start_index}, "
f"End index: {annotation.end_index}"
)
elif event.type == "response.completed":
output = event.response.output_text
print(f"\nFollow-up completed!")
print(f"Full response: {output}")
except Exception as e:
print(f"Error occurred: {e}")
raise e
Comment on lines +127 to +128
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exception is caught and printed but then re-raised, making the error message on line 127 redundant since the exception will propagate anyway with its original message. Consider either:

  1. Removing the print statement and just re-raising the exception
  2. Logging the error properly instead of printing
  3. Not re-raising if you want to handle it gracefully

Example:

except Exception as e:
    # Let the exception propagate with its original traceback
    raise
Suggested change
print(f"Error occurred: {e}")
raise e
raise

Copilot uses AI. Check for mistakes.
finally:
if isinstance(agent, AgentVersionObject):
print("\nCleaning up...")
project_client.agents.delete_version(agent_name=agent.name, agent_version=agent.version)
print("Agent deleted")


if __name__ == "__main__":
main()
assert isinstance(output, str) and len(output) > 0, "Output should be a non-empty string"
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# Information about product item_number: 1

## Brand
Contoso Galaxy Innovations

## Category
Smart Eyewear

## Features
- Augmented Reality interface
- Voice-controlled AI agent
- HD video recording with 3D audio
- UV protection and blue light filtering
- Wireless charging with extended battery life

## User Guide

### 1. Introduction
Introduction to your new SmartView Glasses

### 2. Product Overview
Overview of features and controls

### 3. Sizing and Fit
Finding your perfect fit and style adjustments

### 4. Proper Care and Maintenance
Cleaning and caring for your SmartView Glasses

### 5. Break-in Period
Adjusting to the augmented reality experience

### 6. Safety Tips
Safety guidelines for public and private spaces

### 7. Troubleshooting
Quick fixes for common issues

## Warranty Information
Two-year limited warranty on all electronic components

## Contact Information
Customer Support at [email protected]

## Return Policy
30-day return policy with no questions asked

## FAQ
- How to sync your SmartView Glasses with your devices
- Troubleshooting connection issues
- Customizing your augmented reality environment
Loading
Loading