Skip to content

fix: /resume latest searches all workspaces#2811

Open
TheArchitectit wants to merge 9 commits into
ultraworkers:mainfrom
TheArchitectit:fix/resume-latest
Open

fix: /resume latest searches all workspaces#2811
TheArchitectit wants to merge 9 commits into
ultraworkers:mainfrom
TheArchitectit:fix/resume-latest

Conversation

@TheArchitectit
Copy link
Copy Markdown

@TheArchitectit TheArchitectit commented Apr 27, 2026

Summary

Fixes /resume latest not finding sessions. Two separate bugs that together made session resume nearly unusable when switching directories.

Problem this solves

Bug 1: /resume latest only searches current workspace

Before: sessions were only searched in the current workspace's fingerprinted directory (<cwd>/.claw/sessions/<fingerprint>/). If you started claw from a different directory than where your session was created, /resume latest found zero sessions even though sessions existed elsewhere on disk. Since sessions are partitioned by workspace fingerprint (hash of the CWD), switching directories made all previous sessions invisible.

This is especially painful for users who work in multiple project directories — switching from ~/project-a to ~/project-b means /resume latest in project-b can never find sessions from project-a.

Fix: Three-tier session lookup fallback in latest_session():

  1. Tier 1: Current workspace's fingerprint dir (existing behavior, unchanged)
  2. Tier 2: Scan all fingerprint subdirs under the project-local <cwd>/.claw/sessions/
  3. Tier 3: Scan all fingerprint subdirs under the global ~/.claw/sessions/

scan_global_sessions() iterates all fingerprint subdirectories using collect_sessions_from_dir_unvalidated() which skips workspace validation. Results are sorted by recency.

Bug 2: /resume latest returns the empty current session

Before: /resume latest always returned the most recently created session — which was the empty session just created on startup. So every time you ran /resume latest from a fresh claw instance, it would "resume" a brand new empty session instead of your previous conversation with actual history.

