How to get the citations of a Azure AI Foundry Agent response

Edgar Silva 20 Reputation points
2025-07-11T19:33:24.03+00:00

Hello I developed an Agent using Azure AI Foundry and deployed it to Teams using 365 agents toolkit and the agent answer the questions but I'd like the answer to point to the documents that informed the answer similarly to how it happens in Foundry playground, here's a snippet of the code that handles the messages:

@bot_app.activity("message")

async def on_message_activity(context: TurnContext, state: TurnState):

"""Handle incoming messages using Azure AI Foundry Agent Service"""

try:

user_message = context.activity.text

user_id = context.activity.from_property.id

user_name = getattr(context.activity.from_property, 'name', 'User')

print(f"📨 Processing message from {user_name}: {user_message}")

Handle special commands first

if user_message.lower().strip() in ['help', 'info']:

await context.send_activity(MessageFactory.text(INFO_MESSAGE))

return

elif user_message.lower().strip() in ['intro', 'welcome']:

await context.send_activity(MessageFactory.text(WELCOME_MESSAGE))

return

Process with Azure AI Foundry

Get or create conversation thread for this user

thread_key = f"thread_{user_id}"

thread_id = state.conversation.get(thread_key)

if not thread_id:

print("🔧 Creating new Azure AI Foundry thread...")

print("Assistant ID: ", config.AZURE_OPENAI_ASSISTANT_ID)

Create a new thread using the corrected method

thread = project_client.agents.create_thread_and_process_run(

agent_id=config.AZURE_OPENAI_ASSISTANT_ID

)

thread_id = thread.thread_id # Use thread_id from the response

state.conversation[thread_key] = thread_id

print(f"✅ Created new thread: {thread_id}")

Add user message to thread using the corrected API structure

message = project_client.agents.messages.create(

thread_id=thread_id,

role=MessageRole.USER,

content=user_message

)

print(f"📤 Added message: {message.id}")

Create and run the agent using the corrected method

run = project_client.agents.runs.create_and_process(

thread_id=thread_id,

agent_id=config.AZURE_OPENAI_ASSISTANT_ID

)

print(f"🚀 Started run: {run.id}")

Get the run status using the corrected method

completed_run = project_client.agents.runs.get(

thread_id=thread_id,

run_id=run.id

)

print(f"📊 Run status: {completed_run.status}")

if completed_run.status == "completed":

Get messages using the corrected API structure

messages = project_client.agents.messages.list(

thread_id=thread_id,

order=ListSortOrder.ASCENDING

)

Find the latest assistant message

assistant_response = None

for msg in messages:

if msg.text_messages and len(msg.text_messages) > 0:

assistant_response = msg.text_messages[-1].text.value

if assistant_response:

Send the response first

await context.send_activity(MessageFactory.text(assistant_response))

else:

No response - forward to support

await context.send_activity(MessageFactory.text(

"I processed your message but couldn't generate a response."

))

else:

Technical error - forward to support

error_msg = f"Sorry, I encountered a technical issue (status: {completed_run.status})."

await context.send_activity(MessageFactory.text(error_msg))

except Exception as e:

print(f"❌ Error in message handler: {str(e)}")

traceback.print_exc()

await context.send_activity(MessageFactory.text(

"Sorry, I encountered an error processing your message."

))

Microsoft Teams | Development
{count} votes

1 answer

