Skip to content

Valet 0.4.0

Latest

Choose a tag to compare

@IbrahimIrfan IbrahimIrfan released this 09 Nov 21:23

Valet 0.4.0 lets you pick the model for each chat, adds slash commands and @mentions, and adds voice.

docker pull ghcr.io/askvalet/valet:0.4.0

Configs from 0.3.0 work as they are. Everything below is off until you add it.

Highlights

Pick the model for each chat

You can list more models under assistant.models. Each chat can use any of them, and a new chat starts on the main one again. auto adds every model your server lists. A { auto: true, … } entry lists another server, like OpenRouter or Anthropic. Past eight models, the menu gets a search box. The Reasoning menu beside it sets how much the model thinks (Auto, Off, Low, Medium, High), for that chat only. Background calls always use the main model, and the server only accepts models you configured or that a listed server offers.

The model menu with a search typed: Fast under Configured, then the server's own models

assistant:
  baseURL: http://ollama:11434/v1
  model: qwen3:8b                      # the default, and what background calls use
  models:
    - { name: Deep, model: qwen3:32b, reasoning: high }
    - { name: Claude, provider: anthropic, model: claude-sonnet-5-5, apiKey: "${ANTHROPIC_API_KEY}" }
    - auto                             # everything the main server lists
    - { auto: true, name: OpenRouter, baseURL: https://openrouter.ai/api/v1, apiKey: "${OPENROUTER_KEY}" }

Docs: More than one model

Slash commands, @mentions and your own commands

Type / at the start of the message box for /model, /reasoning, /new, /compact and /help. These run in Valet straight away, without the model and without using tokens. Type @ to name an integration, and its tools are used first. Commands you add under chat.commands show up in the / menu, in ⌘K and in /help. They go through the chat like anything you type, with the same access and approvals.

The / menu open above the message box

chat:
  commands:
    morning-brief:
      description: Last night, today's calendar and Hacker News
      prompt: >-
        Give me my morning brief: what happened overnight, what's on my calendar today,
        and the Hacker News stories worth reading. Keep it short, problems first.
    watch: { prompt: "Add {input} to my watchlist and tell me when it's out", reasoning: low }
    blocks: { prompt: "Who's blocking the most today?", tools: [dns] }

Docs: Commands and mentions

Voice

The voice block adds a mic to the message box and a speaker under each answer. It works with any server that speaks the OpenAI audio API. Your words go into the box so you can check them before sending. The speaker reads the answer's text, without markdown, tables or cards. The browser only ever talks to Valet, so the speech server's address and key stay on your server. Nothing is stored.

An answer being read aloud: the speaker under it has turned into a stop button

On your own network, with Speaches (runs well on a CPU):

voice:
  stt: { baseURL: http://speaches:8000/v1, model: Systran/faster-distil-whisper-small.en, language: en }
  tts: { model: speaches-ai/Kokoro-82M-v1.0-ONNX, voice: af_heart }

With OpenAI: voice: { stt: { baseURL: https://api.openai.com/v1, apiKey: "${OPENAI_API_KEY}", model: gpt-4o-mini-transcribe }, tts: { model: gpt-4o-mini-tts, voice: alloy } }

Docs: Voice. Hear it in the demo: press the speaker under any answer.

Pi-hole: which devices

Pi-hole's tool now lists the devices with the most blocked queries, by name where Pi-hole or its local DNS records know one. Give it a domain and it tells you which devices looked it up lately. Ask "Which devices asked for doubleclick.net lately?" or "Who's blocking the most today?".

Docs: Pi-hole

Also

  • If you ask something else instead of answering an approval card, that now counts as a no. The card goes away, its step reads Skipped, and nothing runs. Before, the card could stay pressable and spin forever.
  • An answer's copy, ask again and read-aloud buttons show when you hover over it, so long chats look cleaner. On a phone, the latest answer keeps them and a tap shows them on the others.
  • The chat says "Working…" while it waits and "Thinking…" only when the model is actually reasoning.
  • The model, the reasoning level and the context meter moved from the chat's header to a row under the message box.
  • The chat's menus are solid now, so they're easy to read over a wallpaper.
  • The message box says "Type / for commands".
  • The demo has voice: answers are read aloud, and the mic links to the setup docs.

Full changelog

Added

  • assistant.models: more models to pick from in the chat, for one chat at a time. Each entry needs only model; what it leaves out comes from the main settings (the address only to the same provider, the key only to the same server). The server accepts only a configured choice, the context meter follows the chosen model's window, and background calls stay on the main model. config check names duplicate names and an Anthropic choice without a key. Without models nothing changes.

  • auto in assistant.models (or models: auto): the chat also offers every model the main server lists at /models. Valet asks the server itself, so its key stays on the server, and keeps the list five minutes, with a refresh in the menu; if the server doesn't answer, the configured models still work and the menu says so. A request may name only the default, a configured model or one in the latest list (asked again once before it's refused). Past eight choices the menu becomes a list you type to narrow: configured models first, then the ones picked lately in this browser, then the rest, a hundred at a time.

  • { auto: true, baseURL, apiKey, provider, name } in assistant.models lists another server's models too (several are fine: a local server, OpenRouter and Anthropic, say). It fills in from the main settings by the same rules as a configured model, and each model it finds runs on its own server with that server's key. A model whose id another choice already has is offered as <name or host>/<id>. The menu puts each server's models under its name or host, the search covers all of them, and a server that doesn't answer is named.

  • auto with provider: anthropic lists Anthropic's models (GET /v1/models, every page, by display name). config check no longer flags it, and names an Anthropic auto entry without a key instead.

  • Discovered lists leave out models that clearly aren't for chat: embeddings, speech and transcription, image models, moderation, rerankers, legacy completion models, and OpenRouter models that don't write text.

  • A Reasoning menu in the chat (Auto, Off, Low, Medium, High) sets how much the model thinks for that chat, over the config; a new chat is back on Auto. Background calls are unaffected, and so are access and approvals.

  • reasoning: medium, for the assistant and each of models.

  • voice: talk to the chat and hear it answer, over the OpenAI audio API (OpenAI, or a local server like Speaches). voice.stt adds a mic to the message box: tap to start and tap to stop, or hold and let go, with a level and a timer while it listens; the words go in the box to check (autoSend sends them). voice.tts adds a speaker under each answer, beside copy, that reads it aloud (the start of it, without markdown or cards) and is a stop while it talks; another answer or a new question stops it, and speakReplies reads each finished answer without a press. Valet calls the speech server through POST /api/voice/transcribe and /api/voice/speak, behind sign-in like the chat, so the address and key stay on the server; recordings up to two minutes, readings up to 2,000 characters, a per-person limit each minute, nothing stored. Voice changes no permissions. config check validates the block. Off unless set.

  • Commands in the chat. Typing / at the start of the message box opens a menu, narrowed as you type (arrows, Tab or Enter, Esc): /model [name] switches this chat to the best match among the picker's choices, or opens the picker; /reasoning off|low|medium|high|auto; /new (or /clear); /compact summarises the conversation now with the same summariser as the automatic path, behind the same quiet line; /help lists them all. They're handled by Valet, with no model and no tokens, and none of them changes what the assistant may do. The chat's message box says "Type / for commands" (labels.message).

  • @mentions. Typing @ offers the integrations the chat may use, by id and name; a chosen one shows as a token in the message. The request names them, and the server refuses any it doesn't know or the assistant may not use. With assistant.tools: lazy their tools are loaded from the first step, so there's no step spent asking for them; with all a line tells the model what the question is about. @plex typed by hand works the same. A mention never grants anything beyond assistant.access.

  • chat.commands: your own commands, as a prompt ({input} is what's typed after the name) with an optional description, model, reasoning and tools (as an @mention). They're in the / menu, ⌘K and /help, and run through the normal chat with the same access and approvals. config check names bad or built-in names, a model that isn't a choice, and an integration in tools that isn't there or can't be used. The assistant can add one through its usual config edit, approved before it's saved. The demo has /morning-brief and /downloads.

  • The public demo reads its answers aloud and shows the mic. It has no server, so each scripted answer was recorded ahead with a local speech server (Kokoro's af_heart, about 2 MB in all, npm run demo:voices records them again) and an answer with live numbers is read by the browser's own voice; the mic never records and says where voice is set up instead.

  • The docs show the model menu, the reasoning menu, the / and @ menus, a custom command, /help, an answer being read aloud, the mic listening and a skipped approval.

Changed

  • An answer's copy, ask again and "Worked for" show while the pointer is over it (or one of them has focus), so a long chat reads cleaner; their space stays, so nothing moves. On a touch screen the latest answer keeps them and a tap shows them on the others. Suggestions, approval cards and errors always show.
  • While it waits for the model, and between steps, the chat says Working; Thinking is only for when reasoning is coming in, so a model with reasoning off no longer says it's thinking. labels.working changes the word.
  • The model, the reasoning level and the context meter moved from the chat's header to a quiet row under the message box, on the right; their menus open upward. The header shows just the assistant's name.
  • Pi-hole's adblock_status also lists the devices with the most blocked queries, by name where Pi-hole or its local DNS records know one, and takes an optional domain (a plain name matches anywhere, * as in Pi-hole) to say which devices looked it up lately.

Fixed

  • An approval card left unanswered when you ask something else is now a no: the card goes, its step reads Skipped instead of spinning forever, it can't be pressed later, nothing runs, and the model is told it wasn't done.

Compare: v0.3.0...v0.4.0