Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pkg/aiusechat/uctypes/uctypes.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const (
AIProvider_OpenAI = "openai"
AIProvider_Azure = "azure"
AIProvider_AzureLegacy = "azure-legacy"
AIProvider_Novita = "novita"
AIProvider_Custom = "custom"
)

Expand Down
16 changes: 16 additions & 0 deletions pkg/aiusechat/usechat-mode.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ const (
OpenRouterChatEndpoint = "https://openrouter.ai/api/v1/chat/completions"
NanoGPTChatEndpoint = "https://nano-gpt.com/api/v1/chat/completions"
GroqChatEndpoint = "https://api.groq.com/openai/v1/chat/completions"
NovitaChatEndpoint = "https://api.novita.ai/openai/v1/chat/completions"
AzureLegacyEndpointTemplate = "https://%s.openai.azure.com/openai/deployments/%s/chat/completions?api-version=%s"
AzureResponsesEndpointTemplate = "https://%s.openai.azure.com/openai/v1/responses"
AzureChatEndpointTemplate = "https://%s.openai.azure.com/openai/v1/chat/completions"
Expand All @@ -36,6 +37,7 @@ const (
GroqAPITokenSecretName = "GROQ_KEY"
AzureOpenAIAPITokenSecretName = "AZURE_OPENAI_KEY"
GoogleAIAPITokenSecretName = "GOOGLE_AI_KEY"
NovitaAPITokenSecretName = "NOVITA_API_KEY"
)

func resolveAIMode(requestedMode string, premium bool) (string, *wconfig.AIModeConfigType, error) {
Expand Down Expand Up @@ -125,6 +127,20 @@ func applyProviderDefaults(config *wconfig.AIModeConfigType) {
config.APITokenSecretName = GroqAPITokenSecretName
}
}
if config.Provider == uctypes.AIProvider_Novita {
if config.APIType == "" {
config.APIType = uctypes.APIType_OpenAIChat
}
if config.Endpoint == "" {
config.Endpoint = NovitaChatEndpoint
}
if config.APITokenSecretName == "" {
config.APITokenSecretName = NovitaAPITokenSecretName
}
if len(config.Capabilities) == 0 {
config.Capabilities = []string{uctypes.AICapabilityTools, uctypes.AICapabilityImages}
}
}
Comment on lines +130 to +143
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

Novita AI OpenAI-compatible API docs: does Novita support /v1/responses, or is /v1/chat/completions the only supported generation endpoint? Please provide the official documentation URL.

💡 Result:

Novita AI does not support the /v1/responses endpoint. The supported OpenAI-compatible generation endpoints are /v1/chat/completions and /v1/completions. No mention of /v1/responses appears in the official documentation across multiple pages. Official documentation URLs: - API Reference Overview: https://novita.ai/docs/api-reference/api-reference-overview (lists LLM APIs including Create Chat Completion and Create Completion) - LLM API Guide: https://novita.ai/docs/model-api/reference/llm/llm.html and https://novita.ai/docs/guides/llm-api (shows curl examples for /openai/v1/chat/completions and /openai/v1/completions) - List Models: https://novita.ai/docs/api-reference/model-apis-llm-list-models (compatible with OpenAI /v1/models)

Citations:


🏁 Script executed:

# Find definitions of APIType in the codebase
fd -t f "\.go$" | xargs rg "APIType_OpenAI|type APIType|const.*APIType" | head -50

Repository: wavetermdev/waveterm

Length of output: 3747


🏁 Script executed:

# Look for the uctypes package to understand available APIType values
fd -t f "uctypes" -o -t d "uctypes" | head -20

Repository: wavetermdev/waveterm

Length of output: 180


🏁 Script executed:

# Search for how Novita provider is configured elsewhere in the codebase
rg "AIProvider_Novita" -A 5 -B 5 | head -100

Repository: wavetermdev/waveterm

Length of output: 1389


🏁 Script executed:

# Find NovitaChatEndpoint definition
rg "NovitaChatEndpoint|NovitaAPITokenSecretName" -A 2 -B 2

Repository: wavetermdev/waveterm

Length of output: 1428


🏁 Script executed:

# Look for endpoint URL patterns and how APIType maps to endpoints
rg "chat/completions|/responses|Endpoint.*APIType" -B 3 -A 3 | head -100

Repository: wavetermdev/waveterm

Length of output: 6797


🏁 Script executed:

# Check the usechat-backend.go to see how APIType_OpenAIResponses vs APIType_OpenAIChat are handled
cat pkg/aiusechat/usechat-backend.go | head -200

Repository: wavetermdev/waveterm

Length of output: 8505


🏁 Script executed:

# Look for validation of APIType/endpoint combinations
rg "isValidAzureResourceName|isAzureAPIType|isOpenAIAPIType" -B 2 -A 10

Repository: wavetermdev/waveterm

Length of output: 3454


🏁 Script executed:

# Check if there's any validation or constraint for Novita in particular
rg -A 20 "func.*Novita|Novita.*func" pkg/aiusechat/usechat-mode.go

Repository: wavetermdev/waveterm

Length of output: 46


🏁 Script executed:

# Look at OpenAI provider configuration to see if they have similar constraints
rg -B 5 -A 15 "AIProvider_OpenAI {" pkg/aiusechat/usechat-mode.go

Repository: wavetermdev/waveterm

Length of output: 165


🏁 Script executed:

# Look for the complete usechat-mode.go file around the Novita section to see full context
sed -n '120,200p' pkg/aiusechat/usechat-mode.go

Repository: wavetermdev/waveterm

Length of output: 2840


Constrain Novita provider to OpenAI Chat API to prevent endpoint/request format mismatches.

Novita's OpenAI-compatible API only supports /v1/chat/completions and /v1/completions endpoints—not /v1/responses. The current code defaults to Chat Completions but allows ai:apitype to be manually set to openai-responses, which would cause runtime 4xx failures if the request formatter doesn't match the actual endpoint.

Suggested hardening
 if config.Provider == uctypes.AIProvider_Novita {
-	if config.APIType == "" {
-		config.APIType = uctypes.APIType_OpenAIChat
-	}
+	// Novita only supports chat-completions; force to prevent APIType/endpoint mismatch.
+	if config.APIType == "" || config.APIType != uctypes.APIType_OpenAIChat {
+		config.APIType = uctypes.APIType_OpenAIChat
+	}
 	if config.Endpoint == "" {
 		config.Endpoint = NovitaChatEndpoint
 	}
 	if config.APITokenSecretName == "" {
 		config.APITokenSecretName = NovitaAPITokenSecretName
 	}
 	if len(config.Capabilities) == 0 {
 		config.Capabilities = []string{uctypes.AICapabilityTools, uctypes.AICapabilityImages}
 	}
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if config.Provider == uctypes.AIProvider_Novita {
if config.APIType == "" {
config.APIType = uctypes.APIType_OpenAIChat
}
if config.Endpoint == "" {
config.Endpoint = NovitaChatEndpoint
}
if config.APITokenSecretName == "" {
config.APITokenSecretName = NovitaAPITokenSecretName
}
if len(config.Capabilities) == 0 {
config.Capabilities = []string{uctypes.AICapabilityTools, uctypes.AICapabilityImages}
}
}
if config.Provider == uctypes.AIProvider_Novita {
// Novita only supports chat-completions; force to prevent APIType/endpoint mismatch.
if config.APIType == "" || config.APIType != uctypes.APIType_OpenAIChat {
config.APIType = uctypes.AIType_OpenAIChat
}
if config.Endpoint == "" {
config.Endpoint = NovitaChatEndpoint
}
if config.APITokenSecretName == "" {
config.APITokenSecretName = NovitaAPITokenSecretName
}
if len(config.Capabilities) == 0 {
config.Capabilities = []string{uctypes.AICapabilityTools, uctypes.AICapabilityImages}
}
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pkg/aiusechat/usechat-mode.go` around lines 130 - 143, When config.Provider
equals uctypes.AIProvider_Novita, force config.APIType to
uctypes.APIType_OpenAIChat unconditionally (do not allow a manual ai:apitype
override such as openai-responses) to prevent mismatched request/endpoint
behavior; update the block around config.Provider/uctypes.AIProvider_Novita to
always set config.APIType = uctypes.APIType_OpenAIChat (overwriting any existing
value) and optionally add a short comment explaining Novita only supports OpenAI
chat/completions endpoints.

if config.Provider == uctypes.AIProvider_AzureLegacy {
if config.AzureAPIVersion == "" {
config.AzureAPIVersion = AzureLegacyDefaultAPIVersion
Expand Down
2 changes: 1 addition & 1 deletion pkg/wconfig/settingsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ type AIModeConfigType struct {
DisplayOrder float64 `json:"display:order,omitempty"`
DisplayIcon string `json:"display:icon,omitempty"`
DisplayDescription string `json:"display:description,omitempty"`
Provider string `json:"ai:provider,omitempty" jsonschema:"enum=wave,enum=google,enum=groq,enum=openrouter,enum=nanogpt,enum=openai,enum=azure,enum=azure-legacy,enum=custom"`
Provider string `json:"ai:provider,omitempty" jsonschema:"enum=wave,enum=google,enum=groq,enum=openrouter,enum=nanogpt,enum=openai,enum=azure,enum=azure-legacy,enum=novita,enum=custom"`
APIType string `json:"ai:apitype,omitempty" jsonschema:"enum=google-gemini,enum=openai-responses,enum=openai-chat"`
Model string `json:"ai:model,omitempty"`
ThinkingLevel string `json:"ai:thinkinglevel,omitempty" jsonschema:"enum=low,enum=medium,enum=high"`
Expand Down
1 change: 1 addition & 0 deletions schema/waveai.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"openai",
"azure",
"azure-legacy",
"novita",
"custom"
]
},
Expand Down