Fix: load_session_loose() skips:

  • The current session ID (so /resume latest from a running REPL doesn't return itself)
  • Sessions with message_count == 0 (so empty startup sessions are skipped, returning the previous one with actual history)

The exclude ID flows from the REPL CLI through load_session_reference()SessionStore::load_session_loose()resolve_reference()latest_session().

Cross-workspace resume

load_session_loose() allows cross-workspace resume for alias references (latest, last, recent), printing a note like:

  Note: resuming session from a different workspace (origin: /home/user/project-alpha)

Explicit session IDs still enforce workspace validation — you must be explicit about cross-workspace resume.

Files changed

File What changed
runtime/src/session_control.rs Added global_sessions_root(), scan_global_sessions() with 3-tier fallback, load_session_loose() for cross-workspace aliases, collect_sessions_from_dir_unvalidated(). Updated latest_session() to try global fallback. Updated error message hint.
runtime/src/config_validate.rs Added provider top-level field + PROVIDER_FIELDS constant (shared with #2810 — needed because user's settings.json already contains the provider key)
rusty-claude-cli/src/main.rs Use load_session_loose() for alias references so /resume latest can find sessions across workspaces
commands/src/lib.rs #[allow(clippy::unnecessary_wraps)] on two helper functions that return Result for future-proofing

Test plan

  • cargo test --workspace — all tests pass
  • cargo clippy --workspace --all-targets -- -D warnings — clean
  • /resume latest in REPL — returns previous session with messages, not empty current session
  • Start claw, have a conversation, exit, start claw again, /resume latest — brings back the previous chat
  • Session message count and turn count shown correctly on resume
  • /resume <explicit-id> from different workspace — still errors with WorkspaceMismatch
  • /resume latest from a completely different directory — finds session across workspaces

💘 Generated with Crush

@TheArchitectit TheArchitectit marked this pull request as draft April 27, 2026 00:38
@TheArchitectit TheArchitectit marked this pull request as ready for review April 27, 2026 01:54
@Pilser
Copy link
Copy Markdown

Pilser commented Apr 27, 2026

hello @TheArchitectit , Can you also fix when xai configured and ask who are you the model respond that it is claude model yet it config it show xai is the one configured , and I dont have claude key so its xai model claim being claude ,

I recently sent this,
massage to @programming-pupil
programming-pupil this massage and he fixed only xai api to be compatible but model identity still failed .

here the old massage (Can you also fix this? ## xAI / Grok-3 Integration
Problem

claw always routed requests to api.anthropic.com regardless of which model was specified. Using --model grok-3 still sent requests to Anthropic, causing 401 errors.
Root Cause

AnthropicRuntimeClient.client was hardcoded to AnthropicClient, which always uses Authorization: x-api-key and sends to Anthropic's endpoint. ProviderClient already existed in the codebase and could route by model name prefix (grok-* → xAI, claude-* → Anthropic) but was never wired into the CLI runner.
Fix — claw-code-parity/rust/crates/rusty-claude-cli/src/main.rs

Added ProviderClient to the use api::{...} import block
Changed AnthropicRuntimeClient.client field type from AnthropicClient → ProviderClient
Changed AnthropicRuntimeClient::new() to use ProviderClient::from_model_with_anthropic_auth(&model, Some(resolve_cli_auth_source()?))
Updated push_prompt_cache_record signature from &AnthropicClient → &ProviderClient

Fix: claw Says "I'm Claude Opus 4.6" When Using Grok
Problem

When asked "what model are you?", claw replied "I'm Claude, specifically Claude 3.7 Sonnet" even when running grok-3.
Root Cause

runtime/src/prompt.rs:38:

pub const FRONTIER_MODEL_NAME: &str = "Claude Opus 4.6";

This was injected into every session's system prompt as:

Model family: Claude Opus 4.6

Grok reads its own system prompt and reports that as its identity. No Anthropic API key required — it's just hardcoded text.
Fix — claw-code-parity/rust/crates/runtime/src/prompt.rs

Added model_name: Option<String> field to SystemPromptBuilder
Added pub fn with_model(mut self, model_name: impl Into<String>) -> Self builder method
Changed environment_section() to use self.model_name.as_deref().unwrap_or(FRONTIER_MODEL_NAME) instead of the constant
Added pub fn load_system_prompt_for_model(...) — same as load_system_prompt but accepts model_name: Option<&str> and calls builder.with_model(name)

Fix — claw-code-parity/rust/crates/runtime/src/lib.rs

Added load_system_prompt_for_model to the pub use prompt::{...} re-export block

Fix — claw-code-parity/rust/crates/rusty-claude-cli/src/main.rs

Imported load_system_prompt_for_model from runtime
Changed build_system_prompt() signature to build_system_prompt(model: &str)
Passes Some(model) to load_system_prompt_for_model
Updated LiveCli::new() to call build_system_prompt(&model)

)

code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 27, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 27, 2026
@TheArchitectit
Copy link
Copy Markdown
Author

The other feature which allows you set to provider should take care of this?

code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 28, 2026
code-yeongyu added a commit to code-yeongyu/claw-code-1 that referenced this pull request Apr 29, 2026
@TheArchitectit
Copy link
Copy Markdown
Author

what else do you need to merge this in?

TheArchitectit and others added 9 commits May 10, 2026 21:31
Previously /resume latest only searched the current workspace's
fingerprinted session directory. If you started claw from a different
directory, it found zero sessions even though sessions existed
elsewhere on disk.

Changes:
- Add global_sessions_root() pointing to ~/.claw/sessions/
- Add scan_global_sessions() to scan all workspace namespaces
- Modify latest_session() to fall back to global scan when no
  workspace-local sessions are found
- Add load_session_loose() that skips workspace validation for
  alias references (latest/last/recent) so cross-workspace resume
  works while still enforcing workspace check for explicit IDs
- Wire load_session_loose() into CLI's load_session_reference()
- Add provider field to config validation schema (needed because
  user's settings.json already has the provider key)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The previous implementation only scanned ~/.claw/sessions/ for the
global fallback, but sessions are actually stored in the project-local
<cwd>/.claw/sessions/<fingerprint>/ by SessionStore::from_cwd().
Now scans both the global root and the project-local parent directory
(checking all fingerprint subdirs) so /resume latest finds sessions
regardless of where they're stored.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some OpenAI-compatible providers (e.g., GLM-5) omit the `id` field in
streaming and non-streaming responses. Adding #[serde(default)] allows
the parser to accept these responses instead of failing with
"missing field `id`".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds scripts/install.sh that builds the release binary and links it
to ~/.local/bin/claw. Run after code changes to update the CLI.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns HTML (e.g., error page, wrong endpoint) instead
of JSON in an SSE stream, provide a clear error message instead of
hanging or failing with a cryptic parse error.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When a provider returns a JSON error (e.g., {"error":{"message":"..."}})
without SSE framing (no "data:" prefix), the SSE parser was silently
ignoring it and hanging. Now detects and surfaces these errors.

Also handles HTML responses that lack SSE framing.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Some providers (GLM, DeepSeek) emit reasoning tokens in `reasoning_content`
or nested `thinking.content` fields instead of `content`. Added support
for these fields so reasoning models work correctly.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The final streaming chunk from some providers contains only finish_reason
and usage, with no delta field. Made it optional to prevent parse errors.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
When preserve_recent_messages == 0, raw_keep_from equals messages.len(),
causing index out of bounds when accessing session.messages[k].

Added k >= session.messages.len() check to prevent panic.

Reason: Compaction with preserve_recent_messages=0 triggered OOB access
when checking for tool-use/tool-result pair preservation at boundary.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants