Skip to content

fix: write relative schema refs for AgentSpec files#6251

Merged
hramezani merged 3 commits into
pydantic:mainfrom
VectorPeak:codex/agent-spec-schema-ref-6250
Jul 6, 2026
Merged

fix: write relative schema refs for AgentSpec files#6251
hramezani merged 3 commits into
pydantic:mainfrom
VectorPeak:codex/agent-spec-schema-ref-6250

Conversation

@VectorPeak

@VectorPeak VectorPeak commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Keep AgentSpec.to_file schema references portable when callers pass an absolute schema path that lives beside the saved spec.

What Problem This Solves

AgentSpec.to_file() accepts schema_path so callers can emit a JSON Schema file alongside the generated agent.json or agent.yaml. A common way to call this API is to build both paths from the same output directory, which means schema_path may be an absolute Path even though it points to a sibling file beside the generated spec.

Today that absolute-path input is serialized back into the generated spec unchanged. If the caller passes an absolute schema_path located in the same directory as the generated spec, the saved schema reference still becomes a machine-local absolute path instead of a portable sibling reference.

For example, a caller may write both files into the same output directory:

spec_path   = /repo/agents/weather/agent.json
schema_path = /repo/agents/weather/agent_schema.json

Before this change, agent.json stores the machine-local path as the schema reference:

{"$schema": "/repo/agents/weather/agent_schema.json", "...": "..."}

After this change, it stores the portable sibling reference instead:

{"$schema": "agent_schema.json", "...": "..."}

The same rule applies to YAML output:

spec_path   = /repo/agents/weather/agent.yaml
schema_path = /repo/agents/weather/agent_schema.json

After this change, the YAML language-server comment uses the same relative sibling reference:

# yaml-language-server: $schema=agent_schema.json

This PR intentionally does not relativize schema files outside the generated spec directory. For example, /shared/schemas/agent_schema.json remains an absolute reference because it is not a sibling artifact of the generated spec.
A minimal local reproduction before this change produced:

schema_path= C:\Users\MiaoXing\AppData\Local\Temp\tmpe0wvnupc\agent_schema.json
schema_ref= C:\Users\MiaoXing\AppData\Local\Temp\tmpe0wvnupc\agent_schema.json
schema_exists= True
is_absolute_ref= True

That makes the generated spec file depend on the machine where it was produced. The spec may work locally, but once it is moved to another directory, committed to a repository, shared with another developer, or consumed by tooling in a different workspace, the schema reference can point back to a private temp directory that does not exist there.

It can also leak local path details, such as usernames or temporary build directories, into files that otherwise look safe to publish. The issue is only the serialized reference text; the schema file itself is still written to the requested location.

This behavior is inconsistent with the sibling Dataset.to_file() path handling. Dataset.to_file() already treats an absolute schema path under the target file directory as a local schema file and serializes it as a relative reference. AgentSpec.to_file() should follow the same portability rule for colocated schema files while preserving absolute references for schema files outside the generated spec directory.

Change

  • Relativize AgentSpec.to_file schema references when schema_path is absolute and located under the saved spec file directory.
  • Preserve existing behavior for relative schema_path values.
  • Preserve absolute schema references when the schema file is outside the spec file directory.
  • Add regression coverage for same-directory absolute schema_path serialization.

Evidence

Before this change, saving an agent spec with an absolute schema path in the same directory writes the absolute local path into the schema reference:

from pathlib import Path
from tempfile import TemporaryDirectory
import json

from pydantic_ai.agent.spec import AgentSpec

with TemporaryDirectory() as td:
    root = Path(td)
    spec_path = root / 'agent.json'
    schema_path = root / 'agent_schema.json'

    AgentSpec(model='test', name='demo').to_file(
        spec_path,
        schema_path=schema_path,
        fmt='json',
    )

    data = json.loads(spec_path.read_text(encoding='utf-8'))
    print(data['$schema'])
    print(Path(data['$schema']).is_absolute())

Observed before the fix:

C:\Users\MiaoXing\AppData\Local\Temp\...\agent_schema.json
True

Expected after the fix:

agent_schema.json
False

Possible call chain / impact

User/tooling calls AgentSpec.to_file(...)
  -> schema_path is an absolute Path under spec_path.parent
  -> current AgentSpec.to_file absolute-path branch
  -> schema_ref = str(schema_path)
  -> JSON schema field or YAML language-server comment receives local absolute path

This PR only changes the generated schema reference text for schema files located under the saved spec directory. It does not change schema generation, spec validation, AgentSpec.from_file, capability schema generation, or external absolute schema paths.

Validation

  • PYTHONUTF8=1 uv run --project D:\ZXY\Github\pydantic-ai\pydantic_ai_slim pytest D:\ZXY\Github\pydantic-ai\tests\test_capabilities.py::test_to_file_json_with_absolute_schema_path D:\ZXY\Github\pydantic-ai\tests\test_capabilities.py::test_to_file_yaml_with_absolute_schema_path D:\ZXY\Github\pydantic-ai\tests\test_capabilities.py::test_to_file_json_with_external_absolute_schema_path - passed, 3 tests
  • PYTHONUTF8=1 uv run --project D:\ZXY\Github\pydantic-ai ruff check pydantic_ai_slim\pydantic_ai\agent\spec.py tests\test_capabilities.py - passed
  • git -C D:\ZXY\Github\pydantic-ai diff --check - passed

