Rune retested after the previous merge fix (bigger token budget,
stronger instruction) with the exact same DDNS Docker debugging
conversations and got the identical failure — same error text,
same models. Logs showed a single ~86s request with a large prompt
(31k tokens cached) and no truncation signal available to check.
The remaining suspect: the transcript was formatted as "**User:**" /
"**Assistant:**" markdown, which closely mimics a live chat turn
format. Over a long, noisy transcript that includes something reading
like a directive ("no more editing", etc), the model can lose track of
"this is data to merge" and slip into continuing/replying to it
instead — matching exactly what was observed. Replaced the transcript
markers with synthetic, non-chat-like tokens (<<<USER_TURN>>> etc) and
added an explicit "this is not a live conversation" framing both
before and after the transcript block, not just once at the top.
Also: log OpenRouter's finishReason when it's "length" (i.e. the
response was actually cut off) so a future failure like this is
distinguishable from a formatting/instruction-following miss without
guessing from the log lines Rune already has available.
Three changes, all aimed at the same failure: merges of large
conversations (e.g. long debugging sessions) were reliably failing to
parse on both Haiku 4.5 and GLM 5.2.
- maxTokens was a flat 4000 regardless of input size — a merge of two
long conversations needs a much larger completion budget than that,
so the model's JSON array output was getting cut off mid-generation.
Now scaled with transcript size (8000-16000).
- Strengthened the prompt: explicitly tell the model not to respond to
or continue anything found inside the transcripts (a real observed
failure mode was the model echoing/continuing transcript content
instead of merging it), and to emit nothing but the JSON array.
- parseTurns now falls back to scanning for a bracket-balanced JSON
array anywhere in the response (respecting quoted strings) if the
model still wraps the array in commentary despite instructions not
to, instead of failing outright on the first non-JSON response.
Consolidates the mac.oai.pm subdomain references (introduced in the
PolyForm Noncommercial relicense) to the root oai.pm domain, across
the LICENSE file, README, and all Swift source file headers.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Switches the project from AGPL to a source-available license that
restricts commercial use — selling oAI or any part of it, standalone
or bundled into another product/service, now requires a separate
commercial license from the copyright holder. Noncommercial use,
study, modification, and sharing remain fully permitted.
Updates: LICENSE (canonical PolyForm Noncommercial 1.0.0 text +
commercial licensing contact note), SPDX headers and file-header
boilerplate across all Swift source files, the in-app About dialog's
license link (+ its localization catalog entry), README.md and
DEVELOPMENT.md license sections.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
primaryModel was being set to the model that performed the merge (or,
in AI mode, stamped onto every synthesized message). It should instead
be the most recently used model among the source conversations being
combined.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lets users multi-select 2+ saved conversations and merge them into one,
either by chronological concatenation or by having the default model
synthesize a single coherent conversation from the source transcripts.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>