11import { createStore } from "solid-js/store"
2- import { batch , createEffect , createMemo , createSignal } from "solid-js"
2+ import { batch , createEffect , createMemo , createSignal , onMount } from "solid-js"
33import { useSync } from "@tui/context/sync"
44import { Theme } from "@tui/context/theme"
55import { uniqueBy } from "remeda"
66import path from "path"
77import { Global } from "@/global"
88import { iife } from "@/util/iife"
99import { createSimpleContext } from "./helper"
10+ import { useToast } from "../ui/toast"
11+ import type { Provider } from "@opencode-ai/sdk"
1012
1113export const { use : useLocal , provider : LocalProvider } = createSimpleContext ( {
1214 name : "Local" ,
13- init : ( ) => {
15+ init : ( props : { initialModel ?: string ; initialAgent ?: string } ) => {
1416 const sync = useSync ( )
17+ const toast = useToast ( )
18+
19+ function isModelValid ( model : { providerID : string , modelID : string } ) {
20+ const provider = sync . data . provider . find ( ( x ) => x . id === model . providerID )
21+ return ! ! provider ?. models [ model . modelID ]
22+ }
23+
24+ function getFirstValidModel ( ...modelFns : ( ( ) => { providerID : string , modelID : string } | undefined ) [ ] ) {
25+ for ( const modelFn of modelFns ) {
26+ const model = modelFn ( )
27+ if ( ! model ) continue
28+ if ( isModelValid ( model ) )
29+ return model
30+ }
31+ }
32+
33+ // Set initial model if provided
34+ onMount ( ( ) => {
35+ batch ( ( ) => {
36+ if ( props . initialAgent ) {
37+ agent . set ( props . initialAgent )
38+ }
39+ if ( props . initialModel ) {
40+ const [ providerID , modelID ] = props . initialModel . split ( "/" )
41+ if ( ! providerID || ! modelID )
42+ return toast . show ( {
43+ type : "warning" ,
44+ message : `Invalid model format: ${ props . initialModel } ` ,
45+ duration : 3000 ,
46+ } )
47+ model . set ( { providerID, modelID } , { recent : true } )
48+ }
49+ } )
50+ } )
51+
52+ // Automatically update model when agent changes
53+ createEffect ( ( ) => {
54+ const value = agent . current ( )
55+ if ( value . model ) {
56+ if ( isModelValid ( value . model ) )
57+ model . set ( {
58+ providerID : value . model . providerID ,
59+ modelID : value . model . modelID ,
60+ } )
61+ else
62+ toast . show ( {
63+ type : "warning" ,
64+ message : `Agent ${ value . name } 's configured model ${ value . model . providerID } /${ value . model . modelID } is not valid` ,
65+ duration : 3000 ,
66+ } )
67+ }
68+ } )
1569
1670 const agent = iife ( ( ) => {
1771 const agents = createMemo ( ( ) => sync . data . agent . filter ( ( x ) => x . mode !== "subagent" ) )
18- const [ store , setStore ] = createStore < {
72+ const [ agentStore , setAgentStore ] = createStore < {
1973 current : string
2074 } > ( {
2175 current : agents ( ) [ 0 ] . name ,
@@ -25,22 +79,25 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
2579 return agents ( )
2680 } ,
2781 current ( ) {
28- return agents ( ) . find ( ( x ) => x . name === store . current ) !
82+ return agents ( ) . find ( ( x ) => x . name === agentStore . current ) !
2983 } ,
3084 set ( name : string ) {
31- setStore ( "current" , name )
85+ if ( ! agents ( ) . some ( ( x ) => x . name === name ) )
86+ return toast . show ( {
87+ type : "warning" ,
88+ message : `Agent not found: ${ name } ` ,
89+ duration : 3000 ,
90+ } )
91+ setAgentStore ( "current" , name )
3292 } ,
3393 move ( direction : 1 | - 1 ) {
34- let next = agents ( ) . findIndex ( ( x ) => x . name === store . current ) + direction
35- if ( next < 0 ) next = agents ( ) . length - 1
36- if ( next >= agents ( ) . length ) next = 0
37- const value = agents ( ) [ next ]
38- setStore ( "current" , value . name )
39- if ( value . model )
40- model . set ( {
41- providerID : value . model . providerID ,
42- modelID : value . model . modelID ,
43- } )
94+ batch ( ( ) => {
95+ let next = agents ( ) . findIndex ( ( x ) => x . name === agentStore . current ) + direction
96+ if ( next < 0 ) next = agents ( ) . length - 1
97+ if ( next >= agents ( ) . length ) next = 0
98+ const value = agents ( ) [ next ]
99+ setAgentStore ( "current" , value . name )
100+ } )
44101 } ,
45102 color ( name : string ) {
46103 const index = agents ( ) . findIndex ( ( x ) => x . name === name )
@@ -51,7 +108,7 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
51108 } )
52109
53110 const model = iife ( ( ) => {
54- const [ store , setStore ] = createStore < {
111+ const [ modelStore , setModelStore ] = createStore < {
55112 ready : boolean
56113 model : Record <
57114 string ,
@@ -75,43 +132,35 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
75132 file
76133 . json ( )
77134 . then ( ( x ) => {
78- setStore ( "recent" , x . recent )
135+ setModelStore ( "recent" , x . recent )
79136 } )
80- . catch ( ( ) => { } )
137+ . catch ( ( ) => { } )
81138 . finally ( ( ) => {
82- setStore ( "ready" , true )
139+ setModelStore ( "ready" , true )
83140 } )
84141
85142 createEffect ( ( ) => {
86143 Bun . write (
87144 file ,
88145 JSON . stringify ( {
89- recent : store . recent ,
146+ recent : modelStore . recent ,
90147 } ) ,
91148 )
92149 } )
93150
94- const fallback = createMemo ( ( ) => {
95- function isValid ( providerID : string , modelID : string ) {
96- const provider = sync . data . provider . find ( ( x ) => x . id === providerID )
97- if ( ! provider ) return false
98- const model = provider . models [ modelID ]
99- if ( ! model ) return false
100- return true
101- }
102-
151+ const fallbackModel = createMemo ( ( ) => {
103152 if ( sync . data . config . model ) {
104153 const [ providerID , modelID ] = sync . data . config . model . split ( "/" )
105- if ( isValid ( providerID , modelID ) ) {
154+ if ( isModelValid ( { providerID, modelID } ) ) {
106155 return {
107156 providerID,
108157 modelID,
109158 }
110159 }
111160 }
112161
113- for ( const item of store . recent ) {
114- if ( isValid ( item . providerID , item . modelID ) ) {
162+ for ( const item of modelStore . recent ) {
163+ if ( isModelValid ( item ) ) {
115164 return item
116165 }
117166 }
@@ -123,21 +172,25 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
123172 }
124173 } )
125174
126- const current = createMemo ( ( ) => {
175+ const currentModel = createMemo ( ( ) => {
127176 const a = agent . current ( )
128- return store . model [ agent . current ( ) . name ] ?? ( a . model ? a . model : fallback ( ) )
177+ return getFirstValidModel (
178+ ( ) => modelStore . model [ a . name ] ,
179+ ( ) => a . model ,
180+ fallbackModel ,
181+ ) !
129182 } )
130183
131184 return {
132- current,
185+ current : currentModel ,
133186 get ready ( ) {
134- return store . ready
187+ return modelStore . ready
135188 } ,
136189 recent ( ) {
137- return store . recent
190+ return modelStore . recent
138191 } ,
139192 parsed : createMemo ( ( ) => {
140- const value = current ( )
193+ const value = currentModel ( )
141194 const provider = sync . data . provider . find ( ( x ) => x . id === value . providerID ) !
142195 const model = provider . models [ value . modelID ]
143196 return {
@@ -147,11 +200,20 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
147200 } ) ,
148201 set ( model : { providerID : string ; modelID : string } , options ?: { recent ?: boolean } ) {
149202 batch ( ( ) => {
150- setStore ( "model" , agent . current ( ) . name , model )
203+ if ( ! isModelValid ( model ) ) {
204+ toast . show ( {
205+ message : `Model ${ model . providerID } /${ model . modelID } is not valid` ,
206+ type : "warning" ,
207+ duration : 3000 ,
208+ } )
209+ return
210+ }
211+
212+ setModelStore ( "model" , agent . current ( ) . name , model )
151213 if ( options ?. recent ) {
152- const uniq = uniqueBy ( [ model , ...store . recent ] , ( x ) => x . providerID + x . modelID )
214+ const uniq = uniqueBy ( [ model , ...modelStore . recent ] , ( x ) => x . providerID + x . modelID )
153215 if ( uniq . length > 5 ) uniq . pop ( )
154- setStore ( "recent" , uniq )
216+ setModelStore ( "recent" , uniq )
155217 }
156218 } )
157219 } ,
@@ -160,30 +222,30 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
160222
161223 const kv = iife ( ( ) => {
162224 const [ ready , setReady ] = createSignal ( false )
163- const [ store , setStore ] = createStore ( {
225+ const [ kvStore , setKvStore ] = createStore ( {
164226 openrouter_warning : false ,
165227 } )
166228 const file = Bun . file ( path . join ( Global . Path . state , "kv.json" ) )
167229
168230 file
169231 . json ( )
170232 . then ( ( x ) => {
171- setStore ( x )
233+ setKvStore ( x )
172234 } )
173- . catch ( ( ) => { } )
235+ . catch ( ( ) => { } )
174236 . finally ( ( ) => {
175237 setReady ( true )
176238 } )
177239
178240 return {
179241 get data ( ) {
180- return store
242+ return kvStore
181243 } ,
182244 get ready ( ) {
183245 return ready ( )
184246 } ,
185247 set ( key : string , value : any ) {
186- setStore ( key as any , value )
248+ setKvStore ( key as any , value )
187249 Bun . write (
188250 file ,
189251 JSON . stringify ( {
@@ -204,4 +266,4 @@ export const { use: useLocal, provider: LocalProvider } = createSimpleContext({
204266 }
205267 return result
206268 } ,
207- } )
269+ } )
0 commit comments