Skip to content

Commit 44b88d9

Browse files
committed
Polish ui banners; reorder commands
1 parent bc79b52 commit 44b88d9

5 files changed

Lines changed: 35 additions & 45 deletions

File tree

CHANGELOG.md

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,39 @@ All notable changes to Sofos are documented in this file.
66

77
### Added
88

9-
- **`/think` is renamed to `/effort` and now opens an inline picker.** The picker lists only the reasoning-effort levels the active model supports — derived from the model's per-row entry in the registry, so an unsupported level can't be picked. Up and Down highlight a level, Enter confirms, Esc cancels. The direct form `/effort <level>` still works; the seven `/think <level>` shortcuts that used to clutter the command catalog are gone in favour of the one picker entry. **Breaking change**: `/think` is no longer recognised.
10-
- **A new `/model` command opens an inline picker that lets you switch the active model.** Up and Down highlight an entry, Enter confirms, Esc cancels. Each row shows the model id, a short description, and a `(current)` tag on the model you are using right now. Models on the other provider are greyed out and tagged `(re-launch session to activate)`, because the underlying API client is built once at startup and cannot swap providers mid-session. The cursor skips greyed rows so you cannot land on a model the running session cannot reach. Typing `/model <name>` switches directly without opening the picker; same-provider switches happen in place, cross-provider attempts are refused with a clear "re-launch with `--model <name>`" message.
11-
- **`--model` now lists the supported models when it rejects a value.** Passing `--model gpt-9.9` (or any slug outside the supported set) exits with `[supported models: claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex]`, mirroring the existing `--reasoning-effort` rejection so the failure mode is consistent.
12-
- **An inline suggestion list appears the moment you type `/`.** As soon as the input begins with a slash, a small panel below the input box lists every available slash command together with a short description, filtered by what you have typed so far. Up and Down highlight an entry, Enter runs it, Tab inserts it into the input so you can finish typing arguments, and Esc closes the panel. The Tab autocomplete that previously worked silently for a single match still does, but it now goes through the same suggestion list.
13-
- **New `view_image` tool lets the model open an image on demand.** Given a local image file path or an `http(s)://` URL, the tool attaches the image to the conversation so the model can describe it. For a folder of images, the model is told to call `list_directory` first and then `view_image` once per file. Supports JPEG, PNG, GIF, and WebP up to 20 MB per local file; URLs are passed through to the model provider, which fetches them on its side. External paths reuse the same Read-permission prompt as `read_file`, so granting access to a directory once covers both tools. Local images larger than 2048 pixels on the long side are downscaled proportionally before they reach the model so a 4K screenshot does not burn through the per-image token budget; smaller images are sent unchanged.
9+
- **`/think` was renamed to `/effort` and now opens an inline picker.** The picker lists only the reasoning levels the active model supports. Up and Down highlight a level, Enter confirms, Esc cancels. `/effort <level>` still works directly. **Breaking change**: `/think` is no longer recognised.
10+
- **New `/model` command opens an inline picker for switching the active model.** Up and Down highlight a row, Enter confirms, Esc cancels. Each row shows the model id, a short description, and a `(current)` tag on the active one. Models on the other provider are greyed out and labelled `(re-launch session to activate)`, because the API client is built once at startup and cannot swap providers mid-session — the cursor skips those rows so you can't land on a model the session cannot reach. `/model <name>` switches directly without the picker; same-provider switches happen in place, cross-provider attempts are refused with a "re-launch with `--model <name>`" message.
11+
- **`--model` lists the supported models when it rejects a value.** Passing `--model gpt-9.9` (or any unsupported slug) exits with `[supported models: claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5, gpt-5.5, gpt-5.4, gpt-5.4-mini, gpt-5.3-codex]`, matching how `--reasoning-effort` already behaves.
12+
- **An inline suggestion list appears as soon as you type `/`.** A small panel below the input shows every slash command with a short description, filtered as you type. Up and Down highlight a row, Enter runs it, Tab inserts the name so you can finish typing arguments, Esc closes the panel. The previous silent single-match Tab completion still works — it now goes through the same list.
13+
- **New `view_image` tool lets the model open an image on demand.** Pass a local file path or `http(s)://` URL and the image is attached to the conversation. Supports JPEG, PNG, GIF, and WebP up to 20 MB per local file; URLs are forwarded to the provider, which fetches them on its side. External paths use the same Read prompt as `read_file`, so granting a directory once covers both tools. Local images larger than 2048 px on the long side are downscaled before sending, so a 4K screenshot doesn't burn through the per-image token budget. For a folder of images the model is told to call `list_directory` first, then `view_image` per file.
1414

1515
### Changed
1616

17-
- **Image references typed inline in a prompt are no longer auto-attached.** Previously, a path or URL with an image extension typed in a message would be detected, stripped from the text, and attached as an image content block. Two ergonomic problems followed: vague asks such as "look at the image in `assets/`" without a filename did nothing, and unrelated text that happened to end in `.png` could be misread as a path. Attaching an image now goes through the new `view_image` tool, which the model invokes after reading the prompt; clipboard paste (Ctrl-V) continues to attach images directly.
17+
- **Image paths typed inline in a prompt are no longer auto-attached.** A path or URL ending in an image extension used to be stripped from the message and attached as an image block. That misread unrelated text that happened to end in `.png`, and did nothing for vague asks like "look at the image in `assets/`". The model now uses the `view_image` tool instead. Clipboard paste (Ctrl-V) still attaches images directly.
18+
- **Bash commands run under a supervisor with a time limit, live output caps, and interrupt support.** Output is streamed instead of buffered, the 10 MB-per-stream cap fires while reading rather than after exit, a 300-second wall-clock limit kills commands that never finish (a stuck `tail -f`, a runaway test), and ESC or Ctrl+C terminates the whole process group instead of waiting for the command to clean up on its own. The error message names the reason — cap, timeout, or interrupt — so the model can recover.
19+
- **MCP tool names are joined to the server name with a triple underscore.** The old single underscore could collide — server `a_b` tool `c` produced the same id as server `a` tool `b_c` — letting a tool call land on the wrong server. Triple underscores can't appear in either name (registrations with them are rejected with a warning), so collisions are no longer possible. Existing configs are unaffected.
1820

1921
### Security
2022

21-
- **Shell command and process substitution are now blocked in bash commands.** Constructs such as `echo $(rm bad)`, backtick substitution, and process substitution `<(cmd)` / `>(cmd)` previously slipped past the permission system because only the outer command name was checked. They are now refused before the command runs, with a clear message that names the marker. Single-quoted literals and arithmetic expansion `$((expr))` continue to work.
22-
- **Workspace symlinks can no longer route bash reads outside the workspace.** When a bash command names a workspace-relative path that resolves through a symlink to a file outside the workspace, the path is now sent through the same external-path prompt that absolute and tilde paths already use.
23-
- **MCP tools are filtered out in safe mode by default.** Previously safe mode only restricted Sofos's native tools, so any tool exposed by a configured MCP server still ran in safe-mode sessions. Each MCP server entry now has a `safe_mode` setting — `disabled` (default, filtered), `read_only`, or `allow` — and only servers whose setting opts them in have their tools listed to the model when safe mode is on. The startup banner and `/safe` confirmation list which servers were filtered out and which were opted in so the user can see the actual scope of the session.
24-
25-
### Changed
26-
27-
- **Bash commands run under a supervisor with a time limit, live output caps, and interrupt support.** Output is streamed instead of buffered, the per-stream 10 MB cap is enforced while reading rather than after exit, a 300-second wall-clock limit ends commands that never finish (for example a stuck `tail -f` or a runaway test), and pressing ESC or Ctrl+C now terminates the whole process group instead of waiting for the command to exit on its own. The error message names the reason — output cap, timeout, or interrupt — so the model can recover.
28-
- **MCP tool names are joined to their server name with a triple underscore separator.** The previous single underscore meant that a server called `a_b` exposing a tool `c` produced the same identifier as server `a` exposing tool `b_c`, so a tool call could be routed to the wrong server. The new separator cannot appear in a server or tool name (registrations that contain it are rejected with a warning), and collisions between distinct `(server, tool)` pairs are no longer possible. Existing configurations are not affected by the change because the prefixed name is derived at startup, not stored.
23+
- **Shell command and process substitution are blocked in bash commands.** `$(rm bad)`, backticks, and process substitution `<(cmd)` / `>(cmd)` used to slip past the permission system because only the outer command was checked. They are now refused with a message that names the marker. Single-quoted literals and arithmetic expansion `$((expr))` still work.
24+
- **Workspace symlinks can no longer route bash reads outside the workspace.** When a workspace-relative path resolves through a symlink to a file outside the workspace, it now goes through the same external-path prompt that absolute and `~/` paths already use.
25+
- **MCP tools are filtered out in safe mode by default.** Safe mode used to restrict only Sofos's native tools, leaving every MCP-exposed tool fully available. Each MCP server entry now has a `safe_mode` setting — `disabled` (default, filtered), `read_only`, or `allow` — and only opted-in servers expose their tools while safe mode is on. The startup banner and `/safe` confirmation list which servers were filtered and which were opted in.
2926

3027
### Fixed
3128

32-
- **A first response that is cut off by the token limit no longer runs partial tool calls.** Sofos already protected follow-up responses inside the tool loop, but the very first response from the model was processed without checking its stop reason. A cut-off mid-tool-call would leave the tool arguments half-formed and Sofos would then fail the call with a confusing parameter-missing error. The token-limit warning and the early exit now fire on the initial response too.
33-
- **Internal errors are no longer recorded as assistant output.** When a system error landed at a point where the conversation ended with tool results, Sofos used to insert the error message as a fake assistant turn so the providers' role alternation rules would accept the next request. The model saw the error as something it had written. The error is now appended to the trailing user turn instead, which keeps alternation valid without impersonating the assistant.
34-
- **External image paths now use the interactive Read prompt instead of a hard error.** Pasting an image path that resolves outside the workspace used to fail unless the user had already added a matching `Read(...)` rule to the configuration; the rest of the file tools have prompted the user interactively for years. Image loading now shares the same session-scoped allow and deny lists as `read_file`, so granting Read access to a directory once covers both file reads and image loads under that directory.
35-
- **Tool descriptions now match what the executor actually enforces.** `edit_file` and `morph_edit_file` say that editing an external file prompts for both Read and Write access (the previous text only mentioned Write, but the executor needs Read to load the file before applying the edit). `delete_file` and `delete_directory` say they accept absolute and `~/` paths with a Write grant (the previous text claimed the tools were workspace-only, while the executor has supported external deletions for several releases).
36-
- **`web_fetch` no longer scans large HTML pages with quadratic memory and CPU.** The previous implementation built a full lowercase copy of the page plus two `Vec<char>` buffers and indexed into them with `char_indices().nth(i)` on every iteration, which combined to O(n²) work and several full-size duplicates of the input. The pass is now a linear byte scan that stops accumulating output once the model-facing budget is reached. The raw body cap is also tightened from 64 MB to 8 MB, which is enough for almost every real page and small enough that even a worst-case input stays inside a reasonable memory budget.
37-
- **Session ids carry a random suffix, so two Sofos processes started in the same millisecond no longer overwrite each other's saved history.** A new helper picks a fresh id that does not match any existing session file in the workspace, falling back to a regenerated id on the rare chance the random suffix collides.
38-
- **Unknown slash commands no longer reach the model as plain prompts.** A typo such as `/resuem` or an unsupported variant such as `/think turbo` used to be sent verbatim to the assistant, which would politely explain that it does not understand the command while charging input tokens. Sofos now recognises any line that starts with `/` but fails to parse, prints a short error, and lists the valid commands.
39-
- **The `read_file` transcript summary counts file content lines instead of wrapper lines.** The line range used to include the two-line `File content of '...':` prefix that the tool wraps around the file body, so a one-line file looked like three lines and a hundred-line file looked like a 1–102 range. The summary now reports `Read N lines from <path>` based on the actual file content, and the obsolete `offset` field has been removed from the wording because `read_file` does not accept a range argument.
40-
- **Pasting more than twenty images into one message no longer drops them silently.** The marker pool tops out at twenty circled-number characters, after which the previous code inserted a plain `*` that the submission parser could not recover. Sofos now rejects the extra paste with a clear "limit reached" warning and leaves the existing images untouched so the user can send them in batches.
41-
- **Provider selection moved out of duplicated `model.starts_with("gpt-")` checks into a single function in the model registry.** Startup and resume now ask the same helper which client a model belongs to, so adding a new OpenAI prefix (or a third vendor) is a one-line change instead of two sites that can drift.
29+
- **A first response cut off by the token limit no longer runs partial tool calls.** Follow-up responses inside the tool loop already handled this, but the first response was processed without checking its stop reason — a mid-tool-call cut-off left the arguments half-formed, and the call failed with a confusing parameter-missing error. The token-limit warning and early exit now fire on the initial response too.
30+
- **Internal errors are no longer recorded as assistant output.** When a system error happened after a tool result, Sofos used to insert it as a fake assistant turn so the next request would be accepted — the model then read its own error as something it had said, which could poison the next reply. The error now lives on the trailing user turn instead, so the transcript never impersonates the model.
31+
- **External image paths use the interactive Read prompt instead of a hard error.** Pasting an image path outside the workspace used to fail unless a matching `Read(...)` rule was already in the config; the rest of the file tools have prompted interactively for years. Image loading now shares the same session-scoped allow and deny lists as `read_file`, so granting Read access to a directory once covers both.
32+
- **Tool descriptions match what the executor actually enforces.** `edit_file` and `morph_edit_file` now mention that editing an external file prompts for both Read and Write (the executor needs Read to load the file before applying the edit). `delete_file` and `delete_directory` now mention that absolute and `~/` paths work with a Write grant — the previous text claimed they were workspace-only, while the executor has supported external deletions for several releases.
33+
- **`web_fetch` no longer hangs on large HTML pages.** A page of a few megabytes used to make the tool freeze or run out of memory; it now returns quickly and stops accumulating output once the response budget is filled. The maximum body size is also tightened from 64 MB to 8 MB, enough for almost every real page.
34+
- **Session ids carry a random suffix, so two Sofos processes started in the same millisecond can no longer overwrite each other's saved history.** A helper picks an id that doesn't match any existing session file in the workspace, regenerating on the rare chance of a suffix collision.
35+
- **Unknown slash commands no longer reach the model as plain prompts.** A typo like `/resuem` or an unsupported variant like `/effort turbo` used to be sent verbatim to the assistant, which would politely explain it didn't understand while charging input tokens. Sofos now catches any line that starts with `/` but fails to parse, prints a short error, and lists the valid commands.
36+
- **The `read_file` transcript summary counts file content lines, not wrapper lines.** The line range used to include the two-line `File content of '...':` prefix, so a one-line file looked like three lines and a 100-line file looked like a 1–102 range. The summary now reports `Read N lines from <path>` based on the actual content; the obsolete `offset` field has been removed because `read_file` doesn't accept a range argument.
37+
- **Pasting more than twenty images into one message no longer drops them silently.** The marker pool tops out at twenty circled-number characters; past that, the previous code inserted a plain `*` that the submission parser couldn't recover. The extra paste is now rejected with a clear "limit reached" warning and the existing images stay intact so the user can send them in batches.
4238

4339
### Removed
4440

45-
- **The README no longer claims first-class Windows support.** The terminal UI opens `/dev/tty` and the bash executor relies on POSIX process groups, neither of which work on Windows out of the box. The platform line on the README now says "Tested on macOS, supported on Linux, experimental on Windows"; running the TUI on a non-Unix system surfaces a clear configuration error instead of failing with an opaque file-not-found.
46-
- **A number of long historical narratives in source comments were trimmed.** Code comments now focus on the current invariant; the "what used to happen" stories were either redundant with another comment in the same module or no longer load-bearing for understanding the present code.
41+
- **The README no longer claims first-class Windows support.** The terminal UI and the bash executor both depend on Unix-only behavior, so running Sofos on Windows was always best-effort. The platform line now reads "Tested on macOS, supported on Linux, experimental on Windows", and starting the TUI on a non-Unix system shows a clear configuration error instead of an opaque file-not-found.
4742

4843
## [0.2.12] - 2026-05-16
4944

assets/screenshot.png

277 KB
Loading

0 commit comments

Comments
 (0)