Fixes #6250

Checklist

  • Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
  • No breaking changes in accordance with the version policy.
  • PR title is fit for the release changelog.

Review in cubic

@github-actions github-actions Bot added size: S Small PR (≤100 weighted lines) bug Report that something isn't working, or PR implementing a fix labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

AgentSpec.to_file now writes a parent-relative $schema reference when the provided schema_path is colocated with the output file. The test suite adds JSON and YAML coverage for colocated absolute schema paths, plus a JSON case where the schema file is stored in a different directory and the absolute path is preserved.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The code changes and tests directly address #6250 by relativizing colocated absolute schema refs while preserving external absolutes.
Out of Scope Changes check ✅ Passed The added tests support the stated fix, and no unrelated scope creep is evident.
Title check ✅ Passed The title is concise and accurately summarizes the main change to AgentSpec schema reference handling.
Description check ✅ Passed The description is detailed and covers the problem, change, validation, and checklist items, with a linked issue included.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
tests/test_capabilities.py (1)

2130-2141: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Only JSON output is exercised; YAML colocated-absolute-schema case is untested.

to_file's schema_ref branch is shared between JSON and YAML output paths, but this new test only asserts the JSON $schema value.

➕ Suggested addition
def test_to_file_yaml_with_absolute_schema_path(tmp_path: Path):
    spec = AgentSpec(model='test', name='my-agent')
    spec_path = Path(tmp_path) / 'agent.yaml'
    schema_path = Path(tmp_path) / 'agent_schema.json'

    spec.to_file(spec_path, schema_path=schema_path)

    content = spec_path.read_text(encoding='utf-8')
    assert content.startswith('# yaml-language-server: $schema=agent_schema.json')
    assert schema_path.exists()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_capabilities.py` around lines 2130 - 2141, Add a YAML coverage
test for the shared schema_ref path in AgentSpec.to_file, since only the JSON
absolute-schema case is currently verified. Create a test alongside
test_to_file_json_with_absolute_schema_path that writes to a .yaml target,
passes an absolute schema_path, and asserts the emitted YAML starts with the
yaml-language-server $schema comment using the relative schema filename while
also confirming the schema file is created. Use the existing AgentSpec.to_file,
spec_path, and schema_path symbols to keep it aligned with the current JSON
test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/test_capabilities.py`:
- Line 2130: The test function test_to_file_json_with_absolute_schema_path has
an incorrect tmp_path annotation: pytest provides a pathlib.Path, not a str.
Update the parameter type in this test signature to match the actual fixture
type so the annotation is accurate and consistent with pytest’s typing, and keep
using the existing tmp_path symbol where it is consumed.

---

Nitpick comments:
In `@tests/test_capabilities.py`:
- Around line 2130-2141: Add a YAML coverage test for the shared schema_ref path
in AgentSpec.to_file, since only the JSON absolute-schema case is currently
verified. Create a test alongside test_to_file_json_with_absolute_schema_path
that writes to a .yaml target, passes an absolute schema_path, and asserts the
emitted YAML starts with the yaml-language-server $schema comment using the
relative schema filename while also confirming the schema file is created. Use
the existing AgentSpec.to_file, spec_path, and schema_path symbols to keep it
aligned with the current JSON test.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: df5731a9-153b-430b-ad0b-84e4db713730

📥 Commits

Reviewing files that changed from the base of the PR and between 0e7401a and 25e490d.

📒 Files selected for processing (2)
  • pydantic_ai_slim/pydantic_ai/agent/spec.py
  • tests/test_capabilities.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • pydantic/logfire (manual)
  • pydantic/pydantic-ai (manual)
  • pydantic/pydantic (auto-detected)

Comment thread tests/test_capabilities.py Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes portability of schema references emitted by AgentSpec.to_file() by writing a relative $schema reference when the provided schema_path is an absolute path located under the output spec file’s directory (while preserving absolute refs for external schema locations).

Changes:

  • Update AgentSpec.to_file() to serialize $schema as a relative path when an absolute schema_path is within path.parent.
  • Preserve existing behavior for relative schema_path values and for absolute schema paths outside the spec directory.
  • Add regression tests covering JSON and YAML outputs for colocated absolute schema paths, plus a test ensuring external absolute schema paths remain absolute in the emitted spec.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
pydantic_ai_slim/pydantic_ai/agent/spec.py Relativizes $schema when schema_path is absolute but under the spec’s output directory, improving portability.
tests/test_capabilities.py Adds regression coverage for colocated absolute schema paths (JSON/YAML) and for external absolute schema paths.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@hramezani
hramezani merged commit 4d71209 into pydantic:main Jul 6, 2026
66 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Report that something isn't working, or PR implementing a fix size: S Small PR (≤100 weighted lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

AgentSpec.to_file writes absolute $schema for colocated schema paths

3 participants