`makeHTTPClient(proxyURL)` had been duplicated across AI backends with
equivalent behavior. This change consolidates the logic into a single
helper in `aiutil` and updates backends to consume it, then removes
backend-local tests that only re-verified that shared utility behavior.
- **Shared client construction**
- Added `aiutil.MakeHTTPClient(proxyURL string) (*http.Client, error)`
in `pkg/aiusechat/aiutil/aiutil.go`.
- Standardizes proxy parsing and `http.Transport.Proxy` setup in one
place.
- Keeps streaming-safe client semantics (`Timeout: 0`) and existing
invalid proxy URL error behavior.
- **Backend refactor**
- Removed duplicated client/proxy setup blocks from:
- `pkg/aiusechat/openaichat/openaichat-backend.go`
- `pkg/aiusechat/gemini/gemini-backend.go`
- `pkg/aiusechat/openai/openai-backend.go`
- `pkg/aiusechat/anthropic/anthropic-backend.go`
- Replaced with direct calls to the shared helper.
- **Test cleanup**
- Deleted backend tests that only covered basic proxy client creation
and no backend-specific behavior:
- `pkg/aiusechat/openaichat/openaichat-backend_test.go`
- `pkg/aiusechat/gemini/gemini-backend_test.go`
```go
httpClient, err := aiutil.MakeHTTPClient(chatOpts.Config.ProxyURL)
if err != nil {
return nil, nil, nil, err
}
resp, err := httpClient.Do(req)
```
<!-- START COPILOT CODING AGENT TIPS -->
---
💬 We'd love your input! Share your thoughts on Copilot coding agent in
our [2 minute survey](https://gh.io/copilot-coding-agent-survey).
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
`WriteWaveHomeConfigFile()` previously used direct `os.WriteFile`, which
can expose truncation/partial-write states to the JSON file watcher.
This change switches config persistence to temp-file + rename semantics
and serializes writes through a single process-wide lock for config file
writes.
- **Atomic file write helper**
- Added `AtomicWriteFile()` in `pkg/util/fileutil/fileutil.go`.
- Writes to `<filename>.tmp` in the same directory, then renames to the
target path.
- Performs temp-file cleanup on error paths.
- Introduced a shared suffix constant (`TempFileSuffix`) used by
implementation/tests.
- **Config write path update**
- Updated `WriteWaveHomeConfigFile()` in `pkg/wconfig/settingsconfig.go`
to:
- Use a package-level mutex (`configWriteLock`) so only one config write
runs at a time (across all config files).
- Call `fileutil.AtomicWriteFile(...)` instead of direct
`os.WriteFile(...)`.
- **Focused coverage for atomic behavior**
- Added `pkg/util/fileutil/fileutil_test.go` with tests for:
- Successful atomic write (target file contains expected payload and no
leftover `.tmp` file).
- Rename-failure path cleanup (temp file is removed).
```go
func WriteWaveHomeConfigFile(fileName string, m waveobj.MetaMapType) error {
configWriteLock.Lock()
defer configWriteLock.Unlock()
fullFileName := filepath.Join(wavebase.GetWaveConfigDir(), fileName)
barr, err := jsonMarshalConfigInOrder(m)
if err != nil {
return err
}
return fileutil.AtomicWriteFile(fullFileName, barr, 0644)
}
```
<!-- START COPILOT CODING AGENT TIPS -->
---
🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
This change adds first-class `groq` provider support to Wave AI mode
resolution and documents it in the Wave AI modes guide. Users can now
configure Groq modes via `ai:provider` with provider defaults applied
automatically.
- **Provider support in backend config resolution**
- Added `groq` as a recognized AI provider constant.
- Added Groq provider defaults in mode resolution:
- `ai:apitype`: `openai-chat`
- `ai:endpoint`: `https://api.groq.com/openai/v1/chat/completions`
- `ai:apitokensecretname`: `GROQ_KEY`
- **Schema/config surface update**
- Extended `AIModeConfigType` provider enum to include `groq`, so
`ai:provider: "groq"` is valid in Wave AI config.
- **Documentation updates (`waveai-modes.mdx`)**
- Added `groq` to supported providers.
- Added a Groq-specific configuration example and default behavior
notes.
- Updated provider reference and capability guidance to include Groq.
- **Focused coverage**
- Added a targeted unit test for Groq provider default application in
`applyProviderDefaults`.
```json
{
"groq-kimi-k2": {
"display:name": "Groq - Kimi K2",
"ai:provider": "groq",
"ai:model": "moonshotai/kimi-k2-instruct"
}
}
```
<!-- START COPILOT CODING AGENT TIPS -->
---
💡 You can make Copilot smarter by setting up custom instructions,
customizing its development environment and configuring Model Context
Protocol (MCP) servers. Learn more [Copilot coding agent
tips](https://gh.io/copilot-coding-agent-tips) in the docs.
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
This PR adds a new app setting to control whether block focus follows
cursor movement:
- `app:focusfollowscursor: "off" | "on" | "term"`
- Default is `"off"` (no behavior change unless enabled)
## What changed
- Added hover-focus behavior on block pointer enter.
- Added guardrails so hover focus does not trigger when:
- touch input is used
- pointer buttons are pressed (drag/select scenarios)
- modal is open
- pointer events are disabled
- block is resizing
- Added config key plumbing across settings types and schema:
- `pkg/wconfig/settingsconfig.go`
- `pkg/wconfig/metaconsts.go`
- `schema/settings.json`
- `pkg/wconfig/defaultconfig/settings.json` ->
`"app:focusfollowscursor": "off"`
- Added docs for the new key and default example:
- `docs/docs/config.mdx`
## Behavior
- `"off"`: do not focus on cursor movement
- `"on"`: focus follows cursor for all block types
- `"term"`: focus follows cursor only for terminal blocks
This change adds an optional `workspaces` field to widget config entries
so widgets can be scoped to specific workspace UUIDs. Widgets with no
`workspaces` field (or an empty array) continue to render globally,
preserving current `widgets.json` behavior.
- **Config model updates**
- Added `workspaces []string` to `wconfig.WidgetConfigType` with
`json:"workspaces,omitempty"`.
- Updated frontend generated type `WidgetConfigType` with `workspaces?:
string[]`.
- **Sidebar widget filtering**
- `frontend/app/workspace/widgets.tsx` now applies workspace-aware
filtering when building the sidebar widget list:
- include if `workspaces` is missing or empty
- include if current `workspace.oid` is present in `workspaces`
- otherwise exclude
- Existing `defwidget@ai` filtering logic remains intact.
- **Isolated filtering logic + coverage**
- Added `frontend/app/workspace/widgetfilter.ts` with:
- `shouldIncludeWidgetForWorkspace(widget, workspaceId)`
- Added focused tests in `frontend/app/workspace/widgetfilter.test.ts`
for:
- missing/empty `workspaces`
- matching/non-matching workspace IDs
- missing active workspace ID
```ts
function shouldIncludeWidgetForWorkspace(widget: WidgetConfigType, workspaceId?: string): boolean {
const workspaces = widget.workspaces;
return !Array.isArray(workspaces) || workspaces.length === 0 || (workspaceId != null && workspaces.includes(workspaceId));
}
```
- **Screenshot**
-
<screenshot>https://github.com/user-attachments/assets/b1727003-793b-4eff-8fc1-00eac9c50b83</screenshot>
<!-- START COPILOT CODING AGENT TIPS -->
---
🔒 GitHub Advanced Security automatically protects Copilot coding agent
pull requests. You can protect all pull requests by enabling Advanced
Security for your repositories. [Learn more about Advanced
Security.](https://gh.io/cca-advanced-security)
---------
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
Co-authored-by: sawka <mike@commandline.dev>
- Add tab:confirmclose boolean config option to SettingsType (Go),
schema/settings.json, and gotypes.d.ts
- Update close-tab IPC handler to use ipcMain.handle (async) and accept
confirmClose param
- Show a native confirmation dialog via dialog.showMessageBoxSync when
confirmClose is true
- Update preload.ts to use ipcRenderer.invoke for close-tab, returning
Promise<boolean>
- Update closeTab type signature in custom.d.ts to return
Promise<boolean>
- Update tabbar.tsx and keymodel.ts to await closeTab result and only
delete layout model on confirmed close
- Document tab:confirmclose in docs/docs/config.mdx
---------
Co-authored-by: kiloconnect[bot] <240665456+kiloconnect[bot]@users.noreply.github.com>
| app:hideaibutton <VersionBadge version="v0.14" /> | bool | Set to true
to hide the AI button in the tab bar (defaults to false) |
| app:disablectrlshiftarrows <VersionBadge version="v0.14" /> | bool |
Set to true to disable Ctrl+Shift+Arrow keybindings for block navigation
(defaults to false) |
| app:disablectrlshiftdisplay <VersionBadge version="v0.14" /> | bool |
Set to true to disable the Ctrl+Shift visual indicator display (defaults
to false) |
This pull request introduces a new `test-conn` command-line tool for
testing SSH connection flows and user input handling, along with
improvements to user input provider extensibility and several
configuration and validation enhancements.
* New `test-conn` CLI Tool
* User Input Provider Abstraction
* Refactored user input handling to use a pluggable `UserInputProvider`
interface, with a default `FrontendProvider` and the ability to set a
custom provider
* AI Configuration and Verbosity updates
* Enforced that a `SwapToken` must be present in `CommandOptsType` when
starting a remote shell with wsh, improving validation and error
handling. (`pkg/shellexec/shellexec.go`)
* Improved config directory watcher logic to log the config directory
path and avoid logging errors for non-existent subdirectories
* Track wave version when job was created (for future backward compat)
* New Flyover Menu off of "shell durability" icon. Help + Actions + UX
* Bug with conn typeahead not closing when clicking disconnect
* Auto-reconnect jobs that have been disconnected (check for "gone"
state)
* Disable tab indicator stuff (only indicates tab not block)
* Fix bug with dev logging path on connserver
* Fix bugs with restarting blockcontrollers on startup
* Fix bugs with getting HasExited status from job manager
* Fix startup files, quoting, tilde, etc in start job flow
* ...
# Add configurable verbosity for OpenAI Responses API
Fixes#2775
## Problem
Models like `gpt-5.2-codex` and other newer OpenAI models only support
`medium` reasoning and verbosity levels, but the codebase was using
`low` by default. This caused 400 Bad Request errors:
```
Failed to stream openai-responses chat: openai 400 Bad Request:
Unsupported value: 'low' is not supported with the 'gpt-5.2-codex' model.
Supported values are: 'medium'.
```
## Solution
This PR implements a scalable, user-configurable approach instead of
hardcoding model-specific constraints:
1. **Changed default verbosity** from `"low"` to `"medium"` - more
widely supported across OpenAI models
2. **Added `ai:verbosity` config option** - allows users to configure
verbosity per model in `waveai.json`
3. **Changed rate limit fallback** from `low` to `medium` thinking level
for better compatibility
4. **Removed hardcoded model checks** - solution is scalable for future
models
## Changes
### Backend Changes
- `pkg/aiusechat/openai/openai-convertmessage.go` - Use configurable
verbosity with safe defaults
- `pkg/aiusechat/uctypes/uctypes.go` - Add `Verbosity` field to
`AIOptsType`
- `pkg/aiusechat/usechat.go` - Pass verbosity from config to options
- `pkg/wconfig/settingsconfig.go` - Add `Verbosity` to
`AIModeConfigType`
### Schema Changes
- `schema/waveai.json` - Add `ai:verbosity` with enum values
(low/medium/high)
- `frontend/types/gotypes.d.ts` - Auto-generated TypeScript types
### Configuration Example
Users can now configure both thinking level and verbosity per model:
```json
{
"openai-gpt52-codex": {
"display:name": "GPT-5.2 Codex",
"ai:provider": "openai",
"ai:model": "gpt-5.2-codex",
"ai:thinkinglevel": "medium",
"ai:verbosity": "medium"
}
}
```
Working on bug fixes and UX. Streams restarting, fixed lots of bugs,
timing issues, concurrency bugs. Get status shipped to the FE to drive
"shield" state display. Deal with stale streams.
Also big UX changes to the block headers. Specialize the terminal
headers to prioritize the connection (sense of place), remove old
terminal icon and word "Terminal" from the header. Also drop "Web" and
"Preview" labels on web/preview blocks.
Added `wsh focusblock` command.
* Adds a Confirm on Quit dialog (and new config to disable it)
* New MacOS keybinding for Cmd:ArrowLeft/Cmd:ArrowRight to send Ctrl-A
and Ctrl-E respectively
* Fix Ctrl-V regression on windows to allow config setting to override
* Remove questionnaire in bug template
* Full featured tab indicators -- icon, color, priority, clear features.
Can be manipulated by new `wsh tabindicator` command
* Hook up BEL to new tab indicator system. BEL can now play a sound
and/or set an indicator (controlled by two new config options)
- [x] Add new API type constant for Google Gemini in uctypes.go
- [x] Create gemini directory under pkg/aiusechat/
- [x] Implement gemini-backend.go with streaming chat support
- [x] Implement gemini-convertmessage.go for message conversion
- [x] Implement gemini-types.go for Google-specific types
- [x] Add gemini backend to usechat-backend.go
- [x] Support tool calling with structured arguments
- [x] Support image upload (base64 inline data)
- [x] Support PDF upload (base64 inline data)
- [x] Support file upload (text files, directory listings)
- [x] Build verification passed
- [x] Add documentation for Gemini backend usage
- [x] Security scan passed (CodeQL found 0 issues)
- [x] Code review passed with no comments
- [x] Revert tsunami demo go.mod/go.sum files (per feedback - twice)
- [x] Add `--gemini` flag to main-testai.go for testing
- [x] Fix schema validation for tool calling (clean unsupported fields)
- [x] Preserve non-map property values in schema cleaning
## Summary
Successfully implemented a complete Google Gemini backend for WaveTerm's
AI chat system. The implementation:
- **Follows existing patterns**: Matches the structure of OpenAI and
Anthropic backends
- **Fully featured**: Supports all required capabilities including tool
calling, images, PDFs, and files
- **Properly tested**: Builds successfully with no errors or warnings
- **Secure**: Passed CodeQL security scanning with 0 issues
- **Well documented**: Includes comprehensive package documentation with
usage examples
- **Minimal changes**: Only affects backend code under pkg/aiusechat
(tsunami demo files reverted twice)
- **Testable**: Added `--gemini` flag to main-testai.go for easy testing
with SSE output
- **Schema compatible**: Cleans JSON schemas to remove fields
unsupported by Gemini API while preserving valid structure
## Testing
To test the Gemini backend using main-testai.go:
```bash
export GOOGLE_APIKEY="your-api-key"
cd cmd/testai
go run main-testai.go --gemini 'What is 2+2?'
go run main-testai.go --gemini --model gemini-1.5-pro 'Explain quantum computing'
go run main-testai.go --gemini --tools 'Help me configure GitHub Actions monitoring'
```
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: sawka <2722291+sawka@users.noreply.github.com>
New UI Setting: Launch On Fullscreen
A new option has been added to the view menu allowing users to
enable fullscreen mode automatically when Wave launches. This setting is
persistent and can be toggled on a per-user basis.
also updates ROADMAP.md, and fixes a node pruning bug on the FE, and
adds a new diff viewer that we can view the write_text_file and
edit_text_file diffs in. adds a backup file system that can be used to restore AI edited files back to their original states.
While there is significant overlap between SettingsType and
AiSettingsType, they are distinct entities and should be treated as such
until more changes have been made.
This allows code generation to properly embed structs when embedded in
the original types. It affects the generation of `gotypes.d.ts` and
`metaconsts.go`.
Additionally, the `AiSettingsType` has been split off and embedded into
the original `SettingsType` to make schema generation easier.
👋 Hello, I'm not sure if this warranted an Issue first but it seemed
small enough to just raise a PR. I'm happy to add something to the
documentation as well if you agree with the proposal.
There are some widgets that I'd rather not be displayed in the sidebar -
at the moment these are default widgets for which I cannot see any
existing means of omitting them via configuration. I'm proposing a
`display:hidden` field on the widget settings such that I can configure
the following:
```json
{
"defwidget@ai": {
"display:hidden": true
}
}
```
I'm considering this option to be distinct from any means of outright
"disabling" the widget - that is to say that I've not chosen to filter
the widgets from the configuration because I'm not fully aware of the
project goals. Where for example I imagine that it might be useful to be
able to interact with a widget or it's config via the CLI or shortcut
regardless of visibility?
<img width="1421" alt="example"
src="https://github.com/user-attachments/assets/7cafa942-727d-4140-8940-38b4022f2ef0"
/>
lots of misc connection refactoring / fixes:
* adds blocklogger as a way to writing logging information from the backend directly to the a terminal block
* use blocklogger in conncontroller
* use blocklogger in sshclient
* fix remote name in password prompt
* use sh -c to get around shell weirdness
* remove cmd.exe special cases
* use GetWatcher().GetFullConfig() rather than re-reading the config file
* change order of things we do when establishing a connection. ask for wsh up front. then do domain socket, then connserver
* reduce number of sessions required in the common case when wsh is already installed. running the connserver is now a "multi-command" which checks if it is installed, then asks for the version
* send jwt token over stdin instead of in initial command string
* fix focus bug for frontend conn modal
* track more information in connstatus
* simplify wshinstall function
* add nowshreason
* other misc cleanup