@@ -5,7 +5,6 @@ import { KeyedMutex } from "@opencode-ai/core/effect/keyed-mutex"
55import { SessionV1 } from "@opencode-ai/core/v1/session"
66import { Context , Duration , Effect , Layer , Option , Ref , Schema , Semaphore } from "effect"
77import { stringify } from "yaml"
8- import { Agent } from "@/agent/agent"
98import { Config } from "@/config/config"
109import { Provider } from "@/provider/provider"
1110import { Project } from "@/project/project"
@@ -63,17 +62,10 @@ export class ControllerError extends Schema.TaggedErrorClass<ControllerError>()(
6362export const layer : Layer . Layer <
6463 Service ,
6564 never ,
66- | Agent . Service
67- | Config . Service
68- | Provider . Service
69- | Project . Service
70- | MemoryConfig . Service
71- | MemoryModel . Service
72- | MemoryStore . Service
65+ Config . Service | Provider . Service | Project . Service | MemoryConfig . Service | MemoryModel . Service | MemoryStore . Service
7366> = Layer . effect (
7467 Service ,
7568 Effect . gen ( function * ( ) {
76- const agent = yield * Agent . Service
7769 const config = yield * Config . Service
7870 const provider = yield * Provider . Service
7971 const project = yield * Project . Service
@@ -85,37 +77,24 @@ export const layer: Layer.Layer<
8577 const locks = KeyedMutex . makeUnsafe < string > ( )
8678 const state = yield * InstanceState . make ( ( ) => Effect . succeed ( { sessions : new Map < SessionID , SessionCache > ( ) } ) )
8779
88- const models = Effect . fn ( "Memory.models " ) ( function * ( ) {
80+ const availableModels = Effect . fn ( "Memory.availableModels " ) ( function * ( ) {
8981 const providers = yield * provider . list ( )
90- return Object . values ( providers )
91- . flatMap ( ( info ) =>
82+ return new Set (
83+ Object . values ( providers ) . flatMap ( ( info ) =>
9284 Object . values ( info . models )
9385 . filter ( ( model ) => model . capabilities . input . text && model . capabilities . output . text )
94- . map ( ( model ) => ( {
95- id : `${ model . providerID } /${ model . id } ` ,
96- name : model . name ,
97- input_cost : model . cost . input ,
98- output_cost : model . cost . output ,
99- context_limit : model . limit . context ,
100- output_limit : model . limit . output ,
101- } ) ) ,
102- )
103- . sort ( ( a , b ) => a . input_cost + a . output_cost - ( b . input_cost + b . output_cost ) || a . id . localeCompare ( b . id ) )
86+ . map ( ( model ) => `${ model . providerID } /${ model . id } ` ) ,
87+ ) ,
88+ )
10489 } )
10590
10691 const selectBootstrapModel = Effect . fn ( "Memory.selectBootstrapModel" ) ( function * (
107- candidates : Effect . Success < ReturnType < typeof models > > ,
92+ available : Effect . Success < ReturnType < typeof availableModels > > ,
10893 conversationModel ?: string ,
10994 ) {
110- if ( candidates . length === 0 )
111- return yield * new ControllerError ( { message : "No configured text models for MEMORY" } )
112- const available = new Set ( candidates . map ( ( candidate ) => candidate . id ) )
113- const smallModel = ( yield * config . get ( ) ) . small_model
114- if ( smallModel && available . has ( smallModel ) ) return smallModel
115- const compaction = yield * agent . get ( "compaction" )
116- const compactionModel = compaction . model
117- ? `${ compaction . model . providerID } /${ compaction . model . modelID } `
118- : undefined
95+ const settings = yield * config . get ( )
96+ if ( settings . small_model && available . has ( settings . small_model ) ) return settings . small_model
97+ const compactionModel = settings . agent ?. compaction ?. model
11998 if ( compactionModel && available . has ( compactionModel ) ) return compactionModel
12099 const defaultModel = yield * provider . defaultModel ( ) . pipe ( Effect . option )
121100 const fallback = Option . isSome ( defaultModel )
@@ -127,11 +106,11 @@ export const layer: Layer.Layer<
127106 } )
128107
129108 const selectConfiguration = Effect . fn ( "Memory.selectConfiguration" ) ( function * (
130- candidates : Effect . Success < ReturnType < typeof models > > ,
109+ available : Effect . Success < ReturnType < typeof availableModels > > ,
131110 current ?: MemorySchema . Config ,
132111 conversationModel ?: string ,
133112 ) {
134- const selected = yield * selectBootstrapModel ( candidates , conversationModel )
113+ const selected = yield * selectBootstrapModel ( available , conversationModel )
135114 if ( current ) return MemorySchema . updateConfig ( current , { model : selected } )
136115 return {
137116 schema_version : MemorySchema . SCHEMA_VERSION ,
@@ -151,19 +130,19 @@ export const layer: Layer.Layer<
151130 config : MemorySchema . Config ,
152131 conversationModel ?: string ,
153132 ) {
154- const candidates = yield * models ( )
155- if ( candidates . some ( ( candidate ) => candidate . id === config . model ) ) return config
133+ const available = yield * availableModels ( )
134+ if ( available . has ( config . model ) ) return config
156135 yield * Effect . logWarning ( "configured MEMORY model is unavailable — selecting a replacement" , {
157136 model : config . model ,
158137 } )
159- return yield * selectConfiguration ( candidates , config , conversationModel )
138+ return yield * selectConfiguration ( available , config , conversationModel )
160139 } )
161140
162141 const initializeGlobal = Effect . fn ( "Memory.initializeGlobal" ) ( function * ( conversationModel ?: string ) {
163142 const existing = yield * configStore . loadGlobal ( )
164143 const config = existing
165144 ? yield * ensureConfiguredModel ( existing . config , conversationModel )
166- : yield * selectConfiguration ( yield * models ( ) , undefined , conversationModel )
145+ : yield * selectConfiguration ( yield * availableModels ( ) , undefined , conversationModel )
167146 if ( existing ?. config . model === config . model ) return
168147 const created = yield * configStore . writeGlobal ( config , existing ?. path )
169148 if ( created ) yield * Effect . logInfo ( "global MEMORY config initialized" , { model : config . model } )
@@ -325,12 +304,16 @@ export const layer: Layer.Layer<
325304 } ) {
326305 const user = latestRealUser ( input . messages )
327306 if ( ! user ) return
307+ const currentUser = currentRealUser ( input . messages )
328308 const configured = yield * configuration ( )
329309 if ( ! configured ) {
330310 yield * clearSession ( input . sessionID )
331311 return
332312 }
333- if ( ! configured . loaded ) yield * initUnsafe ( `${ user . info . model . providerID } /${ user . info . model . modelID } ` )
313+ if ( currentUser )
314+ yield * initUnsafe ( `${ currentUser . info . model . providerID } /${ currentUser . info . model . modelID } ` ) . pipe (
315+ Effect . catchCause ( ( cause ) => Effect . logWarning ( "global MEMORY init failed" , { cause } ) ) ,
316+ )
334317 const current = yield * active ( )
335318 if ( ! current ) {
336319 yield * clearSession ( input . sessionID )
@@ -541,7 +524,7 @@ export const layer: Layer.Layer<
541524 const value = initial . loaded
542525 ? initial
543526 : yield * Effect . gen ( function * ( ) {
544- yield * initializeGlobal ( )
527+ yield * initUnsafe ( )
545528 return ( yield * configuration ( ) ) ?? initial
546529 } )
547530 if ( ! value . loaded ) return "Memory remains off" as const
@@ -581,7 +564,6 @@ export const layer: Layer.Layer<
581564
582565export const defaultLayer : Layer . Layer < Service > = Layer . suspend ( ( ) =>
583566 layer . pipe (
584- Layer . provide ( Agent . defaultLayer ) ,
585567 Layer . provide ( Config . defaultLayer ) ,
586568 Layer . provide ( Provider . defaultLayer ) ,
587569 Layer . provide ( Project . defaultLayer ) ,
@@ -592,7 +574,6 @@ export const defaultLayer: Layer.Layer<Service> = Layer.suspend(() =>
592574)
593575
594576export const node = LayerNode . make ( layer , [
595- Agent . node ,
596577 Config . node ,
597578 Provider . node ,
598579 Project . node ,
@@ -698,6 +679,16 @@ function maintenanceEvidence(messages: SessionV1.WithParts[]) {
698679function latestRealUser ( messages : SessionV1 . WithParts [ ] ) {
699680 const user = messages . findLast ( isRealUser )
700681 if ( ! user ) return undefined
682+ return userInput ( user )
683+ }
684+
685+ function currentRealUser ( messages : SessionV1 . WithParts [ ] ) {
686+ const user = messages . findLast ( ( message ) => message . info . role === "user" )
687+ if ( ! user || ! isRealUser ( user ) ) return undefined
688+ return userInput ( user )
689+ }
690+
691+ function userInput ( user : SessionV1 . WithParts & { info : SessionV1 . User } ) {
701692 return {
702693 info : user . info ,
703694 text : cleanText (
0 commit comments