mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
5e8fe0be1f
* Fix reasoning text done events duplicating streamed delta content (#5157) The OpenAI Responses API sends both reasoning_text.delta (incremental chunks) and reasoning_text.done (full accumulated text) events. The chat client was emitting Content for both, causing ag-ui to append the full done text onto already-accumulated delta text, producing duplicated reasoning output. Stop emitting Content for reasoning_text.done and reasoning_summary_text.done events, matching how output_text.done is already handled (not emitted). The deltas contain all the content; the done event is redundant. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(openai): emit reasoning done content as fallback when no deltas observed (#5157) Address PR review feedback: - Track item_ids that received reasoning deltas via seen_reasoning_delta_item_ids set - Emit content from done events only when no deltas were received for the item_id, preventing silent content loss on stream resumption - Add comment documenting code_interpreter done event asymmetry - Replace redundant ag-ui test with deduplication-focused test - Add integration test for delta+done sequence in OpenAI chat client tests - Add fallback path tests for done events without preceding deltas Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5157: Python: [Bug]: "type": "response.reasoning_text.delta" and "response.reasoning_text.done" both get exposed as "text_reasoning" * Fix AG-UI reasoning streaming to use proper Start/End pattern (#5157) _emit_text_reasoning now follows the same streaming pattern as _emit_text: - Emits ReasoningStartEvent/ReasoningMessageStartEvent only on the first delta for a given message_id - Emits only ReasoningMessageContentEvent for subsequent deltas - Defers ReasoningMessageEndEvent/ReasoningEndEvent until _close_reasoning_block is called (on content type switch or end-of-run) This produces the correct protocol pattern: ReasoningStartEvent ReasoningMessageStartEvent ReasoningMessageContentEvent(delta1) ReasoningMessageContentEvent(delta2) ReasoningMessageEndEvent ReasoningEndEvent Instead of wrapping every delta in a full Start→End sequence. Backward compatibility is preserved: calling _emit_text_reasoning without a flow argument still produces the full sequence per call. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix import ordering lint error in AG-UI test file (#5157) Move inline import of TextMessageContentEvent to the top-level import block and ensure alphabetical ordering to satisfy ruff I001 rule. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix mypy error: rename loop variable to avoid type conflict with WorkflowEvent The 'event' variable was already typed as WorkflowEvent[Any] from the async for loop at line 590. Reusing it in the _close_reasoning_block loop (which returns list[BaseEvent]) caused an incompatible assignment error. Renamed to 'reasoning_evt' to avoid the conflict. Fixes #5162 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address review feedback for #5157: review comment fixes * narrow test result reporting to explicit pytest JUnit XML * Fix test args * Fix pytest-results-action in merge workflow and remove committed test artifacts Apply the same JUnit XML fix from python-tests.yml to python-merge-tests.yml: add --junitxml=pytest.xml to all test commands and narrow the results action path from ./python/**.xml to ./python/pytest.xml. Also remove accidentally committed pytest.xml and python-coverage.xml and add them to .gitignore. --------- Co-authored-by: Copilot <copilot@github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
5e8fe0be1f
·
2026-04-09 22:44:59 +00:00
History
Conversation & Session Management Samples
These samples demonstrate different approaches to managing conversation history and session state in Agent Framework.
Samples
| File | Description |
|---|---|
suspend_resume_session.py |
Suspend and resume conversation sessions, comparing service-managed sessions (Azure AI Foundry) with in-memory sessions (OpenAI). |
custom_history_provider.py |
Implement a custom history provider by extending HistoryProvider, enabling conversation persistence in your preferred storage backend. |
cosmos_history_provider.py |
Use Azure Cosmos DB as a history provider for durable conversation storage with CosmosHistoryProvider. |
cosmos_history_provider_conversation_persistence.py |
Persist and resume conversations across application restarts using CosmosHistoryProvider — serialize session state, restore it, and continue with full Cosmos DB history. |
cosmos_history_provider_messages.py |
Direct message history operations — retrieve stored messages as a transcript, clear session history, and verify data deletion. |
cosmos_history_provider_sessions.py |
Multi-session and multi-tenant management — per-tenant session isolation, list_sessions() to enumerate, switch between sessions, and resume specific conversations. |
redis_history_provider.py |
Use Redis as a history provider for persistent conversation history storage across sessions. |
Prerequisites
For suspend_resume_session.py:
FOUNDRY_PROJECT_ENDPOINT: Your Azure AI Foundry project endpoint (service-managed session)FOUNDRY_MODEL: The Foundry model deployment nameOPENAI_API_KEY: Your OpenAI API key (in-memory session)- Azure CLI authentication (
az login)
For custom_history_provider.py:
OPENAI_API_KEY: Your OpenAI API key
For Cosmos DB samples (cosmos_history_provider*.py):
FOUNDRY_PROJECT_ENDPOINT: Your Azure AI Foundry project endpointFOUNDRY_MODEL: The Foundry model deployment nameAZURE_COSMOS_ENDPOINT: Your Azure Cosmos DB account endpointAZURE_COSMOS_DATABASE_NAME: The database that stores conversation historyAZURE_COSMOS_CONTAINER_NAME: The container that stores conversation history- Either
AZURE_COSMOS_KEYor Azure CLI authentication (az login)
For redis_history_provider.py:
OPENAI_API_KEY: Your OpenAI API key- A running Redis server — default URL is
redis://localhost:6379- Override via the
REDIS_URLenvironment variable for remote or authenticated instances - Quickstart with Docker:
docker run -d --name redis-stack -p 6379:6379 redis/redis-stack-server:latest
- Override via the