feat: bot greets you on connect now
Security Scan and Upload / Security & DefectDojo Upload (pull_request) Successful in 56s
CI / Lint & Test (pull_request) Failing after 5m40s
CI / Build Linux (pull_request) Has been skipped
CI / Build Windows (cross-compile) (pull_request) Has been skipped

This commit is contained in:
2026-01-16 13:57:40 -08:00
parent 0dffec4d43
commit f8e989c5ab
2 changed files with 37 additions and 12 deletions
+17 -2
View File
@@ -21,7 +21,7 @@ pub struct ClaudeStartOptions {
pub allowed_tools: Vec<String>, pub allowed_tools: Vec<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize, Default)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HikariConfig { pub struct HikariConfig {
#[serde(default)] #[serde(default)]
pub model: Option<String>, pub model: Option<String>,
@@ -48,6 +48,21 @@ pub struct HikariConfig {
pub greeting_custom_prompt: Option<String>, pub greeting_custom_prompt: Option<String>,
} }
impl Default for HikariConfig {
fn default() -> Self {
Self {
model: None,
api_key: None,
custom_instructions: None,
mcp_servers_json: None,
auto_granted_tools: Vec::new(),
theme: Theme::default(),
greeting_enabled: true,
greeting_custom_prompt: None,
}
}
}
fn default_greeting_enabled() -> bool { fn default_greeting_enabled() -> bool {
true true
} }
@@ -73,7 +88,7 @@ mod tests {
assert!(config.mcp_servers_json.is_none()); assert!(config.mcp_servers_json.is_none());
assert!(config.auto_granted_tools.is_empty()); assert!(config.auto_granted_tools.is_empty());
assert_eq!(config.theme, Theme::Dark); assert_eq!(config.theme, Theme::Dark);
assert!(!config.greeting_enabled); assert!(config.greeting_enabled);
assert!(config.greeting_custom_prompt.is_none()); assert!(config.greeting_custom_prompt.is_none());
} }
+20 -10
View File
@@ -11,20 +11,25 @@ interface StateChangePayload {
tool_name: string | null; tool_name: string | null;
} }
function generateTimeBasedGreeting(): string { function getTimeOfDay(): string {
const hour = new Date().getHours(); const hour = new Date().getHours();
if (hour >= 5 && hour < 12) { if (hour >= 5 && hour < 12) {
return "Good morning! How can I help you today?"; return "morning";
} else if (hour >= 12 && hour < 17) { } else if (hour >= 12 && hour < 17) {
return "Good afternoon! What are we working on?"; return "afternoon";
} else if (hour >= 17 && hour < 21) { } else if (hour >= 17 && hour < 21) {
return "Good evening! Ready to get some work done?"; return "evening";
} else { } else {
return "Working late? I'm here to help!"; return "late night";
} }
} }
function generateGreetingPrompt(): string {
const timeOfDay = getTimeOfDay();
return `[System: A new session has started. It's currently ${timeOfDay}. Please greet the user warmly and briefly. Keep it short - just 1-2 sentences.]`;
}
async function sendGreeting() { async function sendGreeting() {
const config = configStore.getConfig(); const config = configStore.getConfig();
@@ -32,12 +37,17 @@ async function sendGreeting() {
return; return;
} }
const greetingPrompt = config.greeting_custom_prompt?.trim() || generateTimeBasedGreeting(); const greetingPrompt = config.greeting_custom_prompt?.trim() || generateGreetingPrompt();
// Don't show the system prompt in the UI - just trigger Claude to respond
characterState.setState("thinking");
try { try {
await invoke("send_prompt", { message: greetingPrompt }); await invoke("send_prompt", { message: greetingPrompt });
} catch (error) { } catch (error) {
console.error("Failed to send greeting:", error); console.error("Failed to send greeting:", error);
claudeStore.addLine("error", `Failed to send greeting: ${error}`);
characterState.setTemporaryState("error", 3000);
} }
} }
@@ -48,13 +58,15 @@ interface OutputPayload {
} }
export async function initializeTauriListeners() { export async function initializeTauriListeners() {
await listen<string>("claude:connection", (event) => { await listen<string>("claude:connection", async (event) => {
const status = event.payload as ConnectionStatus; const status = event.payload as ConnectionStatus;
claudeStore.setConnectionStatus(status); claudeStore.setConnectionStatus(status);
if (status === "connected") { if (status === "connected") {
claudeStore.addLine("system", "Connected to Claude Code"); claudeStore.addLine("system", "Connected to Claude Code");
characterState.setState("idle"); characterState.setState("idle");
// Send greeting when connection is established
await sendGreeting();
} else if (status === "disconnected") { } else if (status === "disconnected") {
claudeStore.addLine("system", "Disconnected from Claude Code"); claudeStore.addLine("system", "Disconnected from Claude Code");
characterState.setState("idle"); characterState.setState("idle");
@@ -101,11 +113,9 @@ export async function initializeTauriListeners() {
// no-op // no-op
}); });
await listen<string>("claude:session", async (event) => { await listen<string>("claude:session", (event) => {
claudeStore.setSessionId(event.payload); claudeStore.setSessionId(event.payload);
claudeStore.addLine("system", `Session: ${event.payload.substring(0, 8)}...`); claudeStore.addLine("system", `Session: ${event.payload.substring(0, 8)}...`);
await sendGreeting();
}); });
await listen<string>("claude:cwd", (event) => { await listen<string>("claude:cwd", (event) => {