* feat(wecom): upgrade wecom bot from text-only to full media + progress streaming
- Add image/file message handling with encrypted media download
- Add media upload & send (auto image/file type detection, fallback to text on failure)
- Add real-time per-turn progress streaming via _turn_end_hooks
- Add send_done with automatic file attachment extraction from agent replies
- Add terminal CLI: help/status/stop/exit for runtime control
- Add run stats tracking (received/completed counts)
- Refactor message parsing into shared _accept() method (dedup + auth + register)
- Harden None-safety on body.get(from) and dedup ID fallback
- Move state from module globals to instance attributes
* refactor(wecomapp): parameterize agent & client, remove dead code
- Remove module-level agent creation; inject via constructor
- Make WSClient injectable in start() for testability
- Clean up stale comments and version tag
- Add inline doc for split_limit
Only use a proxy for tgapp when mykeys['proxy'] is explicitly configured, avoiding the dead default local proxy and restoring Telegram polling startup.
Closes#175
The proxy was hardcoded to http://127.0.0.1:2082 which breaks for users
without a local proxy (e.g. international users with direct access).
Now defaults to None; users who need a proxy can set it in mykey.py.
- Add /llm command to list available models
- Add /llm [n] command to switch to specific model
- Improve /status command to show current LLM info with emoji indicators
- Update /help text to include /llm command
- Unify command parsing logic using parts and op variables
This brings fsapp.py (Feishu/Lark) frontend in line with other chat frontends (QQ, DingTalk, WeCom) that already support all slash commands.
When the user runs '/continue N' in stapp, the agent's in-memory context
is restored, but the UI previously showed only a single '✅ restored' line
— all prior chat bubbles were missing.
This change parses the target session log and reconstructs the
user/assistant message pairs into st.session_state.messages, so reopening
a session feels like the conversation was never interrupted.
* continue_cmd.py: add extract_ui_messages(path)
- parses model_responses log into [{role, content}, ...]
- groups multi-turn LLM calls (prompts whose text starts with the
'### [WORKING MEMORY]' header) into a single assistant bubble,
inserting the existing '**LLM Running (Turn N) ...**' marker so
fold_turns() renders them as collapsible segments.
- two small helpers (_user_text / _assistant_text) keep parsing local.
* stapp.py: in the /continue branch, resolve the target log path BEFORE
calling handle_frontend_command (which snapshots the current log and
would otherwise shift list_sessions indices), then replace
session_state.messages with the reconstructed history on success.
Falls back to the previous behavior for bare /continue or failure.
Co-authored-by: wjl2023 <wjl2023@users.noreply.github.com>
Rework the Feishu frontend so each user turn renders as a single
collapsible task card that patches itself in place, replacing the
dq-based streaming path that produced many fragmented messages.
- One _TaskCard per turn; hook reacts to summary / exit_reason events
from the agent loop and patches the same card.
- Each step is a foldable panel: header shows the summary, expanding
reveals three sections (auto-hidden when empty):
* Thinking - from response.thinking (separate field, not content)
* Tool Calls - tool name + truncated JSON args
* Output - response.content, with protocol tags stripped so
the header summary is not duplicated inside
- Final reply rendered as a schema 2.0 markdown card for consistency.
- Code-review pass per code_review_principles.md:
* _TaskCard owns only stateful card lifecycle (start/step/done/fail)
* Pure formatting extracted to module-level _build_step_detail and
_fmt_tool_call (no more reaching into card._private from the hook)
* Hook is a ~10-line dispatcher
* Flattened a 4-level nested lambda into a named function
Replace full-redraw approach with frozen/live slot pattern:
- Completed segments are frozen into individual st.empty() slots
- Only the last (active) segment is re-rendered on each tick
- Reduces flicker and improves performance for long multi-turn conversations