package platform import ( "context" "encoding/json" "net/http" "time" "gitea.entroia.com/Zayden-Jung/foundry-core/internal/codex" ) func (s *service) canvasAIModels(w http.ResponseWriter, r *http.Request, project, account string) error { if r.Method != http.MethodGet { reject(w, 405, "method_not_allowed") return nil } tx, err := s.db.BeginTx(r.Context(), nil) if err != nil { return err } defer tx.Rollback() kind, _, err := lockMaterial(r.Context(), tx, project, r.PathValue("workspace"), r.PathValue("material"), account) if err != nil { return err } if kind != "board" { reject(w, 400, "invalid_material") return nil } ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() models, err := s.canvasAI.Models(ctx) if err != nil { reply(w, 200, response{"models": []any{}, "unavailable_reason": "codex_unavailable"}) return nil } imageAvailable := false for _, model := range models { if model.Available && canvasModelSupports(model, "image") { imageAvailable = true } } capability := response{"available": imageAvailable} if !imageAvailable { capability["unavailable_reason"] = "worker_has_no_verified_image_output" } reply(w, 200, response{"models": models, "image_generation": capability}) return nil } func (s *service) validateCanvasAIModels(w http.ResponseWriter, r *http.Request, raw json.RawMessage) bool { data := canvasNodeData(raw) configured := []map[string]any{} for _, d := range data { if ai, ok := d["ai"].(map[string]any); ok { configured = append(configured, ai) } } if len(configured) == 0 { return true } ctx, cancel := context.WithTimeout(r.Context(), 5*time.Second) defer cancel() models, err := s.canvasAI.Models(ctx) if err != nil { reject(w, 503, "codex_unavailable") return false } catalogue := map[string]codex.CanvasModel{} for _, model := range models { catalogue[model.ID] = model } for _, ai := range configured { params, _ := ai["parameters"].(map[string]any) if len(params) > 0 { reject(w, 400, "invalid_ai_request") return false } id, _ := ai["modelId"].(string) if id == "" && ai["enabled"] != true { continue } model, exists := catalogue[id] if !exists || !model.Available { reject(w, 422, "model_unavailable") return false } // The verified CLI catalog currently exposes an empty parameter schema. // Arbitrary CLI arguments and unknown model-specific keys are rejected. } return true }