@@ -3,6 +3,8 @@ import type {
33 INodeType ,
44 INodeTypeDescription ,
55 SupplyData ,
6+ ILoadOptionsFunctions ,
7+ INodePropertyOptions ,
68} from "n8n-workflow" ;
79import { NodeConnectionTypes } from "n8n-workflow" ;
810import { OpenCodeChatModel } from "./OpenCodeChatModel" ;
@@ -47,116 +49,28 @@ export class LmChatOpenCode implements INodeType {
4749 type : "options" ,
4850 description : "The OpenCode agent to use" ,
4951 default : "build" ,
50- options : [
51- {
52- name : "Build" ,
53- value : "build" ,
54- description : "Agent for building and implementing features" ,
55- } ,
56- {
57- name : "Chat" ,
58- value : "chat" ,
59- description : "General chat agent" ,
60- } ,
61- {
62- name : "Debug" ,
63- value : "debug" ,
64- description : "Agent specialized for debugging" ,
65- } ,
66- ] ,
52+ typeOptions : {
53+ loadOptionsMethod : "getAgents" ,
54+ } ,
6755 } ,
6856 {
6957 displayName : "Model Provider" ,
7058 name : "providerID" ,
7159 type : "options" ,
7260 description : "The model provider to use" ,
7361 default : "anthropic" ,
74- options : [
75- {
76- name : "Anthropic" ,
77- value : "anthropic" ,
78- } ,
79- {
80- name : "OpenAI" ,
81- value : "openai" ,
82- } ,
83- {
84- name : "Google" ,
85- value : "google" ,
86- } ,
87- {
88- name : "Groq" ,
89- value : "groq" ,
90- } ,
91- {
92- name : "Ollama" ,
93- value : "ollama" ,
94- } ,
95- ] ,
96- } ,
97- {
98- displayName : "Model ID" ,
99- name : "modelID" ,
100- type : "string" ,
101- description : "The specific model to use" ,
102- default : "claude-3-5-sonnet-20241022" ,
103- placeholder : "claude-3-5-sonnet-20241022" ,
104- displayOptions : {
105- show : {
106- providerID : [ "anthropic" ] ,
107- } ,
108- } ,
109- } ,
110- {
111- displayName : "Model ID" ,
112- name : "modelID" ,
113- type : "string" ,
114- description : "The specific model to use" ,
115- default : "gpt-4-turbo" ,
116- placeholder : "gpt-4-turbo" ,
117- displayOptions : {
118- show : {
119- providerID : [ "openai" ] ,
120- } ,
62+ typeOptions : {
63+ loadOptionsMethod : "getProviders" ,
12164 } ,
12265 } ,
12366 {
12467 displayName : "Model ID" ,
12568 name : "modelID" ,
126- type : "string" ,
127- description : "The specific model to use" ,
128- default : "gemini-2.0-flash-exp" ,
129- placeholder : "gemini-2.0-flash-exp" ,
130- displayOptions : {
131- show : {
132- providerID : [ "google" ] ,
133- } ,
134- } ,
135- } ,
136- {
137- displayName : "Model ID" ,
138- name : "modelID" ,
139- type : "string" ,
140- description : "The specific model to use" ,
141- default : "llama-3.3-70b-versatile" ,
142- placeholder : "llama-3.3-70b-versatile" ,
143- displayOptions : {
144- show : {
145- providerID : [ "groq" ] ,
146- } ,
147- } ,
148- } ,
149- {
150- displayName : "Model ID" ,
151- name : "modelID" ,
152- type : "string" ,
69+ type : "options" ,
15370 description : "The specific model to use" ,
154- default : "qwen2.5-coder:32b" ,
155- placeholder : "qwen2.5-coder:32b" ,
156- displayOptions : {
157- show : {
158- providerID : [ "ollama" ] ,
159- } ,
71+ default : "" ,
72+ typeOptions : {
73+ loadOptionsMethod : "getModels" ,
16074 } ,
16175 } ,
16276 {
@@ -201,6 +115,132 @@ export class LmChatOpenCode implements INodeType {
201115 ] ,
202116 } ;
203117
118+ methods = {
119+ loadOptions : {
120+ /**
121+ * Fetches available providers from OpenCode API.
122+ * Transforms the provider object keys into dropdown options.
123+ * Returns empty array if server is unreachable.
124+ */
125+ async getProviders (
126+ this : ILoadOptionsFunctions ,
127+ ) : Promise < INodePropertyOptions [ ] > {
128+ const credentials = await this . getCredentials ( "openCodeApi" ) ;
129+ const baseUrl =
130+ ( credentials ?. baseUrl as string ) || "http://127.0.0.1:4096" ;
131+ const apiKey = credentials ?. apiKey as string | undefined ;
132+
133+ try {
134+ const response = await this . helpers . httpRequest ( {
135+ method : "GET" ,
136+ url : `${ baseUrl } /config/providers` ,
137+ headers : apiKey ? { Authorization : `Bearer ${ apiKey } ` } : { } ,
138+ } ) ;
139+
140+ // Transform providers array to options
141+ return response . providers
142+ . map ( ( provider : any ) => ( {
143+ name : provider . name ,
144+ value : provider . id ,
145+ } ) )
146+ . sort ( ( a : INodePropertyOptions , b : INodePropertyOptions ) =>
147+ a . name . localeCompare ( b . name ) ,
148+ ) ;
149+ } catch ( error ) {
150+ console . warn (
151+ "Failed to load providers from OpenCode:" ,
152+ error instanceof Error ? error . message : String ( error ) ,
153+ ) ;
154+ return [ ] ;
155+ }
156+ } ,
157+
158+ /**
159+ * Fetches available agents from OpenCode API.
160+ * Transforms the agents array into dropdown options.
161+ * Returns empty array if server is unreachable.
162+ */
163+ async getAgents (
164+ this : ILoadOptionsFunctions ,
165+ ) : Promise < INodePropertyOptions [ ] > {
166+ const credentials = await this . getCredentials ( "openCodeApi" ) ;
167+ const baseUrl =
168+ ( credentials ?. baseUrl as string ) || "http://127.0.0.1:4096" ;
169+ const apiKey = credentials ?. apiKey as string | undefined ;
170+
171+ try {
172+ const response = await this . helpers . httpRequest ( {
173+ method : "GET" ,
174+ url : `${ baseUrl } /agent` ,
175+ headers : apiKey ? { Authorization : `Bearer ${ apiKey } ` } : { } ,
176+ } ) ;
177+
178+ // Transform agents array to options
179+ // Response is array of objects with 'name' field
180+ return response
181+ . map ( ( agent : any ) => ( {
182+ name : agent . name . charAt ( 0 ) . toUpperCase ( ) + agent . name . slice ( 1 ) ,
183+ value : agent . name ,
184+ } ) )
185+ . sort ( ( a : INodePropertyOptions , b : INodePropertyOptions ) =>
186+ a . name . localeCompare ( b . name ) ,
187+ ) ;
188+ } catch ( error ) {
189+ console . warn (
190+ "Failed to load agents from OpenCode:" ,
191+ error instanceof Error ? error . message : String ( error ) ,
192+ ) ;
193+ return [ ] ;
194+ }
195+ } ,
196+
197+ /**
198+ * Fetches available models for the currently selected provider.
199+ * Requires providerID parameter to be set.
200+ * Returns empty array if no provider selected or server unreachable.
201+ */
202+ async getModels (
203+ this : ILoadOptionsFunctions ,
204+ ) : Promise < INodePropertyOptions [ ] > {
205+ const credentials = await this . getCredentials ( "openCodeApi" ) ;
206+ const baseUrl =
207+ ( credentials ?. baseUrl as string ) || "http://127.0.0.1:4096" ;
208+ const apiKey = credentials ?. apiKey as string | undefined ;
209+ const providerID = this . getCurrentNodeParameter ( "providerID" ) as string ;
210+
211+ if ( ! providerID ) {
212+ return [ ] ;
213+ }
214+
215+ try {
216+ const response = await this . helpers . httpRequest ( {
217+ method : "GET" ,
218+ url : `${ baseUrl } /config/providers` ,
219+ headers : apiKey ? { Authorization : `Bearer ${ apiKey } ` } : { } ,
220+ } ) ;
221+
222+ // Find provider in array and get models object
223+ const provider = response . providers . find (
224+ ( p : any ) => p . id === providerID ,
225+ ) ;
226+ const models = provider ?. models || { } ;
227+
228+ // Convert models object keys to array
229+ return Object . keys ( models ) . map ( ( modelId : string ) => ( {
230+ name : modelId ,
231+ value : modelId ,
232+ } ) ) ;
233+ } catch ( error ) {
234+ console . warn (
235+ "Failed to load models from OpenCode:" ,
236+ error instanceof Error ? error . message : String ( error ) ,
237+ ) ;
238+ return [ ] ;
239+ }
240+ } ,
241+ } ,
242+ } ;
243+
204244 async supplyData (
205245 this : ISupplyDataFunctions ,
206246 itemIndex : number ,
0 commit comments