Sync fork to upstream v2.0.5 (603 commits), preserve fork customizations - #4
Merged
Conversation
minP (Min-P sampling) was a first-class generation parameter — defined in the schema, shipped in the default preset, and parsed/salvaged from stored params — but it was never placed on ChatOptions, so it silently did nothing on every provider. - Add `minP` to ChatOptions. - Thread it through the generate route: preset baseline, connection/chat overrides, and the game-mode reset, then into all three ChatOptions sites. - Map it in the OpenAI provider as `min_p`, gated by the same shouldSendTopK() check as top_k (sent only to backends known to accept the non-standard sampler — the bundled local model — with customParameters as the escape hatch for other backends). minP=0 means "disabled" and is omitted. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…only keys Follow-up to the Tier-1 fixes, from the CodeRabbit review on Pasta-Devs#2669: - Filter out empty/whitespace-only stop sequences (the schema allows them) and trim each entry before dispatch, so an empty stop sequence can't 400 Anthropic or abort OpenAI generation. - Trim the API key before the auth-header guard in all three providers, so a whitespace-only key is treated as blank (no header) instead of emitting a malformed `Bearer ` / `x-api-key: `. Skipped the suggested ENCRYPTION_KEY set-but-empty change: getEncryptionKeyOverride() already routes through normalizeEnvValue(), which collapses empty/whitespace to null, so a set-but-empty value is treated as unset — consistent with every other env override. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Security: remove autonomousIntent from the generate schema so arbitrary client text can no longer be injected into system prompts; the server now derives the intent hint from the validated autonomousIntentKey via getIntentHint(). Correctness fixes: - Daily budget key now uses local date instead of UTC, aligning with schedule day boundaries on non-UTC deployments - /busy-delay route was passing full chat.metadata to parseConversationStatusOverrides instead of the nested field - mergeConversationStatusOverrides now merges objects instead of replacing them, so sibling character overrides survive partial patches - Malformed expiresAt values (NaN) are now treated as expired/null - Midnight-crossing schedule blocks are now correctly identified as both previous and next in getAdjacentBlocks - good_night intent hint now requires the offline block to start within 90 minutes, preventing premature triggering - clearGenerationInProgress called on all scheduler error paths - Scheduler re-reads status and returns early if character is offline - Schedule generation invalidates chatKeys.list() in addition to detail - saveOverride returns boolean; UI resets only on success and clears pendingStatuses after a successful refetch - triggerAutonomousGeneration passes skipPresenceDelay=true after the busy-delay has already been waited out client-side - Background autonomous hook passes skipPresenceDelay=true to /generate - /status slash command fallback removed that mapped display names to fake character IDs - AutonomousCheckResult.reason union extended with missing literals - DelayedCharacterStatus aliased to shared ConversationPresenceStatus Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…end (Pasta-Devs#2673) appendGenerationTailMessages trimmed the prefill only for its presence guard but pushed the untrimmed value as the final assistant message. Anthropic's Messages API rejects a trailing assistant turn that ends in whitespace (HTTP 400), which users see as a content block/refusal — and prefills ending in "\n" or a space are common, so presets that work in SillyTavern fail here. Push assistantPrefill.trimEnd() (strip only the trailing edge Anthropic rejects; leading whitespace is preserved; the user-facing prefill rendering is separate). Mirror the same in the dry-run preview so it matches what is sent. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replace the blocking `await new Promise(setTimeout)` with a per-chat timer (scheduleDelayedGeneration). evaluateChat now returns immediately after scheduling the delay, allowing the poll loop to proceed to the next chat. The runningChats slot is held by the timer callback and released in its finally block, preserving the existing re-entry guard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…cter record
conversationStatus/conversationActivity were written to the shared
character extensions via chars.update(), causing one chat's manual
presence override (e.g. dnd in chat A) to bleed into the sidebar and
input area of unrelated chats.
Replace the per-character write with a single patchMetadata call that
stores {status, activity} per character in a new chat-scoped
conversationCharacterStatuses field. The sidebar now reads per-chat
status from each chat row's own metadata, and ChatArea overlays it into
the characterMap so input-area dots also reflect the correct chat.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…o-grouped agents (Pasta-Devs#2680) executeAgent returned the tool path with `return executeAgentWithTools(...)` and no `await`, so a rethrow from the tool loop (executeToolCall throwing) escaped this function's own try/catch and surfaced as a rejected promise instead of a failed AgentResult. In the pipeline, executeGroup joins batch + tool agents for the same provider+model group with Promise.all. One tool agent's rejection rejected that Promise.all, and executePhase then overwrote EVERY agent in the group — including co-grouped batch agents (tracker, expression) and sibling tool agents that already succeeded — with success:false error results. Adding `await` lets the existing catch convert the rethrow into a failed AgentResult for only the failing agent, preserving per-agent isolation. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…n at serialization (Pasta-Devs#2679) The prefill-only fix (Pasta-Devs#2673 / Pasta-Devs#2674) trims in the prefill helper, so it covers only the case where a prefill is configured. With no prefill, the trailing assistant message can still end in whitespace and reach Anthropic untrimmed → HTTP 400 ("final assistant content must not end with trailing whitespace"), surfacing as a refusal/block. The trailing turn can be a depth-injected role:assistant section, or — under markdown/none wrap — the last chat-history assistant message. Centralize the trim at the point of serialization in the Anthropic provider: a new trimTrailingAssistantWhitespace() strips the trailing edge of the last assistant message, applied in chat() (after mergeConsecutiveMessages) and in chatComplete() (before formatAnthropicPayloadMessages). This covers every trailing-assistant surface — prefill, depth-injected, merged, history — in one place, generalizing the prefill fix. Leading whitespace and non-trailing turns are untouched. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The seat row rendered seats in fixed seating order, so it never reflected the play direction and a Reverse left the row unchanged. Reorder the chips into the actual turn queue — current player first, then each following seat in the live direction — so a Reverse visibly flips the queue and the human persona sits in its real turn slot. Mark the on-deck seat with a small "next" cue. Derived client-side from the direction + currentSeatId already in publicView; no engine change.
Characters can now start a game of UNO themselves instead of the user relying on a narrow client-side trigger phrase or manually running /uno. - New `[uno]` conversation command (the agreement gate): advertised to characters in conversation mode when UNO is available, no game is active, and another player is present. A character includes `[uno]` only when the user proposes a game and they're willing; declining is simply not emitting it. On emit, the server deals a game (human + every non-offline character; the agreeing character is always seated) and, if the opening card lands the turn on a bot, advances bot seats so it resolves to the human's turn. The board hydrates over the existing uno_state_patch SSE — no client change. - Scene exclusion: the `[scene]` guidance now explicitly tells characters NOT to start a roleplay scene for UNO / cards / board games, so "let's play uno" no longer fires a scene by mistake. - Schedule integration: characters seated at an active turn-game are treated as present at the table, bypassing the schedule offline-skip and dnd/idle typing delay for that chat so a seated player never goes silent or replies minutes late mid-game. The new command defaults on and is toggleable like the other conversation commands.
An active UNO game drives generation through its bot-turn requests, which
take the chat's single generation lock. The autonomous-message scheduler
had no turn-game awareness, so every poll it could fire a normal
conversation generation for the chat — seizing that lock and making the
next bot-turn request 409 ("a generation is already in progress"). Since
the client's bot-turn fire never retries, one collision left the game
stuck on a bot's turn.
Gate /autonomous/check on getActiveTurnGame (mirroring the existing
scene-active guard) so autonomous returns shouldTrigger:false while a
game is running. This covers both the server scheduler and any client
autonomous trigger, since both consult /autonomous/check first.
…-agnostic bot runner, generic board SSE) - UnoBoard: submit plays/jump-ins by the clicked card's stable id instead of by (color, value) face, and auto-declare UNO on the play that takes the human from two cards to one. Previously the human was instantly catchable in the gap before they could click "Call UNO!" while the bot loop fired; bots already auto-declare for themselves, so this just makes the human symmetric. - turn-game-bot-runner: stop filtering tool calls against the UNO-specific UNO_TOOL_NAMES list. Try engine.parseToolCall on each tool call and take the first the engine recognizes, so any future engine's tools work without editing the runner. Drops the now-unused shared import. - Generalize the board SSE event from uno_state_patch to turn_game_state_patch (server emitters + client handlers) so a second game reuses the same channel rather than needing a new event. Each game still ships its own client board.
…ensive parse, real rewind) - Move/state routes no longer trust a client-supplied seatId. The acting seat and the view's perspective are always the chat's inferred human seat, so a crafted request can neither drive a bot/other seat nor request another seat's perspective and reveal its hidden hand. Bot seats stay driven by the server-authoritative bot loop. (The service keeps its seatId param for the bot runner.) Client stops sending the now-ignored seatId. - The [uno] command parses chat characterIds defensively (try/catch + string filter, mirroring resolveSeats), so malformed metadata can't throw and silently abort starting a game. - Per-message engine snapshots are now actually used for selection: loadGame resolves the visible message anchor and selects via getForGeneration, so a message edit / branch / regeneration rewinds the authoritative game state (previously it always read the latest snapshot). Human moves anchor their snapshot to the latest visible assistant message so a fresh move isn't masked by an older one, and regenerating the following turn resumes from the post-move state. getActiveTurnGame stays on the latest snapshot (rewind is irrelevant there) to keep the autonomous/bot-loop hot paths cheap.
…ne parity
Addresses the third Copilot review pass on the turn-game (UNO) PR:
- 7-0 jump-in: stop enumerating (and now explicitly reject server-side) a
non-winning 7 played via jump-in. A jump-in can't carry a swap target, so
such a move would otherwise be advertised as legal yet rejected on apply with
a misleading "choose a player to swap" error. It stays legal only when the 7
is the winning (last) card, which needs no swap.
- Move schema: add a refine so `play` / `jump_in` payloads must carry either
`cardId` or a `card` face, matching the documented move contract instead of
accepting `{ type: "play" }` with neither.
- jump_in tool: restrict the value enum to non-wild faces (the engine always
rejects wild jump-ins), so the model can't propose moves that can never be legal.
- Swipe deletion: prune and shift `game_engine_state` snapshots alongside
`game_state_snapshots` when a message swipe is removed, mirroring the existing
RPG-snapshot cleanup. Without this, turn-game snapshots orphaned and their
swipe indices drifted, breaking the visible-anchor rewind and growing the
table unbounded. Removes the now-redundant unused deleteForMessageSwipes helper.
…tion; fix stale SSE comment Copilot review (PR Pasta-Devs#2721, 4th pass): - turn-games.routes.ts: /move and /start could mutate game_engine_state while /api/generate is running the bot-turn loop for the same chat. Both paths read-modify-write the latest snapshot across awaits, so interleaving races the runner and loses updates (worst for out-of-turn moves like jump_in/call_out). Reject with 409 when app.activeGenerations holds an entry for the chat, mirroring the existing guard in generate.routes.ts and the autonomous scheduler. /resign is left ungated on purpose — blocking a quit mid-turn is worse UX; the proper fix there (abort-then-resign) is out of scope for this change. - UnoBoard.tsx: header comment named the SSE event uno_state_patch, but the server emits and the store listens for turn_game_state_patch. Fixed the stale comment so it matches the implementation.
…election Copilot review (PR Pasta-Devs#2721, 5th pass): - ConversationView.tsx: the UnoSetup modal was mounted unkeyed, so its internal selection / house-rule useState persisted across chat switches. Stale selected ids from a previous chat inflated botCount and could deal an empty botCharacterIds list. Key it by chatId so it remounts and resets on a chat switch, matching the ConversationInput pattern just below. - UnoSetup.tsx: toggleSelected's setState callback ignored its `current` argument and closed over the render-time selectedIds, so batched toggles could clobber each other. Derive `next` from the updater's `current` state, falling back to the chat's character ids only before the user's first selection.
…-facing draw_penalty Copilot review (PR Pasta-Devs#2721, 6th pass): - turn-game-bot-runner.service.ts: the move-selection and narration system prompts hard-coded UNO concepts ("friendly game of UNO", "Wild Draw Four", "declared_color", "playing UNO", bans on naming colors/values), which would mis-instruct bots for any future engine and undercut the game-agnostic design. Base the prompts on engine.label and defer game-specific requirements to the tool descriptions and the engine's own describeForModel(...).instructions. The wild/declared_color requirement already lives in the play_card tool schema, so nothing is lost. Narration guidance is now generic: don't reveal your hand/hidden info, don't recite the board, don't explain rules. - uno/engine.ts: describeForModel(...).legalMoves advertised { type: "draw_penalty" }, but no model-facing tool produces that move — the bot resolves a pending +2/+4 with draw_card (-> { type: "draw" }, which handleDraw already routes to the penalty). Map draw_penalty to draw in the model-facing legal-move list so it matches the available tools and the instruction text, while keeping the distinct draw_penalty action for the UI via publicView's yourActions.canDrawPenalty and the engine's internal apply/fallback paths.
…NO command toggle Copilot review (PR Pasta-Devs#2721, 7th pass): - game-engine-state.storage.ts: create() only deduped when input.messageId was truthy, so repeated writes with messageId === "" (the live anchor — e.g. the bot-turn persistence-failure fallback) accumulated unbounded rows for (chatId, "", swipeIndex). Delete the prior (chatId, messageId, swipeIndex) row unconditionally; the tuple still isolates real-message snapshots and distinct swipes, so single-live-row semantics are kept. - UnoBoard.tsx: icon-only controls lacked accessible names (relied on title, which screen readers don't reliably announce). Added aria-labels to the End-game button, the wild/7-swap close button, and the color-swatch picker buttons, plus a descriptive aria-label on each hand-card button via a new cardName() helper (e.g. "Red 7, playable", "Wild Draw Four"). - ChatSettingsDrawer.tsx / ChatSetupWizard.tsx: "uno" is in CONVERSATION_COMMAND_KEYS but both command-toggle option arrays omitted it, so users couldn't enable/disable UNO from the UI. Added a "UNO" entry to both (the only two surfaces that enumerate command toggles).
The bot-turn announce emit used sendSseEvent, which writes directly to the SSE stream and throws if the client has disconnected — aborting the bot-turn loop mid-game. The marker is non-critical, so use the swallowing trySendSseEvent variant, matching the other emits in this file.
…cap observable startTurnGame now rejects unless chat.mode === "conversation". The whole feature (the [uno] command, bot-turn generate gating, board UI) is conversation-only, so a start in another mode would create a game that can't be advanced and would leave stale game_engine_state rows behind. The bot-turn loop also no longer stalls silently when it exhausts MAX_BOT_TURNS: a non-advancing engine now breaks early with a warning (a fallback move should always change the board), and reaching the cap with a bot still on seat logs a warning. We deliberately do not auto-retrigger another bot generate there — that would reintroduce the unbounded cross-request loop the cap exists to bound; the human resumes the game with any move, which re-fires the loop via the normal path.
…legal draw
pickFallback's out-of-turn branch returned { type: "draw" } as its final
fallback, but draw is never legal when it isn't the seat's turn — only
call_out, declare_uno, and jump_in are. That violated the pickFallbackMove
contract (return a deterministic legal move) and could spin/fail a bot loop if
a future caller ever requested a fallback for an interruptible seat. Now return
the first legal enumerated interrupt (preferring the passive catch/declare, then
jump-in); the empty case is a documented defensive sentinel that production —
which only requests a fallback for the seat on turn — never reaches.
…draw play; 404 for moves with no active game After a voluntary draw the only legal play is the drawn card, but the board summary only listed the full hand, so the model could not tell which card it drew (especially with duplicate faces) and would propose an illegal move and fall back. The board now names the drawn card and the instructions point at it. The engine also resolves a post-draw play against the drawn card's id directly, so a hand with duplicate faces no longer rejects a correct play; an arg-less play_card after drawing now plays that card. Separately, POST /:chatId/move returned 409 for every non-ok outcome, including 'No active game in this chat.' — a missing resource. It now returns 404 for that case (matching GET /state) and keeps 409 only for an illegal move against a live game, which still carries the legal moves to retry with.
Local models should get the tools block
…s-chat Refine chat sidebar presence rendering
Add help output and additional update-entry and delete-entry helper functions
…licts # Conflicts: # packages/client/src/components/panels/SettingsPanel.tsx
…le-picker fix(client): resolve silent theme and extension import failures on Gtk/Firefox
Merge v2.0.3 stabilization fixes, docs, and release metadata into staging.
…revent premature cleanup on Gtk/Firefox (Pasta-Devs#2837) Co-authored-by: Spicy Marinara <mgrabower97@gmail.com>
Merge staging into main for the v2.0.3 release.
* Prepare v2.0.4 hotfixes * Serialize Professor Mari connection saves * Flush held thinking stream before rewrite cache * Fix slash continue targeting * fix(summary): restore auto-hide for roleplay rolling summaries The auto-summary hide path added in Pasta-Devs#2821 was inadvertently reverted by f955a64 ("Local models should get the tools block"). That commit landed the tools-block feature, but its branch carried an older copy of generate.routes.ts that overwrote the auto-hide orchestration, so automatic rolling summaries stopped hiding the messages they covered. Manual summaries and unhide-on-delete were untouched and still work; only the automatic path regressed. Re-apply the dropped block onto current staging, keeping the tools-block change intact: - re-add the computeSummaryHideIds / resolveRoleplaySummaryTail imports - recompute autoHideIds (gated on hideSummarisedMessages, tail-protected) - persist hiddenMessageIds on the summary entry so deletion restores exactly the hidden set - call bulkSetHiddenFromAI and echo hiddenMessageIds in the chat_summary SSE payload The helpers, the storage method, and the manual-hide path all survived the revert, so this is a faithful restoration with no new logic. Refs Pasta-Devs#2820 * Prepare v2.0.4 stabilization polish (Pasta-Devs#2841) --------- Co-authored-by: Romuromylus <233513852+Romuromylus@users.noreply.github.com>
* Prepare v2.0.4 hotfixes * Serialize Professor Mari connection saves * Flush held thinking stream before rewrite cache * Fix slash continue targeting * fix(summary): restore auto-hide for roleplay rolling summaries The auto-summary hide path added in Pasta-Devs#2821 was inadvertently reverted by f955a64 ("Local models should get the tools block"). That commit landed the tools-block feature, but its branch carried an older copy of generate.routes.ts that overwrote the auto-hide orchestration, so automatic rolling summaries stopped hiding the messages they covered. Manual summaries and unhide-on-delete were untouched and still work; only the automatic path regressed. Re-apply the dropped block onto current staging, keeping the tools-block change intact: - re-add the computeSummaryHideIds / resolveRoleplaySummaryTail imports - recompute autoHideIds (gated on hideSummarisedMessages, tail-protected) - persist hiddenMessageIds on the summary entry so deletion restores exactly the hidden set - call bulkSetHiddenFromAI and echo hiddenMessageIds in the chat_summary SSE payload The helpers, the storage method, and the manual-hide path all survived the revert, so this is a faithful restoration with no new logic. Refs Pasta-Devs#2820 * Prepare v2.0.4 stabilization polish (Pasta-Devs#2841) * fix(chat): tracker edit targeting, prefill debounce, prompt-editor close, per-chat lorebook disable, convo card info (Pasta-Devs#2847) * fix(tracker): target tracker character edits by unique id; debounce Assistant Prefill input Two roleplay-mode fixes that share no code but ship together per maintainer request. Character tracker manual edits (and removes/avatar uploads) resolved the target character with findIndex by characterId. Present-character ids come from the LLM character-tracker agent and are not guaranteed unique (the prompt allows "ID or name"), so when several present characters shared an id, findIndex always matched the first one and every edit collapsed onto the first character. Resolve the target via a unique-id match that falls back to the rendered index, mirroring the findUniqueNamedIndex rule already used by the other tracker list mutations. Apply it consistently to edit, remove, and avatar upload. The Assistant Prefill field committed every keystroke straight to a per-chat metadata mutation, so the controlled textarea only advanced after the round-trip and invalidation completed — text appeared one character at a time and got worse as chat metadata grew. Buffer the field locally and commit on blur (and on unmount, so closing the drawer mid-edit keeps the text) via a new DraftTextarea that mirrors the existing DraftNumberInput pattern. * fix(tracker): drop edits whose character id vanished; guard prefill draft re-seed while focused Addresses two regressions surfaced by adversarial review of the original fix. resolveCharacterTargetIndex fell back to the rendered index when a provided characterId was absent from live state, which could write or delete onto a different character if the tracker agent rewrote present characters between render and commit. Restore the previous drop-on-absent behavior: return -1 when the id is provided but not found, and fall back to the rendered index only for the duplicate-id (ambiguous) case. DraftTextarea re-seeded its draft from `value` on every external change, so a background metadata write (or a chat switch) could clobber keystrokes the user was mid-typing in the Assistant Prefill field. Guard the re-seed on focus, matching the sibling ThinkingTagsInput / CustomParametersInput. * fix(chat): keep the expanded prompt editor open when clicked inside a chat drawer The conversation-mode Prompt Preset "Edit Prompt" window (and the sibling Game/Scene expanded editors) is a full-screen overlay portalled to <body>, rendered above the chat settings drawer. The drawer closes itself on any capture-phase pointerdown that lands outside its panel or outside a [data-chat-floating-panel] element. Because the editor lives in a separate portal, the very first click inside it — including on the Collapse button — was treated as "outside", so the drawer closed and unmounted the editor before the edit could commit. Mouse users could neither type nor save. Mark the editor overlay with data-chat-floating-panel so the drawer's outside-click handler treats clicks inside it as inside. Closing now only happens via Collapse/Escape, which route through the editor's onClose and persist the change. * feat(lorebook): let users disable auto-activated lorebooks per chat A lorebook bound to a character (or a global / active-persona book) is force-activated in every non-game chat where it applies, with no way to turn it off from the chat UI. With several characters carrying overlapping books, entries pile up and overflow the token budget, and the only escape was to unbind the book globally. The exclusion plumbing already existed but was only wired to the Game Lorebook Keeper: filterRelevantLorebooks() and listActiveEntries() both honor an excludedLorebookIds filter, but generate/scan/dry-run/prompt paths only ever passed the game-keeper exclusions, and there was no UI or metadata field to set a per-chat exclusion. - shared: add ChatMetadata.excludedLorebookIds. - server: rename resolveGameLorebookScopeExclusions -> resolveLorebookScopeExclusions and fold per-chat excludedLorebookIds into the result for every mode, so all callers (generation, lorebook scan, dry-run, prompt preview) drop excluded books before injection. Validate the field on the metadata PATCH route. - client: surface a "disable in this chat" (eye-off) control on auto-activated books in the chat Lorebooks panel, render disabled books greyed with a re-enable control, and write excludedLorebookIds via the metadata mutation. Disabling does not unbind the book — it only suppresses it for this chat. The redundant pin-an-already-active-book control is replaced by disable; inactive books are still added via the picker. * fix(conversation): include character/persona card info when a prompt preset is selected In Conversation mode the model received only the character and user names — no description, personality, scenario, or persona info — whenever a prompt preset was selected (e.g. the default universal preset). The model would report it had no information about the character it was supposed to play. Conversation mode is deliberately excluded from the preset assembler, so in that mode a preset only supplies the conversation prompt text; it never injects character/persona card fields the way the roleplay assembler does. The identity fallback that would supply them was gated off whenever a preset was present (chatMode !== "game" && !presetId), which is correct for roleplay (the assembler covers it) but left conversation mode with nothing. Always run the identity fallback for conversation mode, regardless of preset. The injector already skips any character/persona whose profile is already present in the prompt, so custom conversation prompts that embed {{description}} et al. are not duplicated, and conversation-without-a-preset behavior is unchanged. --------- Co-authored-by: Romuromylus <233513852+Romuromylus@users.noreply.github.com> * Add streaming to professor maris chat (Pasta-Devs#2852) Co-authored-by: Spicy Marinara <mgrabower97@gmail.com> * Don't turn off streaming by default if tool calling is enabled (Pasta-Devs#2854) Co-authored-by: Spicy Marinara <mgrabower97@gmail.com> * Don't send tool available in system prompt if model supports body.tools (Pasta-Devs#2856) Co-authored-by: Spicy Marinara <mgrabower97@gmail.com> * Don't limit mari chat message amount and length by default (Pasta-Devs#2858) Co-authored-by: Spicy Marinara <mgrabower97@gmail.com> * Prepare v2.0.5 stabilization (Pasta-Devs#2859) * Prepare v2.0.5 stabilization * Address v2.0.5 review feedback --------- Co-authored-by: Romuromylus <233513852+Romuromylus@users.noreply.github.com> Co-authored-by: Romu <jeromehbonaparte@gmail.com> Co-authored-by: Sulphuratum <ristauerik@gmail.com>
Brings the fork up to upstream release v2.0.5 while preserving all of this fork's customizations. Conflicts were limited to the five files this fork had customized; resolved as follows: - CharactersPanel.tsx / PersonasPanel.tsx: took upstream's rewritten panels — which independently reimplement "show only ungrouped outside folders" (foldered-id filtering, synthetic "Ungrouped" folder removed, drag-to-folder assignment, and the persona comment shown on member rows) — then re-applied this fork's multi-open persistent-folder feature on top. Folder open/closed state now lives in the UI store (multi-open, synced + persisted across reloads/storage-clears/devices) instead of upstream's single-open local state, while keeping upstream's folder-filter auto-expand behavior. - ui.store.ts: took upstream, re-added expandedPersonaGroupIds / expandedCharacterGroupIds state, the two toggle actions, and registered both in the synced (pickSyncedSettings) and persisted (partialize) subsets. - model-lists.ts: took upstream, restored this fork's CLAUDE_SUBSCRIPTION_MODELS list (Opus/Sonnet/Haiku + [1m] 1M-context entries and legacy labels) so the picker mirrors the Claude Code menu, and added Fable 5 (base + [1m] variant). - claude-subscription.provider.ts: took upstream, re-applied the [1m]-suffix handling (strip the suffix to a real model id, enable the context-1m-2025-08-07 beta) onto upstream's refactored chat().
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
This fork had drifted to 6 commits ahead / 603 behind Pasta-Devs upstream. This brings it up to upstream release v2.0.5, pulling in 603 commits of upstream fixes and features while keeping every fork-specific customization intact.
What
Merges upstream
v2.0.5(Pasta-Devs/main,c391711b) into the fork'smain(e32a18b3). They diverged atc49f1d95, so conflicts were limited to the five files the fork had customized. Resolution:shared/constants/model-lists.ts): kept the fork's curatedCLAUDE_SUBSCRIPTION_MODELS— current models first then(Legacy), with a base (200k) entry plus a separate[1m](1M-context) entry per 1M-capable model, mirroring the Claude Code menu — and added Fable 5 (base +[1m]).[1m]1M-context handling (server/.../claude-subscription.provider.ts): re-applied onto upstream's refactoredchat(). The[1m]suffix isn't a real model id, so it is stripped to a plain id and the SDKcontext-1m-2025-08-07beta is enabled; the suffixed id is kept only for context-fit sizing so the 1M window is used.PersonasPanel.tsx,CharactersPanel.tsx,ui.store.ts): re-applied on top of upstream's rewritten panels. Folder open/closed state now lives in the UI store (expandedPersonaGroupIds/expandedCharacterGroupIds— multiple folders open at once, synced + persisted) instead of upstream's single-open local state, while keeping upstream's folder-filter auto-expand.The merge commit preserves both parents.
pnpm check(typecheck + lint + build) passes; the server builds and boots after a dependency install.Note for updating installs
Upstream v2.0.5 adds new
@earendil-works/*dependencies, so any install updated to this revision needs apnpm installbefore building.