Files
westey a2018b40f9 Python: [BREAKING] Require approval for file-access tools with read-only auto-approval (#6599)
* Require approvals for file-access and expose auto approval funcs for it

* Scope file-access auto-approval rules to local tools; fix base-Agent sample

Address PR #6599 review feedback:
- read_only/all_tools auto-approval rules now reject any call carrying a
  server_label so they stay scoped to FileAccessProvider's local tools and
  never auto-approve a same-named hosted tool.
- Expand the FileAccessProvider docstring to explain the runtime effect of
  approval_mode="always_require" and point to ToolApprovalMiddleware /
  create_harness_agent.
- Fix the base-Agent file_access_data_processing sample, which would otherwise
  stop executing file tools under the new always_require defaults, by adding
  ToolApprovalMiddleware with all_tools_auto_approval_rule.
- Add tests covering hosted (server_label) calls and update docs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* Clean up comments

* Update sample after merge

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-06-23 09:51:12 +00:00

140 lines
5.1 KiB
Markdown

# Harness Agent Samples
This folder demonstrates `create_harness_agent` — a factory function that builds a
pre-configured, batteries-included agent by assembling the full agent pipeline
from a chat client.
## What is `create_harness_agent`?
`create_harness_agent` bundles the following features into a single `Agent` instance:
| Feature | Description |
|---------|-------------|
| Function invocation | Automatic tool calling loop |
| Per-service-call persistence | History persisted after every model call |
| Compaction | Context-window management (sliding window + tool result compaction) |
| TodoProvider | Todo list management for planning and tracking |
| AgentModeProvider | Plan/execute mode tracking |
| MemoryContextProvider | File-based durable memory (when `memory_store` provided) |
| SkillsProvider | File-based skill discovery and progressive loading |
| Shell tool | Shell command execution + environment probing (when `shell_executor` provided) |
| Tool approval | "Don't ask again" standing rules + heuristic auto-approval (enabled by default) |
| Looping | Re-invoke the agent until a `loop_should_continue` predicate is satisfied (when provided) |
| OpenTelemetry | Built-in observability |
Each feature can be disabled or customized via keyword arguments.
## Samples
| File | Description |
|------|-------------|
| `harness_research.py` | Interactive research assistant with web search, a plan/execute workflow, and an execute-mode loop that re-invokes the agent until every todo is complete |
| `harness_data_processing.py` | Data-processing assistant over a folder of CSV files, demonstrating file-access tools and tool approval |
## Running
```bash
# Set your Foundry environment variables
export FOUNDRY_PROJECT_ENDPOINT="https://your-project.services.ai.azure.com/api/projects/your-project-name"
export FOUNDRY_MODEL="your-model-deployment-name"
# Authenticate with Azure (required for AzureCliCredential)
az login
# Run a sample against the released agent-framework (PEP 723 isolated env)
uv run samples/02-agents/harness/harness_research.py
```
### Running against the local repo
To run a sample against your **local** `agent-framework` checkout (so it picks
up uncommitted changes), use the workspace environment instead of the isolated
PEP 723 env. From the `python/` directory, run the script with `uv run python`
and add the `textual` UI dependency the harness console needs:
```bash
uv run --with textual python samples/02-agents/harness/harness_research.py
uv run --with textual python samples/02-agents/harness/harness_data_processing.py
```
The workspace environment already provides the editable `agent-framework`
packages plus the samples' other dependencies (`rich`, `python-dotenv`,
`azure-identity`); only `textual` needs to be supplied with `--with`.
> Note: invoking `uv run python <script>` (with `python`) bypasses the PEP 723
> metadata and uses the workspace env; `uv run <script>` (without `python`)
> uses the isolated env with the released package.
## Key Concepts
### Minimal Setup
`create_harness_agent` requires only a chat client:
```python
from agent_framework import create_harness_agent
from agent_framework.foundry import FoundryChatClient
from azure.identity import AzureCliCredential
agent = create_harness_agent(
client=FoundryChatClient(credential=AzureCliCredential()),
)
```
### With Compaction
Provide token budget parameters to enable automatic context-window compaction:
```python
agent = create_harness_agent(
client=FoundryChatClient(credential=AzureCliCredential()),
max_context_window_tokens=128_000,
max_output_tokens=16_384,
)
```
### Further Customization
Disable or customize any feature:
```python
agent = create_harness_agent(
client=client,
max_context_window_tokens=128_000,
max_output_tokens=16_384,
name="my-agent",
agent_instructions="Custom instructions here.",
disable_todo=True, # Skip todo management
disable_mode=True, # Skip plan/execute modes
disable_compaction=True, # Skip compaction
)
```
### Plan/Execute Workflow
The `AgentModeProvider` enables a two-phase workflow:
1. **Plan mode** — Interactive: the agent asks questions, creates todos, gets approval
2. **Execute mode** — Autonomous: the agent works through todos independently
### Shell Tool
Pass a shell executor (e.g. `LocalShellTool` from `agent-framework-tools`) to enable shell
command execution plus automatic environment probing via a `ShellEnvironmentProvider`. The
tool is only wired when the chat client supports shell tools; otherwise a warning is logged
and the shell tool/provider are skipped. The caller owns the executor's lifecycle.
```python
from agent_framework_tools.shell import LocalShellTool, ShellEnvironmentProviderOptions
async with LocalShellTool(acknowledge_unsafe=True) as shell:
agent = create_harness_agent(
client=client,
max_context_window_tokens=128_000,
max_output_tokens=16_384,
shell_executor=shell,
# Optional: customize environment probing.
shell_environment_provider_options=ShellEnvironmentProviderOptions(probe_tools=("git", "python")),
)
```