Skip to content

Bug: model-conditional tool substitution (apply_patch vs edit/write) is undocumented, makes model-agnostic plugin hooks impossible #19942

Closed as not planned

Description

@evatths

Description

Plugin hooks for file-editing operations cannot be written in a model-agnostic way because the tool that fires depends on which model is in use — and this behavior is nowhere documented.

For gpt-5 and later GPT-series models, apply_patch is substituted for edit and write. For all other models (Claude, Gemini, GPT-4o, o-series), edit and write are used. A plugin author has no way to know this without reading the source.

The substitution logic (from packages/opencode/src/tool/registry.ts)

const usePatch =
  model.modelID.includes("gpt-") &&
  !model.modelID.includes("oss") &&
  !model.modelID.includes("gpt-4")

if (tool.id === "apply_patch") return usePatch
if (tool.id === "edit" || tool.id === "write") return !usePatch

Which models get which tools

Model family File edit tool input.tool in hook
Claude, Gemini, o1, o3, o4-mini edit + write "edit" / "write"
gpt-4, gpt-4o, gpt-4o-mini, gpt-4.5 edit + write "edit" / "write"
gpt-5, gpt-5.x, gpt-3.5-* apply_patch "apply_patch"

Note: gpt-4o is not affected because it contains the substring "gpt-4".

Impact on plugin authors

There is no way to write a single model-agnostic post-edit hook today:

// Only fires for Claude/Gemini/GPT-4o — silently skipped for gpt-5 users:
if (input.tool === "edit") { ... }

// Only fires for gpt-5 — silently skipped for everyone else:
if (input.tool === "apply_patch") { ... }

A plugin author must check all three names and handle them differently, but this is nowhere documented in the plugin or tools docs.

Suggested fix

At minimum, document this behavior on the Plugins page and/or the Tools page.

A more complete fix would be a stable abstraction — for example, a synthetic "file.edit" hook event that normalizes across edit, write, and apply_patch — so plugin authors don't need model-specific branching.


OpenCode version

1.3.6

Steps to reproduce

  1. Write a plugin hook: if (input.tool === "edit") { /* post-edit logic */ }
  2. Run the same file-edit task with a Claude model — hook fires correctly
  3. Run the same task with a gpt-5-series model — hook silently never fires
  4. No error, no warning

Verified via:

  • GitHub source (dev branch): src/tool/registry.ts
  • Compiled binary string search (v1.3.6) confirming the same logic

Operating System

macOS

Activity

  1. github-actions commented on Mar 29, 2026

    @github-actions
    Contributor

    This issue might be a duplicate of (or closely related to) existing issues. Please check:

  2. github-actions commented on Jul 3, 2026

    @github-actions
    Contributor

    To stay organized issues are automatically closed after 60 days of no activity. If the issue is still relevant please open a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions