chore: import upstream snapshot with attribution
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
CodeQL / Analyze (csharp) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
dotnet-build-and-test / dotnet-test-functions (push) Has been cancelled
dotnet-build-and-test / paths-filter (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Debug, windows-latest, net9.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, ubuntu-latest, net8.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-build (Release, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, ubuntu-latest, net10.0) (push) Has been cancelled
dotnet-build-and-test / dotnet-test (Release, integration, true, windows-latest, net472) (push) Has been cancelled
dotnet-build-and-test / dotnet-foundry-hosted-it (push) Has been cancelled
dotnet-build-and-test / dotnet-build-and-test-check (push) Has been cancelled
dotnet-build-and-test / Integration Test Report (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.metadata
|
||||
|
||||
from ._execute_code_tool import HyperlightExecuteCodeTool
|
||||
from ._provider import HyperlightCodeActProvider
|
||||
from ._types import AllowedDomain, AllowedDomainInput, FileMount, FileMountInput
|
||||
|
||||
try:
|
||||
__version__ = importlib.metadata.version(__name__)
|
||||
except importlib.metadata.PackageNotFoundError:
|
||||
__version__ = "0.0.0"
|
||||
|
||||
__all__ = [
|
||||
"AllowedDomain",
|
||||
"AllowedDomainInput",
|
||||
"FileMount",
|
||||
"FileMountInput",
|
||||
"HyperlightCodeActProvider",
|
||||
"HyperlightExecuteCodeTool",
|
||||
"__version__",
|
||||
]
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,139 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
|
||||
from agent_framework import FunctionTool
|
||||
|
||||
from ._types import AllowedDomain
|
||||
|
||||
|
||||
def _format_tool_summaries(tools: Sequence[FunctionTool]) -> str:
|
||||
if not tools:
|
||||
return "- No tools are currently registered inside the sandbox."
|
||||
|
||||
lines: list[str] = []
|
||||
for tool_obj in tools:
|
||||
parameters = tool_obj.parameters().get("properties", {})
|
||||
parameter_names = [name for name in parameters if isinstance(name, str)]
|
||||
parameter_summary = ", ".join(parameter_names) if parameter_names else "none"
|
||||
description = str(tool_obj.description or "").strip() or "No description provided."
|
||||
lines.append(f"- `{tool_obj.name}`: {description} Parameters: {parameter_summary}.")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _format_filesystem_capabilities(
|
||||
*,
|
||||
filesystem_enabled: bool,
|
||||
workspace_enabled: bool,
|
||||
mounted_paths: Sequence[str],
|
||||
) -> str:
|
||||
if not filesystem_enabled:
|
||||
return "Filesystem access is unavailable because no workspace root or file mounts are configured."
|
||||
|
||||
lines = ["Filesystem access is enabled."]
|
||||
lines.append("Read files from `/input`.")
|
||||
lines.append("Write generated artifacts to `/output`; returned files will be attached to the tool result.")
|
||||
|
||||
if workspace_enabled:
|
||||
lines.append("The configured workspace root is available under `/input/`.")
|
||||
|
||||
if mounted_paths:
|
||||
lines.append("Additional mounted paths:")
|
||||
lines.extend(f"- `{mounted_path}`" for mounted_path in mounted_paths)
|
||||
elif not workspace_enabled:
|
||||
lines.append("No workspace root or explicit file mounts are currently configured.")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def _format_network_capabilities(
|
||||
*,
|
||||
allowed_domains: Sequence[AllowedDomain],
|
||||
) -> str:
|
||||
if not allowed_domains:
|
||||
return "Outbound network access is unavailable because no allow-listed targets are configured."
|
||||
|
||||
lines = ["Outbound network access is allowed only for these configured targets:"]
|
||||
for allowed_domain in allowed_domains:
|
||||
methods_text = (
|
||||
", ".join(allowed_domain.methods) if allowed_domain.methods else "all methods allowed by the backend"
|
||||
)
|
||||
lines.append(f"- `{allowed_domain.target}`: {methods_text}.")
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def build_codeact_instructions(
|
||||
*,
|
||||
tools: Sequence[FunctionTool],
|
||||
tools_visible_to_model: bool,
|
||||
filesystem_enabled: bool = False,
|
||||
) -> str:
|
||||
"""Build dynamic CodeAct instructions for the effective sandbox state."""
|
||||
usage_note = (
|
||||
"Some tools may also appear directly, but prefer `execute_code` whenever you need to combine Python "
|
||||
"control flow with sandbox tool calls."
|
||||
if tools_visible_to_model
|
||||
else "Provider-owned sandbox tools are not exposed separately; use `execute_code` when you need them."
|
||||
)
|
||||
|
||||
output_note = (
|
||||
"To surface results from `execute_code`, end the code with `print(...)`; the sandbox does not "
|
||||
"return the value of the last expression."
|
||||
)
|
||||
if filesystem_enabled:
|
||||
output_note += (
|
||||
" For larger artifacts, write them to `/output/<filename>` instead — returned files will be "
|
||||
"attached to the tool result."
|
||||
)
|
||||
|
||||
return f"""You have one primary tool: execute_code.
|
||||
|
||||
Prefer one execute_code call per request when possible.
|
||||
Its tool description contains the current `call_tool(...)` guidance, sandbox
|
||||
tool registry, and capability limits.
|
||||
|
||||
{output_note}
|
||||
|
||||
{usage_note}
|
||||
"""
|
||||
|
||||
|
||||
def build_execute_code_description(
|
||||
*,
|
||||
tools: Sequence[FunctionTool],
|
||||
filesystem_enabled: bool,
|
||||
workspace_enabled: bool,
|
||||
mounted_paths: Sequence[str],
|
||||
allowed_domains: Sequence[AllowedDomain],
|
||||
) -> str:
|
||||
"""Build the dynamic execute_code tool description for standalone usage."""
|
||||
filesystem_text = _format_filesystem_capabilities(
|
||||
filesystem_enabled=filesystem_enabled,
|
||||
workspace_enabled=workspace_enabled,
|
||||
mounted_paths=mounted_paths,
|
||||
)
|
||||
network_text = _format_network_capabilities(
|
||||
allowed_domains=allowed_domains,
|
||||
)
|
||||
|
||||
return f"""Execute Python in an isolated Hyperlight sandbox.
|
||||
|
||||
Inside the sandbox, `call_tool(name, **kwargs)` is available as a built-in for
|
||||
registered host callbacks. Use the tool name as the first argument and keyword
|
||||
arguments only. Do not pass a dict or any other positional arguments after the
|
||||
tool name.
|
||||
|
||||
Registered sandbox tools:
|
||||
{_format_tool_summaries(tools)}
|
||||
|
||||
Filesystem capabilities:
|
||||
{filesystem_text}
|
||||
|
||||
Network capabilities:
|
||||
{network_text}
|
||||
|
||||
Prefer `execute_code` when you need to combine one or more `call_tool(...)`
|
||||
calls with Python control flow, loops, or post-processing.
|
||||
"""
|
||||
@@ -0,0 +1,111 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable, Sequence
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from agent_framework import AgentSession, ContextProvider, FunctionTool, SessionContext
|
||||
from agent_framework._tools import ApprovalMode
|
||||
|
||||
from ._execute_code_tool import HyperlightExecuteCodeTool, SandboxRuntime
|
||||
from ._types import AllowedDomain, AllowedDomainInput, FileMount, FileMountInput
|
||||
|
||||
|
||||
class HyperlightCodeActProvider(ContextProvider):
|
||||
"""Inject a Hyperlight-backed CodeAct surface using provider-owned tools."""
|
||||
|
||||
DEFAULT_SOURCE_ID = "hyperlight_codeact"
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
source_id: str = DEFAULT_SOURCE_ID,
|
||||
*,
|
||||
tools: FunctionTool | Callable[..., Any] | Sequence[FunctionTool | Callable[..., Any]] | None = None,
|
||||
approval_mode: ApprovalMode | None = None,
|
||||
workspace_root: str | Path | None = None,
|
||||
file_mounts: FileMountInput | Sequence[FileMountInput] | None = None,
|
||||
allowed_domains: AllowedDomainInput | Sequence[AllowedDomainInput] | None = None,
|
||||
backend: str = "wasm",
|
||||
module: str | None = "python_guest.path",
|
||||
module_path: str | None = None,
|
||||
_registry: SandboxRuntime | None = None,
|
||||
) -> None:
|
||||
super().__init__(source_id)
|
||||
self._execute_code_tool = HyperlightExecuteCodeTool(
|
||||
tools=tools,
|
||||
approval_mode=approval_mode,
|
||||
workspace_root=workspace_root,
|
||||
file_mounts=file_mounts,
|
||||
allowed_domains=allowed_domains,
|
||||
backend=backend,
|
||||
module=module,
|
||||
module_path=module_path,
|
||||
_registry=_registry,
|
||||
)
|
||||
|
||||
def add_tools(
|
||||
self,
|
||||
tools: FunctionTool | Callable[..., Any] | Sequence[FunctionTool | Callable[..., Any]],
|
||||
) -> None:
|
||||
"""Add provider-owned sandbox tools."""
|
||||
self._execute_code_tool.add_tools(tools)
|
||||
|
||||
def get_tools(self) -> list[FunctionTool]:
|
||||
"""Return the provider-owned sandbox tools."""
|
||||
return self._execute_code_tool.get_tools()
|
||||
|
||||
def remove_tool(self, name: str) -> None:
|
||||
"""Remove one provider-owned sandbox tool by name."""
|
||||
self._execute_code_tool.remove_tool(name)
|
||||
|
||||
def clear_tools(self) -> None:
|
||||
"""Remove all provider-owned sandbox tools."""
|
||||
self._execute_code_tool.clear_tools()
|
||||
|
||||
def add_file_mounts(self, file_mounts: FileMountInput | Sequence[FileMountInput]) -> None:
|
||||
"""Add provider-managed file mounts."""
|
||||
self._execute_code_tool.add_file_mounts(file_mounts)
|
||||
|
||||
def get_file_mounts(self) -> list[FileMount]:
|
||||
"""Return the provider-managed file mounts."""
|
||||
return self._execute_code_tool.get_file_mounts()
|
||||
|
||||
def remove_file_mount(self, mount_path: str) -> None:
|
||||
"""Remove one provider-managed file mount."""
|
||||
self._execute_code_tool.remove_file_mount(mount_path)
|
||||
|
||||
def clear_file_mounts(self) -> None:
|
||||
"""Remove all provider-managed file mounts."""
|
||||
self._execute_code_tool.clear_file_mounts()
|
||||
|
||||
def add_allowed_domains(self, domains: AllowedDomainInput | Sequence[AllowedDomainInput]) -> None:
|
||||
"""Add provider-managed outbound allow-list entries."""
|
||||
self._execute_code_tool.add_allowed_domains(domains)
|
||||
|
||||
def get_allowed_domains(self) -> list[AllowedDomain]:
|
||||
"""Return the provider-managed outbound allow-list entries."""
|
||||
return self._execute_code_tool.get_allowed_domains()
|
||||
|
||||
def remove_allowed_domain(self, domain: str) -> None:
|
||||
"""Remove one provider-managed outbound allow-list entry."""
|
||||
self._execute_code_tool.remove_allowed_domain(domain)
|
||||
|
||||
def clear_allowed_domains(self) -> None:
|
||||
"""Remove all provider-managed outbound allow-list entries."""
|
||||
self._execute_code_tool.clear_allowed_domains()
|
||||
|
||||
async def before_run(
|
||||
self,
|
||||
*,
|
||||
agent: Any,
|
||||
session: AgentSession | None,
|
||||
context: SessionContext,
|
||||
state: dict[str, Any],
|
||||
) -> None:
|
||||
"""Inject CodeAct instructions and a run-scoped execute_code tool before each run."""
|
||||
run_tool = self._execute_code_tool.create_run_tool()
|
||||
state[self.source_id] = run_tool.build_serializable_state()
|
||||
context.extend_instructions(self.source_id, run_tool.build_instructions(tools_visible_to_model=False))
|
||||
context.extend_tools(self.source_id, [run_tool])
|
||||
@@ -0,0 +1,28 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Sequence
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple, TypeAlias
|
||||
|
||||
|
||||
class FileMount(NamedTuple):
|
||||
"""Map a host file or directory into the sandbox input tree."""
|
||||
|
||||
host_path: str | Path
|
||||
mount_path: str
|
||||
|
||||
|
||||
FileMountHostPath: TypeAlias = str | Path
|
||||
FileMountInput: TypeAlias = str | tuple[FileMountHostPath, str] | FileMount
|
||||
|
||||
|
||||
class AllowedDomain(NamedTuple):
|
||||
"""Allow outbound requests to one target, optionally restricted to specific HTTP methods."""
|
||||
|
||||
target: str
|
||||
methods: tuple[str, ...] | None = None
|
||||
|
||||
|
||||
AllowedDomainInput: TypeAlias = str | tuple[str, str | Sequence[str]] | AllowedDomain
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
Reference in New Issue
Block a user