[Bug]: Slash commands right after desktop startup act on the fallback session (/compact reports an empty memory)
QwenPaw Version
2.2.1 (desktop/Tauri build from the official release, backend rebuilt from tag v2.2.1
for verification)
Description
Right after the desktop app starts, a slash command typed into the chat box acts on a
different conversation than the one on screen. The most visible case is /compact,
which answers " No messages to compact. Current memory is empty." while the open chat
clearly has messages. The same request in a browser tab against the same backend works.
Root cause chain (verified against a running instance):
- The console submits the request with an empty
session_idwhile the route / chat list is still resolving.isSubmissionTargetReady()inconsole/src/pages/Chat/submissionBizParams.tsreturnstruewhenever the route has no chat id (return !routeChatId || routeChatId === "new" || !!resolvedRouteSessionId;), so nothing holds the submission back, whilegetSessionIdentity()inconsole/src/pages/Chat/sessionApi/index.tsstill yieldssessionId: "". _extract_session_and_payload()(src/qwenpaw/app/routers/console.py) passes the empty string on, andConsoleChannel.resolve_session_id()falls back to"<channel>:<sender_id>", i.e.console:default.- The command then executes against that fallback session — an unrelated, stale chat.
Related PR(s): none yet (see Additional Notes)
Security considerations: none — no new inputs, no credential or config handling.
Component(s) Affected
- Core / Backend (app, agents, config, providers, utils, local_models)
- Console (frontend web UI)
- Channels (DingTalk, Feishu, QQ, Discord, iMessage, etc.)
- Skills
- CLI
- Documentation (website)
- Tests
- CI/CD
- Scripts / Deploy
Environment
- QwenPaw version: 2.2.1
- OS: macOS 15 (Apple silicon)
- Install method: official desktop release (Tauri bundle, PyInstaller backend)
- Python version (if applicable): 3.11 (bundled runtime)
Steps to Reproduce
- Have at least one existing conversation with messages.
- Start the desktop app (or restart its backend) with that conversation open.
- Within the first ~10 seconds after the window appears — before the conversation list
has settled — send
/compact.
Actual vs Expected
- Actual: the reply is " No messages to compact. Current memory is empty." The
backend loaded the fallback session instead of the open chat, and a ghost chat whose
session_idis literallyconsole:defaultappears inchats.jsonand gets itsupdated_atbumped on every such request. - Expected: the command acts on the conversation the user has open — or the request is rejected with a clear error. It should never be silently retargeted to another session.
Logs / Screenshots
Failing request from the desktop app (note the session file):
2026-09-16 13:03:40 | INFO | qwenpaw/app/chats/session.py:334 | Load session state from
.../workspaces/default/sessions/console/default_console--default.json successfully.
2026-09-16 13:03:40 | INFO | qwenpaw/agents/command_handler.py:1336 | Processing command: compact
2026-09-16 13:03:40 | INFO | qwenpaw/app/chats/session.py:303 | Saved session state to
.../sessions/console/default_console--default.json successfully.Working request from a browser tab against the same backend — captured body:
{"session_id":"1789553264935-bo27ft9","user_id":"default","channel":"console",
"input":[{"role":"user","content":[{"type":"text","text":"/compact"}]}],"stream":true}2026-09-16 13:08:34 | INFO | qwenpaw/app/chats/session.py:334 | Load session state from
.../sessions/console/default_1789553264935-bo27ft9.json successfully.
2026-09-16 13:08:34 | INFO | qwenpaw/agents/command_handler.py:1336 | Processing command: compact
2026-09-16 13:08:47 | INFO | qwenpaw/agents/context/scroll/manager.py:466 | scroll: compact
timing outcome=done total=13110.5ms ...Additional Notes
Two independent guards, either of which stops the silent retargeting:
- Console: do not submit while the target identity is unresolved — drop the
!routeChatIdshortcut inisSubmissionTargetReady()so an unresolved session blocks the send instead of producing an emptysession_id. - Backend: treat an explicitly empty
session_idas a client error (HTTP 400) in_extract_session_and_payload()instead of letting it reach the channel fallback; a missing field can keep its documented default.
I have the backend guard implemented with unit tests locally ("" and " " → HTTP 400
with a readable message, valid session unchanged) and can open a PR for it if you want it
separately from the console-side fix.
Source: agentscope-ai/QwenPaw