From 987b7312d5df066d87bd59de140bf7f555941e07 Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Mon, 13 Apr 2026 14:33:28 -0600 Subject: [PATCH] Rename package to pydantic-ai-harness (#207) - Package name: pydantic-harness -> pydantic-ai-harness - Python module: pydantic_harness -> pydantic_ai_harness - Display name: Pydantic Harness -> Pydantic AI Harness - All URLs updated to github.com/pydantic/pydantic-ai-harness Co-authored-by: Claude Opus 4.6 (1M context) --- .github/ISSUE_TEMPLATE/bug-report.yml | 2 +- .github/ISSUE_TEMPLATE/capability-request.yml | 2 +- AGENTS.md | 6 +- README.md | 96 +++++++-------- .../__init__.py | 2 +- .../code_mode/README.md | 8 +- pydantic_ai_harness/code_mode/__init__.py | 6 + .../code_mode/_capability.py | 4 +- .../code_mode/_toolset.py | 2 +- .../py.typed | 0 pydantic_harness/code_mode/__init__.py | 6 - pyproject.toml | 16 +-- tests/_code_mode/test_code_mode.py | 6 +- tests/_code_mode/test_dbos.py | 4 +- tests/_code_mode/test_temporal.py | 4 +- tests/test_placeholder.py | 6 +- uv.lock | 110 +++++++++--------- 17 files changed, 140 insertions(+), 140 deletions(-) rename {pydantic_harness => pydantic_ai_harness}/__init__.py (79%) rename {pydantic_harness => pydantic_ai_harness}/code_mode/README.md (96%) create mode 100644 pydantic_ai_harness/code_mode/__init__.py rename {pydantic_harness => pydantic_ai_harness}/code_mode/_capability.py (95%) rename {pydantic_harness => pydantic_ai_harness}/code_mode/_toolset.py (99%) rename {pydantic_harness => pydantic_ai_harness}/py.typed (100%) delete mode 100644 pydantic_harness/code_mode/__init__.py diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index e583c91..4c6f1a9 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -28,7 +28,7 @@ body: - type: input id: version attributes: - label: pydantic-harness version + label: pydantic-ai-harness version placeholder: e.g., 0.1.0 validations: required: true diff --git a/.github/ISSUE_TEMPLATE/capability-request.yml b/.github/ISSUE_TEMPLATE/capability-request.yml index c49a2e6..66b0a75 100644 --- a/.github/ISSUE_TEMPLATE/capability-request.yml +++ b/.github/ISSUE_TEMPLATE/capability-request.yml @@ -1,5 +1,5 @@ name: Capability Request -description: Propose a new capability for pydantic-harness +description: Propose a new capability for pydantic-ai-harness labels: ['capability', 'needs:triage'] body: - type: input diff --git a/AGENTS.md b/AGENTS.md index d3273d9..85686ca 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,4 @@ -# Pydantic Harness +# Pydantic AI Harness ## Local setup @@ -16,7 +16,7 @@ Fill in the absolute path where the `capabilities` branch of `pydantic-ai` is ch ## Vocabulary -- **Capability**: an `AbstractCapability` subclass that bundles tools, hooks, instructions, and model settings into a reusable unit. This is the core abstraction of pydantic-harness +- **Capability**: an `AbstractCapability` subclass that bundles tools, hooks, instructions, and model settings into a reusable unit. This is the core abstraction of pydantic-ai-harness - **Hook**: a lifecycle method on `AbstractCapability` that intercepts agent graph execution (e.g. `before_model_request`, `wrap_run`, `after_tool_execute`) - **Toolset**: a collection of tools that a capability can provide to the agent - **Guard**: a type of capability that validates inputs/outputs or controls tool access (e.g. `InputGuardrail`, `CostGuard`) @@ -71,7 +71,7 @@ Always run `make lint && make typecheck && make test` before committing. ## File structure ``` -pydantic_harness/ +pydantic_ai_harness/ __init__.py # public API re-exports / # each capability gets its own package __init__.py # public exports for the capability diff --git a/README.md b/README.md index 367d614..a959cd8 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# Pydantic Harness +# Pydantic AI Harness -[![CI](https://github.com/pydantic/pydantic-harness/actions/workflows/main.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-harness/actions/workflows/main.yml?query=branch%3Amain) -[![PyPI](https://img.shields.io/pypi/v/pydantic-harness.svg)](https://pypi.python.org/pypi/pydantic-harness) -[![versions](https://img.shields.io/pypi/pyversions/pydantic-harness.svg)](https://github.com/pydantic/pydantic-harness) -[![license](https://img.shields.io/github/license/pydantic/pydantic-harness.svg)](https://github.com/pydantic/pydantic-harness/blob/main/LICENSE) +[![CI](https://github.com/pydantic/pydantic-ai-harness/actions/workflows/main.yml/badge.svg?event=push)](https://github.com/pydantic/pydantic-ai-harness/actions/workflows/main.yml?query=branch%3Amain) +[![PyPI](https://img.shields.io/pypi/v/pydantic-ai-harness.svg)](https://pypi.python.org/pypi/pydantic-ai-harness) +[![versions](https://img.shields.io/pypi/pyversions/pydantic-ai-harness.svg)](https://github.com/pydantic/pydantic-ai-harness) +[![license](https://img.shields.io/github/license/pydantic/pydantic-ai-harness.svg)](https://github.com/pydantic/pydantic-ai-harness/blob/main/LICENSE) **The batteries for your [Pydantic AI](https://ai.pydantic.dev/) agent.** @@ -11,7 +11,7 @@ Pydantic AI's [capabilities](https://ai.pydantic.dev/capabilities/) and [hooks](https://ai.pydantic.dev/hooks/) API is how you give an agent its harness -- bundles of tools, lifecycle hooks, instructions, and model settings that extend what the agent can do without any framework changes. -**Pydantic Harness** is the official capability library for Pydantic AI, maintained by the [Pydantic AI](https://github.com/pydantic/pydantic-ai) team. Pydantic AI core ships capabilities that require model or framework support, and capabilities fundamental to every agent -- [web search](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools), [tool search](https://ai.pydantic.dev/deferred-tools/), [thinking](https://ai.pydantic.dev/capabilities/#thinking). Everything else lives here: standalone building blocks you pick and choose to turn your agent into a coding agent, a research assistant, or anything else. This is also where new capabilities start -- as they stabilize and prove themselves broadly essential, they can graduate into core. +**Pydantic AI Harness** is the official capability library for Pydantic AI, maintained by the [Pydantic AI](https://github.com/pydantic/pydantic-ai) team. Pydantic AI core ships capabilities that require model or framework support, and capabilities fundamental to every agent -- [web search](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools), [tool search](https://ai.pydantic.dev/deferred-tools/), [thinking](https://ai.pydantic.dev/capabilities/#thinking). Everything else lives here: standalone building blocks you pick and choose to turn your agent into a coding agent, a research assistant, or anything else. This is also where new capabilities start -- as they stabilize and prove themselves broadly essential, they can graduate into core. The [capability matrix](#capability-matrix) tracks where we are. [Tell us what to prioritize.](#help-us-prioritize) @@ -20,13 +20,13 @@ The [capability matrix](#capability-matrix) tracks where we are. [Tell us what t ## Installation ```bash -uv add pydantic-harness +uv add pydantic-ai-harness ``` Extras for specific capabilities: ```bash -uv add "pydantic-harness[code-mode]" # CodeMode (adds the Monty sandbox) +uv add "pydantic-ai-harness[code-mode]" # CodeMode (adds the Monty sandbox) ``` Requires Python 3.10+ and `pydantic-ai-slim>=1.80.0`. @@ -37,7 +37,7 @@ Requires Python 3.10+ and `pydantic-ai-slim>=1.80.0`. import logfire from pydantic_ai import Agent from pydantic_ai.capabilities import MCP # from the core pydantic-ai package -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode logfire.configure() logfire.instrument_pydantic_ai() @@ -50,56 +50,56 @@ agent = Agent( ], ) -result = agent.run_sync('Rank the open PRs on pydantic/pydantic-harness by thumbs-up reactions. Which 5 should we merge first?') +result = agent.run_sync('Rank the open PRs on pydantic/pydantic-ai-harness by thumbs-up reactions. Which 5 should we merge first?') print(result.output) ``` [`MCP`](https://ai.pydantic.dev/capabilities/#provider-adaptive-tools) (from the core `pydantic-ai` package) connects your agent to any MCP server -- here, [GitHub's official MCP server](https://github.com/github/github-mcp-server). -[`CodeMode`](pydantic_harness/code_mode/) wraps all tools into a single `run_code` tool powered by our [Monty](https://github.com/pydantic/monty) sandbox, so the model can orchestrate multiple tool calls with Python code instead of one model round-trip per call. +[`CodeMode`](pydantic_ai_harness/code_mode/) wraps all tools into a single `run_code` tool powered by our [Monty](https://github.com/pydantic/monty) sandbox, so the model can orchestrate multiple tool calls with Python code instead of one model round-trip per call. [`logfire`](https://pydantic.dev/logfire) gives you a trace for every agent run. With CodeMode, you can see the `run_code` span with each nested tool call as a child span -- making it easy to debug what the model's code actually did. See the [Pydantic AI Logfire docs](https://ai.pydantic.dev/logfire/) for setup details. ## Capability matrix -We studied leading coding agents, agent frameworks, and Claw-style assistants to map every capability area that matters for production agents. Each one is tracked as an [issue](https://github.com/pydantic/pydantic-harness/issues) in this repo. +We studied leading coding agents, agent frameworks, and Claw-style assistants to map every capability area that matters for production agents. Each one is tracked as an [issue](https://github.com/pydantic/pydantic-ai-harness/issues) in this repo. **Vote on whatever is linked in the Status column** -- PRs if we're actively building it, issues if it's planned -- to help us decide what to work on next. | Category | Capability | Description | Status | Community alternatives | |---|---|---|---|---| -| **Tools & execution** | **Code mode** | Sandboxed Python execution via [Monty](https://github.com/pydantic/monty) -- one `run_code` call replaces N tool calls | :white_check_mark: [Docs](pydantic_harness/code_mode/) | | +| **Tools & execution** | **Code mode** | Sandboxed Python execution via [Monty](https://github.com/pydantic/monty) -- one `run_code` call replaces N tool calls | :white_check_mark: [Docs](pydantic_ai_harness/code_mode/) | | | | **Tool search** | Progressive tool discovery for large tool sets | :white_check_mark: [Pydantic AI](https://ai.pydantic.dev/deferred-tools/) | | -| | **File system** | Read, write, edit, search files with path traversal prevention | :construction: [PR #177](https://github.com/pydantic/pydantic-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm‑co) | -| | **Shell** | Execute commands with allowlists, denylists, and timeouts | :construction: [PR #177](https://github.com/pydantic/pydantic-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm‑co) | -| | **Repo context injection** | Auto-load CLAUDE.md/AGENTS.md and repo structure | :construction: [PR #175](https://github.com/pydantic/pydantic-harness/pull/175) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | -| | **Verification loop** | Run tests after edits, auto-fix failures | :construction: [PR #169](https://github.com/pydantic/pydantic-harness/pull/169) | | -| **Context management** | **Sliding window** | Trim conversation history to stay within token limits | :construction: [PR #191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | -| | **Context compaction** | LLM-powered summarization of older messages | :construction: [PR #191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | -| | **Limit warnings** | Warn agent before hitting context/iteration limits | :construction: [PR #191](https://github.com/pydantic/pydantic-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | -| | **Tool output management** | Truncate, summarize, or spill large tool outputs | :construction: [PR #185](https://github.com/pydantic/pydantic-harness/pull/185) | | -| | **System reminders** | Inject periodic reminders to counteract instruction drift | :construction: [PR #181](https://github.com/pydantic/pydantic-harness/pull/181) | | -| **Memory & persistence** | **Memory** | Persistent key-value memory across sessions | :construction: [PR #179](https://github.com/pydantic/pydantic-harness/pull/179) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | -| | **Session persistence** | Save and restore full conversation state | :construction: [PR #176](https://github.com/pydantic/pydantic-harness/pull/176) | | -| | **Checkpointing** | Save, rewind, and fork conversation state | :memo: [#196](https://github.com/pydantic/pydantic-harness/issues/196) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | -| **Agent orchestration** | **Sub-agents** | Delegate subtasks to specialized child agents | :construction: [PR #178](https://github.com/pydantic/pydantic-harness/pull/178) | [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai) (vstorm‑co) | -| | **Skills** | Progressive tool loading -- search, activate, deactivate | :construction: [PR #183](https://github.com/pydantic/pydantic-harness/pull/183) | [pydantic-ai-skills](https://github.com/DougTrajano/pydantic-ai-skills) (DougTrajano), [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | -| | **Planning** | Break complex tasks into structured plans before execution | :construction: [PR #180](https://github.com/pydantic/pydantic-harness/pull/180) | | -| | **Task tracking** | Track tasks, subtasks, and dependencies | :memo: [#65](https://github.com/pydantic/pydantic-harness/issues/65) | [pydantic-ai-todo](https://github.com/vstorm-co/pydantic-ai-todo) (vstorm‑co) | -| | **Teams** | Multi-agent teams with shared state and message bus | :memo: [#195](https://github.com/pydantic/pydantic-harness/issues/195) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | -| **Safety & guardrails** | **Input guardrails** | Validate user input before the agent run starts | :construction: [PR #182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Output guardrails** | Validate model output after the run completes | :construction: [PR #182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Cost/token budgets** | Enforce token and cost limits per run | :construction: [PR #182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Tool access control** | Block tools or require approval before execution | :construction: [PR #182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Async guardrails** | Run validation concurrently with model requests | :construction: [PR #182](https://github.com/pydantic/pydantic-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Secret masking** | Detect and redact secrets in agent I/O | :construction: [PR #172](https://github.com/pydantic/pydantic-harness/pull/172) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | -| | **Approval workflows** | Require human approval for sensitive operations | :construction: [PR #173](https://github.com/pydantic/pydantic-harness/pull/173) | [Pydantic AI](https://ai.pydantic.dev/deferred-tools/#human-in-the-loop-tool-approval) (built‑in) | -| | **Tool budget** | Limit total tool calls or cost per run | :construction: [PR #168](https://github.com/pydantic/pydantic-harness/pull/168) | | -| **Reliability** | **Stuck loop detection** | Detect and break out of repetitive agent loops | :construction: [PR #186](https://github.com/pydantic/pydantic-harness/pull/186) | | -| | **Tool error recovery** | Retry failed tool calls with backoff and budget | :construction: [PR #171](https://github.com/pydantic/pydantic-harness/pull/171) | | -| | **Tool orphan repair** | Fix orphaned tool calls in conversation history | :construction: [PR #184](https://github.com/pydantic/pydantic-harness/pull/184) | | -| **Reasoning** | **Adaptive reasoning** | Adjust thinking effort based on task complexity | :construction: [PR #174](https://github.com/pydantic/pydantic-harness/pull/174) | | -| | **Current time** | Inject current date/time into system prompt | :construction: [PR #170](https://github.com/pydantic/pydantic-harness/pull/170) | | +| | **File system** | Read, write, edit, search files with path traversal prevention | :construction: [PR #177](https://github.com/pydantic/pydantic-ai-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm‑co) | +| | **Shell** | Execute commands with allowlists, denylists, and timeouts | :construction: [PR #177](https://github.com/pydantic/pydantic-ai-harness/pull/177) | [pydantic-ai-backend](https://github.com/vstorm-co/pydantic-ai-backend) (vstorm‑co) | +| | **Repo context injection** | Auto-load CLAUDE.md/AGENTS.md and repo structure | :construction: [PR #175](https://github.com/pydantic/pydantic-ai-harness/pull/175) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | +| | **Verification loop** | Run tests after edits, auto-fix failures | :construction: [PR #169](https://github.com/pydantic/pydantic-ai-harness/pull/169) | | +| **Context management** | **Sliding window** | Trim conversation history to stay within token limits | :construction: [PR #191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | +| | **Context compaction** | LLM-powered summarization of older messages | :construction: [PR #191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | +| | **Limit warnings** | Warn agent before hitting context/iteration limits | :construction: [PR #191](https://github.com/pydantic/pydantic-ai-harness/pull/191) | [summarization-pydantic-ai](https://github.com/vstorm-co/summarization-pydantic-ai) (vstorm‑co) | +| | **Tool output management** | Truncate, summarize, or spill large tool outputs | :construction: [PR #185](https://github.com/pydantic/pydantic-ai-harness/pull/185) | | +| | **System reminders** | Inject periodic reminders to counteract instruction drift | :construction: [PR #181](https://github.com/pydantic/pydantic-ai-harness/pull/181) | | +| **Memory & persistence** | **Memory** | Persistent key-value memory across sessions | :construction: [PR #179](https://github.com/pydantic/pydantic-ai-harness/pull/179) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | +| | **Session persistence** | Save and restore full conversation state | :construction: [PR #176](https://github.com/pydantic/pydantic-ai-harness/pull/176) | | +| | **Checkpointing** | Save, rewind, and fork conversation state | :memo: [#196](https://github.com/pydantic/pydantic-ai-harness/issues/196) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | +| **Agent orchestration** | **Sub-agents** | Delegate subtasks to specialized child agents | :construction: [PR #178](https://github.com/pydantic/pydantic-ai-harness/pull/178) | [subagents-pydantic-ai](https://github.com/vstorm-co/subagents-pydantic-ai) (vstorm‑co) | +| | **Skills** | Progressive tool loading -- search, activate, deactivate | :construction: [PR #183](https://github.com/pydantic/pydantic-ai-harness/pull/183) | [pydantic-ai-skills](https://github.com/DougTrajano/pydantic-ai-skills) (DougTrajano), [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | +| | **Planning** | Break complex tasks into structured plans before execution | :construction: [PR #180](https://github.com/pydantic/pydantic-ai-harness/pull/180) | | +| | **Task tracking** | Track tasks, subtasks, and dependencies | :memo: [#65](https://github.com/pydantic/pydantic-ai-harness/issues/65) | [pydantic-ai-todo](https://github.com/vstorm-co/pydantic-ai-todo) (vstorm‑co) | +| | **Teams** | Multi-agent teams with shared state and message bus | :memo: [#195](https://github.com/pydantic/pydantic-ai-harness/issues/195) | [pydantic-deep](https://github.com/vstorm-co/pydantic-deepagents) (vstorm‑co) | +| **Safety & guardrails** | **Input guardrails** | Validate user input before the agent run starts | :construction: [PR #182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Output guardrails** | Validate model output after the run completes | :construction: [PR #182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Cost/token budgets** | Enforce token and cost limits per run | :construction: [PR #182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Tool access control** | Block tools or require approval before execution | :construction: [PR #182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Async guardrails** | Run validation concurrently with model requests | :construction: [PR #182](https://github.com/pydantic/pydantic-ai-harness/pull/182) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Secret masking** | Detect and redact secrets in agent I/O | :construction: [PR #172](https://github.com/pydantic/pydantic-ai-harness/pull/172) | [pydantic-ai-shields](https://github.com/vstorm-co/pydantic-ai-shields) (vstorm‑co) | +| | **Approval workflows** | Require human approval for sensitive operations | :construction: [PR #173](https://github.com/pydantic/pydantic-ai-harness/pull/173) | [Pydantic AI](https://ai.pydantic.dev/deferred-tools/#human-in-the-loop-tool-approval) (built‑in) | +| | **Tool budget** | Limit total tool calls or cost per run | :construction: [PR #168](https://github.com/pydantic/pydantic-ai-harness/pull/168) | | +| **Reliability** | **Stuck loop detection** | Detect and break out of repetitive agent loops | :construction: [PR #186](https://github.com/pydantic/pydantic-ai-harness/pull/186) | | +| | **Tool error recovery** | Retry failed tool calls with backoff and budget | :construction: [PR #171](https://github.com/pydantic/pydantic-ai-harness/pull/171) | | +| | **Tool orphan repair** | Fix orphaned tool calls in conversation history | :construction: [PR #184](https://github.com/pydantic/pydantic-ai-harness/pull/184) | | +| **Reasoning** | **Adaptive reasoning** | Adjust thinking effort based on task complexity | :construction: [PR #174](https://github.com/pydantic/pydantic-ai-harness/pull/174) | | +| | **Current time** | Inject current date/time into system prompt | :construction: [PR #170](https://github.com/pydantic/pydantic-ai-harness/pull/170) | | > Packages by [vstorm-co](https://github.com/vstorm-co) are endorsed by the Pydantic AI team. We're working with them to upstream some of their implementations into this repo. @@ -107,7 +107,7 @@ We studied leading coding agents, agent frameworks, and Claw-style assistants to **Vote on whatever is linked in the Status column above.** If there's a PR, vote on the PR -- it means we're actively building it. If there's only an issue, vote on the issue. -Want something that's not on the list? [Open a capability request](https://github.com/pydantic/pydantic-harness/issues/new?template=capability-request.yml). +Want something that's not on the list? [Open a capability request](https://github.com/pydantic/pydantic-ai-harness/issues/new?template=capability-request.yml). ## Build your own @@ -119,11 +119,11 @@ Want something that's not on the list? [Open a capability request](https://githu We welcome capability contributions. Here's how: -1. **Start with an issue.** [Open a capability request](https://github.com/pydantic/pydantic-harness/issues/new?template=capability-request.yml) describing the behavior you want. This lets us discuss the approach and priority before code is written -- we can close an approach without closing the problem. +1. **Start with an issue.** [Open a capability request](https://github.com/pydantic/pydantic-ai-harness/issues/new?template=capability-request.yml) describing the behavior you want. This lets us discuss the approach and priority before code is written -- we can close an approach without closing the problem. 2. **Then open a PR.** Once the issue exists, you're welcome to open a PR with an implementation. Link the issue in your PR. We review based on community interest -- upvotes on both the issue and PR count. 3. **Don't chase green CI.** Get the approach working, then let us know. We'll take it from there -- we may push to your branch, rewrite, or open a follow-up PR. You'll be credited as the original author. (See the [Pydantic AI contributing guide](https://github.com/pydantic/pydantic-ai/blob/main/CONTRIBUTING.md).) -> **Note**: PRs that modify `pyproject.toml` or `uv.lock` from non-team members are auto-closed by CI to prevent supply chain risk. If you need a new dependency, [open an issue](https://github.com/pydantic/pydantic-harness/issues/new). +> **Note**: PRs that modify `pyproject.toml` or `uv.lock` from non-team members are auto-closed by CI to prevent supply chain risk. If you need a new dependency, [open an issue](https://github.com/pydantic/pydantic-ai-harness/issues/new). ### Development @@ -138,14 +138,14 @@ make testcov # pytest with 100% branch coverage ## Version policy -Pydantic Harness uses **0.x versioning** to signal that APIs are still stabilizing. During 0.x: +Pydantic AI Harness uses **0.x versioning** to signal that APIs are still stabilizing. During 0.x: - **Minor releases** (0.1 → 0.2) may include breaking changes — renamed parameters, changed defaults, restructured APIs. As the library grows, especially as capabilities gain provider-native support (starting as a local implementation, then auto-switching to the provider's built-in API when available), we may need to reshape APIs we couldn't fully anticipate in the initial design. - **Patch releases** (0.1.0 → 0.1.1) will not intentionally break existing behavior. - **All breaking changes** are documented in release notes with migration guidance. - Where practical, we'll keep the previous behavior available under a deprecated name or configuration option before removing it. -This is why Pydantic Harness is a separate package from [Pydantic AI](https://github.com/pydantic/pydantic-ai), which has a [stricter version policy](https://ai.pydantic.dev/version-policy/). As the core capabilities stabilize, we'll move toward 1.0 with stability guarantees to match. +This is why Pydantic AI Harness is a separate package from [Pydantic AI](https://github.com/pydantic/pydantic-ai), which has a [stricter version policy](https://ai.pydantic.dev/version-policy/). As the core capabilities stabilize, we'll move toward 1.0 with stability guarantees to match. ## Pydantic AI references diff --git a/pydantic_harness/__init__.py b/pydantic_ai_harness/__init__.py similarity index 79% rename from pydantic_harness/__init__.py rename to pydantic_ai_harness/__init__.py index d0f0067..0a60fd7 100644 --- a/pydantic_harness/__init__.py +++ b/pydantic_ai_harness/__init__.py @@ -1,4 +1,4 @@ -"""Agent harness for composable, reusable AI agent capabilities, for Pydantic AI.""" +"""The batteries for your Pydantic AI agent -- the official capability library.""" from typing import TYPE_CHECKING diff --git a/pydantic_harness/code_mode/README.md b/pydantic_ai_harness/code_mode/README.md similarity index 96% rename from pydantic_harness/code_mode/README.md rename to pydantic_ai_harness/code_mode/README.md index 3444104..c98a32b 100644 --- a/pydantic_harness/code_mode/README.md +++ b/pydantic_ai_harness/code_mode/README.md @@ -21,7 +21,7 @@ Standard tool calling requires one model round-trip per tool call. An agent that ```python from pydantic_ai import Agent -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode agent = Agent('anthropic:claude-sonnet-4-6', capabilities=[CodeMode()]) @@ -56,7 +56,7 @@ tokyo_c = await convert_temp(fahrenheit=tokyo['temp_f']) Code mode requires the Monty sandbox: ```bash -uv add "pydantic-harness[code-mode]" +uv add "pydantic-ai-harness[code-mode]" ``` ## Selective tool sandboxing @@ -81,7 +81,7 @@ Tools that match the selector are wrapped inside `run_code`. Non-matching tools ```python from pydantic_ai import Agent from pydantic_ai.toolsets import FunctionToolset -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode search_tools = FunctionToolset(tools=[search, fetch]).with_metadata(code_mode=True) @@ -149,7 +149,7 @@ capabilities: ```python from pydantic_ai import Agent -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode agent = Agent.from_file('agent.yaml', custom_capability_types=[CodeMode]) result = agent.run_sync('...') diff --git a/pydantic_ai_harness/code_mode/__init__.py b/pydantic_ai_harness/code_mode/__init__.py new file mode 100644 index 0000000..42304fa --- /dev/null +++ b/pydantic_ai_harness/code_mode/__init__.py @@ -0,0 +1,6 @@ +"""Code mode capability: route tool calls through a sandboxed Python environment.""" + +from pydantic_ai_harness.code_mode._capability import CodeMode +from pydantic_ai_harness.code_mode._toolset import CodeModeToolset + +__all__ = ['CodeMode', 'CodeModeToolset'] diff --git a/pydantic_harness/code_mode/_capability.py b/pydantic_ai_harness/code_mode/_capability.py similarity index 95% rename from pydantic_harness/code_mode/_capability.py rename to pydantic_ai_harness/code_mode/_capability.py index 84c2106..57eeaab 100644 --- a/pydantic_harness/code_mode/_capability.py +++ b/pydantic_ai_harness/code_mode/_capability.py @@ -9,7 +9,7 @@ from pydantic_ai.capabilities import AbstractCapability, CapabilityOrdering from pydantic_ai.capabilities._tool_search import ToolSearch as _ToolSearch from pydantic_ai.tools import AgentDepsT, ToolSelector -from pydantic_harness.code_mode._toolset import CodeModeToolset +from pydantic_ai_harness.code_mode._toolset import CodeModeToolset @dataclass @@ -26,7 +26,7 @@ class CodeMode(AbstractCapability[AgentDepsT]): ```python from pydantic_ai import Agent - from pydantic_harness import CodeMode + from pydantic_ai_harness import CodeMode # Sandbox all tools agent = Agent('openai:gpt-5', capabilities=[CodeMode()]) diff --git a/pydantic_harness/code_mode/_toolset.py b/pydantic_ai_harness/code_mode/_toolset.py similarity index 99% rename from pydantic_harness/code_mode/_toolset.py rename to pydantic_ai_harness/code_mode/_toolset.py index 19fe335..0b65acc 100644 --- a/pydantic_harness/code_mode/_toolset.py +++ b/pydantic_ai_harness/code_mode/_toolset.py @@ -41,7 +41,7 @@ try: ) except ImportError as _import_error: # pragma: no cover raise ImportError( - 'pydantic-monty is required for CodeMode. Install it with: pip install "pydantic-harness[code-mode]"' + 'pydantic-monty is required for CodeMode. Install it with: pip install "pydantic-ai-harness[code-mode]"' ) from _import_error from typing_extensions import NotRequired, TypedDict diff --git a/pydantic_harness/py.typed b/pydantic_ai_harness/py.typed similarity index 100% rename from pydantic_harness/py.typed rename to pydantic_ai_harness/py.typed diff --git a/pydantic_harness/code_mode/__init__.py b/pydantic_harness/code_mode/__init__.py deleted file mode 100644 index 8a267a4..0000000 --- a/pydantic_harness/code_mode/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Code mode capability: route tool calls through a sandboxed Python environment.""" - -from pydantic_harness.code_mode._capability import CodeMode -from pydantic_harness.code_mode._toolset import CodeModeToolset - -__all__ = ['CodeMode', 'CodeModeToolset'] diff --git a/pyproject.toml b/pyproject.toml index 1fb66fa..5b6addd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -3,7 +3,7 @@ requires = ['hatchling', 'uv-dynamic-versioning>=0.7.0'] build-backend = 'hatchling.build' [project] -name = 'pydantic-harness' +name = 'pydantic-ai-harness' dynamic = ['version'] description = 'The batteries for your Pydantic AI agent' readme = 'README.md' @@ -43,13 +43,13 @@ dbos = [ ] [project.urls] -Homepage = 'https://github.com/pydantic/pydantic-harness' -Source = 'https://github.com/pydantic/pydantic-harness' -Issues = 'https://github.com/pydantic/pydantic-harness/issues' +Homepage = 'https://github.com/pydantic/pydantic-ai-harness' +Source = 'https://github.com/pydantic/pydantic-ai-harness' +Issues = 'https://github.com/pydantic/pydantic-ai-harness/issues' [dependency-groups] dev = [ - 'pydantic-harness[code-mode]', + 'pydantic-ai-harness[code-mode]', 'pytest', 'anyio[trio]', 'pytest-anyio', @@ -74,7 +74,7 @@ bump = true [tool.hatch.build.targets.wheel] -packages = ['pydantic_harness'] +packages = ['pydantic_ai_harness'] [tool.ruff] line-length = 120 @@ -119,10 +119,10 @@ anyio_mode = 'auto' [tool.coverage.run] branch = true -source = ['pydantic_harness', 'tests'] +source = ['pydantic_ai_harness', 'tests'] [tool.coverage.paths] -source = ['.', '/home/runner/work/pydantic-harness/pydantic-harness'] +source = ['.', '/home/runner/work/pydantic-ai-harness/pydantic-ai-harness'] [tool.coverage.report] fail_under = 100 diff --git a/tests/_code_mode/test_code_mode.py b/tests/_code_mode/test_code_mode.py index 6551860..485386e 100644 --- a/tests/_code_mode/test_code_mode.py +++ b/tests/_code_mode/test_code_mode.py @@ -26,9 +26,9 @@ from pydantic_ai.usage import RunUsage from pydantic_core import SchemaValidator, core_schema from typing_extensions import TypedDict -from pydantic_harness import CodeMode -from pydantic_harness.code_mode import CodeModeToolset -from pydantic_harness.code_mode._toolset import ( # pyright: ignore[reportPrivateUsage] +from pydantic_ai_harness import CodeMode +from pydantic_ai_harness.code_mode import CodeModeToolset +from pydantic_ai_harness.code_mode._toolset import ( # pyright: ignore[reportPrivateUsage] _SEARCH_TOOLS_MODIFIER, _TOOL_SEARCH_ADDENDUM, _PrintCapture, diff --git a/tests/_code_mode/test_dbos.py b/tests/_code_mode/test_dbos.py index c319876..a6b8a65 100644 --- a/tests/_code_mode/test_dbos.py +++ b/tests/_code_mode/test_dbos.py @@ -25,7 +25,7 @@ from pydantic_ai.messages import ModelRequest, ModelResponse, TextPart, ToolCall from pydantic_ai.models.function import AgentInfo, FunctionModel from pydantic_ai.toolsets.function import FunctionToolset -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode # --------------------------------------------------------------------------- # Fixtures @@ -36,7 +36,7 @@ from pydantic_harness import CodeMode def dbos_instance(tmp_path_factory: pytest.TempPathFactory) -> Generator[DBOS, Any, None]: dbos_sqlite_file = tmp_path_factory.mktemp('dbos') / 'dbostest.sqlite' dbos_config: DBOSConfig = { - 'name': 'pydantic_harness_dbos_tests', + 'name': 'pydantic_ai_harness_dbos_tests', 'system_database_url': f'sqlite:///{dbos_sqlite_file}', 'run_admin_server': False, 'enable_otlp': False, diff --git a/tests/_code_mode/test_temporal.py b/tests/_code_mode/test_temporal.py index d28ca68..9eb26cc 100644 --- a/tests/_code_mode/test_temporal.py +++ b/tests/_code_mode/test_temporal.py @@ -38,12 +38,12 @@ from pydantic_ai.messages import ModelRequest, ModelResponse, TextPart, ToolCall from pydantic_ai.models.function import AgentInfo, FunctionModel from pydantic_ai.toolsets.function import FunctionToolset -from pydantic_harness import CodeMode +from pydantic_ai_harness import CodeMode pytestmark = pytest.mark.anyio TEMPORAL_PORT = 7244 # avoid conflict with other test suites -TASK_QUEUE = 'pydantic-harness-code-mode-queue' +TASK_QUEUE = 'pydantic-ai-harness-code-mode-queue' BASE_ACTIVITY_CONFIG = ActivityConfig( start_to_close_timeout=timedelta(seconds=60), retry_policy=RetryPolicy(maximum_attempts=1), diff --git a/tests/test_placeholder.py b/tests/test_placeholder.py index e4c7fbe..a66e1c6 100644 --- a/tests/test_placeholder.py +++ b/tests/test_placeholder.py @@ -3,12 +3,12 @@ from pathlib import Path from pydantic_ai import Agent from pydantic_ai.models.test import TestModel -import pydantic_harness +import pydantic_ai_harness def test_import(): - assert pydantic_harness.__doc__ is not None - assert isinstance(pydantic_harness.__all__, list) + assert pydantic_ai_harness.__doc__ is not None + assert isinstance(pydantic_ai_harness.__all__, list) def test_test_model_fixture(test_model: TestModel): diff --git a/uv.lock b/uv.lock index b404c66..01616ae 100644 --- a/uv.lock +++ b/uv.lock @@ -863,6 +863,61 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5a/87/b70ad306ebb6f9b585f114d0ac2137d792b48be34d732d60e597c2f8465a/pydantic-2.12.5-py3-none-any.whl", hash = "sha256:e561593fccf61e8a20fc46dfc2dfe075b8be7d0188df33f221ad1f0139180f9d", size = 463580, upload-time = "2025-11-26T15:11:44.605Z" }, ] +[[package]] +name = "pydantic-ai-harness" +source = { editable = "." } +dependencies = [ + { name = "pydantic-ai-slim" }, +] + +[package.optional-dependencies] +code-mode = [ + { name = "pydantic-monty" }, +] +dbos = [ + { name = "pydantic-ai-slim", extra = ["dbos"] }, +] +temporal = [ + { name = "pydantic-ai-slim", extra = ["temporal"] }, +] + +[package.dev-dependencies] +dev = [ + { name = "anyio", extra = ["trio"] }, + { name = "coverage" }, + { name = "logfire", extra = ["httpx"] }, + { name = "pydantic-ai-harness", extra = ["code-mode"] }, + { name = "pytest" }, + { name = "pytest-anyio" }, +] +lint = [ + { name = "pyright" }, + { name = "ruff" }, +] + +[package.metadata] +requires-dist = [ + { name = "pydantic-ai-slim", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, + { name = "pydantic-ai-slim", extras = ["dbos"], marker = "extra == 'dbos'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, + { name = "pydantic-ai-slim", extras = ["temporal"], marker = "extra == 'temporal'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, + { name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = ">=0.0.10" }, +] +provides-extras = ["code-mode", "dbos", "temporal"] + +[package.metadata.requires-dev] +dev = [ + { name = "anyio", extras = ["trio"] }, + { name = "coverage" }, + { name = "logfire", extras = ["httpx"], specifier = ">=4.31.0" }, + { name = "pydantic-ai-harness", extras = ["code-mode"] }, + { name = "pytest" }, + { name = "pytest-anyio" }, +] +lint = [ + { name = "pyright", specifier = ">=1.1.408" }, + { name = "ruff", specifier = ">=0.14" }, +] + [[package]] name = "pydantic-ai-slim" version = "1.80.0" @@ -1015,61 +1070,6 @@ dependencies = [ { name = "typing-inspection" }, ] -[[package]] -name = "pydantic-harness" -source = { editable = "." } -dependencies = [ - { name = "pydantic-ai-slim" }, -] - -[package.optional-dependencies] -code-mode = [ - { name = "pydantic-monty" }, -] -dbos = [ - { name = "pydantic-ai-slim", extra = ["dbos"] }, -] -temporal = [ - { name = "pydantic-ai-slim", extra = ["temporal"] }, -] - -[package.dev-dependencies] -dev = [ - { name = "anyio", extra = ["trio"] }, - { name = "coverage" }, - { name = "logfire", extra = ["httpx"] }, - { name = "pydantic-harness", extra = ["code-mode"] }, - { name = "pytest" }, - { name = "pytest-anyio" }, -] -lint = [ - { name = "pyright" }, - { name = "ruff" }, -] - -[package.metadata] -requires-dist = [ - { name = "pydantic-ai-slim", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, - { name = "pydantic-ai-slim", extras = ["dbos"], marker = "extra == 'dbos'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, - { name = "pydantic-ai-slim", extras = ["temporal"], marker = "extra == 'temporal'", git = "https://github.com/pydantic/pydantic-ai.git?subdirectory=pydantic_ai_slim&branch=main" }, - { name = "pydantic-monty", marker = "extra == 'code-mode'", specifier = ">=0.0.10" }, -] -provides-extras = ["code-mode", "dbos", "temporal"] - -[package.metadata.requires-dev] -dev = [ - { name = "anyio", extras = ["trio"] }, - { name = "coverage" }, - { name = "logfire", extras = ["httpx"], specifier = ">=4.31.0" }, - { name = "pydantic-harness", extras = ["code-mode"] }, - { name = "pytest" }, - { name = "pytest-anyio" }, -] -lint = [ - { name = "pyright", specifier = ">=1.1.408" }, - { name = "ruff", specifier = ">=0.14" }, -] - [[package]] name = "pydantic-monty" version = "0.0.11"