feat: add multiple messages pattern to dotnet agent-framework sample#246
Open
sellakumaran wants to merge 4 commits intomainfrom
Open
feat: add multiple messages pattern to dotnet agent-framework sample#246sellakumaran wants to merge 4 commits intomainfrom
sellakumaran wants to merge 4 commits intomainfrom
Conversation
Demonstrates the recommended pattern for sending multiple discrete messages to a Teams user from a single agent turn: - Immediate ack via SendActivityAsync before LLM processing - Typing indicator loop (refreshed every 4s, properly awaited in finally) - StreamingResponse retained as best-effort for non-Teams/WebChat clients Documents the pattern in README with code examples and notes on typing indicator limitations (1:1 and small group chats only, ~5s timeout). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.OpenSSF Scorecard
Scanned Files
|
- Add ArgumentNullException guard for turnContext before InvokeObservedAgentOperation - Expand empty OperationCanceledException catch block with explanatory comment Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…) across all dotnet and nodejs samples
Implements issue #268 pattern — send an immediate ack message, run a typing
indicator loop every ~4s, then deliver the LLM response as a second discrete
message. All changes include README documentation.
dotnet/semantic-kernel:
- Send ack + single typing indicator in MessageActivityAsync before GetAgent365Agent
so they arrive before the streaming connection opens
- Read OboAuthHandlerName from config (was hardcoded)
- Register InstallationUpdate for both agentic and non-agentic identities
- Add SKIP_TOOLING_ON_ERRORS to launchSettings for local dev
nodejs (openai, langchain, langchain/quickstart-before, claude, vercel-sdk,
devin, perplexity, copilot-studio):
- Add ack sendActivity before LLM call
- Add setInterval typing loop (~4s); stopped in finally block
- Add/fix InstallationUpdate handler where missing (copilot-studio, quickstart-before)
nodejs/langchain/quickstart-before (additional pre-existing fixes):
- Fix build errors: instructions → systemPrompt (langchain 1.2.32 API change)
- Add @types/express and @types/node devDependencies
- Add Azure OpenAI support alongside standard OpenAI in client.ts
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Python (openai, claude, crewai, google-adk, agent-framework): add immediate
ack message ("Got it — working on it…"), explicit typing indicator await
before create_task, and asyncio background loop refreshing every 4s
- Node.js (openai, claude, langchain, vercel-sdk, copilot-studio): remove
startTypingTimer: true (fires before ack, wrong order) and add explicit
await sendActivity(typing) after ack, before setInterval loop
- dotnet agent-framework: add explicit typing await on main thread before
Task.Run, fix loop order (Delay first then send), move null guard to top
of OnMessageAsync (fixes Copilot review finding)
- crewai: fix pysqlite3-binary to Linux-only (no Windows wheel), add Azure
LLM config (azure/gpt-4o) to agents.yaml
- All Python READMEs: add "Sending Multiple Messages in Teams" section with
correct code example including explicit typing line
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
| // Each SendActivityAsync call produces a discrete Teams message, enabling the multiple-messages pattern. | ||
| // NOTE: For Teams agentic identities, streaming is buffered into a single message by the SDK; | ||
| // use SendActivityAsync for any messages that must arrive immediately. | ||
| await turnContext.SendActivityAsync(MessageFactory.Text("Got it — working on it…"), cancellationToken).ConfigureAwait(false); |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds a consistent “multiple discrete messages per turn” UX pattern across the Agent365 sample agents (ack → typing → final response), and documents the approach/limitations for Teams clients.
Changes:
- Updated Python and Node.js sample message handlers to send an immediate ack and keep a typing indicator alive during LLM work.
- Updated .NET agent-framework and semantic-kernel samples to document (and in agent-framework, implement) multi-message + typing patterns.
- Added cross-sample tracking doc and a few sample maintenance tweaks (CrewAI config, platform-specific dependency condition, quickstart fixes, env/launch settings).
Reviewed changes
Copilot reviewed 37 out of 37 changed files in this pull request and generated 14 comments.
Show a summary per file
| File | Description |
|---|---|
| python/openai/sample-agent/host_agent_server.py | Adds ack + typing-loop around LLM processing. |
| python/openai/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| python/google-adk/sample-agent/hosting.py | Adds ack + typing-loop to ADK hosting message handler. |
| python/google-adk/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| python/crewai/sample_agent/src/crew_agent/config/agents.yaml | Pins CrewAI agents to an Azure GPT-4o LLM. |
| python/crewai/sample_agent/pyproject.toml | Makes pysqlite3-binary Linux-only. |
| python/crewai/sample_agent/host_agent_server.py | Adds ack + typing-loop around LLM processing (with observability scope). |
| python/crewai/sample_agent/README.md | Documents multi-message + typing pattern for Teams. |
| python/claude/sample-agent/host_agent_server.py | Adds ack + typing-loop around LLM processing. |
| python/claude/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| python/agent-framework/sample-agent/host_agent_server.py | Adds ack + typing-loop around LLM processing. |
| python/agent-framework/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/vercel-sdk/sample-agent/src/agent.ts | Adds ack + typing loop; removes startTypingTimer. |
| nodejs/vercel-sdk/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/perplexity/sample-agent/src/agent.ts | Adds ack + typing loop to the message activity handler. |
| nodejs/perplexity/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/openai/sample-agent/src/agent.ts | Adds ack + typing loop; removes startTypingTimer. |
| nodejs/openai/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/openai/sample-agent/.env.template | Adds HOST binding guidance for Playground. |
| nodejs/langchain/sample-agent/src/agent.ts | Adds ack + typing loop; removes startTypingTimer. |
| nodejs/langchain/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/langchain/quickstart-before/src/client.ts | Adds Azure OpenAI fallback configuration and renames prompt field. |
| nodejs/langchain/quickstart-before/src/agent.ts | Adds ack + typing loop and InstallationUpdate handler. |
| nodejs/langchain/quickstart-before/package.json | Adds missing TS type dependencies. |
| nodejs/langchain/quickstart-before/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/devin/sample-agent/src/agent.ts | Adds ack + typing loop in message handling flow. |
| nodejs/devin/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/copilot-studio/sample-agent/src/agent.ts | Adds ack + typing loop and InstallationUpdate handler. |
| nodejs/copilot-studio/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| nodejs/claude/sample-agent/src/agent.ts | Adds ack + typing loop; removes startTypingTimer. |
| nodejs/claude/sample-agent/README.md | Documents multi-message + typing pattern for Teams. |
| dotnet/semantic-kernel/sample-agent/README.md | Documents install/uninstall + multi-message pattern and typing limitations. |
| dotnet/semantic-kernel/sample-agent/Properties/launchSettings.json | Adds SKIP_TOOLING_ON_ERRORS env var for local runs. |
| dotnet/semantic-kernel/sample-agent/Agents/MyAgent.cs | Moves ack/typing earlier and updates auth handler selection logic. |
| dotnet/agent-framework/sample-agent/README.md | Documents multi-message + typing loop pattern for Teams. |
| dotnet/agent-framework/sample-agent/Agent/MyAgent.cs | Implements ack + typing loop + best-effort streaming behavior. |
| docs/multiple-messages-tracking.md | Adds tracking doc for multi-message rollout across samples. |
You can also share your feedback on Copilot code review. Take the survey.
Comment on lines
+77
to
+78
| typingInterval = setInterval(async () => { | ||
| await turnContext.sendActivity({ type: 'typing' } as Activity); |
Comment on lines
+190
to
+191
| typingInterval = setInterval(async () => { | ||
| await turnContext.sendActivity(Activity.fromObject({ type: "typing" })); |
Comment on lines
1
to
10
| # Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| """ | ||
| Generic Agent Host Server | ||
| A generic hosting server that can host any agent class that implements the required interface. | ||
| """ | ||
|
|
||
| import asyncio | ||
| import logging | ||
| import os |
Comment on lines
1
to
+6
| # Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| """Generic Agent Host Server - Hosts agents implementing AgentInterface""" | ||
|
|
||
| # --- Imports --- | ||
| import asyncio |
Comment on lines
+215
to
+216
| await context.send_activity(Activity(type="typing")) | ||
| await context.send_activity("Got it — working on it…") |
Comment on lines
1
to
+4
| # Copyright (c) Microsoft. All rights reserved. | ||
|
|
||
| # --- Imports --- | ||
| import asyncio |
Comment on lines
+52
to
+60
| OboAuthHandlerName = _configuration.GetValue<string>("AgentApplication:OboAuthHandlerName"); | ||
| string[] autoSignInHandlersForNotAgenticAuth = !string.IsNullOrEmpty(OboAuthHandlerName) ? [OboAuthHandlerName] : []; | ||
|
|
||
| // Register Agentic specific Activity routes. These will only be used if the incoming Activity is Agentic. | ||
| this.OnAgentNotification("*", AgentNotificationActivityAsync, RouteRank.Last, autoSignInHandlers: new[] { AgenticIdAuthHandler }); | ||
| OnActivity(ActivityTypes.InstallationUpdate, OnHireMessageAsync, isAgenticOnly: true, autoSignInHandlers: new[] { AgenticIdAuthHandler }); | ||
| OnActivity(ActivityTypes.InstallationUpdate, OnHireMessageAsync, isAgenticOnly: false); | ||
| OnActivity(ActivityTypes.Message, MessageActivityAsync, rank: RouteRank.Last, isAgenticOnly: true, autoSignInHandlers: new[] { AgenticIdAuthHandler }); | ||
| OnActivity(ActivityTypes.Message, MessageActivityAsync, rank: RouteRank.Last, isAgenticOnly: false, autoSignInHandlers: autoSignInHandlersForNotAgenticAuth); |
Comment on lines
+78
to
+79
| typingInterval = setInterval(async () => { | ||
| await turnContext.sendActivity({ type: 'typing' } as Activity); |
Comment on lines
+70
to
+71
| typingInterval = setInterval(async () => { | ||
| await turnContext.sendActivity({ type: 'typing' } as Activity); |
Comment on lines
+69
to
+73
| typingInterval = setInterval(async () => { | ||
| await turnContext.sendActivity({ type: 'typing' } as Activity); | ||
| }, 4000); | ||
| }; | ||
| const stopTypingLoop = () => { clearInterval(typingInterval); }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Demonstrates the recommended pattern for sending multiple discrete messages to a Teams user from a single agent turn:
Documents the pattern in README with code examples and notes on typing indicator limitations (1:1 and small group chats only, ~5s timeout).