main.go

  1package main
  2
  3import (
  4	"encoding/json"
  5	"fmt"
  6	"os"
  7
  8	"github.com/kujtimiihoxha/opencode/internal/config"
  9	"github.com/kujtimiihoxha/opencode/internal/llm/models"
 10)
 11
 12// JSONSchemaType represents a JSON Schema type
 13type JSONSchemaType struct {
 14	Type                 string           `json:"type,omitempty"`
 15	Description          string           `json:"description,omitempty"`
 16	Properties           map[string]any   `json:"properties,omitempty"`
 17	Required             []string         `json:"required,omitempty"`
 18	AdditionalProperties any              `json:"additionalProperties,omitempty"`
 19	Enum                 []any            `json:"enum,omitempty"`
 20	Items                map[string]any   `json:"items,omitempty"`
 21	OneOf                []map[string]any `json:"oneOf,omitempty"`
 22	AnyOf                []map[string]any `json:"anyOf,omitempty"`
 23	Default              any              `json:"default,omitempty"`
 24}
 25
 26func main() {
 27	schema := generateSchema()
 28
 29	// Pretty print the schema
 30	encoder := json.NewEncoder(os.Stdout)
 31	encoder.SetIndent("", "  ")
 32	if err := encoder.Encode(schema); err != nil {
 33		fmt.Fprintf(os.Stderr, "Error encoding schema: %v\n", err)
 34		os.Exit(1)
 35	}
 36}
 37
 38func generateSchema() map[string]any {
 39	schema := map[string]any{
 40		"$schema":     "http://json-schema.org/draft-07/schema#",
 41		"title":       "OpenCode Configuration",
 42		"description": "Configuration schema for the OpenCode application",
 43		"type":        "object",
 44		"properties":  map[string]any{},
 45	}
 46
 47	// Add Data configuration
 48	schema["properties"].(map[string]any)["data"] = map[string]any{
 49		"type":        "object",
 50		"description": "Storage configuration",
 51		"properties": map[string]any{
 52			"directory": map[string]any{
 53				"type":        "string",
 54				"description": "Directory where application data is stored",
 55				"default":     ".opencode",
 56			},
 57		},
 58		"required": []string{"directory"},
 59	}
 60
 61	// Add working directory
 62	schema["properties"].(map[string]any)["wd"] = map[string]any{
 63		"type":        "string",
 64		"description": "Working directory for the application",
 65	}
 66
 67	// Add debug flags
 68	schema["properties"].(map[string]any)["debug"] = map[string]any{
 69		"type":        "boolean",
 70		"description": "Enable debug mode",
 71		"default":     false,
 72	}
 73
 74	schema["properties"].(map[string]any)["debugLSP"] = map[string]any{
 75		"type":        "boolean",
 76		"description": "Enable LSP debug mode",
 77		"default":     false,
 78	}
 79
 80	// Add MCP servers
 81	schema["properties"].(map[string]any)["mcpServers"] = map[string]any{
 82		"type":        "object",
 83		"description": "Model Control Protocol server configurations",
 84		"additionalProperties": map[string]any{
 85			"type":        "object",
 86			"description": "MCP server configuration",
 87			"properties": map[string]any{
 88				"command": map[string]any{
 89					"type":        "string",
 90					"description": "Command to execute for the MCP server",
 91				},
 92				"env": map[string]any{
 93					"type":        "array",
 94					"description": "Environment variables for the MCP server",
 95					"items": map[string]any{
 96						"type": "string",
 97					},
 98				},
 99				"args": map[string]any{
100					"type":        "array",
101					"description": "Command arguments for the MCP server",
102					"items": map[string]any{
103						"type": "string",
104					},
105				},
106				"type": map[string]any{
107					"type":        "string",
108					"description": "Type of MCP server",
109					"enum":        []string{"stdio", "sse"},
110					"default":     "stdio",
111				},
112				"url": map[string]any{
113					"type":        "string",
114					"description": "URL for SSE type MCP servers",
115				},
116				"headers": map[string]any{
117					"type":        "object",
118					"description": "HTTP headers for SSE type MCP servers",
119					"additionalProperties": map[string]any{
120						"type": "string",
121					},
122				},
123			},
124			"required": []string{"command"},
125		},
126	}
127
128	// Add providers
129	providerSchema := map[string]any{
130		"type":        "object",
131		"description": "LLM provider configurations",
132		"additionalProperties": map[string]any{
133			"type":        "object",
134			"description": "Provider configuration",
135			"properties": map[string]any{
136				"apiKey": map[string]any{
137					"type":        "string",
138					"description": "API key for the provider",
139				},
140				"disabled": map[string]any{
141					"type":        "boolean",
142					"description": "Whether the provider is disabled",
143					"default":     false,
144				},
145			},
146		},
147	}
148
149	// Add known providers
150	knownProviders := []string{
151		string(models.ProviderAnthropic),
152		string(models.ProviderOpenAI),
153		string(models.ProviderGemini),
154		string(models.ProviderGROQ),
155		string(models.ProviderBedrock),
156	}
157
158	providerSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["provider"] = map[string]any{
159		"type":        "string",
160		"description": "Provider type",
161		"enum":        knownProviders,
162	}
163
164	schema["properties"].(map[string]any)["providers"] = providerSchema
165
166	// Add agents
167	agentSchema := map[string]any{
168		"type":        "object",
169		"description": "Agent configurations",
170		"additionalProperties": map[string]any{
171			"type":        "object",
172			"description": "Agent configuration",
173			"properties": map[string]any{
174				"model": map[string]any{
175					"type":        "string",
176					"description": "Model ID for the agent",
177				},
178				"maxTokens": map[string]any{
179					"type":        "integer",
180					"description": "Maximum tokens for the agent",
181					"minimum":     1,
182				},
183				"reasoningEffort": map[string]any{
184					"type":        "string",
185					"description": "Reasoning effort for models that support it (OpenAI, Anthropic)",
186					"enum":        []string{"low", "medium", "high"},
187				},
188			},
189			"required": []string{"model"},
190		},
191	}
192
193	// Add model enum
194	modelEnum := []string{}
195	for modelID := range models.SupportedModels {
196		modelEnum = append(modelEnum, string(modelID))
197	}
198	agentSchema["additionalProperties"].(map[string]any)["properties"].(map[string]any)["model"].(map[string]any)["enum"] = modelEnum
199
200	// Add specific agent properties
201	agentProperties := map[string]any{}
202	knownAgents := []string{
203		string(config.AgentCoder),
204		string(config.AgentTask),
205		string(config.AgentTitle),
206	}
207
208	for _, agentName := range knownAgents {
209		agentProperties[agentName] = map[string]any{
210			"$ref": "#/definitions/agent",
211		}
212	}
213
214	// Create a combined schema that allows both specific agents and additional ones
215	combinedAgentSchema := map[string]any{
216		"type":                 "object",
217		"description":          "Agent configurations",
218		"properties":           agentProperties,
219		"additionalProperties": agentSchema["additionalProperties"],
220	}
221
222	schema["properties"].(map[string]any)["agents"] = combinedAgentSchema
223	schema["definitions"] = map[string]any{
224		"agent": agentSchema["additionalProperties"],
225	}
226
227	// Add LSP configuration
228	schema["properties"].(map[string]any)["lsp"] = map[string]any{
229		"type":        "object",
230		"description": "Language Server Protocol configurations",
231		"additionalProperties": map[string]any{
232			"type":        "object",
233			"description": "LSP configuration for a language",
234			"properties": map[string]any{
235				"disabled": map[string]any{
236					"type":        "boolean",
237					"description": "Whether the LSP is disabled",
238					"default":     false,
239				},
240				"command": map[string]any{
241					"type":        "string",
242					"description": "Command to execute for the LSP server",
243				},
244				"args": map[string]any{
245					"type":        "array",
246					"description": "Command arguments for the LSP server",
247					"items": map[string]any{
248						"type": "string",
249					},
250				},
251				"options": map[string]any{
252					"type":        "object",
253					"description": "Additional options for the LSP server",
254				},
255			},
256			"required": []string{"command"},
257		},
258	}
259
260	return schema
261}
262