refactor: rename the commands after what they do

Slugs and titles now say what each command does, and every command is
described the same way.

- `sessions` "Chat Sessions" -> `chat-history` "Chat History"
- `models` "Ollama Models" -> `manage-models` "Manage Models"
- `setup` "Set Up Lam Agent" -> "Setup & Status", which no longer repeats
  the extension name
- Drop the redundant "Lam Agent" subtitle from chat, snip and models: the
  extension name is already shown next to the command

`chat` and `snip` keep their slugs, so the deeplinks and hotkeys the README
documents still work, and the two cross-launches (`snip` -> `chat`,
chat -> `snip`) are untouched. The other two slugs change, so a deeplink or
a shortcut bound to `sessions` or `models` needs rebinding.

In-view navigation titles are aligned with the new titles (the setup view
was "Lam Agent Setup"), and the README's command table, architecture tree
and prose follow.
This commit is contained in:
2026-10-07 17:17:23 +08:00
parent 2adc6d74b5
commit bb78962a36
14 changed files with 41 additions and 44 deletions
+16 -16
View File
@@ -68,12 +68,12 @@ npm run build
Setup is two prompts on first launch, then one command you can revisit any time.
1. **The API key.** Vicinae prompts for required preferences before a command runs, so the very first launch asks for your Ollama API key.
2. **The model.** The next prompt asks which model to use. Type it exactly, e.g. `deepseek-v4.1-flash:cloud` or `gpt-oss:120b`. Typing it by hand is the fragile part, so run **Ollama Models** afterwards and pick the real one from the list.
3. **`Set Up Lam Agent`** verifies the connection, lists every model your key can actually reach, and reports which one is in use and where that came from.
2. **The model.** The next prompt asks which model to use. Type it exactly, e.g. `deepseek-v4.1-flash:cloud` or `gpt-oss:120b`. Typing it by hand is the fragile part, so run **Manage Models** afterwards and pick the real one from the list.
3. **`Setup & Status`** verifies the connection, lists every model your key can actually reach, and reports which one is in use and where that came from.
To change the model later, run **Ollama Models** and pick one, or edit the **Model** preference directly.
To change the model later, run **Manage Models** and pick one, or edit the **Model** preference directly.
> An extension can read preferences but not write them, which is why a pick made in **Ollama Models** is stored by the extension and layered over the preference rather than saved into it. See [Models](#models) for how the two are reconciled, and for what a reset does.
> An extension can read preferences but not write them, which is why a pick made in **Manage Models** is stored by the extension and layered over the preference rather than saved into it. See [Models](#models) for how the two are reconciled, and for what a reset does.
## Keyboard shortcuts
@@ -83,7 +83,7 @@ To change the model later, run **Ollama Models** and pick one, or edit the **Mod
| `↩` with an empty bar | Open the highlighted conversation |
| `⌘ N` | New chat |
| `⌘ ⇧ S` | Snip a region and attach it to this chat (only with a vision model) |
| `⌘ ⇧ ⌫` | Delete the highlighted conversation (also in **Chat Sessions**) |
| `⌘ ⇧ ⌫` | Delete the highlighted conversation (also in **Chat History**) |
Prompts are single line. An earlier `⌘ ↩` multi-line composer was removed. See [Architecture](#architecture) for why a `Form.TextArea` cannot be laid out cleanly in a launcher. The `Tab` shortcut went with it: the left column *is* the conversation switcher now, so an accessory dropdown would only duplicate it.
@@ -118,16 +118,16 @@ vicinae 'vicinae://launch/lam-agent/chat?fallbackText=summarise%20this'
| --- | --- |
| **Chat with Lam** | The chat surface. Bind this to your global shortcut. |
| **Snip to Lam** | Capture a region and start a new chat about it. A `no-view` command, so the launcher window closes before the selector appears. Bind this to a second shortcut for one-key "snip and ask". |
| **Chat Sessions** | Browse, reopen, and delete past conversations. |
| **Ollama Models** | Browse the models the configured host can reach, pick the one Lam uses, and pull or delete models on a server you run. See [Models](#models). |
| **Set Up Lam Agent** | Verify the connection, list available models, check whether the selected model can see images, and clear out chats or unattached photos. |
| **Chat History** | Browse, reopen, and delete past conversations. |
| **Manage Models** | Browse the models the configured host can reach, pick the one Lam uses, and pull or delete models on a server you run. See [Models](#models). |
| **Setup & Status** | Verify the connection, list available models, check whether the selected model can see images, and clear out chats or unattached photos. |
## Configuration
| Preference | Default | Notes |
| --- | --- | --- |
| **Ollama API Key** | None | Required. Stored by Vicinae as a password preference. |
| **Model** | None | Required. Any model your key can reach. **Ollama Models** can pick one for you, and a pick takes precedence over this value until you reset it from the setup screen. |
| **Model** | None | Required. Any model your key can reach. **Manage Models** can pick one for you, and a pick takes precedence over this value until you reset it from the setup screen. |
| **Ollama Host** | `https://ollama.com` | Set to `http://localhost:11434` for a local server. |
| **Location** | None | The place Lam should treat as yours, for example `Cebu City, Philippines`. Optional. The only exact location available, and the only one that stops anything being inferred. |
| **IP Geolocation** | off | Off by default. When on, and only when **Location** is empty, your IP is sent to ipwho.is to resolve a rough area. |
@@ -145,7 +145,7 @@ vicinae 'vicinae://launch/lam-agent/chat?fallbackText=summarise%20this'
## Models
**Ollama Models** lists everything the configured host can reach, filtered by the search bar. Each row shows the parameter count and how much disk it takes, with tags for the model in use and for anything that reports image input. Picking one writes it to LocalStorage and `loadPreferences` layers it over the `Model` preference, so it takes effect on the next question with no restart.
**Manage Models** lists everything the configured host can reach, filtered by the search bar. Each row shows the parameter count and how much disk it takes, with tags for the model in use and for anything that reports image input. Picking one writes it to LocalStorage and `loadPreferences` layers it over the `Model` preference, so it takes effect on the next question with no restart.
| Action | Notes |
| --- | --- |
@@ -211,7 +211,7 @@ If you turn on **IP Geolocation**, and only then, `get_location` resolves a roug
**It is coarser than "city-level" suggests, and that is worth knowing before trusting it.** An IP address identifies the point where the traffic left the ISP, not the person. Measured from one machine on Globe Telecom, an IPv4 lookup resolved to Cebu City and an IPv6 lookup moments later resolved to Talisay in Calabarzon, roughly 500km apart. If you want a place you can rely on, set **Location** and turn this off.
The answer is cached for 6 hours rather than looked up per question, because an area does not change between questions and every lookup hands over another copy of your address. `Set Up Lam Agent` clears that cache, and the capability cache, when you re-test.
The answer is cached for 6 hours rather than looked up per question, because an area does not change between questions and every lookup hands over another copy of your address. `Setup & Status` clears that cache, and the capability cache, when you re-test.
This extension does not use GPS. That would mean CoreLocation on macOS, which has no command-line interface, or GeoClue on Linux, whose usual provider resolves nearby Wi-Fi networks through a Mozilla service anyway. Neither is worth it for "is it late where you are".
@@ -287,7 +287,7 @@ The index entry for a conversation carries its image paths (`SessionSummary.atta
### Doing it by hand
**Set Up Lam Agent** has a Maintenance section with the same two jobs as explicit actions:
**Setup & Status** has a Maintenance section with the same two jobs as explicit actions:
| Action | What it deletes |
| --- | --- |
@@ -352,8 +352,8 @@ The list shows the sources the answer cited, falling back to everything the turn
src/
chat.tsx # "chat" command entrypoint, thin wrapper
snip.tsx # "snip" command entrypoint, no-view: captures then hands over
models.tsx # "models" command: browse, pick, pull, delete
sessions.tsx # browse, reopen, delete conversations
manage-models.tsx # "manage-models" command: browse, pick, pull, delete
chat-history.tsx # "chat-history" command: browse, reopen, delete conversations
setup.tsx # connection check + live model list
lib/
ollama.ts # the only file that talks HTTP
@@ -423,7 +423,7 @@ The rendered height stays capped at 200px whatever is asked for (`Math.min(_rawH
**The logic layer has no Vicinae imports.** `agent.ts`, `ollama.ts`, `tools.ts` and friends are plain TypeScript, which is why they unit test without a runtime. A test enforces this.
**Preferences have exactly one reader.** `loadPreferences` applies the model chosen in **Ollama Models** on top of what Vicinae holds, and it is asynchronous because that pick lives in LocalStorage. `getLamPreferences` is deliberately not exported, because a second, synchronous reader would look correct and silently ignore the pick. Views take preferences through `hooks/usePreferences`, and the chat view is split in two so that `useChat` is only ever created once the model is known, rather than being pinned to whatever the preference said a moment earlier.
**Preferences have exactly one reader.** `loadPreferences` applies the model chosen in **Manage Models** on top of what Vicinae holds, and it is asynchronous because that pick lives in LocalStorage. `getLamPreferences` is deliberately not exported, because a second, synchronous reader would look correct and silently ignore the pick. Views take preferences through `hooks/usePreferences`, and the chat view is split in two so that `useChat` is only ever created once the model is known, rather than being pinned to whatever the preference said a moment earlier.
**Sessions are capped twice over**, once per turn and once per session, because `LocalStorage` has no documented ceiling.
@@ -441,7 +441,7 @@ The hand-off goes through `snip` specifically rather than straight to `chat` on
**An attached image is sent once and never replayed.** It is the largest thing a request can carry, so `buildMessages` attaches it to the question it belongs to and drops it afterwards, exactly as it already drops tool output. The cost is that a follow-up about a screenshot needs the image attached again; the alternative is re-sending every screenshot in the conversation on every turn. Only the path and mime type go into storage: `MAX_STORED_CHARS_PER_TURN` exists so one turn cannot dominate `LocalStorage`, and base64 would blow past it on a single 1080p capture.
**Whether the model can see is a tri-state, and the prompt gets the whole answer.** `canSeeImages` stays fail-closed, because offering the snip action to a model that cannot read would waste the selection gesture. But the system prompt needs `"unknown"` kept apart from `"no"`: telling a model it cannot see when the check merely failed is a false claim about the user's setup, and telling it nothing is what made it reason about its own capability instead of describing the image it had been sent. A model name that does not exist on the server is the common way to end up at `"unknown"`, which is one more reason the Models command picks names from the list rather than taking them typed.
**Whether the model can see is a tri-state, and the prompt gets the whole answer.** `canSeeImages` stays fail-closed, because offering the snip action to a model that cannot read would waste the selection gesture. But the system prompt needs `"unknown"` kept apart from `"no"`: telling a model it cannot see when the check merely failed is a false claim about the user's setup, and telling it nothing is what made it reason about its own capability instead of describing the image it had been sent. A model name that does not exist on the server is the common way to end up at `"unknown"`, which is one more reason the Manage Models command picks names from the list rather than taking them typed.
## Development