Repository navigation
[FEATURE]: Add V2 model-context plugin hook #35408
Description
Feature hasn't been suggested before.
- I searched existing issues. This expands the unresolved design in [FEATURE]: Design V2 per-model tool filtering #34491 from per-model tool filtering into the shared V2 model-context hook required for prompts, messages, tools, and both inference backends.
Describe the enhancement you want to request
Add a scoped V2 plugin hook for mutating the complete model-facing context of each provider turn, then move the current model-specific system-prompt and edit-tool-family behavior into a built-in plugin using that hook.
Discussion: https://discord.com/channels/1391832426048651334/1523183156704968816/1523183156704968816
Current state
V2 currently hardcodes two related model-family decisions in Core:
SessionRunnerSystemPrompt.provider(model)selects the system prompt from the API model ID.ToolRegistry.materialize(...)gives OpenAI/GPT modelsapply_patchand other modelsedit+write.
Plugins can register tools and intercept tool execution, but they cannot mutate the turn context before it is sent to the model. The AI SDK hooks only construct SDK/language-model objects; they do not see the outgoing context.
Proposed hook
Expose a hook such as ctx.session.context(...), invoked once per provider turn after Core assembles the context and immediately before inference dispatch.
The event should contain readonly execution identity plus a mutable, backend-neutral context:
interface SessionContextEvent {
readonly sessionID: string
readonly agentID: string
readonly model: {
readonly selected: {
readonly providerID: string
readonly modelID: string
readonly variant?: string
}
readonly api: {
readonly provider: string
readonly modelID: string
}
}
context: {
system: SystemPart[]
messages: Message[]
tools: ToolDefinition[]
toolChoice?: ToolChoice
responseFormat?: ResponseFormat
providerOptions?: ProviderOptions
generation?: GenerationOptions
cache?: CachePolicy
}
}The exact naming and exported types can change during implementation, but the seam should represent the complete model-facing context rather than a model-specific “optimization” abstraction.
Backend placement
Run the hook above the inference backend split:
SessionRunner -> assemble canonical context -> plugin hooks -> LLM adapter
\----> AI SDK adapter
Both @opencode-ai/llm and AI SDK execution must consume the same post-hook context. A hook placed inside llm.stream alone is insufficient because it would not affect AI SDK calls.
Transport/auth internals should remain outside the context hook.
Tool settlement invariant
After hooks finish, local tool settlement must be restricted to the final advertised tool names. Removing a tool from context.tools must remove it from the captured settlement set; adding a local tool definition still requires a corresponding ctx.tool.register(...) registration. Provider-native tools remain representable through their definitions.
Built-in model-context plugin
Move these behaviors out of SessionRunner and ToolRegistry into a built-in plugin:
- Select the model-family system prompt.
- Preserve the current explicit-agent-system override semantics.
- Select
apply_patchversusedit+write. - Move the model prompt assets beside that plugin.
The plugin should receive both selected catalog identity and resolved API identity so aliases and cross-provider GPT routes behave correctly.
Do not implement this through durable SystemContext: model-family prompts must switch immediately when the model changes and must not become checkpointed model belief/history.
Work items
- Add the scoped context-hook registry and host adapter.
- Add Effect and Promise plugin API types/adapters.
- Invoke the hook at the provider-turn request-assembly seam.
- Define one canonical context representation with lowering for
@opencode-ai/llmand AI SDK. - Restrict tool settlement to the final post-hook advertised roster.
- Add the built-in model-context plugin and move prompt/tool-family policy into it.
- Remove hardcoded prompt selection and model checks from the runner/registry.
- Cover hook ordering, disposal, model aliases, agent prompt overrides, tool settlement, and both inference adapters.
Activity
opencode-agent commentedon Jul 5, 2026
Consolidated #34491 here. Preserve its remaining requirements while implementing this issue: tool filtering may depend on model/provider/agent/plugin inputs; composition and precedence must be defined; and we should decide whether clients need representation for unavailable tools.
opencode-agent commentedon Jul 10, 2026
Audit: PR #35794 partially addresses this by adding
session.hook("request", ...)for plugins to mutate system, messages, and model-facing tools. Keeping open because the issue also asks to move model-specific behavior into built-in plugins and settle composition/precedence semantics.kunickiaj commentedon Sep 10, 2026
Tested this with a memory plugin after #48212. User message IDs remain stable, including when prompts are batched.
Could
session.contextalso include a turn ID and retry count? Retries and tool continuations can share the same latest message ID, so plugins otherwise have to compare transcripts. The existing assistant message ID may work as the turn ID.