Python: Channel spec#5549
Conversation
ADR 0026: - Tighten Decision Outcome Summary so each concept is mentioned once; defer full definitions to the Terminology section. - Update ChannelInvocationHook bullet to match the clarified gap microsoft#7 language (uniform ChannelRequest envelope, hook timing, illustrative examples). - Drop Decision Drivers bullets that just restated Business Goals; cross-link to the goals section instead. - Replace the More Information bullet list with a pointer to Non-Goals. Spec 002: - Trim requirement microsoft#21 to point at the canonical LinkPolicy section instead of restating the full contract. - Add a #linkpolicy-and-trust_level subsection anchor for cross-refs. - Trim the Terminology LinkPolicy entry's two-hosts caveat (canonical version stays in the Key Types section). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Automated Code Review
Reviewers: 4 | Confidence: 93%
✓ Correctness
This is a well-structured design spec for Python hosting channels. Two correctness issues were found in the illustrative code samples: (1) Scenario 10 calls AgentRunInputs.from_text() but AgentRunInputs is a type alias (str | Content | Message | Sequence[...]), not a class — it has no from_text() method; and (2) Scenarios 3 and 8 use inconsistent mutation patterns on ChannelRequest (dataclasses.replace() vs .replace() method). These would mislead implementors.
✓ Security Reliability
No actionable issues found in this dimension.
✓ Test Coverage
No actionable issues found in this dimension.
✓ Design Approach
The ADR is thoughtful overall, but it bakes in the wrong persistence boundary by making session resolution user-scoped via
isolation_key. The existing framework contracts in both .NET and Python treat sessions as conversation/thread state, not user identity, so this approach would collapse multiple concurrent conversations for the same user into one shared history and make later cross-channel/background delivery semantics fragile. I would request changes to separate identity/linking from conversation/session lookup. The spec is directionally strong, but two design choices look fundamentally off. First, it treatsWorkflowas interchangeable withSupportsAgentRunin the host contract even though the current Python workflow runtime keeps mutable state on the workflow instance and has no session parameter, which would leak state across unrelated users/channels if a host fronts a singleton workflow. Second, the cross-channel continuity story is still keyed offChannelSession.keycompatibility, so the host is not actually owning session identity in a channel-neutral way; linked identities will still fragment whenever channels naturally emit different thread/conversation IDs.
Suggestions
- Scenario 10 (line 957):
AgentRunInputs.from_text(payload["text"])will fail —AgentRunInputsis a type alias (str | Content | Message | Sequence[...]), not a class with afrom_text()classmethod. Usepayload["text"]directly (a plainstrsatisfiesAgentRunInputs) orContent.from_text(payload["text"])if you want rich content.
Automated review by eavanvalkenburg's agents
moonbox3
left a comment
There was a problem hiding this comment.
I approached this review in the context of AG-UI...
- Document FoundryHostedAgentHistoryProvider roundtrip of additional_properties namespaces via the agent_framework container key on stored OutputItems. - Add Foundry storage gap subsection capturing the update_item service ask required for post-push delivery_tracking[] mutation. - Triage open questions: 18 resolved (now in a Resolved Questions decisions log), 3 notes-updated, 6 unchanged. Capture spec-body follow-ups implied by the resolutions in a new Decisions-driven follow-ups subsection. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…rix, open-question pass - Surface A2A and MCP-tool channels as explicitly designed-in but fast-follow work after the first Responses + Invocations + Telegram release. Updated ADR business goals, non-goals, and More Information; added spec reqs microsoft#25 (A2AChannel) and microsoft#26 (MCPToolChannel) under v1 Fast Follow; renumbered the WhatsApp/Teams entry to microsoft#27. - New 'The Responses store parameter' subsection in the spec: 2x3 destination matrix making explicit that 'store' has no canonical meaning at the hosted-agent layer — the developer decides what it maps to across service-side, hosted-agent storage, and caller-side. Includes design properties on forwarding-vs-mapping, per-deployment documentation responsibility, and richer storage vocabulary via OpenAI's extra_body. - Fixed contradicting spec text that previously claimed ResponsesChannel maps store=False to session_mode=disabled by default; updated channel options table, session_mode terminology entry, and Scenario 3 prose/comment to match the new model. - Renamed FoundryHistoryProvider -> FoundryHostedAgentHistoryProvider throughout the spec (9 occurrences) so the name reinforces the intended hosted-agent use case. - ADR open-questions pass: walked through all 15 entries with the user. 13 resolved (moved to a new 'Resolved Questions (decisions log)' table), 2 kept open with refined wording (Q6 'Channel' GA name, Q14 Responses WS subprotocol). Added a 'Decisions-driven follow-ups' bullet list capturing the spec-body / sample edits implied by the resolutions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
b53331a to
2d1ea3a
Compare
…lti-user conversation design - Rename the planned Teams channel to ActivityChannel (package agent-framework-hosting-activity). Promoted to req microsoft#27 (v1 fast follow) alongside A2A and MCP-tool, with native translations from Activity Protocol objects to AF types so the contract is explicit rather than implicit through Invocations. Channel sits behind Azure Bot Service, which fronts Teams / Web Chat / Slack / etc. Naming reserves a TeamsChannel name for any future direct-to-Teams transport that bypasses Bot Service (now stretch req microsoft#28 with WhatsApp). ResponseTarget channel ids and JSON examples updated from "teams" to "activity". Appendix B updated to acknowledge that ActivityChannel deliberately reuses the Bot Service connector model (the no-connector stance applies to the rest of the channel set). - Add first-class design for multi-user surfaces (Telegram groups / supergroups / forum topics; Activity Protocol groupChat and team channels). Cleanly separate user identity (ChannelIdentity.native_id = from.id / from.aadObjectId) from conversation locator (ChannelRequest.conversation_id = chat.id (+ message_thread_id / replyToId)). New per-channel options: conversation_scope (per_user / per_user_per_conversation (default in groups) / per_conversation) and accept_in_group addressing rule (mention_only (default) / command_only / mention_or_command / all). Specifies originating reply must include conversation + thread locator, ChannelPush behavior in groups, link-ceremony privacy (challenges redirected to user DMs), and the Activity-channel mapping for personal / groupChat / channel conversationType plus Teams replyToId threading. Broadcast Telegram Channels and adaptive-card Invoke activity flows scoped as fast follow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…file-based v1); align agentserver dependency posture
- Rename RunHandle → ContinuationToken (opaque URL-safe `token` field) throughout
ADR + spec; update routes to /{continuation_token}; spec out equivalent
continuation-token support for the Invocations channel (Q20 done).
- Introduce HostStateStore as the single persistence seam for host-execution
metadata (continuation tokens, identity-link grants, last-seen records).
V1 default: FileHostStateStore (atomic JSON-per-record under ./.af-hosting/,
per-namespace TTLs) — background runs and link grants now survive host
restarts. InMemoryHostStateStore for tests; pluggable Cosmos / SQL / Redis
remain v1 fast follow under req microsoft#23. Closes Q9, Q11, Q14.
- Drop blanket "no agentserver dependency" claims. Hosting core is still
independent of agentserver, but channel packages MAY consume lower-level
building blocks (notably the Foundry response-store SDK that
FoundryHostedAgentHistoryProvider builds on).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…s-channel continuity Scenario 6 (cross-channel continuity) previously forward-referenced Scenario 7 (linker) twice, since continuity depends on the link/merge ceremony. Invert the order so the linker scenario establishes the mechanism first and the continuity scenario builds on it. Update internal cross-references, the require_link section anchor, and Scenario 8's prerequisites/comment to match. Also tightened the new Scenario 7's closing note to point at HostStateStore (file-based default) for cross-host continuity, and dropped a stale MfaIdentityLinker reference from the linker variants paragraph (Q13 dropped MFA from phase 1). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…et.identities The previous Scenario 7 (cross-channel chat continuity) implied two independent auto-issued isolation_keys would converge by themselves — they don't, that needs a linker. Replace with a more realistic and complementary scenario: a trusted server-side application backend exposes Responses + Telegram against the same agent and uses extra_body to carry app-internal identity hints (app_user_id, push_to_telegram_chat_id) that a Responses run_hook translates into both an isolation_key promotion and a push to a known Telegram chat. Includes a closing variant pointing back at Scenario 6's linker for the no-app-table flow. Adds the ResponseTarget.identities([ChannelIdentity(...)]) variant to the type table and req microsoft#12 to support 'caller already knows the channel-native recipient' delivery without going through the link store. Bypasses the link store but still consults LinkPolicy per delivery. Drops MfaIdentityLinker references from req microsoft#11, req microsoft#24, and the linker helpers table (Q13 had already dropped MFA from phase 1; the spec body just hadn't caught up). Marks ADR Q8 follow-up done. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…me-from-checkpoint flow Scenario 9 now builds the workflow with a FileCheckpointStorage so executor frames are persisted across runs, and demonstrates how the run_hook surfaces a caller-supplied resume_from_checkpoint into request.attributes so the host's workflow dispatch can pass it to Workflow.run(checkpoint_id=...). Closing paragraph clarifies that CheckpointStorage is workflow-runtime state, kept structurally separate from HostStateStore and ContextProvider — three protocols that MAY share a backend but stay independently typed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… not limited to result.text) Add a 'Result is rich, not just text' callout under the channel-authoring sample. Inventories the typed Contents on the underlying AgentRunResult (TextContent, DataContent, UriContent, FunctionCallContent / FunctionResultContent, HostedFile/VectorStoreContent, UsageContent, TextReasoningContent, ErrorContent + additional_properties), the typed structured output via result.value, and shows concrete examples per channel shape: Telegram (MarkdownV2 + sendPhoto/sendAudio + inline keyboards), Responses (full content-list round-trip), chat UI (GFM/HTML + collapsible tool/reasoning panels), voice (TTS + earcons), typed RPC (result.value first). result.text is positioned as a convenience for single-string channels, not the contract. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…oft#28 Add a Teams-native channel package built on the MIT-licensed microsoft/teams.py SDK as fast-follow alongside the generic ActivityChannel (req microsoft#27). Where ActivityChannel targets the generic Activity Protocol surface, TeamsChannel exploits Teams-specific affordances the generic protocol does not surface natively: Adaptive Cards (typed builder), streamed replies, AI-generated badge, feedback controls + form, suggested-prompt chips, inline citations, modal Dialogs, Message Extensions (action / search / link unfurling), proactive / targeted / threaded messages, and SSO via MSAL. Mounts the SDK's App into the host's Starlette app via a custom HttpServerAdapter; reuses the same host-tracked-session family as ActivityChannel (from.aadObjectId -> ChannelIdentity). The SDK already ships a 'Build an agent using Microsoft Agent Framework' guide so the integration story is direct. Renumber the WhatsApp / direct-to-Teams stretch item to req microsoft#29 and clarify its 'direct-to-Teams' placeholder is a future transport that bypasses both Bot Service and the teams.py SDK. Add the SDK to Dependencies & Commitment Status as a proposed runtime dep of agent-framework-hosting-teams. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split the WhatsApp + direct-to-Teams stretch entry into two distinct items and reword the direct-to-Teams item to be honest about its current feasibility: - It MUST not rely on Azure Bot Service (otherwise it is just ActivityChannel / TeamsChannel under a different name). - No such transport is publicly available today: Graph chat APIs and microsoft/teams.py both ultimately route through Bot Service for the bot-as-conversation-participant pattern. - The slot is kept on the roadmap to preserve the naming line in case Microsoft ships a Bot-Service-free transport (native Teams REST/RPC, a Graph subscription strong enough to drive both inbound and outbound message flow, ...). - Reaffirm TeamsChannel (req microsoft#28) as the canonical Teams channel until then. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ence table Make explicit that TeamsChannel (req microsoft#28) uses Azure Bot Service in v1 — the microsoft/teams.py SDK is a higher-level Pythonic wrapper over the same Activity Protocol pipeline that ActivityChannel exposes raw. The difference is what the developer writes against, not the network path. A Bot-Service-free Teams transport is not currently possible and stays tracked as the speculative req microsoft#30. Add the ActivityChannel vs TeamsChannel audience comparison table to req microsoft#28 so the choice is obvious to readers: - ActivityChannel: maximum portability across all Bot Service-fronted channels. - TeamsChannel: Teams-first deployments wanting Cards / Dialogs / Message Extensions / citations / feedback / suggested prompts / SSO out of the box. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
a4a8749
into
microsoft:feature/python-hosting
Motivation and Context
Description
Contribution Checklist