mirror of
https://github.com/microsoft/agent-framework.git
synced 2026-06-16 21:04:09 +08:00
57c901a245
* update hyperlight to beta and move samples, add hosted agent sample * Python: Fix hyperlight WasmSandbox cross-thread Drop and harden sample Root cause: when a worker-side closure raised, the exception's __traceback__ retained frame locals that included the partially constructed PyO3 sandbox. Future.result() re-raised that exception on the caller thread, and when the caller's exception was eventually GC'd the frame locals were released off-thread, dec_ref'ing the unsendable sandbox from the wrong thread and tripping the PyO3 panic '_native_wasm::WasmSandbox is unsendable, but is being dropped on another thread'. Fix: * Add _SandboxWorker._run_on_worker which catches every exception on the worker, drops __traceback__ there, deletes the original exception, and re-raises a fresh instance on the caller thread. initialize and execute route through it; dispose keeps its bare-submit semantics. * Add an opt-in diagnostic module _drop_diagnostic (no-op unless HYPERLIGHT_TRACE_DROPS=1) that installs a sys.unraisablehook and dumps owner-thread + per-thread stacks on any future cross-thread unsendable Drop. Useful for triaging similar PyO3 regressions. * Tests: cross-thread invocation, traceback-leak isolation, _SandboxEntry attribute-shape check, and a stale-reference stress test driven through asyncio.to_thread. Sample (samples/04-hosting/foundry-hosted-agents/responses/06_hyperlight_codeact): * Dockerfile installs agent-framework-* from in-tree source with python/ as build context so unreleased fixes can be validated end-to-end. * call_server.py pins the Responses API version. * main.py enables include_detailed_errors=True so future tool failures surface the actual exception text instead of a bare 'Error: Function failed.' string. * README.md documents the in-tree-package build and the Hyperlight hypervisor requirement (/dev/kvm on Linux, MSHV on Windows). Hosted environments without hypervisor passthrough surface 'No Hypervisor was found for Sandbox'; this is a hosting constraint, not a hyperlight bug. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: remove _drop_diagnostic from hyperlight package The diagnostic module was useful while bisecting the cross-thread Drop bug, but it is no longer needed now that _SandboxWorker._run_on_worker prevents the panic at the source. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: address PR review feedback on hyperlight - Use lazy agent_framework.hyperlight import in sample main.py. - Env-driven endpoint (FOUNDRY_AGENT_ENDPOINT) in call_server.py; remove personal URLs. - Align agent.yaml model deployment with manifest (gpt-4.1-mini). - Tighten Dockerfile requirements guard; drop dangling deploy.ps1 reference. - Preserve exception args when sanitizing tracebacks in _run_on_worker. - Add public _SandboxWorker.is_alive(); update test to avoid private attr. - Add namespace coverage tests for agent_framework.hyperlight lazy loader. - Add prominent note: Foundry hosted-agent runtime does not yet support Hyperlight (no hypervisor exposed); container works locally with /dev/kvm. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: bump hyperlight-sandbox dependencies to 0.4.x Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Python: renumber hyperlight codeact sample to 08 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Coerce worker exception args to strings for cross-thread safety Stringify exc.args on the worker thread before propagating, so any PyO3 unsendable object captured in args (e.g. via a caller-supplied callback or underlying SDK) cannot be Dropped on the calling thread. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * moved sample --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
140 lines
4.5 KiB
Markdown
140 lines
4.5 KiB
Markdown
# agent-framework-hyperlight
|
|
|
|
Hyperlight-backed CodeAct integrations for Microsoft Agent Framework.
|
|
|
|
## Installation
|
|
|
|
```bash
|
|
pip install agent-framework-hyperlight --pre
|
|
```
|
|
|
|
This package depends on `hyperlight-sandbox`, the packaged Python guest, and the
|
|
Wasm backend package on supported platforms. If the backend is not published for
|
|
your current platform yet, `execute_code` will fail at runtime when it tries to
|
|
create the sandbox.
|
|
|
|
## Quick start
|
|
|
|
### Context provider (recommended)
|
|
|
|
Use `HyperlightCodeActProvider` to automatically inject the `execute_code` tool
|
|
and CodeAct instructions into every agent run. Tools registered on the provider
|
|
are available inside the sandbox via `call_tool(...)` but are **not** exposed as
|
|
direct agent tools.
|
|
|
|
```python
|
|
from agent_framework import Agent, tool
|
|
from agent_framework_hyperlight import HyperlightCodeActProvider
|
|
|
|
@tool
|
|
def compute(operation: str, a: float, b: float) -> float:
|
|
"""Perform a math operation."""
|
|
ops = {"add": a + b, "subtract": a - b, "multiply": a * b, "divide": a / b}
|
|
return ops[operation]
|
|
|
|
codeact = HyperlightCodeActProvider(
|
|
tools=[compute],
|
|
approval_mode="never_require",
|
|
)
|
|
|
|
agent = Agent(
|
|
client=client,
|
|
name="CodeActAgent",
|
|
instructions="You are a helpful assistant.",
|
|
context_providers=[codeact],
|
|
)
|
|
|
|
result = await agent.run("Multiply 6 by 7 using execute_code.")
|
|
```
|
|
|
|
### Standalone tool
|
|
|
|
Use `HyperlightExecuteCodeTool` directly when you want full control over how the
|
|
tool is added to the agent. This is useful when mixing sandbox tools with
|
|
direct-only tools on the same agent.
|
|
|
|
```python
|
|
from agent_framework import Agent, tool
|
|
from agent_framework_hyperlight import HyperlightExecuteCodeTool
|
|
|
|
@tool
|
|
def send_email(to: str, subject: str, body: str) -> str:
|
|
"""Send an email (direct-only, not available inside the sandbox)."""
|
|
return f"Email sent to {to}"
|
|
|
|
execute_code = HyperlightExecuteCodeTool(
|
|
tools=[compute],
|
|
approval_mode="never_require",
|
|
)
|
|
|
|
agent = Agent(
|
|
client=client,
|
|
name="MixedToolsAgent",
|
|
instructions="You are a helpful assistant.",
|
|
tools=[send_email, execute_code],
|
|
)
|
|
```
|
|
|
|
### Manual static wiring
|
|
|
|
For fixed configurations where provider lifecycle overhead is unnecessary, build
|
|
the CodeAct instructions once and pass them to the agent at construction time:
|
|
|
|
```python
|
|
execute_code = HyperlightExecuteCodeTool(
|
|
tools=[compute],
|
|
approval_mode="never_require",
|
|
)
|
|
|
|
codeact_instructions = execute_code.build_instructions(tools_visible_to_model=False)
|
|
|
|
agent = Agent(
|
|
client=client,
|
|
name="StaticWiringAgent",
|
|
instructions=f"You are a helpful assistant.\n\n{codeact_instructions}",
|
|
tools=[execute_code],
|
|
)
|
|
```
|
|
|
|
### File mounts and network access
|
|
|
|
Mount host directories into the sandbox and allow outbound HTTP to specific
|
|
domains:
|
|
|
|
```python
|
|
from agent_framework_hyperlight import HyperlightCodeActProvider, FileMount
|
|
|
|
codeact = HyperlightCodeActProvider(
|
|
tools=[compute],
|
|
file_mounts=[
|
|
"/host/data", # shorthand — same path in sandbox
|
|
("/host/models", "/sandbox/models"), # explicit host → sandbox mapping
|
|
FileMount("/host/config", "/sandbox/config"), # named tuple
|
|
],
|
|
allowed_domains=[
|
|
"api.github.com", # all methods
|
|
("internal.api.example.com", "GET"), # GET only
|
|
],
|
|
)
|
|
```
|
|
|
|
## Notes
|
|
|
|
- This package is intentionally separate from `agent-framework-core` so CodeAct
|
|
usage and installation remain optional. With `agent-framework-core[all]` (or
|
|
the meta `agent-framework`) installed it is also reachable through the
|
|
lazy-loading namespace `agent_framework.hyperlight`.
|
|
- `file_mounts` accepts a single string shorthand, an explicit `(host_path,
|
|
mount_path)` pair, or a `FileMount` named tuple. The host-side path in the
|
|
explicit forms may be a `str` or `Path`. Use the explicit two-value form when
|
|
the host path differs from the sandbox path.
|
|
- `allowed_domains` accepts a single string target such as `"github.com"` to
|
|
allow all backend-supported methods, an explicit `(target, method_or_methods)`
|
|
tuple such as `("github.com", "GET")`, or an `AllowedDomain` named tuple.
|
|
- Tools registered with the sandbox return their native Python value
|
|
(`dict`, `list`, primitives, or custom objects) directly to the guest via the
|
|
Hyperlight FFI. Any `result_parser` configured on a `FunctionTool` is
|
|
intended for LLM-facing consumers and does not run on the sandbox path —
|
|
apply formatting inside the tool function itself if you need it for
|
|
in-sandbox consumers.
|