@@ -13,12 +13,18 @@ import {
1313 type NewSessionResponse ,
1414 type PromptRequest ,
1515 type PromptResponse ,
16+ type SetSessionConfigOptionRequest ,
17+ type SetSessionConfigOptionResponse ,
18+ type SetSessionModelRequest ,
19+ type SetSessionModelResponse ,
20+ type SetSessionModeRequest ,
21+ type SetSessionModeResponse ,
1622} from "@agentclientprotocol/sdk"
1723import { InstallationVersion } from "@opencode-ai/core/installation/version"
1824import type { OpencodeClient } from "@opencode-ai/sdk/v2"
1925import { Context , Effect , Layer , ManagedRuntime } from "effect"
2026import * as ACPNextError from "./error"
21- import { buildConfigOptions } from "./config-option"
27+ import { buildConfigOptions , parseModelSelection } from "./config-option"
2228import { Directory } from "./directory"
2329import { ACPNextSession } from "./session"
2430import { ModelID , ProviderID } from "@/provider/schema"
@@ -34,6 +40,11 @@ export type Interface = {
3440 readonly authenticate : ( input : AuthenticateRequest ) => Effect . Effect < AuthenticateResponse , Error >
3541 readonly newSession : ( input : NewSessionRequest ) => Effect . Effect < NewSessionResponse , Error >
3642 readonly loadSession : ( input : LoadSessionRequest ) => Effect . Effect < LoadSessionResponse , Error >
43+ readonly setSessionConfigOption : (
44+ input : SetSessionConfigOptionRequest ,
45+ ) => Effect . Effect < SetSessionConfigOptionResponse , Error >
46+ readonly setSessionMode : ( input : SetSessionModeRequest ) => Effect . Effect < SetSessionModeResponse , Error >
47+ readonly setSessionModel : ( input : SetSessionModelRequest ) => Effect . Effect < SetSessionModelResponse , Error >
3748 readonly prompt : ( input : PromptRequest ) => Effect . Effect < PromptResponse , Error >
3849 readonly cancel : ( input : CancelNotification ) => Effect . Effect < void , Error >
3950}
@@ -180,11 +191,96 @@ export function make(input: {
180191 }
181192 } )
182193
194+ const setSessionConfigOption = Effect . fn ( "ACPNext.setSessionConfigOption" ) ( function * (
195+ params : SetSessionConfigOptionRequest ,
196+ ) {
197+ const current = yield * session . get ( params . sessionId )
198+ const snapshot = yield * directorySnapshot ( current . cwd )
199+ if ( typeof params . value !== "string" ) {
200+ return yield * new ACPNextError . InvalidConfigOptionError ( { configId : params . configId } )
201+ }
202+
203+ if ( params . configId === "model" ) {
204+ const selected = yield * parseSelectedModel ( snapshot , params . value )
205+ const variant = selected . variant ?? selectVariant ( snapshot , selected . model )
206+ const state = yield * session
207+ . setVariant ( params . sessionId , Directory . variants ( snapshot , selected . model ) ? variant : undefined )
208+ . pipe ( Effect . andThen ( session . setModel ( params . sessionId , selected . model ) ) )
209+ return {
210+ configOptions : configOptions ( snapshot , {
211+ model : state . model ?? selected . model ,
212+ variant : state . variant ,
213+ modeId : state . modeId ,
214+ } ) ,
215+ }
216+ }
217+
218+ if ( params . configId === "effort" ) {
219+ const model = current . model ?? selectDefaultModel ( snapshot )
220+ const variants = Directory . variants ( snapshot , model )
221+ if ( ! variants || ! Object . keys ( variants ) . includes ( params . value ) ) {
222+ return yield * new ACPNextError . InvalidEffortError ( { effort : params . value } )
223+ }
224+ const state = yield * session . setVariant ( params . sessionId , params . value )
225+ return {
226+ configOptions : configOptions ( snapshot , {
227+ model : state . model ?? model ,
228+ variant : state . variant ,
229+ modeId : state . modeId ,
230+ } ) ,
231+ }
232+ }
233+
234+ if ( params . configId === "mode" ) {
235+ if ( ! snapshot . availableModes . some ( ( mode ) => mode . id === params . value ) ) {
236+ return yield * new ACPNextError . InvalidModeError ( { mode : params . value } )
237+ }
238+ const state = yield * session . setMode ( params . sessionId , params . value )
239+ return {
240+ configOptions : configOptions ( snapshot , {
241+ model : state . model ?? selectDefaultModel ( snapshot ) ,
242+ variant : state . variant ,
243+ modeId : state . modeId ,
244+ } ) ,
245+ }
246+ }
247+
248+ return yield * new ACPNextError . InvalidConfigOptionError ( { configId : params . configId } )
249+ } )
250+
251+ const setSessionMode = Effect . fn ( "ACPNext.setSessionMode" ) ( function * ( params : SetSessionModeRequest ) {
252+ const current = yield * session . get ( params . sessionId )
253+ const snapshot = yield * directorySnapshot ( current . cwd )
254+ if ( ! snapshot . availableModes . some ( ( mode ) => mode . id === params . modeId ) ) {
255+ return yield * new ACPNextError . InvalidModeError ( { mode : params . modeId } )
256+ }
257+ yield * session . setMode ( params . sessionId , params . modeId )
258+ return { }
259+ } )
260+
261+ const setSessionModel = Effect . fn ( "ACPNext.setSessionModel" ) ( function * ( params : SetSessionModelRequest ) {
262+ const current = yield * session . get ( params . sessionId )
263+ const snapshot = yield * directorySnapshot ( current . cwd )
264+ const selected = yield * parseSelectedModel ( snapshot , params . modelId )
265+ yield * session
266+ . setVariant (
267+ params . sessionId ,
268+ Directory . variants ( snapshot , selected . model )
269+ ? ( selected . variant ?? selectVariant ( snapshot , selected . model ) )
270+ : undefined ,
271+ )
272+ . pipe ( Effect . andThen ( session . setModel ( params . sessionId , selected . model ) ) )
273+ return { }
274+ } )
275+
183276 return {
184277 initialize,
185278 authenticate,
186279 newSession,
187280 loadSession,
281+ setSessionConfigOption,
282+ setSessionMode,
283+ setSessionModel,
188284 prompt : Effect . fn ( "ACPNext.prompt" ) ( function * ( _input : PromptRequest ) {
189285 return yield * new ACPNextError . UnsupportedOperationError ( { method : "session/prompt" } )
190286 } ) ,
@@ -371,6 +467,30 @@ function configOptions(snapshot: Directory.Snapshot, session: ConfigState) {
371467 } )
372468}
373469
470+ function parseSelectedModel ( snapshot : Directory . Snapshot , modelId : string ) {
471+ const selected = parseModelSelection ( modelId , Object . values ( snapshot . providers ) )
472+ const provider = snapshot . providers [ ProviderID . make ( selected . model . providerID ) ]
473+ const model = provider ?. models [ ModelID . make ( selected . model . modelID ) ]
474+ if ( ! model ) {
475+ return Effect . fail (
476+ new ACPNextError . InvalidModelError ( {
477+ providerId : selected . model . providerID ,
478+ modelId,
479+ } ) ,
480+ )
481+ }
482+ if ( selected . variant && ! model . variants ?. [ selected . variant ] ) {
483+ return Effect . fail ( new ACPNextError . InvalidEffortError ( { effort : selected . variant } ) )
484+ }
485+ return Effect . succeed ( {
486+ model : {
487+ providerID : provider . id ,
488+ modelID : model . id ,
489+ } ,
490+ variant : selected . variant ,
491+ } )
492+ }
493+
374494function sendAvailableCommands (
375495 connection : Pick < AgentSideConnection , "sessionUpdate" > | undefined ,
376496 sessionId : string ,
0 commit comments