@@ -4,6 +4,7 @@ import type { AISDKHooks } from "@opencode-ai/plugin/effect/aisdk"
44import type { SessionHooks } from "@opencode-ai/plugin/effect/session"
55import type { ShellHooks } from "@opencode-ai/plugin/effect/shell"
66import type { ToolFailures , ToolHooks } from "@opencode-ai/plugin/effect/tool"
7+ import type { ModelHookOptions } from "@opencode-ai/plugin/effect/registration"
78import { Context , Effect , Layer , Scope } from "effect"
89import { makeLocationNode } from "@opencode-ai/util/effect/app-node"
910import { State } from "../state.js"
@@ -26,16 +27,26 @@ interface Failures extends Record<keyof Domains, unknown> {
2627}
2728
2829type Callback < Event , Error > = ( event : Event ) => Effect . Effect < void , Error >
30+ type Entry = { readonly callback : Function ; readonly options ?: ModelHookOptions }
31+
32+ const eventProviderID = ( event : unknown ) => {
33+ if ( typeof event !== "object" || event === null || ! ( "model" in event ) ) return undefined
34+ const model = event . model
35+ if ( typeof model !== "object" || model === null || ! ( "providerID" in model ) ) return undefined
36+ return typeof model . providerID === "string" ? model . providerID : undefined
37+ }
2938
3039export interface Interface {
3140 readonly has : < Domain extends keyof Domains > (
3241 domain : Domain ,
3342 name : keyof Domains [ Domain ] & keyof Failures [ Domain ] ,
43+ providerID ?: string ,
3444 ) => Effect . Effect < boolean >
3545 readonly register : < Domain extends keyof Domains , Name extends keyof Domains [ Domain ] & keyof Failures [ Domain ] > (
3646 domain : Domain ,
3747 name : Name ,
3848 callback : Callback < Domains [ Domain ] [ Name ] , Failures [ Domain ] [ Name ] > ,
49+ options ?: ModelHookOptions ,
3950 ) => Effect . Effect < State . Registration , never , Scope . Scope >
4051 readonly trigger : < Domain extends keyof Domains , Name extends keyof Domains [ Domain ] & keyof Failures [ Domain ] > (
4152 domain : Domain ,
@@ -49,36 +60,47 @@ export class Service extends Context.Service<Service, Interface>()("@opencode/Pl
4960const layer = Layer . effect (
5061 Service ,
5162 Effect . gen ( function * ( ) {
52- const callbacks = new Map < string , Function [ ] > ( )
63+ const callbacks = new Map < string , Entry [ ] > ( )
5364 const key = ( domain : keyof Domains , name : PropertyKey ) => `${ domain } .${ String ( name ) } `
5465
55- const register : Interface [ "register" ] = Effect . fn ( "PluginHooks.register" ) ( function * ( domain , name , callback ) {
56- const scope = yield * Scope . Scope
57- const id = key ( domain , name )
58- let active = true
59- callbacks . set ( id , [ ...( callbacks . get ( id ) ?? [ ] ) , callback ] )
60- const dispose = Effect . sync ( ( ) => {
61- if ( ! active ) return
62- active = false
63- const next = ( callbacks . get ( id ) ?? [ ] ) . filter ( ( item ) => item !== callback )
64- if ( next . length === 0 ) callbacks . delete ( id )
65- else callbacks . set ( id , next )
66- } )
67- yield * Scope . addFinalizer ( scope , dispose )
68- return { dispose }
69- } )
66+ const register : Interface [ "register" ] = Effect . fn ( "PluginHooks.register" ) (
67+ function * ( domain , name , callback , options ) {
68+ const scope = yield * Scope . Scope
69+ const id = key ( domain , name )
70+ let active = true
71+ const entry = { callback, options }
72+ callbacks . set ( id , [ ...( callbacks . get ( id ) ?? [ ] ) , entry ] )
73+ const dispose = Effect . sync ( ( ) => {
74+ if ( ! active ) return
75+ active = false
76+ const next = ( callbacks . get ( id ) ?? [ ] ) . filter ( ( item ) => item !== entry )
77+ if ( next . length === 0 ) callbacks . delete ( id )
78+ else callbacks . set ( id , next )
79+ } )
80+ yield * Scope . addFinalizer ( scope , dispose )
81+ return { dispose }
82+ } ,
83+ )
7084
7185 const trigger : Interface [ "trigger" ] = Effect . fnUntraced ( function * ( domain , name , event ) {
72- for ( const callback of callbacks . get ( key ( domain , name ) ) ?? [ ] ) {
73- const result : Effect . Effect < void , Failures [ typeof domain ] [ typeof name ] > = Reflect . apply ( callback , undefined , [
74- event ,
75- ] )
86+ for ( const entry of callbacks . get ( key ( domain , name ) ) ?? [ ] ) {
87+ if ( entry . options ?. providerID !== undefined && entry . options . providerID !== eventProviderID ( event ) ) continue
88+ const result : Effect . Effect < void , Failures [ typeof domain ] [ typeof name ] > = Reflect . apply (
89+ entry . callback ,
90+ undefined ,
91+ [ event ] ,
92+ )
7693 yield * result
7794 }
7895 return event
7996 } )
8097
81- const has : Interface [ "has" ] = ( domain , name ) => Effect . sync ( ( ) => callbacks . has ( key ( domain , name ) ) )
98+ const has : Interface [ "has" ] = ( domain , name , providerID ) =>
99+ Effect . sync ( ( ) =>
100+ ( callbacks . get ( key ( domain , name ) ) ?? [ ] ) . some (
101+ ( entry ) => entry . options ?. providerID === undefined || entry . options . providerID === providerID ,
102+ ) ,
103+ )
82104
83105 return Service . of ( { has, register, trigger } )
84106 } ) ,
0 commit comments