Skip to content

feat(agent-integrator): convert tools list to object for opencode target#1478

Open
futbolsalas15 wants to merge 9 commits into
microsoft:mainfrom
futbolsalas15:camilo/fix-opencode-tools-conversion
Open

feat(agent-integrator): convert tools list to object for opencode target#1478
futbolsalas15 wants to merge 9 commits into
microsoft:mainfrom
futbolsalas15:camilo/fix-opencode-tools-conversion

Conversation

@futbolsalas15
Copy link
Copy Markdown

@futbolsalas15 futbolsalas15 commented May 26, 2026

TL;DR

OpenCode expects the tools frontmatter field in agent/skill files to be an object ({Read: true, Glob: true}). Some agent files — especially those authored for other harnesses — define it as a list (e.g. [Read, Glob]) or a comma-separated string. When apm install copies such files to .opencode/agents/ verbatim, opencode rejects them with a schema validation error.

What this PR does

  1. Adds _write_opencode_agent() to AgentIntegrator — a new transform method that converts tools from list or comma-separated-string to object format, preserving all other frontmatter and the markdown body.
  2. Wires opencode_agent format_id into the integrate_agents_for_target dispatch so the conversion runs automatically when deploying to .opencode/agents/.
  3. Adds 9 test cases covering: list→object, comma-separated→object, absent tools, already-object, empty list, missing frontmatter, symlink rejection, body preservation, and end-to-end via target dispatch.

How to test

uv run pytest tests/unit/integration/test_agent_integrator.py -v -k OpenCode

OpenCode expects the `tools` frontmatter field in agent files to be an
object (`{Read: true, Glob: true}`) rather than a list
(`[Read, Glob]`).  This adds a new `_write_opencode_agent` method
that converts list- or comma-separated-string `tools` to the object
format, and wires it into the `integrate_agents_for_target` dispatch
for the `opencode_agent` format_id.

Previously, the opencode target fell through to `copy_agent` (verbatim
copy), which would pass the list-format `tools` through to opencode,
causing a schema validation error:

  SchemaError: Expected object | undefined, got [...]
    at ["tools"]
Copilot AI review requested due to automatic review settings May 26, 2026 04:05
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds OpenCode agent integration by converting the tools frontmatter field from list/string formats into OpenCode’s expected object format, and covers the behavior with unit/integration tests.

Changes:

  • Add opencode_agent dispatch path in AgentIntegrator.integrate_agents_for_target.
  • Implement _write_opencode_agent to convert tools frontmatter (list / comma-separated string → object).
  • Add tests covering conversion behavior, symlink rejection, and end-to-end target integration.

Reviewed changes

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

File Description
tests/unit/integration/test_agent_integrator.py Adds test coverage for OpenCode-specific tools conversion and target integration behavior.
src/apm_cli/integration/agent_integrator.py Introduces OpenCode agent transformer and hooks it into target-driven dispatch.

Comment thread src/apm_cli/integration/agent_integrator.py
Comment thread src/apm_cli/integration/agent_integrator.py
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread src/apm_cli/integration/agent_integrator.py
…ists in opencode agent writer

- Normalize yaml.safe_load result: if frontmatter is not a dict (e.g.
  bare list), treat as empty and emit a diagnostic warning instead of
  crashing on fm.get('tools').
- Add target.parent.mkdir(parents=True, exist_ok=True) before writing,
  aligning with _write_windsurf_agent_skill pattern.
- Add test for non-dict frontmatter handling.

Addresses Copilot review comments on lines 393, 406, and 426.
…r docstring

The docstring claimed 'preserving all other frontmatter' but re-serialising via yaml.safe_dump drops YAML comments and can reorder keys. Updated to accurately describe what is preserved (key values) and what is not (comments, ordering).

Addresses Copilot review comments on line 424.
@futbolsalas15
Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree company="JobNimbus"

@futbolsalas15 futbolsalas15 requested a review from Copilot May 26, 2026 04:17
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread tests/unit/integration/test_agent_integrator.py Outdated
…ir consistency

- Move conversion diagnostic inside list/str branches so it only fires when actual conversion occurs (not for e.g. int/float tools)
- Strip whitespace from list-form tools entries, aligning with string-form behavior
- Add target.parent.mkdir() to the early-return (no frontmatter) path

Addresses Copilot review comments 1, 2, 3.
- Change 'tools' not-in-content assertion to 'tools:' to avoid false negatives from the word appearing in body/frontmatter
- Add whitespace-padded list entry to exercise strip() normalization

Addresses Copilot review comment 4.
@futbolsalas15 futbolsalas15 requested a review from Copilot May 26, 2026 04:21
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/apm_cli/integration/agent_integrator.py
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
Comment thread tests/unit/integration/test_agent_integrator.py Outdated
…ve early-return branch

- Emit diagnostic warn when YAML parsing fails (comment 1)
- Use conversion_occurred flag: when no tools conversion is needed, pass through original content verbatim instead of re-serialising (fixes empty-fm {} output, comment 2)
- Drop the early-return branch that duplicated copy_agent; all paths now share a single resolve_links + write tail (comment 3)
- Update docstring to reflect pass-through preservation when no conversion occurs
- Wrap os.symlink() in try/except (OSError, NotImplementedError) with pytest.skip, matching established project pattern
- Move import pytest to top of function so skip guard is reachable

Addresses Copilot review comment 4.
@futbolsalas15 futbolsalas15 requested a review from Copilot May 26, 2026 04:30
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

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

Comment thread src/apm_cli/integration/agent_integrator.py
Comment thread src/apm_cli/integration/agent_integrator.py
Comment thread tests/unit/integration/test_agent_integrator.py Outdated
Comment thread tests/unit/integration/test_agent_integrator.py
Comment thread src/apm_cli/integration/agent_integrator.py Outdated
…dict frontmatter preservation

- Catch yaml.YAMLError instead of broad Exception
- Update test_handles_non_dict_frontmatter docstring from
  "treated as empty" to "preserved as-is"
- Verify original list items survive serialisation
@danielmeppiel danielmeppiel added the panel-review Trigger the apm-review-panel gh-aw workflow label May 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

panel-review Trigger the apm-review-panel gh-aw workflow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants