fix(desktop): session persistence — refresh/login/context/empty-content 4-bug fix
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled

1. App.tsx: add restoreSession() call on startup to prevent redirect
   to login page after refresh (isRestoring guard + BootstrapScreen)
2. CloneManager: call syncAgents() after loadClones() to restore
   currentAgent and conversation history on app load
3. zclaw-memory: add get_or_create_session() so frontend session UUID
   is persisted directly — kernel no longer creates mismatched IDs
4. openai.rs: assistant message content must be non-empty for
   Kimi/Qwen APIs — replace empty content with meaningful placeholders

Also includes admin-v2 ModelServices unified page (merge providers +
models + API keys into expandable row layout)
This commit is contained in:
iven
2026-03-31 13:38:59 +08:00
parent 3e5d64484e
commit 6cae768401
29 changed files with 1982 additions and 933 deletions

View File

@@ -360,10 +360,14 @@ impl OpenAiDriver {
if let Some(calls) = calls {
if !calls.is_empty() {
// Merge assistant content + reasoning into the tool call message
// Merge assistant content + reasoning into the tool call message.
// IMPORTANT: Some APIs (Kimi, Qwen) require `content` to be non-empty
// even when tool_calls is set. Use a meaningful placeholder if content is empty.
let content_value = content.filter(|s| !s.trim().is_empty())
.unwrap_or_else(|| "正在调用工具...".to_string());
out.push(OpenAiMessage {
role: "assistant".to_string(),
content: content.filter(|s| !s.is_empty()),
content: Some(content_value),
reasoning_content: reasoning.filter(|s| !s.is_empty()),
tool_calls: Some(calls),
tool_call_id: None,
@@ -371,11 +375,14 @@ impl OpenAiDriver {
return;
}
}
// No tool calls — emit a plain assistant message
// No tool calls — emit a plain assistant message.
// Ensure content is always Some() and non-empty to satisfy API requirements.
if content.is_some() || reasoning.is_some() {
let content_value = content.filter(|s| !s.trim().is_empty())
.unwrap_or_else(|| "正在思考...".to_string());
out.push(OpenAiMessage {
role: "assistant".to_string(),
content: content.filter(|s| !s.is_empty()),
content: Some(content_value),
reasoning_content: reasoning.filter(|s| !s.is_empty()),
tool_calls: None,
tool_call_id: None,