Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
AI responses commonly include citations and feedback controls. An AI engine can return source markers such as [doc1] in generated text. StreamingResponse converts those markers to numbered references, attaches the corresponding citation metadata, and adds thumbs-up and thumbs-down controls to the final message.
Add citations and feedback to a streaming response
Add each citation in the same order as its marker in the generated text. When text is queued, the streaming response converts [doc1] or [docs1] to [1] by using CitationUtils.FormatCitationsResponse. You typically don't need to call the formatting utility directly.
using Microsoft.Agents.Core.Models;
var citations = new List<Citation>
{
new(
content: "Contoso offers 30 days of annual leave.",
title: "Contoso employee handbook",
url: "https://www.example.com/handbook")
};
turnContext.StreamingResponse.FeedbackLoopEnabled = true;
turnContext.StreamingResponse.EnableGeneratedByAILabel = true;
turnContext.StreamingResponse.QueueTextChunk(
"Contoso employees receive 30 days of annual leave [doc1].");
turnContext.StreamingResponse.AddCitations(citations);
await turnContext.StreamingResponse.EndStreamAsync(cancellationToken);
Use AddCitation(citation, position) when you need to assign a specific reference number. Use AddCitations(citations) to number a collection in list order.
context.streamingResponse.setFeedbackLoop(true)
context.streamingResponse.queueTextChunk(
'Contoso employees receive 30 days of annual leave [doc1].'
)
context.streamingResponse.setCitations([
{
content: 'Contoso offers 30 days of annual leave.',
title: 'Contoso employee handbook',
url: 'https://www.example.com/handbook',
filepath: null
}
])
await context.streamingResponse.endStream()
from microsoft_agents.hosting.core import Citation
context.streaming_response.set_feedback_loop(True)
context.streaming_response.queue_text_chunk(
"Contoso employees receive 30 days of annual leave [doc1]."
)
context.streaming_response.set_citations(
[
Citation(
content="Contoso offers 30 days of annual leave.",
title="Contoso employee handbook",
url="https://www.example.com/handbook",
)
]
)
await context.streaming_response.end_stream()
Handle submitted feedback
Register an AgentApplication.OnFeedbackLoop handler in the agent constructor:
public MyAgent(AgentApplicationOptions options) : base(options)
{
OnFeedbackLoop(OnFeedbackAsync);
}
private Task OnFeedbackAsync(
ITurnContext turnContext,
ITurnState turnState,
FeedbackData feedbackData,
CancellationToken cancellationToken)
{
var reaction = feedbackData.ActionValue?.Reaction;
var feedbackText = feedbackData.ActionValue?.Feedback;
var activityId = feedbackData.ReplyToId;
// Store or process the feedback for the referenced activity.
return Task.CompletedTask;
}
import { onTeamsFeedbackLoop } from '@microsoft/agents-hosting-extensions-msteams'
onTeamsFeedbackLoop(app, async (context, state, feedbackData) => {
const reaction = feedbackData.actionValue?.reaction
const feedbackText = feedbackData.actionValue?.feedback
const activityId = feedbackData.replyToId
// Store or process the feedback for the referenced activity.
})
The Python SDK can enable feedback controls on a streaming response. A typed incoming feedback route isn't currently exposed.
The value in FeedbackData.ActionValue.Reaction represents the thumbs-up or thumbs-down feedback selection. It's separate from an emoji message reaction activity.
Handle message reactions
Message reactions are emoji reactions that users add to or remove from a message. They arrive as message reaction activities rather than feedback-loop submissions.
Register the standard AgentApplication message reaction routes:
public MyAgent(AgentApplicationOptions options) : base(options)
{
OnMessageReactionsAdded(OnReactionsAddedAsync);
OnMessageReactionsRemoved(OnReactionsRemovedAsync);
}
private Task OnReactionsAddedAsync(
ITurnContext turnContext,
ITurnState turnState,
CancellationToken cancellationToken)
{
foreach (var reaction in turnContext.Activity.ReactionsAdded)
{
// Process reaction.Type for turnContext.Activity.ReplyToId.
}
return Task.CompletedTask;
}
private Task OnReactionsRemovedAsync(
ITurnContext turnContext,
ITurnState turnState,
CancellationToken cancellationToken)
{
foreach (var reaction in turnContext.Activity.ReactionsRemoved)
{
// Process reaction.Type for turnContext.Activity.ReplyToId.
}
return Task.CompletedTask;
}
import {
onTeamsMessageReactionsAdded,
onTeamsMessageReactionsRemoved
} from '@microsoft/agents-hosting-extensions-msteams'
onTeamsMessageReactionsAdded(app, async (context) => {
for (const reaction of context.activity.reactionsAdded ?? []) {
// Process reaction.type for context.activity.replyToId.
}
})
onTeamsMessageReactionsRemoved(app, async (context) => {
for (const reaction of context.activity.reactionsRemoved ?? []) {
// Process reaction.type for context.activity.replyToId.
}
})
A typed Teams message reaction route isn't currently exposed in the Python SDK.
For supported reaction types and client behavior, see: