Repository navigation
What's Changed
Everything a reply cost is now recorded with it and kept, and a conversation
can be exported as one JSON file — meant to be handed to a person, or to a
model, that knows nothing of SpecterChat. And what a request carries when
the conversation no longer fits the context window is now decided here,
rather than left to the server.
The database schema changed (v10). Updating from any released version
(0.5.0 to 0.7.3, all on schema v8) keeps your conversations, and the
database is copied before it is touched. But opening that database again
with a build older than this one erases it: those builds recreate
their tables whenever the schema version differs, in either direction.
Update the installed app rather than running both, and keep the copy this
version leaves beside it.
Added
- Export a conversation as JSON. "Export (JSON)" in a conversation's
menu, in the left sidebar, asks where to save and writes everything:
every message with its reasoning, the tool calls with the arguments the
model wrote, the tool results with the server's whole answer, the images
as base64 (screenshots included), what each reply was generated with and
measured at, totals per model, one entry per exchange, the current
settings, and a guide explaining the app and what the model is actually
sent. The API key and the MCP servers' headers are never exported. - Each reply records what it was generated with and what was measured,
once and for good: the model and the server it went to, the sampling
parameters (or the image options), the prompt and output token counts,
the time before the first token, the reasoning time, the total duration,
how the turn ended — finished, stopped, failed, or cut short by a crash —
and what the server reported alongside its answer (finish_reason, usage
details, llama.cpp timings). Kept in the database, so the numbers survive
a restart and later settings changes. - The exact context of each request is recorded: the system prompt as
sent, the MCP servers' instructions included, and the definition of every
tool offered. Stored once and reused while nothing changes, so it costs
almost nothing. - Tool results keep the server's whole answer, not just its text and
images: structured results,_meta, per-item annotations and fields this
version does not know about. Image bytes stay in their attachment, and the
answer refers to them. - Each tool call records how long it took and which server ran it.
- The line under a reply says what the exchange weighed: the tokens the
request carried (↑ — the whole conversation, not just your last message),
the tokens that came back (↓), and, when several turns answered you, the
totals since your message (Σ) on the tokens as on the time. - What a picture weighs is now shown, in kilobytes: on the picture
itself, at its top left corner, under the message you sent it with, in
the line under a reply that returned one, and in the header of a tool
result that took a screenshot — the last one without unfolding it. Token counts say
nothing about the size of an image, and an image is most of what a
conversation weighs. - Hovering the line under a reply spells every figure out in words and
shows the detail: model, server, tokens sent and received, time to the
first token, reasoning time, output speed, the reason the model stopped,
and what the whole exchange has cost so far. - "Images Kept", in the right panel, says how many of the conversation's
images travel with each request — globally or for one conversation. It is
off by default: every image you sent goes out on every turn. Keeping only
the last few makes sense for screenshots, which lose their value as the
conversation moves on, and not for a conversation about three
photographs, so you are the one who says which you are having. What is
left out of a request is never removed from the conversation.
Changed
- The speed shown under a reply is now the generation speed, measured
from the first token, so reading a long prompt no longer drags it down.
Expect higher numbers than before on conversations with a large context. - A stopped or failed reply keeps its duration and says so, instead of
showing nothing. - The line under a reply reads as small icons rather than words —
sent, received, weight, duration, speed, totals, time of day — so a
longer line stays legible under the message. Every figure carries its
unit. - Upgrading the database keeps your conversations. Until now, every
schema change wiped the history; from this version on, each change is an
incremental step, and every version ever released is on the same starting
schema, so nobody loses anything on update. - The database is copied before it is migrated, next to itself
(specter.db.v8.backup), once per schema it comes from. Delete it when
you are satisfied the update went well. - A database written by a newer version is left alone. Instead of
rewriting what it does not understand, the app sets it aside
(specter.db.v11.newer) and starts a new one, so going back to an older
version can no longer destroy a history. - The conversation is trimmed to fit the context window before it is
sent. The whole conversation goes out on every turn — the protocol
keeps nothing between requests — and until now, what happened when it no
longer fitted was the server's business: a server that overflows forgets
on its own, says nothing about it, and can cut a tool call away from the
result answering it. The app now decides. A request carries the context
length you set, less the room reserved for the answer, less a tenth.
Images are left out first, one being worth a thousand tokens of the
conversation that would be dropped to make room for it; what still does
not fit costs whole exchanges, the oldest ones first. The exchange you
are waiting on always travels, even when it is over the window on its
own — sending it is the only way to find out what the server makes of
it — and nothing is ever cut inside an exchange, so a tool call is never
separated from its result. - What a request left out is recorded with the reply and written in the
export (stats.droppedRuns,stats.droppedImages), so a short answer
can be explained afterwards. The conversation itself is never rewritten:
a trim shapes the request, not your history.
Fixed
- A tool call the server sends without an identifier is no longer
dropped, and two calls the server numbers alike are no longer merged
into one — the first was lost. - Each tool result is written as soon as its call returns, instead of
waiting for every tool of the turn: closing or losing the app no longer
drops the results already obtained. - A reply whose tool calls were not all answered is no longer sent back to
the server, which rejected the whole request and blocked the
conversation. - A generated image is no longer sent back on the model's own turn. The
OpenAI schema accepts an image only on a message you send, so a strict
server refused the whole request and the conversation could not go on.
The image now follows the turn that produced it in a message of its own —
after the tool results, when that turn called tools — and "now make it
blue" still edits it. Image servers keep the previous shape, which their
protocol asks for. - The images of a turn that also called tools are no longer lost. That
path never looked at them, so a model that generated a picture and called
a tool in the same turn could not edit the picture afterwards.
Full Changelog: v0.7.3...v0.8.0