* Python: fix CopilotStudioAgent LineTooLong on large activities
Bump microsoft-agents-copilotstudio-client to >=1.2.0,<2 and forward a configurable read_bufsize (default 1 MiB) to the underlying aiohttp ClientSession via ConnectionSettings.client_session_settings. Copilot Studio streams each activity as a single SSE data line, so activities larger than aiohttp's 512 KB per-line limit previously raised aiohttp.http_exceptions.LineTooLong. Adds a client_session_settings parameter to CopilotStudioAgent and unit tests covering the default, override, and partial-settings cases.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2766dc09-ab5f-4adc-8627-98361d7ccef0
* Python: apply read_bufsize default to supplied CopilotStudio settings
Address review feedback on the LineTooLong fix: when a user supplies their own ConnectionSettings but no client, inject the read_bufsize default so activities larger than aiohttp's 512 KB per-line limit still stream. Document configuring read_bufsize on the explicit pre-built-client path in the package and sample READMEs and the explicit-settings sample. Add unit tests covering the supplied-settings path.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2766dc09-ab5f-4adc-8627-98361d7ccef0
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2766dc09-ab5f-4adc-8627-98361d7ccef0
* Add skill to replace hardcoded foundry project endpoint and model
* Include more samples and fix migration samples part 1
* Fix migration samples
* Replace Foundry hosted agent validation skill
* Fix hosted agent file sample
* Fix agent result format
* Reorganize jobs
* Update discovery heuristic for apps
* Split agents into even more jobs
* Add toolbox endpoint
* Add more pre configured resources
* Fix using deployed agent sample
* Add sample status
* Add playbook
* Exclude hidden folder in sample discovery
* Install autogen dependencies
* Grant azure search RBAC role
* Increase timeout for magentic
* Build search resouce id deterministically
* Remove grant in the workflow
* Move azure cli login closer to when the sample actually runs
* Refactor playbook
* Fix using deployed agent sample
* Actually save the playbooks
* Fix action syntax error
* Fix magentic sample
* Address copilot comments
* Fix link inspection
* Address comments
* Correct README
* Fix playbook path
* Remove trailing space
* Python: Add hosted agent sample for the agent harness
* Disable file providers and fix call_server usage in hosted harness sample
Addresses PR review: disable the harness file-memory and file-access
providers so the headless sample doesn't expose file tools or write
outside storage/, and correct the app.py docstring to match
call_server.py (which takes no prompt argument).
* Python: update hosted harness sample for current APIs
---------
Co-authored-by: Evan Mattson <evan.mattson@microsoft.com>
* feat(python): add Mistral chat client
Implements native Mistral support (#7366) with streaming, tool calling,
and structured output. Talks to the REST API directly over httpx: the
mistralai SDK's pinned OpenTelemetry deps conflict with the workspace.
* refactor(python): simplify Mistral client per review
Drop the streamed tool-call accumulator and multi-choice parsing in
favor of the framework's built-in fragment merging, mark n unsupported,
omit unset strict from json_schema, and leave CI secret wiring to
maintainers.
* test(python): drop n forwarding assertion
n is typed as unsupported on MistralChatOptions; the option-mapping test
still passed n, failing pyrefly/ty/zuban/mypy in CI.
* refactor(python): drop n from MistralChatOptions
n is not part of the base ChatOptions, so removing the key rejects it
without an explicit None override.
* feat(python): mark Mistral feature usage
Both clients flip the shared FeatureIndex.MISTRAL bit before each
request, matching the feature-usage telemetry other providers emit.
* fix(python): key streamed tool calls by index
Mistral omits the tool call id on continuation fragments, and the
framework only coalesces empty-id fragments into the immediately
preceding call, so interleaved parallel calls merged into the wrong
call with corrupted arguments. Accumulate fragments per (choice,
index) and emit each call only once complete.
* fix(python): restore Mistral SDK client injection
Dropping the mistralai dependency turned the embedding client's
client= parameter into a breaking change for injected SDK clients.
Add http_client= for httpx.AsyncClient and keep client= working:
httpx goes to the REST path, a duck-typed mistralai.Mistral goes
through the legacy SDK path with a DeprecationWarning until the
next major release.
* chore(python): tidy Mistral sample header
* Python: Support archive-type MCP skills in MCPSkillsSource
Add `archive`-type skill support to `MCPSkillsSource` so an MCP server can
advertise packaged skills (ZIP / TAR / gzip-compressed TAR) that are
downloaded, safely unpacked to a local directory, and served like file-based
skills, while keeping the guarantee that MCP-delivered scripts are never
executed.
- Dispatch `skill://index.json` entries by `type`: `skill-md` (existing,
fetched on demand) and `archive` (new). Unknown types are skipped.
- `_ArchiveEntryLoader` downloads, extracts, and prunes archive skills and
delegates discovery to an internal `FileSkillsSource` created with no
script extensions and no runner, so bundled scripts surface as read-only
resources only.
- Hardened stdlib extraction: path-traversal (zip-slip) guard, non-regular
TAR member skipping, and file-count / uncompressed-size / download-size
limits.
- Configure via `archive_*` constructor kwargs (no options object, per Python
conventions); use `CachingSkillsSource` for refresh rather than a source
level refresh interval.
- Fix `FileSkillsSource` to treat `None` extensions as "use defaults" and an
empty tuple as "discover none" (an empty tuple previously fell back to
defaults).
Port of .NET PR #6631.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
* Propagate non-not-found archive download errors in MCPSkillsSource
Only swallow "resource not found" MCP errors when downloading an archive
resource; re-raise every other error (auth failure, INTERNAL_ERROR,
connection drop, timeout) so a transient transport failure is not silently
turned into a missing skill. This matches the existing failure model used by
`_try_read_index` and `MCPSkill.get_resource`, and avoids a failed
`CachingSkillsSource` refresh overwriting a previously cached list with a
partial result.
Add tests asserting archive-download INTERNAL_ERROR and ConnectionError
propagate out of `get_skills`.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
* Python: Expose archive skill options on FoundryToolbox and demo in sample
- FoundryToolbox.as_skills_provider() now forwards the MCPSkillsSource archive
options (archive_skills_directory, archive_resource_extensions,
archive_resource_search_depth, archive_max_file_count, archive_max_size_bytes,
archive_max_uncompressed_size_bytes). Only explicitly-set options are
forwarded so unset ones keep the MCPSkillsSource defaults. This lets a hosted
toolbox agent redirect archive extraction to a writable directory (the default
is under the cwd, which may be read-only in a container).
- Add unit tests covering default (no options forwarded) and override forwarding.
- Update the 12_foundry_toolbox_mcp_skills sample to demonstrate all three
progressive-disclosure stages with an archive skill: escalation-policy now
ships a references/refund-matrix.md resource and is uploaded as a ZIP archive;
main.py disables load_skill and read_skill_resource approval and points
archive extraction at a temp directory. README, toolbox.yaml, and ignore files
updated accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36
* Python: Fix ty type error in toolbox archive-option test
Cast provider._source to _FoundryToolboxSkillsSource before accessing the
private _archive_options, so the ty checker (which runs over tests) resolves
the concrete type instead of the SkillsSource base. Replaces the mypy-style
type: ignore that ty did not honor.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36
* Rework archive-type skill support in MCPSkillsSource to unpack archives
entirely in memory instead of extracting them to a local directory, and
apply reviewer feedback.
* Python: Raise on archive member path-traversal (zip-slip)
Treat a `..` path-traversal member in an archive skill as a hostile archive
and reject the whole skill, matching how the file-count and uncompressed-size
limits reject a malformed archive (previously the member was silently skipped
while the rest of the skill still loaded).
- `_normalize_archive_member_name` now raises `ValueError` on a `..` escape;
benign degenerate entries (empty, `.`, `/`) still return None (skipped) and
absolute paths are still neutralized to relative. The raise propagates to
`_ArchiveEntryLoader._build_skill`, which already skips the skill on error.
- Update tests: traversal cases now assert a raise, and add an end-to-end test
that a zip-slip archive drops the whole skill.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
* Python: Revert archive skill demo in toolbox MCP skills sample
Restore the 12_foundry_toolbox_mcp_skills sample to its pre-PR, skill-md-only
form (matching the .NET Agent_Step26_FoundryToolboxMcpSkills sample, which uses
skill-md and no ZIP archive):
- Revert main.py, toolbox.yaml, README.md, .azdignore, .dockerignore, and
escalation-policy/SKILL.md to the single-file SKILL.md version.
- Remove the archive demo files added by this PR (.gitignore and
escalation-policy/references/refund-matrix.md).
- Soften two README notes so they no longer claim archive skills are
unsupported/silently dropped (this PR adds archive support); instead frame
single-file SKILL.md as a focus choice and point to the archive_* options.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
* Python: Clarify archive framing in mcp_based_skill sample README
The mcp_based_skill sample is a generic MCP consumer that discovers whatever
the server advertises; it does not itself demonstrate archive skills. Reword
the archive note so it reads as an MCPSkillsSource capability rather than a
sample feature, and fix the stale "unpacked to a local directory" claim to
"unpacked in memory" (matching the in-memory extraction implementation).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 9e358a4e-538f-46be-8c58-128b6182352d
Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36
* Python: Add GitHub Copilot BYOK sample
Demonstrates routing GitHubCopilotAgent requests through a custom OpenAI-compatible
endpoint via ProviderConfig instead of the default GitHub Copilot backend.
* Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* Python: Address BYOK sample review feedback
- Make the provider type configurable via BYOK_PROVIDER_TYPE (default "openai") instead
of hardcoding "openai" — a partial autofix commit had already updated the docstring to
document this env var but left the code hardcoded, which this finishes.
- Stop calling the endpoint "OpenAI-compatible" everywhere; Anthropic isn't OpenAI-wire-
compatible, so reword to "your own endpoint" and list the actual supported providers
(mirrors the equivalent .NET sample fix).
---------
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
* feat(observability): add support for OpenAI cache write tokens in usage details
* feat(openai): add cache write tokens handling in usage details
* Fix test
* Python: Add TodoProvider and AgentModeProvider context provider samples
Add two Python samples under samples/02-agents/context_providers/ mirroring the
.NET samples from #7262:
- todo_provider.py: scripted walkthrough of TodoProvider that plans multi-step
work and prints the evolving todo list after each turn.
- agent_mode_provider.py: interactive loop using AgentModeProvider with a /mode
slash command, demonstrating built-in plan/execute and custom modes.
Also index both samples in the context_providers README.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8725831c-086b-475f-90e6-cdba41d59c33
* Python: Address review comments on AgentModeProvider sample
- Replace the AGENT_MODE_USE_CUSTOM env var with an in-file USE_CUSTOM_MODES
constant for choosing between built-in and custom modes.
- Use plain input() in the interactive loop instead of asyncio.to_thread.
- Update the README prerequisites to reference the in-file toggle.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8725831c-086b-475f-90e6-cdba41d59c33
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 8725831c-086b-475f-90e6-cdba41d59c33
Promote the GitHub Copilot package from release candidate (1.0.0rc4) to released (1.0.0): bump the version, switch the classifier to Production/Stable, update PACKAGE_STATUS.md, and drop the --pre install flag from the package and sample READMEs. Add a github-copilot-1.0.0 CHANGELOG section covering the promotion and the input-attachment forwarding shipped in this release. No core/root bump: this is a standalone package promotion and the core[all] extra references the package without a version pin.
Copilot-Session: f523064c-60b4-4d18-bf95-c16c5fda9126
* Python: Support prompt cache breakpoints for GPT-5.6 models in OpenAI clients
Add request-level prompt_cache_options to OpenAIChatOptions and
OpenAIChatCompletionOptions, and forward a per-part prompt_cache_breakpoint
from Content.additional_properties onto the content blocks each API supports.
Text parts that carry a breakpoint keep typed list content, since the
plain-string form cannot hold one; without a breakpoint the existing string
forms are unchanged.
* Clarify system-message content-shape comment
* Address review: SDK prompt cache types, private helper, add sample
Replace the custom PromptCacheOptions TypedDict with the openai SDK's own
types for each API, which raises the openai floor to 2.45.0 where those
types were introduced. Make the breakpoint helper private to the two chat
clients. Add a prompt caching sample with a README entry, and unquote the
helper's Content annotation so the pyupgrade hook passes.
* Guard the prompt cache options import for older openai versions
The SDK's PromptCacheOptions types only exist in openai 2.45.0 and
later, so each client falls back to a local mirror when the import
fails and the dependency floor stays at 2.25.0. A TYPE_CHECKING-only
import is not enough because the options classes are introspected with
get_type_hints() at runtime. Verified against openai 2.25.0: the
package imports, the fallback resolves, and part-level breakpoints
still work; sending the option itself requires 2.45.0, which the field
docstrings now note.
* Make the old-openai fallback for PromptCacheOptions deliberately empty
Assigning None instead, as suggested in review, trips pyright's
reportInvalidTypeForm on the field annotation (the symbol becomes
type | None after the try/except). An empty TypedDict gives the same
effect for users on older openai versions: any content they put in
prompt_cache_options is flagged by their type checker, since the
option cannot be sent on those versions anyway, while
get_type_hints() on the options classes keeps working at runtime.
* Guard prompt_cache_options at runtime instead of via an empty fallback type
The empty-TypedDict fallback flagged valid `prompt_cache_options` usage under
pyright on every openai version — including this PR's own
`client_prompt_caching.py` sample (`poe check -S`) — because pyright resolves the
try/except symbol to the fallback shape regardless of the installed openai, while
mypy/ty resolve the failed import to `Any` and never warn. So a type-only "warn on
old openai" signal is not achievable cleanly across type checkers.
Restore the faithful fallback (mirrors the SDK's `mode`/`ttl` shape) so the option
type-checks identically on every supported openai version, and add a runtime guard:
setting `prompt_cache_options` on openai < 2.45 now raises a clear
ChatClientInvalidRequestException instead of forwarding an unusable option to the
SDK. This keeps the option non-silent for all users regardless of type checker,
without forcing an openai upgrade. Adds tests covering the guard for both clients.
* Gate system/developer breakpoint shape on a real mapping value
The system/developer branch switched to list-form content whenever
prompt_cache_breakpoint was set to any non-None value, but the option is
only attached when the value is a mapping. A malformed value (e.g. a
string) therefore changed the message shape without adding a breakpoint.
Decide the shape from the built part instead, matching the user-role path.
* Bump Python package versions for 1.12.0 release
Bump packages represented in the 1.12.0 changelog, promote Foundry Hosting, Azure Content Understanding, Gemini, Mistral, Monty, and Tools to beta, and apply the requested beta cohort date stamp. Root and core move to 1.12.0, released and RC packages use their selected increments, alpha packages including Hosting MCP use the 260721 stamp, and core floors are raised only for proven consumers.
Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf
* fix version in readme
* Add Responses conversation ID changes to release notes
Include the breaking Hosting Responses conversation ID helper changes from #7234 in the Python 1.12.0 changelog.
Copilot-Session: 2dd9980a-b869-4c16-8642-75b7a6d6ebdf
* feat(durabletask): surface HITL respond-URL addressing to workflow executors
Let a workflow notify a human reviewer (e.g. email an approval link) from inside the
graph, without the caller threading the instanceId/requestId by hand.
- durabletask: the orchestrator injects host_context {instance_id, workflow_name,
request_path_prefix} into each activity input; CapturingRunnerContext surfaces it as
host_metadata. No new core API.
- azurefunctions: WorkflowHitlContext.from_context(ctx) builds the canonical
respond/status URLs (returns None in-process so callers degrade gracefully).
Re-exported through the agent_framework.azure lazy namespace.
- Nested sub-workflows: the address context (root instance + workflow name +
accumulated {executor}~{ordinal}~ prefix) propagates down call_sub_orchestrator via a
new SUBWORKFLOW_ADDRESS_KEY marker, so an executor at any depth builds a URL that
targets the addressable top-level instance with a qualified request id. The per-child
ordinal matches the read-side enumerate() index used by the status/respond endpoints.
The marker is stripped from untrusted input alongside SUBWORKFLOW_INPUT_KEY
(confused-deputy / info-leak guard).
- Samples 12 and 13 reworked into the retry-safe two-step notify pattern: the emitter
generates an explicit request id and a downstream NotifyExecutor builds the URL and
notifies, so failed upstream retries never produce a dead link.
Tests: unit coverage for the metadata round-trip, address/ordinal agreement (fan-out at
depth and nested prefix accumulation), marker stripping, and URL building; integration
tests assert the helper-built URL equals the server respondUrl and resumes the run, for
both the flat (12) and nested (13) samples.
* refactor(durabletask): read back request_info id instead of generating one in samples
Add WorkflowHitlContext.pending_request_id(ctx), an async helper that returns the
id request_info just generated (read from the runner context's pending request-info
events). This works on any host via the core RunnerContext protocol method, so it
needs no core change.
Samples 12 and 13 now call request_info() and read the id back to forward to the
NotifyExecutor, instead of minting a uuid by hand and passing request_id=. The
read-back happens in the same activity execution that generated the id, so the
pending request event and the notify message still commit together with the same id
(retry-safe; failed upstream retries notify no one).
* docs(azurefunctions): document request_info id read-back and notify safety
Tighten pending_request_id docstring to require calling it immediately after request_info, and explain why that is safe on the durable host (each executor runs in its own activity with its own runner context, so the pending set only holds this executor's requests and the newest is the one just emitted). Document the two-step notify pattern in the 12 and 13 sample READMEs, including the downstream-notifier retry safety and the nested address-prefix propagation.
* fix(python): resolve ty typing error and address PR review comments
- test_subworkflow_orchestration: replace the mypy-only type:ignore[arg-type] with a cast so the ty checker passes too (the other four checkers already honored the ignore).
- samples 12/13 README: guard the notify snippet against None before build_respond_url to match the documented graceful-degradation behavior.
- integration tests 12/13: reword comments that implied request_info now generates an explicit uuid4; it generates the id internally by default.
* fix(python): honor configurable Functions route prefix and address HITL PR review
- Resolve the route prefix from host.json (extensions.http.routePrefix, default api) in a new azurefunctions _routes module, used by both the server endpoints and WorkflowHitlContext, so a custom or empty routePrefix no longer 404s respond/status URLs (was hardcoded /api/ in four places).
- Extract respond/status URL construction into one shared builder called from _app.py and _hitl_context.py, removing the sync-by-test duplication.
- Broaden loopback detection (localhost, 127.0.0.0/8, 0.0.0.0, ::1, [::1]) via a _is_loopback helper so local links use http.
- Pin the host_context key names as shared constants in durabletask so producer and azurefunctions consumer cannot drift.
- Reword a stale base_url comment to reference WEBSITE_HOSTNAME.
- Add unit tests for the route module and loopback handling.
* refactor(azurefunctions): derive server-side HITL URLs from the request URL
The run and status endpoints now derive the base URL and route prefix from the incoming request URL (the value the host actually routed) via split_request_url, so the caller-visible respond/status URLs no longer depend on reading host.json on the server. The in-workflow helper keeps reading host.json since it has no request context. Replaces strip_route_prefix and updates its tests.
* test(durabletask): enforce sub-workflow ordinal and read-index agreement
Extract the read-side subworkflows grouping into a shared _index_subworkflows helper (used by the orchestrator) and add test_readside_index_matches_dispatch_ordinal, which round-trips a fan-out through that helper and asserts subworkflows[executor][ordinal] resolves to the child the dispatch stamped that ordinal onto. Turns the previously comment-only write-ordinal / read-index invariant into a shared, CI-enforced one.
* fix(azurefunctions): suppress bandit B104 on loopback host set
* Python: feat: cross-session origin attribution on context messages
Add an optional origin_session_id parameter to SessionContext.extend_messages
that propagates into the existing _attribution payload on
Message.additional_properties. Downstream context observers can use it to
detect when a provider injects content stored under a different session than
the requesting one.
Populate the field from the harness memory consolidation pipeline
(_harness/_memory.py) when injected topics include contributions from
sessions other than the current one. Add a self-contained sample observer
under samples/02-agents/context_providers/cross_session_observer.py
demonstrating how to subscribe to the signal.
Backward-compatible: omitting the parameter preserves the existing
attribution shape exactly. Tests added in test_sessions.py and
test_harness_memory.py cover the new parameter, the harness cross-session
case, and the same-session case.
Motivated by Dai et al., Stateful Agent Backdoor (arXiv:2605.06158, May
2026), which specifically surveys MAF in section 6.1 / Table 10.
See #5914 for design discussion.
Surfaced during independent audit conducted by @finnoybu (Ken Tannenbaum, AEGIS Initiative); [MEDIUM, python/packages/core].
* Address cross-session attribution review feedback
* Address follow-up review feedback
* Address follow-up review comments
* Address origin attribution review feedback
---------
Co-authored-by: finnoybu <21694570+finnoybu@users.noreply.github.com>
* Python: Make foundry toolbox MCP skills sample self-contained
Rework sample 12 (foundry_toolbox_mcp_skills) so users can build it from
zero with azd, mirroring samples 04 and 09:
- Bundle two single-file SKILL.md skills (support-style, escalation-policy)
and a skills-only toolbox.yaml (with one connectionless code_interpreter
tool, required by `azd ai toolbox create`).
- Rewrite the README as an azd-native, from-zero guide (create skills ->
create toolbox -> set TOOLBOX_ENDPOINT -> run) and fix the stale
MCPSkillsSource API description to match main.py.
- Switch config from TOOLBOX_NAME to the versioned TOOLBOX_ENDPOINT
(.env.example, agent.yaml, agent.manifest.yaml); add .azdignore.
Also enable the sample to run unattended behind ResponsesHostServer:
- Forward disable_load_skill_approval / disable_read_skill_resource_approval
/ disable_run_skill_script_approval from FoundryToolbox.as_skills_provider()
to the underlying SkillsProvider, so load_skill needs no approval round-trip
(the Responses host runs without an AgentSession, which the default approval
flow requires). main.py now uses as_skills_provider(disable_load_skill_approval=True).
- Add unit tests covering the default and overridden approval behaviour.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36
* Python: Address PR review on toolbox MCP skills sample
- Remove the unused parameters section from agent.manifest.yaml (TOOLBOX_ENDPOINT
is supplied via environment_variables, matching sample 04).
- README: state the sample is self-contained directly instead of contrasting
with the C# sample.
- README: describe skill discovery behaviour without naming the internal
MCPSkillsSource class.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 4f14f83d-1868-45c1-be1a-12f49a58ac36
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* docs: add env example files for durabletask samples
* docs: clarify env example values and comments
* docs: set default Redis URL in streaming sample env example
* Add Python hosting protocol helper surface
Introduce AgentFrameworkState and SessionStore for app-owned hosting routes, add Responses run conversion/rendering helpers, and update the local Responses sample to use native FastAPI routing with streaming support.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix CI failures, session continuity, and streaming model reporting
- Fix constrained TargetT TypeVar in AgentFrameworkState: split __init__
into per-shape overloads (instance/sync factory/async factory/awaitable)
since a bound TypeVar combined with one big Callable/Awaitable union
parameter was unsolvable across pyright/pyrefly/ty/zuban.
- Fix _FakeAgent test fixtures to structurally satisfy SupportsAgentRun
(matching attribute types and overloaded run()), which the above surfaced.
- Add SessionStore.put() to alias an additional session id to an
already-resolved session, and use it in the local_responses sample to fix
a real session-continuity bug: previous_response_id rotates every turn,
so without aliasing the newly minted response id, turn 3+ of a
conversation silently lost all prior history. Verified against a live
Foundry model across a 3-turn conversation.
- Fix responses_stream_events_from_run to report the real model instead of
the "agent" fallback: AgentResponse.from_updates never carries a raw
representation forward, so capture model from the individual streamed
updates' raw representations instead. Verified live.
- Add response_model=None to the sample's FastAPI route (it could not boot
at all: FastAPI tried to build a Pydantic response model from the
JSONResponse | StreamingResponse return annotation).
- Map responses_to_run's ValueError to HTTP 400 instead of a 500.
- Add HTTP round-trip integration tests (packages/hosting-responses) that
exercise the same FastAPI + AgentFrameworkState + Responses helper wiring
as the sample via httpx.ASGITransport, including a regression test for
the session-continuity fix.
- Add Workflow-target test coverage, SessionStore.put/reset_session tests,
and TypeError-path coverage to packages/hosting/tests/hosting/test_state.py.
- Extend call_server.py / call_server_af.py to a third conversation turn so
they actually exercise the continuity chain (previous scripts stopped at
turn 2, which would never have revealed the bug above).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Simplify session-continuity aliasing: fold put() into get()
Per feedback: the growth of SessionStore was not the problem -- it's
intentional, since OpenAI's previous_response_id is designed to let a
caller continue (fork) from any earlier response, not just the latest
one, so every response id has to stay independently resolvable. That
part stays as-is.
What was too complex was the call site: routes had to manually fetch a
session and then conditionally alias it with a separate put() call.
Folded that into a single get(session_id, alias=...) call instead:
- SessionStore.get() gains an optional `alias` keyword that registers an
additional id for the same session in the same call (no-op if alias is
None or equal to session_id). Removed the separate put() method.
- AgentFrameworkState.get_session() passes `alias` through.
- local_responses sample and the HTTP round-trip integration tests now
do `await state.get_session(lookup_id, alias=response_id)` instead of
pulling the store out and orchestrating get()/put() by hand.
- Documented that this in-memory SessionStore intentionally never evicts
(by design, to support forking), and that a storage-backed replacement
(Redis, a database, ...) is responsible for its own TTL/eviction
policy.
Verified against a live Foundry model across a 3-turn previous_response_id
chain after the simplification.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Refine hosting state helpers
Split the shared state surface into AgentState and WorkflowState, keep SessionStore and CheckpointStore as plain storage, and make state helpers responsible for get-or-create behavior. Update the Responses sample and HTTP round-trip tests to store the post-run session explicitly under the minted response id, and support WorkflowBuilder/orchestration-style builders via structural build() support.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix hosting state test protocol fakes
Widen fake agents' get_session service_session_id parameter to match the SupportsAgentRun protocol under the Python 3.11 test typing checkers.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Simplify Responses stream helper naming
Rename responses_stream_events_from_run to responses_stream_from_run across exports, tests, docs, and the local Responses sample to align with the generic <protocol>_stream_from_run helper convention.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add state-level storage setters
Add AgentState.set_session and WorkflowState.set_checkpoint_storage so app code can pair get-or-create helpers with explicit post-run storage without reaching into the underlying stores. Update Responses docs, tests, and sample to use state.set_session.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Simplify WorkflowState checkpoint handling
Remove CheckpointStore from WorkflowState so workflow checkpointing uses the existing CheckpointStorage abstraction directly. Keep WorkflowState focused on resolving workflow targets, including builders, and update hosting docs/tests accordingly.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Rename Responses streaming run helper
Rename responses_stream_from_run to responses_from_streaming_run across the hosting-responses exports, tests, docs, and local Responses sample.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Align Python hosting spec with protocol helpers
Rewrite SPEC-002 to match the accepted helper-first hosting ADR and the implementation PR: AgentState, WorkflowState, SessionStore, Responses helpers, app-owned security/state responsibilities, and the minimal FastAPI Responses shape.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Remove old Python hosting channel implementation
Remove the unreleased AgentFrameworkHost/channel implementation, the old hosting-telegram package, and old host/channel samples. Keep agent-framework-hosting focused on AgentState, WorkflowState, and SessionStore, and keep hosting-responses focused on helper-first Responses conversion. Update SPEC-002 to match the accepted helper-first ADR and the implementation surface.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Restore helper-first workflow sample
Rebuild the local Responses workflow sample on the protocol-helper surface, add production-readiness cautions to the local hosting samples, and align file-backed workflow checkpoint/cursor storage under one sample storage root.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Address hosting helper review feedback
Handle streaming failures as terminal Responses SSE events, guard concurrent target/session initialization, and scope workflow sample checkpoint storage per continuation.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify Responses sample continuation behavior
Document unknown conversation_id behavior in the agent sample and make the workflow sample explicitly reject conversation_id while continuing to use responses_session_id for previous_response_id.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Clarify Responses sample option policy
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>