Repository navigation
Upstream sync - #2
Merged
Merged
Conversation
…on this branch Heavy upstream refactor brought in: - jcode-protocol crate extraction (replaces monolithic protocol.rs) - jcode-config-types, jcode-session-types, etc. extracted - session.rs re-exports types from session/model.rs and submodules - Rewind / RewindUndo replace the old request shape Features dropped here (still on master): - /branches and /checkout RPC dispatch (Request::Checkout removed; no compatible server handler in upstream's new routing) - Backend.rewind / .checkout / .mcp_control helpers removed - ServerEvent::Rewound / McpResult / McpControl handling stripped - Session.reasoning_effort field gone in upstream - ToolPermissionMode kept as a local enum in safety.rs since safety code still uses it but the type is absent from upstream's config Schema kept so tree-branching can be re-ported later: - StoredMessage.parent_id, Session.active_leaf_id - StoredDisplayRole::UserCommand - Session::active_path / leaves / set_active_leaf / find_message_by_short_id - Session::add_system_note / add_user_command / active_real_leaf - truncate_messages re-anchors active_leaf_id Library + binary compile. /branches and /checkout are NOT functional on this branch — switch to master to use them.
…am-sync Re-port the features that were dropped during the merge into upstream's new request-routing layer: - Re-add Request::Checkout to jcode-protocol with the same shape as before. Server-side handle_checkout dispatch lives inline in client_lifecycle.rs (no separate handler file in upstream's structure) and follows the rewind pattern: lock agent, validate target as a real leaf, set_active_leaf + record_user_command + record_system_note, then push the new history via handle_get_history. - Restore Backend::checkout helper that mirrors Backend::rewind: clears has_loaded_history so the server's follow-up history payload paints. - /branches and /checkout slash commands re-added in commands.rs. /branches reads from disk so it works in remote and standalone modes; /checkout bails out in remote mode so the RPC dispatcher in remote/key_handling.rs takes over. - /rewind and /checkout now also record a UserCommand entry (the typed slash command) and a System note (the "✓ ..." reply) on the active branch so the user can see in scroll-back what they typed to navigate. Agent helpers re-added: session_ref, checkout_active_leaf, record_system_note, record_user_command. Tree primitives on Session were already preserved through the merge. Library + binary build clean. Master remains untouched.
…ests cover leaves/active_real_leaf Three pieces that the previous merge commits had left unfinished: - All test files now compile. Earlier I only ran cargo check --lib so ~22 broken test fixtures slipped through: missing parent_id: None on StoredMessage literals (10 in client_session_tests/reload.rs, plus one each in 8 other test modules) and missing profile_id + static_context_limits on OpenRouterProvider literals (2 sites). Mechanical fix. - Per-tool permission gating restored. Upstream removed cfg.safety.tool_permission_mode plus the Registry::ensure_tool_permission caller, so safety::tool_permission_requirement was a dead island. Added Registry::ensure_tool_permission back at the same point in the execute() flow. Mode is now read from JCODE_TOOL_PERMISSION_MODE (default Autopilot — same effective behavior as upstream); set it to ask|strict|confirm to opt into the gating that master had. Avoids having to re-add a config field to the jcode-config-types crate. - New unit test covers leaves()/active_real_leaf() with a tree that has two real branch tips plus navigation notes (UserCommand + System appended after a checkout). Confirms /branches won't surface the notes as fake branches and the active marker walks back through them. cargo test --lib session::tests::cases passes (27 tests). Library + binary build clean.
Merge regressed commit 1f78dc8. /info was back to printing `{short_name} ({id[..8]})` which in remote mode shows the TUI's local placeholder id (an animal name unrelated to the actual session), producing things like 'Session: jaguar (session_)' where the parens just contain the universal 'session_' prefix. Switch to active_client_session_id() so the displayed id is the real server-owned session id — the one that exists in ~/.jcode/sessions/. This is the same fix that was on master before the upstream merge.
Real bug, not the rewind: every time a session was loaded from disk (load_from_path, load_for_remote_startup, session_from_remote_startup_snapshot) the new active_leaf_id field stayed None even when messages existed. On the next append, append_stored_message saw active_leaf_id=None, gave the new message parent_id=None (treating it as a root), and advanced the leaf to that new message. From that point on active_path() walked back from the new leaf, found parent_id=None, and returned just that one message — so render and provider_messages both showed only the latest prompt+reply. Prior history vanished from the UI even though it was still on disk in session.messages. Add Session::ensure_active_leaf_backfilled() and call it from all three load paths. Backfill picks the last message's id as the leaf, preserving linear semantics for sessions that have never branched. Reproducing test: ensure_active_leaf_backfilled_prevents_history_loss_on_load constructs a session, clears active_leaf_id (simulating the load anti-pattern), runs the backfill, appends a new message, and asserts the active path includes all three messages.
Two changes investigating "user prompts disappearing from chat": 1. Fix: Interleave-path prompts now appear in display_messages. When the user presses Enter while is_processing is true (e.g., right after a streaming response finishes but before the Done event has flipped the flag back), send_action routes the message through SendAction::Interleave -> remote.soft_interrupt(). That path was sending the content to the server but never pushing a user-styled DisplayMessage to the chat, so the user typed something and saw nothing visible (their prompt vanished). Now we mirror the prompt to display before sending, matching what Submit already does. 2. Diagnostics: log every push/replace/clear of display_messages and the should_apply branch in the History event handler. With these on, future "lost prompt" reports can be traced exactly: was the prompt pushed? coalesced? replaced? cleared? Useful when the bug is intermittent and we need to see what happened in a specific session. The interleave fix solves the most common cause of the symptom. There is a remaining intermittent render-side issue where a pushed user message doesn't appear visually even though it's in display_messages (the diagnostics confirm the data is correct). Reproducing this reliably needs interactive driving of the TUI; the data layer has been ruled out so the bug is somewhere in body cache invalidation or the render-line pipeline.
…s a branch immediately Three matched changes that together give the user-mental-model rewind: - /rewind N now keeps the first N user prompts AND each one's full assistant turn (replies/tools), instead of upstream's 'keep N visible messages' which was off by one for any prompt-reply pair. Server dispatch in client_lifecycle.rs calls rewind_to_prompt instead of rewind_to_message. - Re-add Agent::rewind_to_prompt that was removed during the upstream merge. Non-destructive: moves the active leaf back, preserves the dropped suffix on disk so /branches sees it as a sibling. The tree itself replaces upstream's rewind_undo snapshot mechanism. - Session::leaves() now also includes the current active_real_leaf even when it has children. After /rewind the active leaf is a fork point with the dropped tail hanging off it; without this the user would have to type a new prompt to materialize the rewound state as a visible branch in /branches. Now /branches lists both immediately and the leaf_label still walks back to the most recent user prompt for each, matching 'branch title = last kept prompt.' Also sticky: the body-cache fix from v0.11.19 (clear_body_cache on display_messages clear/replace) — that one was the lost-message bug. This commit is the rewind-semantics layer on top. cargo test --lib session::tests::cases passes (28). Library + binary build clean.
Treat any message that is the parent of a navigation note (UserCommand / System) as a branch tip alongside true leaves and the current active leaf. Without this, after /rewind + /checkout the rewound fork point fell out of /branches because it had children (the dropped suffix) and was no longer the active leaf. Also remove the unused branch_anchors field on Session — dead scaffolding that was never initialized or read.
Several fixes that together stop Sonnet from going on a goose chase
when asked to "look something up online":
- Beef up the websearch tool description from "Search the web." to a
full paragraph spelling out when to use it and what it returns. The
three-word version was too thin; the model would skip it in favor of
whatever Claude-Code-shaped tool name (`ToolSearch`, `WebSearch`)
was in its prior.
- Alias `WebSearch` and `web_search` to `websearch` (and `WebFetch` to
`webfetch`) since those are direct synonyms in the model's training.
Do NOT alias `ToolSearch` — Claude Code's `ToolSearch` returns tool
schemas, not search results, so wiring it to websearch produces
confusion ("I got results but the model says it has no web search
tool"). Better to fail Unknown.
- When a tool call fails with Unknown tool, surface a corrective hint
pointing at the closest jcode equivalent (e.g. `ToolSearch` → "use
`websearch` instead") plus the full available tool list. Fixes the
pattern where the model tries one wrong name, sees Unknown, and
gives up instead of looking at the catalog.
- Tool-list lock now invalidates correctly when MCP tools register
asynchronously. Previous attempt compared post-filter `locked.len()`
against pre-filter `tool_count()`, which were perpetually 34 vs 35
for non-canary sessions and caused an infinite invalidate→re-lock
loop that burned prompt cache every turn. Track `tool_count` at
lock time and compare against the live count instead.
- Global instructions (AGENTS.md) now prefer `$JCODE_HOME/AGENTS.md`
over the shared `~/AGENTS.md` if present. Lets users keep separate
global files for jcode vs other AGENTS.md-aware tools (e.g. Claude
Code), so Claude-Code-specific tool names like `mcp__context7` or
`claude-renames` stop leaking into jcode's prompt.
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.
No description provided.