Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/apps/desktop/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ pub mod storage_commands;
pub mod subagent_api;
pub mod system_api;
pub mod terminal_api;
pub mod token_usage_api;
pub mod tool_api;

pub use app_state::{AppState, AppStatistics, HealthStatus, RemoteWorkspace};
195 changes: 0 additions & 195 deletions src/apps/desktop/src/api/token_usage_api.rs

This file was deleted.

9 changes: 0 additions & 9 deletions src/apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ use api::startchat_agent_api::*;
use api::storage_commands::*;
use api::subagent_api::*;
use api::system_api::*;
use api::token_usage_api::*;
use api::tool_api::*;

/// Agentic Coordinator state
Expand Down Expand Up @@ -619,14 +618,6 @@ pub async fn run() {
i18n_get_supported_languages,
i18n_get_config,
i18n_set_config,
// Token Usage
record_token_usage,
get_model_token_stats,
get_all_model_token_stats,
get_session_token_stats,
query_token_usage,
clear_model_token_stats,
clear_all_token_stats,
// Remote Connect
api::remote_connect_api::remote_connect_get_device_info,
api::remote_connect_api::remote_connect_get_lan_ip,
Expand Down
18 changes: 18 additions & 0 deletions src/crates/core/src/agentic/session/session_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,24 @@ impl SessionManager {
.await?;
}

if let Some(cron) = crate::service::cron::get_global_cron_service() {
match cron.delete_jobs_for_session(session_id).await {
Ok(removed) if removed > 0 => {
info!(
"Removed {} scheduled job(s) for deleted session_id={}",
removed, session_id
);
}
Ok(_) => {}
Err(e) => {
warn!(
"Failed to remove scheduled jobs for deleted session_id={}: {}",
session_id, e
);
}
}
}

// 4. Clean up associated Terminal session
use crate::service::terminal::TerminalApi;
if let Ok(terminal_api) = TerminalApi::from_singleton() {
Expand Down
50 changes: 44 additions & 6 deletions src/crates/core/src/service/cron/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,25 @@ impl CronService {
Ok(existed)
}

/// Remove all scheduled jobs bound to the given session (e.g. after session delete).
pub async fn delete_jobs_for_session(&self, session_id: &str) -> BitFunResult<usize> {
let session_id = session_id.trim();
if session_id.is_empty() {
return Ok(0);
}
let _guard = self.mutation_lock.lock().await;
let mut jobs = self.jobs.write().await;
let before = jobs.len();
jobs.retain(|_, job| job.session_id.trim() != session_id);
let removed = before - jobs.len();
if removed > 0 {
self.persist_jobs_locked(&jobs).await?;
drop(jobs);
self.wakeup.notify_one();
}
Ok(removed)
}

pub async fn run_job_now(&self, job_id: &str) -> BitFunResult<CronJob> {
{
let _guard = self.mutation_lock.lock().await;
Expand Down Expand Up @@ -532,14 +551,28 @@ impl CronService {
job.state.last_run_status = Some(CronJobRunStatus::Error);
job.state.last_error = Some(error.clone());
job.state.last_run_finished_at_ms = Some(now_after_submit);
job.state.retry_at_ms = Some(now_after_submit + DEFAULT_RETRY_DELAY_MS);
job.state.consecutive_failures = job.state.consecutive_failures.saturating_add(1);
job.updated_at_ms = now_after_submit;

warn!(
"Failed to enqueue scheduled job: job_id={}, session_id={}, error={}",
job.id, job.session_id, error
);
if cron_enqueue_error_is_missing_session(&error) {
job.enabled = false;
job.state.next_run_at_ms = None;
job.state.pending_trigger_at_ms = None;
job.state.retry_at_ms = None;
job.state.consecutive_failures =
job.state.consecutive_failures.saturating_add(1);
info!(
"Scheduled job auto-disabled (session no longer exists): job_id={}, session_id={}",
job.id, job.session_id
);
} else {
job.state.retry_at_ms = Some(now_after_submit + DEFAULT_RETRY_DELAY_MS);
job.state.consecutive_failures =
job.state.consecutive_failures.saturating_add(1);
warn!(
"Failed to enqueue scheduled job: job_id={}, session_id={}, error={}",
job.id, job.session_id, error
);
}
}
}

Expand Down Expand Up @@ -718,3 +751,8 @@ struct EnqueueInput {
workspace_path: String,
user_input: String,
}

/// Permanent failure: coordinator cannot load session metadata (session deleted from disk).
fn cron_enqueue_error_is_missing_session(error: &str) -> bool {
error.contains("Session metadata not found")
}
1 change: 1 addition & 0 deletions src/web-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"type": "module",
"scripts": {
"dev": "vite",
"dev:force": "vite --force",
"build": "vite build",
"build:desktop": "vite build --mode desktop",
"build:web": "vite build --mode web",
Expand Down
6 changes: 3 additions & 3 deletions src/web-ui/src/app/components/NavPanel/MainNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ const MainNav: React.FC<MainNavProps> = ({
const createCodeTooltip = t('nav.sessions.newCodeSession');
const createCoworkTooltip = t('nav.sessions.newCoworkSession');
const assistantTooltip = t('nav.items.persona');
const openProjectTooltip = t('header.openProject');
const addWorkspaceTooltip = t('nav.tooltips.addWorkspace');
const isAssistantActive = activeTabId === 'assistant';
const agentsTooltip = t('nav.tooltips.agents');
const skillsTooltip = t('nav.tooltips.skills');
Expand Down Expand Up @@ -577,12 +577,12 @@ const MainNav: React.FC<MainNavProps> = ({
onToggle={() => toggleSection('workspace')}
actions={
<div className="bitfun-nav-panel__workspace-action-wrap">
<Tooltip content={openProjectTooltip} placement="right" followCursor disabled={workspaceMenuOpen}>
<Tooltip content={addWorkspaceTooltip} placement="right" followCursor disabled={workspaceMenuOpen}>
<button
ref={workspaceMenuButtonRef}
type="button"
className={`bitfun-nav-panel__section-action${workspaceMenuOpen ? ' is-active' : ''}`}
aria-label={openProjectTooltip}
aria-label={addWorkspaceTooltip}
aria-expanded={workspaceMenuOpen}
onClick={toggleWorkspaceMenu}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,17 +268,15 @@ const PersistentFooterActions: React.FC = () => {
const isAnyActive = isBrowserActive || isMermaidActive;
return (
<>
<Tooltip content={t('nav.multimodalTools')} placement="right" disabled={multimodalOpen}>
<button
type="button"
className={`bitfun-nav-panel__footer-btn bitfun-nav-panel__footer-btn--icon${isAnyActive ? ' is-active' : ''}${multimodalOpen ? ' is-hover-open' : ''}`}
aria-label={t('nav.multimodalTools')}
aria-expanded={multimodalOpen}
aria-haspopup="menu"
>
<Layers size={15} />
</button>
</Tooltip>
<button
type="button"
className={`bitfun-nav-panel__footer-btn bitfun-nav-panel__footer-btn--icon${isAnyActive ? ' is-active' : ''}${multimodalOpen ? ' is-hover-open' : ''}`}
aria-label={t('nav.multimodalTools')}
aria-expanded={multimodalOpen}
aria-haspopup="menu"
>
<Layers size={15} />
</button>

{multimodalOpen && (
<div
Expand Down
Loading
Loading