fix: 4 pre-release bug fixes — identity override, model config, agent sync, auto-identity
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

P1: identity.rs get_identity() returns empty soul/instructions for agents
without explicit identity files. This prevents the default ZCLAW personality
from overriding agent_config.system_prompt. New get_identity_or_default()
method added for the DEFAULT agent.

P2: messaging.rs now uses agent_config.model.model when available, falling
back to global Kernel config. This allows per-agent model selection.

P2: agentStore.ts loadClones retries up to 3 times (300ms interval) when
getClient() returns null, handling the coordinator initialization race.

P2: agent_create Tauri command auto-populates identity files (soul +
instructions) from creation parameters, ensuring build_system_prompt()
has content for new agents.

Also fixes conversationStore upsertActiveConversation to persist generated
conversation IDs, preventing duplicate entries on new conversations.
This commit is contained in:
iven
2026-04-08 21:47:46 +08:00
parent 8eeb616f61
commit adcce0d70c
5 changed files with 112 additions and 21 deletions

View File

@@ -221,13 +221,39 @@ impl AgentIdentityManager {
}
}
/// Get identity files for an agent (creates default if not exists)
/// Get identity files for an agent.
///
/// Returns empty soul/instructions for agents without explicit identity files.
/// This ensures `build_system_prompt()` returns an empty string when no
/// identity has been configured, allowing `agent_config.system_prompt` to
/// take precedence via the `system_prompt_override` flow in `messaging.rs`.
///
/// The default soul/instructions are only used when explicitly requested
/// via `get_identity_or_default()` (e.g., for the DEFAULT agent).
pub fn get_identity(&mut self, agent_id: &str) -> IdentityFiles {
if let Some(existing) = self.identities.get(agent_id) {
return existing.clone();
}
// Initialize with defaults
// Return empty identity — do NOT auto-populate with defaults.
// The identity system should be opt-in: only agents with explicit
// SOUL.md / USER.md files get identity-based prompts.
let empty = IdentityFiles {
soul: String::new(),
instructions: String::new(),
user_profile: default_user_profile(),
heartbeat: None,
};
empty
}
/// Get identity files for an agent, falling back to defaults.
/// Used for the DEFAULT ZCLAW agent which should always have a personality.
pub fn get_identity_or_default(&mut self, agent_id: &str) -> IdentityFiles {
if let Some(existing) = self.identities.get(agent_id) {
return existing.clone();
}
let defaults = IdentityFiles {
soul: default_soul(),
instructions: default_instructions(),
@@ -741,9 +767,20 @@ mod tests {
use super::*;
#[test]
fn test_get_identity_creates_default() {
fn test_get_identity_returns_empty_for_new_agent() {
let mut manager = AgentIdentityManager::new();
let identity = manager.get_identity("test-agent");
let agent_id = format!("test-empty-{}", std::process::id());
let identity = manager.get_identity(&agent_id);
// New agents without explicit identity files should have empty soul/instructions
assert!(identity.soul.is_empty());
assert!(identity.instructions.is_empty());
}
#[test]
fn test_get_identity_or_default_creates_default() {
let mut manager = AgentIdentityManager::new();
let agent_id = format!("test-default-{}", std::process::id());
let identity = manager.get_identity_or_default(&agent_id);
assert!(!identity.soul.is_empty());
assert!(!identity.instructions.is_empty());
}
@@ -751,16 +788,18 @@ mod tests {
#[test]
fn test_update_user_profile() {
let mut manager = AgentIdentityManager::new();
manager.update_user_profile("test-agent", "New profile content");
let identity = manager.get_identity("test-agent");
let agent_id = format!("test-profile-{}", std::process::id());
manager.update_user_profile(&agent_id, "New profile content");
let identity = manager.get_identity(&agent_id);
assert_eq!(identity.user_profile, "New profile content");
}
#[test]
fn test_proposal_flow() {
let mut manager = AgentIdentityManager::new();
let agent_id = format!("test-proposal-{}", std::process::id());
let proposal = manager.propose_change(
"test-agent",
&agent_id,
IdentityFile::Soul,
"New soul content",
"Test proposal",
@@ -775,17 +814,18 @@ mod tests {
let result = manager.approve_proposal(&proposal.id);
assert!(result.is_ok());
let identity = manager.get_identity("test-agent");
let identity = manager.get_identity(&agent_id);
assert_eq!(identity.soul, "New soul content");
}
#[test]
fn test_snapshots() {
let mut manager = AgentIdentityManager::new();
manager.update_user_profile("test-agent", "First update");
manager.update_user_profile("test-agent", "Second update");
let agent_id = format!("test-snapshots-{}", std::process::id());
manager.update_user_profile(&agent_id, "First update");
manager.update_user_profile(&agent_id, "Second update");
let snapshots = manager.get_snapshots("test-agent", 10);
let snapshots = manager.get_snapshots(&agent_id, 10);
assert!(snapshots.len() >= 2);
}
}