f2d02e58b3
* Add Python hosting core and Responses channel Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address hosting core review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Adopt source pyright typing setup for hosting packages Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Cover ResponsesChannel custom path routing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Align hosting tests with package layout Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting workflow fixture imports in aggregate tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Apply useful Responses channel hardening Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting package typing checks Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix hosting pyright under Python 3.11 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Avoid static diskcache dependency in hosting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Fix aggregate typing and Docker test resilience Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Simplify local Responses workflow sample Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify generic hosting is not Foundry hosting Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Revert "Clarify generic hosting is not Foundry hosting" This reverts commit 73b584d919053bed43a258d75dc2b76406e9c181. * Clarify isolation key source flexibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Clarify isolation header reuse boundary Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Support multimodal Responses channel outputs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Preserve multimodal streaming Responses output Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Stream Responses output items from updates Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Improve Responses streaming output handling * Tighten Responses channel default option handling - Restore full option parsing in parse_responses_request: known fields are remapped (max_output_tokens→max_tokens, parallel_tool_calls→ allow_multiple_tool_calls), transport/session keys excluded, None values dropped, everything else forwarded as-is so run_hook can inspect the full set. - Add a default _strip_options_hook on ResponsesChannel that removes all parsed options before reaching the agent. Callers cannot inject generation params (temperature, instructions, tools, …) unless the host explicitly allows it. - A custom run_hook replaces the default entirely and receives the full ChannelRequest.options plus the raw protocol_request. - Update tests to cover remap, default-strip, and custom-hook paths. - Clarify host debug-log docstring to match new option flow. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
123 lines
4.5 KiB
Markdown
123 lines
4.5 KiB
Markdown
# agent-framework-hosting
|
|
|
|
Multi-channel hosting for Microsoft Agent Framework agents.
|
|
|
|
`agent-framework-hosting` lets you serve a single agent or workflow target
|
|
through one or more **channels**. The host owns one Starlette ASGI app,
|
|
route/lifecycle composition, and per-`isolation_key` session resolution.
|
|
Each channel owns its protocol parsing and response rendering.
|
|
|
|
The base package contains only channel-neutral plumbing:
|
|
|
|
- `AgentFrameworkHost` — the Starlette host.
|
|
- `Channel` — the channel protocol.
|
|
- `ChannelRequest` / `ChannelSession` / `ChannelIdentity` — the request
|
|
envelope and optional channel metadata.
|
|
- `ChannelContext` / `ChannelContribution` / `ChannelCommand` — channel-side
|
|
hooks for invoking the target and contributing routes, commands, and
|
|
lifecycle callbacks.
|
|
- `ChannelRunHook` / `ChannelResponseHook` / `ChannelStreamUpdateHook` —
|
|
host-invoked customization seams.
|
|
|
|
`ChannelStreamUpdateHook` applies to streamed updates only. It is not a
|
|
substitute for final-response redaction.
|
|
|
|
Concrete channels live in their own packages so you only install what you use:
|
|
|
|
| Package | Transport |
|
|
|---|---|
|
|
| `agent-framework-hosting-responses` | OpenAI Responses API |
|
|
|
|
Additional channel packages can build on the same host contract without adding
|
|
their protocol dependencies to the base package.
|
|
|
|
## Install
|
|
|
|
```bash
|
|
pip install agent-framework-hosting agent-framework-hosting-responses
|
|
# or with Hypercorn pre-installed for the demo `host.serve(...)` helper
|
|
pip install "agent-framework-hosting[serve]" agent-framework-hosting-responses
|
|
# add the [disk] extra to persist reset-session aliases
|
|
pip install "agent-framework-hosting[disk]"
|
|
```
|
|
|
|
## Quickstart
|
|
|
|
```python
|
|
from agent_framework.openai import OpenAIChatClient
|
|
from agent_framework_hosting import AgentFrameworkHost, Channel
|
|
|
|
agent = OpenAIChatClient().as_agent(name="Assistant")
|
|
|
|
# Add channels from sibling packages, e.g. `agent-framework-hosting-responses`
|
|
# exposes a `ResponsesChannel` that serves the OpenAI Responses API.
|
|
channels: list[Channel] = []
|
|
|
|
host = AgentFrameworkHost(target=agent, channels=channels)
|
|
host.serve(port=8000)
|
|
```
|
|
|
|
## Session state and workflow checkpoints
|
|
|
|
By default the host keeps live `AgentSession` objects and reset-session aliases
|
|
in memory. Channels opt into continuity by setting
|
|
`ChannelRequest.session = ChannelSession(isolation_key=...)`; requests with the
|
|
same isolation key reuse the same host-created session.
|
|
|
|
The host treats `isolation_key` as an opaque partition key. Each channel or
|
|
hosting environment decides where that key comes from:
|
|
|
|
- protocol headers supplied by a trusted platform,
|
|
- request body fields such as a previous response or conversation ID,
|
|
- route/path parameters,
|
|
- channel-native metadata such as chat/user IDs, or
|
|
- environment-provided context in an ephemeral host.
|
|
|
|
The host should be able to carry any of those sources as long as the channel or
|
|
platform has already authenticated and authorized the caller before passing the
|
|
key to `ChannelSession`.
|
|
|
|
The built-in request-context helper recognizes the `x-agent-user-isolation-key`
|
|
and `x-agent-chat-isolation-key` header names because some hosting
|
|
environments, including Foundry Hosted Agents, already use them. Reusing those
|
|
header names does **not** mean `agent-framework-hosting` is the supported way to
|
|
run on Foundry Hosted Agents; use `agent-framework-foundry-hosting` for that
|
|
hosting surface.
|
|
|
|
For long-running deployments that need `reset_session(...)` aliases to survive
|
|
restart, pass `state_dir`:
|
|
|
|
```python
|
|
host = AgentFrameworkHost(
|
|
target=agent,
|
|
channels=channels,
|
|
state_dir="./.host-state",
|
|
)
|
|
```
|
|
|
|
This creates `./.host-state/sessions/` and stores only lightweight alias
|
|
bookkeeping. Live `AgentSession` objects are still rehydrated lazily by the
|
|
configured history provider on the next turn.
|
|
|
|
For workflow targets, `checkpoint_location=...` is the clearest way to enable
|
|
checkpoint persistence. As a convenience, `state_dir="./.host-state"` also
|
|
derives `./.host-state/checkpoints/` for workflow targets. Use the mapping form
|
|
when you want only one component:
|
|
|
|
```python
|
|
from agent_framework_hosting import HostStatePaths
|
|
|
|
host = AgentFrameworkHost(
|
|
target=workflow,
|
|
channels=channels,
|
|
state_dir=HostStatePaths(
|
|
sessions="/var/lib/myapp/sessions",
|
|
checkpoints="/var/lib/myapp/checkpoints",
|
|
),
|
|
)
|
|
```
|
|
|
|
Cross-channel identity linking, multicast delivery, background runs,
|
|
continuation tokens, and durable delivery runners are follow-up enhancements,
|
|
not part of this v1 host contract.
|