Skip to content
Merged
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
12 changes: 6 additions & 6 deletions docs/docs/waveai-modes.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ Wave AI now supports provider-based configuration which automatically applies se

### Supported Providers

- **`openai`** - OpenAI API (automatically configures endpoint and secret name)
- **`openrouter`** - OpenRouter API (automatically configures endpoint and secret name)
- **`google`** - Google AI (Gemini)
- **`azure`** - Azure OpenAI Service (modern API)
- **`azure-legacy`** - Azure OpenAI Service (legacy deployment API)
- **`custom`** - Custom API endpoint (fully manual configuration)
- **`openai`** - OpenAI API (automatically configures endpoint and secret name) [[see example](#openai)]
- **`openrouter`** - OpenRouter API (automatically configures endpoint and secret name) [[see example](#openrouter)]
- **`google`** - Google AI (Gemini) [[see example](#google-ai-gemini)]
- **`azure`** - Azure OpenAI Service (modern API) [[see example](#azure-openai-modern-api)]
- **`azure-legacy`** - Azure OpenAI Service (legacy deployment API) [[see example](#azure-openai-legacy-deployment-api)]
- **`custom`** - Custom API endpoint (fully manual configuration) [[see examples](#local-model-examples)]

### Supported API Types

Expand Down
281 changes: 178 additions & 103 deletions frontend/app/aipanel/aimode.tsx

Large diffs are not rendered by default.

55 changes: 30 additions & 25 deletions frontend/app/aipanel/aipanelinput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import { formatFileSizeError, isAcceptableFile, validateFileSize } from "@/app/aipanel/ai-utils";
import { waveAIHasFocusWithin } from "@/app/aipanel/waveai-focus-utils";
import { type WaveAIModel } from "@/app/aipanel/waveai-model";
import { Tooltip } from "@/element/tooltip";
import { cn } from "@/util/util";
import { useAtom, useAtomValue } from "jotai";
import { memo, useCallback, useEffect, useRef } from "react";
Expand Down Expand Up @@ -145,31 +146,35 @@ export const AIPanelInput = memo(({ onSubmit, status, model }: AIPanelInputProps
style={{ fontSize: "13px" }}
rows={2}
/>
<button
type="button"
onClick={handleUploadClick}
className={cn(
"absolute bottom-6 right-1 w-3.5 h-3.5 transition-colors flex items-center justify-center text-gray-400 hover:text-accent cursor-pointer"
)}
>
<i className="fa fa-paperclip text-xs"></i>
</button>
<button
type="submit"
disabled={status !== "ready" || !input.trim()}
className={cn(
"absolute bottom-2 right-1 w-3.5 h-3.5 transition-colors flex items-center justify-center",
status !== "ready" || !input.trim()
? "text-gray-400"
: "text-accent/80 hover:text-accent cursor-pointer"
)}
>
{status === "streaming" ? (
<i className="fa fa-spinner fa-spin text-xs"></i>
) : (
<i className="fa fa-paper-plane text-xs"></i>
)}
</button>
<Tooltip content="Attach files" placement="top" divClassName="absolute bottom-6.5 right-1">
<button
type="button"
onClick={handleUploadClick}
className={cn(
"w-5 h-5 transition-colors flex items-center justify-center text-gray-400 hover:text-accent cursor-pointer"
)}
>
<i className="fa fa-paperclip text-sm"></i>
</button>
</Tooltip>
<Tooltip content="Send message (Enter)" placement="top" divClassName="absolute bottom-1.5 right-1">
<button
type="submit"
disabled={status !== "ready" || !input.trim()}
className={cn(
"w-5 h-5 transition-colors flex items-center justify-center",
status !== "ready" || !input.trim()
? "text-gray-400"
: "text-accent/80 hover:text-accent cursor-pointer"
)}
>
{status === "streaming" ? (
<i className="fa fa-spinner fa-spin text-sm"></i>
) : (
<i className="fa fa-paper-plane text-sm"></i>
)}
</button>
</Tooltip>
</div>
</form>
</div>
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/aipanel/aipanelmessages.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export const AIPanelMessages = memo(({ messages, status, onContextMenu }: AIPane
onContextMenu={onContextMenu}
>
<div className="mb-2">
<AIModeDropdown />
<AIModeDropdown compatibilityMode={true} />
</div>
{messages.map((message, index) => {
const isLastMessage = index === messages.length - 1;
Expand Down
10 changes: 10 additions & 0 deletions frontend/app/aipanel/waveai-model.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,16 @@ export class WaveAIModel {
await createBlock(blockDef, false, true);
}

async openWaveAIConfig() {
const blockDef: BlockDef = {
meta: {
view: "waveconfig",
file: "waveai.json",
},
};
await createBlock(blockDef, false, true);
}

openRestoreBackupModal(toolcallid: string) {
globalStore.set(this.restoreBackupModalToolCallId, toolcallid);
}
Expand Down
10 changes: 7 additions & 3 deletions frontend/app/view/waveconfig/waveconfig-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { RpcApi } from "@/app/store/wshclientapi";
import { TabRpcClient } from "@/app/store/wshrpcutil";
import { SecretsContent } from "@/app/view/waveconfig/secretscontent";
import { WaveConfigView } from "@/app/view/waveconfig/waveconfig";
import { WaveAIVisualContent } from "@/app/view/waveconfig/waveaivisual";
import { isWindows } from "@/util/platformutil";
import { base64ToString, stringToBase64 } from "@/util/util";
import { atom, type PrimitiveAtom } from "jotai";
import type * as MonacoTypes from "monaco-editor/esm/vs/editor/editor.api";
Expand All @@ -22,6 +22,7 @@ export type ConfigFile = {
path: string;
language?: string;
deprecated?: boolean;
description?: string;
docsUrl?: string;
validator?: ConfigValidator;
isSecrets?: boolean;
Expand Down Expand Up @@ -77,10 +78,11 @@ const configFiles: ConfigFile[] = [
path: "connections.json",
language: "json",
docsUrl: "https://docs.waveterm.dev/connections",
description: isWindows() ? "SSH hosts and WSL distros" : "SSH hosts",
hasJsonView: true,
},
{
name: "Widgets",
name: "Sidebar Widgets",
path: "widgets.json",
language: "json",
docsUrl: "https://docs.waveterm.dev/customwidgets",
Expand All @@ -90,12 +92,14 @@ const configFiles: ConfigFile[] = [
name: "Wave AI Modes",
path: "waveai.json",
language: "json",
description: "Local models and BYOK",
docsUrl: "https://docs.waveterm.dev/waveai-modes",
validator: validateWaveAiJson,
hasJsonView: true,
// visualComponent: WaveAIVisualContent,
},
{
name: "Backgrounds",
name: "Tab Backgrounds",
path: "presets/bg.json",
language: "json",
docsUrl: "https://docs.waveterm.dev/presets#background-configurations",
Expand Down
28 changes: 17 additions & 11 deletions frontend/app/view/waveconfig/waveconfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,16 @@ const ConfigSidebar = memo(({ model }: ConfigSidebarProps) => {
<div
key={file.path}
onClick={() => handleFileSelect(file)}
className={`px-4 py-2 border-b border-border cursor-pointer transition-colors whitespace-nowrap overflow-hidden text-ellipsis ${
className={`px-4 py-2 border-b border-border cursor-pointer transition-colors ${
selectedFile?.path === file.path ? "bg-accentbg text-primary" : "hover:bg-secondary/50"
}`}
>
{file.name}
<div className="whitespace-nowrap overflow-hidden text-ellipsis">{file.name}</div>
{file.description && (
<div className="text-xs text-muted mt-0.5 whitespace-nowrap overflow-hidden text-ellipsis">
{file.description}
</div>
)}
</div>
))}
{deprecatedConfigFiles.length > 0 && (
Expand Down Expand Up @@ -168,15 +173,16 @@ const WaveConfigView = memo(({ blockId, model }: ViewComponentProps<WaveConfigVi
{selectedFile.name}
</div>
{selectedFile.docsUrl && (
<a
href={`${selectedFile.docsUrl}?ref=waveconfig`}
target="_blank"
rel="noopener noreferrer"
className="!text-muted-foreground hover:!text-primary transition-colors ml-1 shrink-0 cursor-pointer"
title="View documentation"
>
<i className="fa fa-book text-sm" />
</a>
<Tooltip content="View documentation">
<a
href={`${selectedFile.docsUrl}?ref=waveconfig`}
target="_blank"
rel="noopener noreferrer"
className="!text-muted-foreground hover:!text-primary transition-colors ml-1 shrink-0 cursor-pointer"
>
<i className="fa fa-book text-sm" />
</a>
</Tooltip>
)}
<div className="text-xs text-muted-foreground font-mono pb-0.5 ml-1 truncate @max-w450:hidden">
{selectedFile.path}
Expand Down
3 changes: 2 additions & 1 deletion frontend/types/gotypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,13 @@ declare global {
"ai:model"?: string;
"ai:thinkinglevel"?: string;
"ai:endpoint"?: string;
"ai:apiversion"?: string;
"ai:azureapiversion"?: string;
"ai:apitoken"?: string;
"ai:apitokensecretname"?: string;
"ai:azureresourcename"?: string;
"ai:azuredeployment"?: string;
"ai:capabilities"?: string[];
"ai:switchcompat"?: string[];
"waveai:cloud"?: boolean;
"waveai:premium"?: boolean;
};
Expand Down
9 changes: 6 additions & 3 deletions pkg/wconfig/defaultconfig/waveai.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"ai:apitype": "openai-responses",
"ai:model": "gpt-5-mini",
"ai:thinkinglevel": "low",
"ai:capabilities": ["tools", "images", "pdfs"]
"ai:capabilities": ["tools", "images", "pdfs"],
"ai:switchcompat": ["wavecloud"]
},
"waveai@balanced": {
"display:name": "Balanced",
Expand All @@ -20,7 +21,8 @@
"ai:model": "gpt-5.1",
"ai:thinkinglevel": "low",
"ai:capabilities": ["tools", "images", "pdfs"],
"waveai:premium": true
"waveai:premium": true,
"ai:switchcompat": ["wavecloud"]
},
"waveai@deep": {
"display:name": "Deep",
Expand All @@ -32,6 +34,7 @@
"ai:model": "gpt-5.1",
"ai:thinkinglevel": "medium",
"ai:capabilities": ["tools", "images", "pdfs"],
"waveai:premium": true
"waveai:premium": true,
"ai:switchcompat": ["wavecloud"]
}
}
1 change: 1 addition & 0 deletions pkg/wconfig/settingsconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ type AIModeConfigType struct {
AzureResourceName string `json:"ai:azureresourcename,omitempty"`
AzureDeployment string `json:"ai:azuredeployment,omitempty"`
Capabilities []string `json:"ai:capabilities,omitempty" jsonschema:"enum=pdfs,enum=images,enum=tools"`
SwitchCompat []string `json:"ai:switchcompat,omitempty"`
WaveAICloud bool `json:"waveai:cloud,omitempty"`
WaveAIPremium bool `json:"waveai:premium,omitempty"`
}
Expand Down
10 changes: 8 additions & 2 deletions schema/waveai.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
"ai:apitype": {
"type": "string",
"enum": [
"anthropic-messages",
"google-gemini",
"openai-responses",
"openai-chat"
]
Expand All @@ -49,7 +49,7 @@
"ai:endpoint": {
"type": "string"
},
"ai:apiversion": {
"ai:azureapiversion": {
"type": "string"
},
"ai:apitoken": {
Expand All @@ -75,6 +75,12 @@
},
"type": "array"
},
"ai:switchcompat": {
"items": {
"type": "string"
},
"type": "array"
},
"waveai:cloud": {
"type": "boolean"
},
Expand Down
Loading