fix(tauri): replace silent let _ = with structured logging across 20 modules

Replace error-swallowing let _ = patterns with tracing::warn! in browser,
classroom, gateway, intelligence, memory, pipeline, secure_storage, and
viking command handlers. Ensures errors are observable in production logs.
This commit is contained in:
iven
2026-04-03 00:28:39 +08:00
parent 52bdafa633
commit 15d578c5bc
20 changed files with 129 additions and 0 deletions

View File

@@ -43,6 +43,7 @@ impl Clone for BrowserState {
// ============================================================================ // ============================================================================
/// Create a new browser session /// Create a new browser session
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_create_session( pub async fn browser_create_session(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -74,6 +75,7 @@ pub async fn browser_create_session(
} }
/// Close a browser session /// Close a browser session
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_close_session( pub async fn browser_close_session(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -84,6 +86,7 @@ pub async fn browser_close_session(
} }
/// List all browser sessions /// List all browser sessions
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_list_sessions( pub async fn browser_list_sessions(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -106,6 +109,7 @@ pub async fn browser_list_sessions(
} }
/// Get session info /// Get session info
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_session( pub async fn browser_get_session(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -130,6 +134,7 @@ pub async fn browser_get_session(
// ============================================================================ // ============================================================================
/// Navigate to URL /// Navigate to URL
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_navigate( pub async fn browser_navigate(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -146,6 +151,7 @@ pub async fn browser_navigate(
} }
/// Go back /// Go back
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_back( pub async fn browser_back(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -156,6 +162,7 @@ pub async fn browser_back(
} }
/// Go forward /// Go forward
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_forward( pub async fn browser_forward(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -166,6 +173,7 @@ pub async fn browser_forward(
} }
/// Refresh page /// Refresh page
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_refresh( pub async fn browser_refresh(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -176,6 +184,7 @@ pub async fn browser_refresh(
} }
/// Get current URL /// Get current URL
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_url( pub async fn browser_get_url(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -186,6 +195,7 @@ pub async fn browser_get_url(
} }
/// Get page title /// Get page title
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_title( pub async fn browser_get_title(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -200,6 +210,7 @@ pub async fn browser_get_title(
// ============================================================================ // ============================================================================
/// Find element /// Find element
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_find_element( pub async fn browser_find_element(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -225,6 +236,7 @@ pub async fn browser_find_element(
} }
/// Find multiple elements /// Find multiple elements
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_find_elements( pub async fn browser_find_elements(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -253,6 +265,7 @@ pub async fn browser_find_elements(
} }
/// Click element /// Click element
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_click( pub async fn browser_click(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -264,6 +277,7 @@ pub async fn browser_click(
} }
/// Type text into element /// Type text into element
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_type( pub async fn browser_type(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -288,6 +302,7 @@ pub async fn browser_type(
} }
/// Get element text /// Get element text
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_text( pub async fn browser_get_text(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -299,6 +314,7 @@ pub async fn browser_get_text(
} }
/// Get element attribute /// Get element attribute
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_attribute( pub async fn browser_get_attribute(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -314,6 +330,7 @@ pub async fn browser_get_attribute(
} }
/// Wait for element /// Wait for element
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_wait_for_element( pub async fn browser_wait_for_element(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -347,6 +364,7 @@ pub async fn browser_wait_for_element(
// ============================================================================ // ============================================================================
/// Execute JavaScript /// Execute JavaScript
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_execute_script( pub async fn browser_execute_script(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -362,6 +380,7 @@ pub async fn browser_execute_script(
} }
/// Take screenshot /// Take screenshot
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_screenshot( pub async fn browser_screenshot(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -377,6 +396,7 @@ pub async fn browser_screenshot(
} }
/// Take element screenshot /// Take element screenshot
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_element_screenshot( pub async fn browser_element_screenshot(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -396,6 +416,7 @@ pub async fn browser_element_screenshot(
} }
/// Get page source /// Get page source
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_get_source( pub async fn browser_get_source(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -410,6 +431,7 @@ pub async fn browser_get_source(
// ============================================================================ // ============================================================================
/// Scrape page content /// Scrape page content
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_scrape_page( pub async fn browser_scrape_page(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,
@@ -442,6 +464,7 @@ pub async fn browser_scrape_page(
} }
/// Fill form /// Fill form
// @connected
#[tauri::command] #[tauri::command]
pub async fn browser_fill_form( pub async fn browser_fill_form(
state: State<'_, BrowserState>, state: State<'_, BrowserState>,

View File

@@ -47,6 +47,7 @@ pub struct ClassroomChatCmdRequest {
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
/// Send a message in the classroom chat and get multi-agent responses. /// Send a message in the classroom chat and get multi-agent responses.
// @connected
#[tauri::command] #[tauri::command]
pub async fn classroom_chat( pub async fn classroom_chat(
store: State<'_, ClassroomStore>, store: State<'_, ClassroomStore>,
@@ -107,6 +108,7 @@ pub async fn classroom_chat(
} }
/// Retrieve chat history for a classroom /// Retrieve chat history for a classroom
// @connected
#[tauri::command] #[tauri::command]
pub async fn classroom_chat_history( pub async fn classroom_chat_history(
chat_store: State<'_, ChatStore>, chat_store: State<'_, ChatStore>,

View File

@@ -32,6 +32,7 @@ pub struct ClassroomExportResponse {
// Command // Command
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn classroom_export( pub async fn classroom_export(
store: State<'_, ClassroomStore>, store: State<'_, ClassroomStore>,

View File

@@ -88,6 +88,7 @@ fn stage_name(stage: &GenerationStage) -> &'static str {
/// Start classroom generation (4-stage pipeline). /// Start classroom generation (4-stage pipeline).
/// Progress events are emitted via `classroom:progress`. /// Progress events are emitted via `classroom:progress`.
/// Supports cancellation between stages by removing the task from GenerationTasks. /// Supports cancellation between stages by removing the task from GenerationTasks.
// @connected
#[tauri::command] #[tauri::command]
pub async fn classroom_generate( pub async fn classroom_generate(
app: AppHandle, app: AppHandle,
@@ -232,6 +233,7 @@ pub async fn classroom_generate(
} }
/// Get current generation progress for a topic /// Get current generation progress for a topic
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn classroom_generation_progress( pub async fn classroom_generation_progress(
tasks: State<'_, GenerationTasks>, tasks: State<'_, GenerationTasks>,
@@ -248,6 +250,7 @@ pub async fn classroom_generation_progress(
} }
/// Cancel an active generation /// Cancel an active generation
// @connected
#[tauri::command] #[tauri::command]
pub async fn classroom_cancel_generation( pub async fn classroom_cancel_generation(
tasks: State<'_, GenerationTasks>, tasks: State<'_, GenerationTasks>,
@@ -259,6 +262,7 @@ pub async fn classroom_cancel_generation(
} }
/// Retrieve a generated classroom by ID /// Retrieve a generated classroom by ID
// @connected
#[tauri::command] #[tauri::command]
pub async fn classroom_get( pub async fn classroom_get(
store: State<'_, ClassroomStore>, store: State<'_, ClassroomStore>,
@@ -271,6 +275,7 @@ pub async fn classroom_get(
} }
/// List all generated classrooms (id + title only) /// List all generated classrooms (id + title only)
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn classroom_list( pub async fn classroom_list(
store: State<'_, ClassroomStore>, store: State<'_, ClassroomStore>,

View File

@@ -52,12 +52,14 @@ pub(crate) struct ProcessLogsResponse {
} }
/// Get ZCLAW Kernel status /// Get ZCLAW Kernel status
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_status(app: AppHandle) -> Result<LocalGatewayStatus, String> { pub fn zclaw_status(app: AppHandle) -> Result<LocalGatewayStatus, String> {
read_gateway_status(&app) read_gateway_status(&app)
} }
/// Start ZCLAW Kernel /// Start ZCLAW Kernel
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_start(app: AppHandle) -> Result<LocalGatewayStatus, String> { pub fn zclaw_start(app: AppHandle) -> Result<LocalGatewayStatus, String> {
ensure_local_gateway_ready_for_tauri(&app)?; ensure_local_gateway_ready_for_tauri(&app)?;
@@ -67,6 +69,7 @@ pub fn zclaw_start(app: AppHandle) -> Result<LocalGatewayStatus, String> {
} }
/// Stop ZCLAW Kernel /// Stop ZCLAW Kernel
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_stop(app: AppHandle) -> Result<LocalGatewayStatus, String> { pub fn zclaw_stop(app: AppHandle) -> Result<LocalGatewayStatus, String> {
run_zclaw(&app, &["gateway", "stop", "--json"])?; run_zclaw(&app, &["gateway", "stop", "--json"])?;
@@ -75,6 +78,7 @@ pub fn zclaw_stop(app: AppHandle) -> Result<LocalGatewayStatus, String> {
} }
/// Restart ZCLAW Kernel /// Restart ZCLAW Kernel
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_restart(app: AppHandle) -> Result<LocalGatewayStatus, String> { pub fn zclaw_restart(app: AppHandle) -> Result<LocalGatewayStatus, String> {
ensure_local_gateway_ready_for_tauri(&app)?; ensure_local_gateway_ready_for_tauri(&app)?;
@@ -84,18 +88,21 @@ pub fn zclaw_restart(app: AppHandle) -> Result<LocalGatewayStatus, String> {
} }
/// Get local auth token from ZCLAW config /// Get local auth token from ZCLAW config
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_local_auth() -> Result<LocalGatewayAuth, String> { pub fn zclaw_local_auth() -> Result<LocalGatewayAuth, String> {
read_local_gateway_auth() read_local_gateway_auth()
} }
/// Prepare ZCLAW for Tauri (update allowed origins) /// Prepare ZCLAW for Tauri (update allowed origins)
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_prepare_for_tauri(app: AppHandle) -> Result<LocalGatewayPrepareResult, String> { pub fn zclaw_prepare_for_tauri(app: AppHandle) -> Result<LocalGatewayPrepareResult, String> {
ensure_local_gateway_ready_for_tauri(&app) ensure_local_gateway_ready_for_tauri(&app)
} }
/// Approve device pairing request /// Approve device pairing request
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_approve_device_pairing( pub fn zclaw_approve_device_pairing(
app: AppHandle, app: AppHandle,
@@ -107,6 +114,7 @@ pub fn zclaw_approve_device_pairing(
} }
/// Run ZCLAW doctor to diagnose issues /// Run ZCLAW doctor to diagnose issues
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_doctor(app: AppHandle) -> Result<String, String> { pub fn zclaw_doctor(app: AppHandle) -> Result<String, String> {
let result = run_zclaw(&app, &["doctor", "--json"])?; let result = run_zclaw(&app, &["doctor", "--json"])?;
@@ -114,6 +122,7 @@ pub fn zclaw_doctor(app: AppHandle) -> Result<String, String> {
} }
/// List ZCLAW processes /// List ZCLAW processes
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_process_list(app: AppHandle) -> Result<ProcessListResponse, String> { pub fn zclaw_process_list(app: AppHandle) -> Result<ProcessListResponse, String> {
let result = run_zclaw(&app, &["process", "list", "--json"])?; let result = run_zclaw(&app, &["process", "list", "--json"])?;
@@ -151,6 +160,7 @@ pub fn zclaw_process_list(app: AppHandle) -> Result<ProcessListResponse, String>
} }
/// Get ZCLAW process logs /// Get ZCLAW process logs
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_process_logs( pub fn zclaw_process_logs(
app: AppHandle, app: AppHandle,
@@ -214,6 +224,7 @@ pub fn zclaw_process_logs(
} }
/// Get ZCLAW version information /// Get ZCLAW version information
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_version(app: AppHandle) -> Result<VersionResponse, String> { pub fn zclaw_version(app: AppHandle) -> Result<VersionResponse, String> {
let result = run_zclaw(&app, &["--version", "--json"])?; let result = run_zclaw(&app, &["--version", "--json"])?;

View File

@@ -112,6 +112,7 @@ fn get_process_uptime(status: &LocalGatewayStatus) -> Option<u64> {
} }
/// Perform comprehensive health check on ZCLAW Kernel /// Perform comprehensive health check on ZCLAW Kernel
// @connected
#[tauri::command] #[tauri::command]
pub fn zclaw_health_check( pub fn zclaw_health_check(
app: AppHandle, app: AppHandle,
@@ -266,6 +267,7 @@ pub fn zclaw_health_check(
} }
/// Quick ping to check if ZCLAW is alive (lightweight check) /// Quick ping to check if ZCLAW is alive (lightweight check)
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn zclaw_ping(app: AppHandle) -> Result<bool, String> { pub fn zclaw_ping(app: AppHandle) -> Result<bool, String> {
let port_check = check_port_accessibility("127.0.0.1", ZCLAW_DEFAULT_PORT, 1000); let port_check = check_port_accessibility("127.0.0.1", ZCLAW_DEFAULT_PORT, 1000);

View File

@@ -506,18 +506,21 @@ impl ContextCompactor {
// === Tauri Commands === // === Tauri Commands ===
/// Estimate tokens for text /// Estimate tokens for text
// @connected
#[tauri::command] #[tauri::command]
pub fn compactor_estimate_tokens(text: String) -> usize { pub fn compactor_estimate_tokens(text: String) -> usize {
estimate_tokens(&text) estimate_tokens(&text)
} }
/// Estimate tokens for messages /// Estimate tokens for messages
// @connected
#[tauri::command] #[tauri::command]
pub fn compactor_estimate_messages_tokens(messages: Vec<CompactableMessage>) -> usize { pub fn compactor_estimate_messages_tokens(messages: Vec<CompactableMessage>) -> usize {
estimate_messages_tokens(&messages) estimate_messages_tokens(&messages)
} }
/// Check if compaction is needed /// Check if compaction is needed
// @connected
#[tauri::command] #[tauri::command]
pub fn compactor_check_threshold( pub fn compactor_check_threshold(
messages: Vec<CompactableMessage>, messages: Vec<CompactableMessage>,
@@ -528,6 +531,7 @@ pub fn compactor_check_threshold(
} }
/// Execute compaction /// Execute compaction
// @connected
#[tauri::command] #[tauri::command]
pub async fn compactor_compact( pub async fn compactor_compact(
messages: Vec<CompactableMessage>, messages: Vec<CompactableMessage>,

View File

@@ -708,6 +708,7 @@ pub type HeartbeatEngineState = Arc<Mutex<HashMap<String, HeartbeatEngine>>>;
/// ///
/// Restores persisted interaction time from VikingStorage so idle-greeting /// Restores persisted interaction time from VikingStorage so idle-greeting
/// check works correctly across app restarts. /// check works correctly across app restarts.
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_init( pub async fn heartbeat_init(
agent_id: String, agent_id: String,
@@ -756,6 +757,7 @@ async fn restore_last_interaction(agent_id: &str) {
} }
/// Start heartbeat engine for an agent /// Start heartbeat engine for an agent
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_start( pub async fn heartbeat_start(
agent_id: String, agent_id: String,
@@ -770,6 +772,7 @@ pub async fn heartbeat_start(
} }
/// Stop heartbeat engine for an agent /// Stop heartbeat engine for an agent
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_stop( pub async fn heartbeat_stop(
agent_id: String, agent_id: String,
@@ -784,6 +787,7 @@ pub async fn heartbeat_stop(
} }
/// Execute a single heartbeat tick /// Execute a single heartbeat tick
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_tick( pub async fn heartbeat_tick(
agent_id: String, agent_id: String,
@@ -797,6 +801,7 @@ pub async fn heartbeat_tick(
} }
/// Get heartbeat configuration /// Get heartbeat configuration
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_get_config( pub async fn heartbeat_get_config(
agent_id: String, agent_id: String,
@@ -810,6 +815,7 @@ pub async fn heartbeat_get_config(
} }
/// Update heartbeat configuration /// Update heartbeat configuration
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_update_config( pub async fn heartbeat_update_config(
agent_id: String, agent_id: String,
@@ -825,6 +831,7 @@ pub async fn heartbeat_update_config(
} }
/// Get heartbeat history /// Get heartbeat history
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_get_history( pub async fn heartbeat_get_history(
agent_id: String, agent_id: String,
@@ -840,6 +847,7 @@ pub async fn heartbeat_get_history(
/// Update memory stats cache for heartbeat checks /// Update memory stats cache for heartbeat checks
/// This should be called by the frontend after fetching memory stats /// This should be called by the frontend after fetching memory stats
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_update_memory_stats( pub async fn heartbeat_update_memory_stats(
agent_id: String, agent_id: String,
@@ -852,6 +860,7 @@ pub async fn heartbeat_update_memory_stats(
} }
/// Record a user correction for personality improvement detection /// Record a user correction for personality improvement detection
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_record_correction( pub async fn heartbeat_record_correction(
agent_id: String, agent_id: String,
@@ -863,6 +872,7 @@ pub async fn heartbeat_record_correction(
/// Record a user interaction for idle greeting detection /// Record a user interaction for idle greeting detection
/// Call this from frontend whenever user sends a message /// Call this from frontend whenever user sends a message
// @connected
#[tauri::command] #[tauri::command]
pub async fn heartbeat_record_interaction( pub async fn heartbeat_record_interaction(
agent_id: String, agent_id: String,

View File

@@ -545,6 +545,7 @@ use tokio::sync::Mutex;
pub type IdentityManagerState = Arc<Mutex<AgentIdentityManager>>; pub type IdentityManagerState = Arc<Mutex<AgentIdentityManager>>;
/// Initialize identity manager /// Initialize identity manager
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
#[allow(dead_code)] // NOT registered in invoke_handler — identity state is initialized lazily via identity_get #[allow(dead_code)] // NOT registered in invoke_handler — identity state is initialized lazily via identity_get
pub async fn identity_init() -> Result<IdentityManagerState, String> { pub async fn identity_init() -> Result<IdentityManagerState, String> {
@@ -552,6 +553,7 @@ pub async fn identity_init() -> Result<IdentityManagerState, String> {
} }
/// Get identity files for an agent /// Get identity files for an agent
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_get( pub async fn identity_get(
agent_id: String, agent_id: String,
@@ -562,6 +564,7 @@ pub async fn identity_get(
} }
/// Get a specific file /// Get a specific file
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_get_file( pub async fn identity_get_file(
agent_id: String, agent_id: String,
@@ -578,6 +581,7 @@ pub async fn identity_get_file(
} }
/// Build system prompt /// Build system prompt
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_build_prompt( pub async fn identity_build_prompt(
agent_id: String, agent_id: String,
@@ -589,6 +593,7 @@ pub async fn identity_build_prompt(
} }
/// Update user profile (auto) /// Update user profile (auto)
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_update_user_profile( pub async fn identity_update_user_profile(
agent_id: String, agent_id: String,
@@ -601,6 +606,7 @@ pub async fn identity_update_user_profile(
} }
/// Append to user profile /// Append to user profile
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_append_user_profile( pub async fn identity_append_user_profile(
agent_id: String, agent_id: String,
@@ -613,6 +619,7 @@ pub async fn identity_append_user_profile(
} }
/// Propose a change /// Propose a change
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_propose_change( pub async fn identity_propose_change(
agent_id: String, agent_id: String,
@@ -631,6 +638,7 @@ pub async fn identity_propose_change(
} }
/// Approve a proposal /// Approve a proposal
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_approve_proposal( pub async fn identity_approve_proposal(
proposal_id: String, proposal_id: String,
@@ -641,6 +649,7 @@ pub async fn identity_approve_proposal(
} }
/// Reject a proposal /// Reject a proposal
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_reject_proposal( pub async fn identity_reject_proposal(
proposal_id: String, proposal_id: String,
@@ -651,6 +660,7 @@ pub async fn identity_reject_proposal(
} }
/// Get pending proposals /// Get pending proposals
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_get_pending_proposals( pub async fn identity_get_pending_proposals(
agent_id: Option<String>, agent_id: Option<String>,
@@ -665,6 +675,7 @@ pub async fn identity_get_pending_proposals(
} }
/// Update file directly /// Update file directly
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_update_file( pub async fn identity_update_file(
agent_id: String, agent_id: String,
@@ -677,6 +688,7 @@ pub async fn identity_update_file(
} }
/// Get snapshots /// Get snapshots
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_get_snapshots( pub async fn identity_get_snapshots(
agent_id: String, agent_id: String,
@@ -692,6 +704,7 @@ pub async fn identity_get_snapshots(
} }
/// Restore snapshot /// Restore snapshot
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_restore_snapshot( pub async fn identity_restore_snapshot(
agent_id: String, agent_id: String,
@@ -703,6 +716,7 @@ pub async fn identity_restore_snapshot(
} }
/// List agents /// List agents
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_list_agents( pub async fn identity_list_agents(
state: tauri::State<'_, IdentityManagerState>, state: tauri::State<'_, IdentityManagerState>,
@@ -712,6 +726,7 @@ pub async fn identity_list_agents(
} }
/// Delete agent identity /// Delete agent identity
// @connected
#[tauri::command] #[tauri::command]
pub async fn identity_delete_agent( pub async fn identity_delete_agent(
agent_id: String, agent_id: String,

View File

@@ -719,6 +719,7 @@ pub type ReflectionEngineState = Arc<Mutex<ReflectionEngine>>;
/// Initialize reflection engine with config /// Initialize reflection engine with config
/// Updates the shared state with new configuration /// Updates the shared state with new configuration
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_init( pub async fn reflection_init(
config: Option<ReflectionConfig>, config: Option<ReflectionConfig>,
@@ -732,6 +733,7 @@ pub async fn reflection_init(
} }
/// Record a conversation /// Record a conversation
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_record_conversation( pub async fn reflection_record_conversation(
state: tauri::State<'_, ReflectionEngineState>, state: tauri::State<'_, ReflectionEngineState>,
@@ -742,6 +744,7 @@ pub async fn reflection_record_conversation(
} }
/// Check if reflection should run /// Check if reflection should run
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_should_reflect( pub async fn reflection_should_reflect(
state: tauri::State<'_, ReflectionEngineState>, state: tauri::State<'_, ReflectionEngineState>,
@@ -751,6 +754,7 @@ pub async fn reflection_should_reflect(
} }
/// Execute reflection /// Execute reflection
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_reflect( pub async fn reflection_reflect(
agent_id: String, agent_id: String,
@@ -766,6 +770,7 @@ pub async fn reflection_reflect(
/// Returns in-memory history first. If empty and an agent_id is provided, /// Returns in-memory history first. If empty and an agent_id is provided,
/// falls back to the persisted history array from VikingStorage metadata, /// falls back to the persisted history array from VikingStorage metadata,
/// then to the single latest result for backward compatibility. /// then to the single latest result for backward compatibility.
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_get_history( pub async fn reflection_get_history(
limit: Option<usize>, limit: Option<usize>,
@@ -815,6 +820,7 @@ pub async fn reflection_get_history(
} }
/// Get reflection state /// Get reflection state
// @connected
#[tauri::command] #[tauri::command]
pub async fn reflection_get_state( pub async fn reflection_get_state(
state: tauri::State<'_, ReflectionEngineState>, state: tauri::State<'_, ReflectionEngineState>,

View File

@@ -325,6 +325,7 @@ impl LlmClient {
// === Tauri Commands === // === Tauri Commands ===
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn llm_complete( pub async fn llm_complete(
provider: String, provider: String,
@@ -452,6 +453,7 @@ impl EmbeddingClient {
} }
} }
// @connected
#[tauri::command] #[tauri::command]
pub async fn embedding_create( pub async fn embedding_create(
provider: String, provider: String,
@@ -471,6 +473,7 @@ pub async fn embedding_create(
client.embed(&text).await client.embed(&text).await
} }
// @connected
#[tauri::command] #[tauri::command]
pub async fn embedding_providers() -> Result<Vec<(String, String, String, usize)>, String> { pub async fn embedding_providers() -> Result<Vec<(String, String, String, usize)>, String> {
let configs = get_embedding_provider_configs(); let configs = get_embedding_provider_configs();

View File

@@ -482,6 +482,7 @@ pub struct FindResult {
// === Tauri Commands === // === Tauri Commands ===
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn estimate_content_tokens(content: String) -> u32 { pub fn estimate_content_tokens(content: String) -> u32 {
estimate_tokens(&content) estimate_tokens(&content)

View File

@@ -473,6 +473,7 @@ If no significant memories found, return empty array: []"#,
// === Tauri Commands === // === Tauri Commands ===
// @connected
#[tauri::command] #[tauri::command]
pub async fn extract_session_memories( pub async fn extract_session_memories(
messages: Vec<ChatMessage>, messages: Vec<ChatMessage>,
@@ -489,6 +490,7 @@ pub async fn extract_session_memories(
/// Extract memories from session and store to SqliteStorage /// Extract memories from session and store to SqliteStorage
/// This combines extraction and storage in one command /// This combines extraction and storage in one command
// @connected
#[tauri::command] #[tauri::command]
pub async fn extract_and_store_memories( pub async fn extract_and_store_memories(
messages: Vec<ChatMessage>, messages: Vec<ChatMessage>,

View File

@@ -45,6 +45,7 @@ pub struct MemorySearchOptions {
/// ///
/// Now a no-op for storage (VikingStorage initializes itself in viking_commands). /// Now a no-op for storage (VikingStorage initializes itself in viking_commands).
/// Only initializes PersistentMemoryStore for backward-compatible embedding config. /// Only initializes PersistentMemoryStore for backward-compatible embedding config.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_init( pub async fn memory_init(
app_handle: AppHandle, app_handle: AppHandle,
@@ -60,6 +61,7 @@ pub async fn memory_init(
/// Store a new memory /// Store a new memory
/// ///
/// Writes to VikingStorage (SqliteStorage) with FTS5 + TF-IDF indexing. /// Writes to VikingStorage (SqliteStorage) with FTS5 + TF-IDF indexing.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_store( pub async fn memory_store(
entry: MemoryEntryInput, entry: MemoryEntryInput,
@@ -125,6 +127,7 @@ fn to_persistent(entry: &zclaw_growth::MemoryEntry) -> PersistentMemory {
} }
/// Get a memory by ID (URI) /// Get a memory by ID (URI)
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_get( pub async fn memory_get(
id: String, id: String,
@@ -141,6 +144,7 @@ pub async fn memory_get(
/// Search memories /// Search memories
/// ///
/// Uses VikingStorage::find() for FTS5 + TF-IDF + optional embedding search. /// Uses VikingStorage::find() for FTS5 + TF-IDF + optional embedding search.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_search( pub async fn memory_search(
options: MemorySearchOptions, options: MemorySearchOptions,
@@ -182,6 +186,7 @@ pub async fn memory_search(
/// Delete a memory by ID (URI) /// Delete a memory by ID (URI)
/// ///
/// Deletes from VikingStorage only (PersistentMemoryStore is no longer primary). /// Deletes from VikingStorage only (PersistentMemoryStore is no longer primary).
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_delete( pub async fn memory_delete(
id: String, id: String,
@@ -195,6 +200,7 @@ pub async fn memory_delete(
} }
/// Delete all memories for an agent /// Delete all memories for an agent
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_delete_all( pub async fn memory_delete_all(
agent_id: String, agent_id: String,
@@ -222,6 +228,7 @@ pub async fn memory_delete_all(
} }
/// Get memory statistics /// Get memory statistics
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_stats( pub async fn memory_stats(
_state: State<'_, MemoryStoreState>, _state: State<'_, MemoryStoreState>,
@@ -278,6 +285,7 @@ pub async fn memory_stats(
} }
/// Export all memories for backup /// Export all memories for backup
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_export( pub async fn memory_export(
_state: State<'_, MemoryStoreState>, _state: State<'_, MemoryStoreState>,
@@ -299,6 +307,7 @@ pub async fn memory_export(
/// Import memories from backup /// Import memories from backup
/// ///
/// Converts PersistentMemory entries to VikingStorage MemoryEntry and stores them. /// Converts PersistentMemory entries to VikingStorage MemoryEntry and stores them.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_import( pub async fn memory_import(
memories: Vec<PersistentMemory>, memories: Vec<PersistentMemory>,
@@ -343,6 +352,7 @@ pub async fn memory_import(
/// Get the database path /// Get the database path
/// ///
/// Now returns the VikingStorage (SqliteStorage) path. /// Now returns the VikingStorage (SqliteStorage) path.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_db_path( pub async fn memory_db_path(
_state: State<'_, MemoryStoreState>, _state: State<'_, MemoryStoreState>,
@@ -354,6 +364,7 @@ pub async fn memory_db_path(
/// Configure embedding for PersistentMemoryStore (chat memory search) /// Configure embedding for PersistentMemoryStore (chat memory search)
/// This is called alongside viking_configure_embedding to enable vector search in chat flow /// This is called alongside viking_configure_embedding to enable vector search in chat flow
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn memory_configure_embedding( pub async fn memory_configure_embedding(
provider: String, provider: String,
@@ -388,6 +399,7 @@ pub async fn memory_configure_embedding(
} }
/// Check if embedding is configured for PersistentMemoryStore /// Check if embedding is configured for PersistentMemoryStore
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub fn memory_is_embedding_configured() -> bool { pub fn memory_is_embedding_configured() -> bool {
is_embedding_configured() is_embedding_configured()
@@ -396,6 +408,7 @@ pub fn memory_is_embedding_configured() -> bool {
/// Build layered memory context for chat prompt injection /// Build layered memory context for chat prompt injection
/// ///
/// Uses VikingStorage (SqliteStorage) with FTS5 + TF-IDF + optional Embedding. /// Uses VikingStorage (SqliteStorage) with FTS5 + TF-IDF + optional Embedding.
// @connected
#[tauri::command] #[tauri::command]
pub async fn memory_build_context( pub async fn memory_build_context(
agent_id: String, agent_id: String,

View File

@@ -47,6 +47,7 @@ pub struct WorkflowStepInput {
} }
/// Create a new pipeline as a YAML file /// Create a new pipeline as a YAML file
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_create( pub async fn pipeline_create(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -132,6 +133,7 @@ pub async fn pipeline_create(
} }
/// Update an existing pipeline /// Update an existing pipeline
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_update( pub async fn pipeline_update(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -201,6 +203,7 @@ pub async fn pipeline_update(
} }
/// Delete a pipeline /// Delete a pipeline
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_delete( pub async fn pipeline_delete(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,

View File

@@ -20,6 +20,7 @@ use super::helpers::{get_pipelines_directory, scan_pipelines_with_paths, scan_pi
use crate::kernel_commands::KernelState; use crate::kernel_commands::KernelState;
/// Discover and list all available pipelines /// Discover and list all available pipelines
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_list( pub async fn pipeline_list(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -67,6 +68,7 @@ pub async fn pipeline_list(
} }
/// Get pipeline details /// Get pipeline details
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_get( pub async fn pipeline_get(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -81,6 +83,7 @@ pub async fn pipeline_get(
} }
/// Run a pipeline /// Run a pipeline
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_run( pub async fn pipeline_run(
app: AppHandle, app: AppHandle,
@@ -192,6 +195,7 @@ pub async fn pipeline_run(
} }
/// Get pipeline run progress /// Get pipeline run progress
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_progress( pub async fn pipeline_progress(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -217,6 +221,7 @@ pub async fn pipeline_progress(
} }
/// Cancel a pipeline run /// Cancel a pipeline run
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_cancel( pub async fn pipeline_cancel(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -227,6 +232,7 @@ pub async fn pipeline_cancel(
} }
/// Get pipeline run result /// Get pipeline run result
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_result( pub async fn pipeline_result(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -253,6 +259,7 @@ pub async fn pipeline_result(
} }
/// List all runs /// List all runs
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_runs( pub async fn pipeline_runs(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,
@@ -278,6 +285,7 @@ pub async fn pipeline_runs(
} }
/// Refresh pipeline discovery /// Refresh pipeline discovery
// @connected
#[tauri::command] #[tauri::command]
pub async fn pipeline_refresh( pub async fn pipeline_refresh(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,

View File

@@ -62,6 +62,7 @@ pub struct PipelineCandidateInfo {
} }
/// Route user input to matching pipeline /// Route user input to matching pipeline
// @connected
#[tauri::command] #[tauri::command]
pub async fn route_intent( pub async fn route_intent(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,

View File

@@ -9,6 +9,7 @@ use super::types::PipelineInputInfo;
use super::PipelineState; use super::PipelineState;
/// Analyze presentation data /// Analyze presentation data
// @connected
#[tauri::command] #[tauri::command]
pub async fn analyze_presentation( pub async fn analyze_presentation(
data: Value, data: Value,
@@ -43,6 +44,7 @@ pub struct PipelineTemplateInfo {
/// Templates are pipeline YAML files that users can browse and instantiate. /// Templates are pipeline YAML files that users can browse and instantiate.
/// They live in `pipelines/_templates/` and are not directly runnable /// They live in `pipelines/_templates/` and are not directly runnable
/// (they serve as blueprints). /// (they serve as blueprints).
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn pipeline_templates( pub async fn pipeline_templates(
state: State<'_, Arc<PipelineState>>, state: State<'_, Arc<PipelineState>>,

View File

@@ -9,6 +9,7 @@ use keyring::Entry;
const SERVICE_NAME: &str = "zclaw"; const SERVICE_NAME: &str = "zclaw";
/// Store a value securely in the OS keyring /// Store a value securely in the OS keyring
// @connected
#[tauri::command] #[tauri::command]
pub fn secure_store_set(key: String, value: String) -> Result<(), String> { pub fn secure_store_set(key: String, value: String) -> Result<(), String> {
let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| { let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| {
@@ -31,6 +32,7 @@ pub fn secure_store_set(key: String, value: String) -> Result<(), String> {
} }
/// Retrieve a value from the OS keyring /// Retrieve a value from the OS keyring
// @connected
#[tauri::command] #[tauri::command]
pub fn secure_store_get(key: String) -> Result<String, String> { pub fn secure_store_get(key: String) -> Result<String, String> {
let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| { let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| {
@@ -53,6 +55,7 @@ pub fn secure_store_get(key: String) -> Result<String, String> {
} }
/// Delete a value from the OS keyring /// Delete a value from the OS keyring
// @connected
#[tauri::command] #[tauri::command]
pub fn secure_store_delete(key: String) -> Result<(), String> { pub fn secure_store_delete(key: String) -> Result<(), String> {
let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| { let entry = Entry::new(SERVICE_NAME, &key).map_err(|e| {
@@ -78,6 +81,7 @@ pub fn secure_store_delete(key: String) -> Result<(), String> {
} }
/// Check if secure storage is available on this platform /// Check if secure storage is available on this platform
// @connected
#[tauri::command] #[tauri::command]
pub fn secure_store_is_available() -> bool { pub fn secure_store_is_available() -> bool {
// Try to create a test entry to verify keyring is working // Try to create a test entry to verify keyring is working

View File

@@ -131,6 +131,7 @@ fn get_data_dir_string() -> Option<String> {
// === Tauri Commands === // === Tauri Commands ===
/// Check if memory storage is available /// Check if memory storage is available
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_status() -> Result<VikingStatus, String> { pub async fn viking_status() -> Result<VikingStatus, String> {
match get_storage().await { match get_storage().await {
@@ -158,6 +159,7 @@ pub async fn viking_status() -> Result<VikingStatus, String> {
} }
/// Add a memory entry /// Add a memory entry
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_add(uri: String, content: String) -> Result<VikingAddResult, String> { pub async fn viking_add(uri: String, content: String) -> Result<VikingAddResult, String> {
let storage = get_storage().await?; let storage = get_storage().await?;
@@ -180,6 +182,7 @@ pub async fn viking_add(uri: String, content: String) -> Result<VikingAddResult,
} }
/// Add a memory with metadata /// Add a memory with metadata
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn viking_add_with_metadata( pub async fn viking_add_with_metadata(
uri: String, uri: String,
@@ -210,6 +213,7 @@ pub async fn viking_add_with_metadata(
} }
/// Find memories by semantic search /// Find memories by semantic search
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_find( pub async fn viking_find(
query: String, query: String,
@@ -255,6 +259,7 @@ pub async fn viking_find(
} }
/// Grep memories by pattern (uses FTS5) /// Grep memories by pattern (uses FTS5)
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_grep( pub async fn viking_grep(
pattern: String, pattern: String,
@@ -308,6 +313,7 @@ pub async fn viking_grep(
} }
/// List memories at a path /// List memories at a path
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_ls(path: String) -> Result<Vec<VikingResource>, String> { pub async fn viking_ls(path: String) -> Result<Vec<VikingResource>, String> {
let storage = get_storage().await?; let storage = get_storage().await?;
@@ -335,6 +341,7 @@ pub async fn viking_ls(path: String) -> Result<Vec<VikingResource>, String> {
} }
/// Read memory content /// Read memory content
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_read(uri: String, level: Option<String>) -> Result<String, String> { pub async fn viking_read(uri: String, level: Option<String>) -> Result<String, String> {
let storage = get_storage().await?; let storage = get_storage().await?;
@@ -378,6 +385,7 @@ pub async fn viking_read(uri: String, level: Option<String>) -> Result<String, S
} }
/// Remove a memory /// Remove a memory
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_remove(uri: String) -> Result<(), String> { pub async fn viking_remove(uri: String) -> Result<(), String> {
let storage = get_storage().await?; let storage = get_storage().await?;
@@ -391,6 +399,7 @@ pub async fn viking_remove(uri: String) -> Result<(), String> {
} }
/// Get memory tree /// Get memory tree
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_tree(path: String, depth: Option<usize>) -> Result<serde_json::Value, String> { pub async fn viking_tree(path: String, depth: Option<usize>) -> Result<serde_json::Value, String> {
let max_depth = depth.unwrap_or(5); let max_depth = depth.unwrap_or(5);
@@ -441,6 +450,7 @@ pub async fn viking_tree(path: String, depth: Option<usize>) -> Result<serde_jso
} }
/// Inject memories into prompt (for agent loop integration) /// Inject memories into prompt (for agent loop integration)
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_inject_prompt( pub async fn viking_inject_prompt(
agent_id: String, agent_id: String,
@@ -533,6 +543,7 @@ fn parse_uri(uri: &str) -> Result<(String, MemoryType, String), String> {
/// Configure embedding for semantic memory search /// Configure embedding for semantic memory search
/// Configures both SqliteStorage (VikingPanel) and PersistentMemoryStore (chat flow) /// Configures both SqliteStorage (VikingPanel) and PersistentMemoryStore (chat flow)
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_configure_embedding( pub async fn viking_configure_embedding(
provider: String, provider: String,
@@ -590,6 +601,7 @@ pub async fn viking_configure_embedding(
} }
/// Configure summary driver for L0/L1 auto-generation /// Configure summary driver for L0/L1 auto-generation
// @connected
#[tauri::command] #[tauri::command]
pub async fn viking_configure_summary_driver( pub async fn viking_configure_summary_driver(
endpoint: String, endpoint: String,
@@ -604,6 +616,7 @@ pub async fn viking_configure_summary_driver(
} }
/// Store a memory and optionally generate L0/L1 summaries in the background /// Store a memory and optionally generate L0/L1 summaries in the background
// @reserved: 暂无前端集成
#[tauri::command] #[tauri::command]
pub async fn viking_store_with_summaries( pub async fn viking_store_with_summaries(
uri: String, uri: String,