Sort by: Most helpful
  1. Karan Shewale 2,025 Reputation points Microsoft External Staff
    2025-07-14T07:13:49.8033333+00:00

    Hi Edgar,

    To get citations from your Azure AI Foundry Agent response, you need to access the annotations property of the message content, which contains the citation information. Here's how to modify your code to extract and display citations:

    Updated Code with Citations:

    @bot_app.activity("message")
    async def on_message_activity(context: TurnContext, state: TurnState):
        """Handle incoming messages using Azure AI Foundry Agent Service"""
        try:
            user_message = context.activity.text
            user_id = context.activity.from_property.id
            user_name = getattr(context.activity.from_property, 'name', 'User')
            
            print(f"📨 Processing message from {user_name}: {user_message}")
            
            # Handle special commands first
            if user_message.lower().strip() in ['help', 'info']:
                await context.send_activity(MessageFactory.text(INFO_MESSAGE))
                return
            elif user_message.lower().strip() in ['intro', 'welcome']:
                await context.send_activity(MessageFactory.text(WELCOME_MESSAGE))
                return
            
            # Process with Azure AI Foundry
            thread_key = f"thread_{user_id}"
            thread_id = state.conversation.get(thread_key)
            
            if not thread_id:
                print("🔧 Creating new Azure AI Foundry thread...")
                thread = project_client.agents.create_thread_and_process_run(
                    agent_id=config.AZURE_OPENAI_ASSISTANT_ID
                )
                thread_id = thread.thread_id
                state.conversation[thread_key] = thread_id
                print(f"✅ Created new thread: {thread_id}")
            
            # Add user message to thread
            message = project_client.agents.messages.create(
                thread_id=thread_id,
                role=MessageRole.USER,
                content=user_message
            )
            
            # Create and run the agent
            run = project_client.agents.runs.create_and_process(
                thread_id=thread_id,
                agent_id=config.AZURE_OPENAI_ASSISTANT_ID
            )
            
            # Get the completed run
            completed_run = project_client.agents.runs.get(
                thread_id=thread_id,
                run_id=run.id
            )
            
            if completed_run.status == "completed":
                # Get messages
                messages = project_client.agents.messages.list(
                    thread_id=thread_id,
                    order=ListSortOrder.ASCENDING
                )
                
                # Find the latest assistant message with citations
                assistant_response = None
                citations = []
                
                for msg in messages:
                    if msg.role == MessageRole.ASSISTANT and msg.text_messages:
                        latest_text_msg = msg.text_messages[-1]
                        assistant_response = latest_text_msg.text.value
                        
                        # Extract citations from annotations
                        if hasattr(latest_text_msg.text, 'annotations') and latest_text_msg.text.annotations:
                            for annotation in latest_text_msg.text.annotations:
                                if hasattr(annotation, 'file_citation'):
                                    file_citation = annotation.file_citation
                                    citations.append({
                                        'file_id': file_citation.file_id,
                                        'quote': getattr(file_citation, 'quote', ''),
                                        'text': annotation.text
                                    })
                
                if assistant_response:
                    # Format response with citations
                    formatted_response = await format_response_with_citations(
                        assistant_response, 
                        citations, 
                        project_client
                    )
                    await context.send_activity(MessageFactory.text(formatted_response))
                else:
                    await context.send_activity(MessageFactory.text(
                        "I processed your message but couldn't generate a response."
                    ))
            else:
                error_msg = f"Sorry, I encountered a technical issue (status: {completed_run.status})."
                await context.send_activity(MessageFactory.text(error_msg))
                
        except Exception as e:
            print(f"❌ Error in message handler: {str(e)}")
            traceback.print_exc()
            await context.send_activity(MessageFactory.text(
                "Sorry, I encountered an error processing your message."
            ))
    async def format_response_with_citations(response_text, citations, client):
        """Format the response with citation information"""
        if not citations:
            return response_text
        
        formatted_response = response_text + "\n\n**Sources:**\n"
        
        for i, citation in enumerate(citations, 1):
            try:
                # Get file information
                file_info = client.files.get(citation['file_id'])
                file_name = file_info.filename if hasattr(file_info, 'filename') else f"Document {i}"
                
                formatted_response += f"{i}. {file_name}"
                
                # Add quote if available
                if citation.get('quote'):
                    formatted_response += f" - \"{citation['quote'][:100]}...\""
                
                formatted_response += "\n"
                
            except Exception as e:
                print(f"Error getting file info for {citation['file_id']}: {e}")
                formatted_response += f"{i}. Source document\n"
        
        return formatted_response
    

    Key Changes:

    1. Citation Extraction: Access annotations from the text message to get file citations
    2. File Information: Retrieve file details using the file_id from citations
    3. Formatted Output: Combine the response with source information

    Important Notes:

    • Ensure your agent has access to the knowledge base files
    • Citations are only available when the agent references specific documents
    • File permissions may affect citation retrieval

    Testing: Test with questions that should reference your knowledge base documents to verify citations appear correctly.

    Hope this helps!

    Thanks,  

    Karan Shewale. 

    *************************************************************************  

    If the response is helpful, please click "Accept Answer" and upvote it. You can share your feedback via Microsoft Teams Developer Feedback link. Click here to escalate. 


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.