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
5 changes: 4 additions & 1 deletion src/apps/desktop/src/api/app_state.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@



//! Application state management

use bitfun_core::agentic::side_question::SideQuestionRuntime;
Expand Down Expand Up @@ -168,7 +171,7 @@ impl AppState {
"worker_host.js not found in any candidate location; \
MiniApp Workers will not start"
);
std::path::PathBuf::from("worker_host.js")
std::path::PathBuf::from("/data/storage/el2/base/files").join("woker_host.js")
}
};
let js_worker_pool = JsWorkerPool::new(path_manager, worker_host_path)
Expand Down
1 change: 1 addition & 0 deletions src/apps/desktop/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,6 @@ pub mod subagent_api;
pub mod system_api;
pub mod terminal_api;
pub mod tool_api;
pub mod ohos;

pub use app_state::{AppState, AppStatistics, HealthStatus, RemoteWorkspace};
1 change: 0 additions & 1 deletion src/apps/desktop/src/api/ohos/ohos_file_system.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
use crate::Appstate;
use bitfun_core::util::open_dialog_file;
#[tauri::command]
pub async fn open_oh_file_dialog() -> Result<String, String> {
Expand Down
116 changes: 116 additions & 0 deletions src/apps/desktop/src/api/ohos/window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use crate::AppState;
use bitfun_core::util::JS_THREADSAFE_FUNCTION;
use log::error;
use napi_ohos::threadsafe_function::ThreadsafeFunctionCallMode;
use std::sync::mpsc::channel;
use tauri::State;

#[tauri::command]
pub fn handle_min_window() -> Result<(), String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("handle_min_window").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
function.call(Ok("".to_string()),ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[tauri::command]
pub fn handle_max_window() -> Result<(),String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();

lock.get("handle_max_window").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
function.call(Ok("".to_string()), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[tauri::command]
pub fn handle_restore_window() -> Result<(),String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("handle_restore_window").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
function.call(Ok("".to_string()), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[tauri::command]
pub async fn window_is_minimized() -> Result<bool, String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("window_is_minimized").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
let res = function.call_async(Ok("str".to_string())).await;
match res {
Ok(err) => match err.await{
Ok(result) => {
if result.eq("true") {
Ok(true)
} else {
Ok(false)
}
},
Err(err) => Err(err.to_string()),
}
Err(err) => Err(err.to_string()),
}
}
#[tauri::command]
pub fn window_start_dragging() -> Result<(),String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("window_start_dragging").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
function.call(Ok("".to_string()), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[tauri::command]
pub fn close_window() -> Result<(),String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("close_window").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
function.call(Ok("".to_string()), ThreadsafeFunctionCallMode::NonBlocking);
Ok(())
}
#[tauri::command]
pub async fn window_is_maximized() -> Result<bool, String> {
let function = {
let lock = JS_THREADSAFE_FUNCTION.read();
lock.get("window_is_maximized").cloned()
};
let Some(function) = function else {
return Err("The Arkts has not register the function".to_owned());
};
let res = function.call_async(Ok("str".to_string())).await;
match res {
Ok(err) => match err.await {
Ok(result) => {
if result.eq("true") {
Ok(true)
} else {
Ok(false)
}
},
Err(err) => Err(err.to_string()),
}
Err(err) => Err(err.to_string()),
}
}
18 changes: 18 additions & 0 deletions src/apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ use tauri::Manager;

// Re-export API
pub use api::*;

use crate::ohos::ohos_file_system::open_oh_file_dialog;
use crate::ohos::window::{
close_window,handle_max_window,handle_min_window,handle_restore_window,window_is_maximized,
window_is_minimized, window_start_dragging
};
use std::path::PathBuf;
use api::ai_rules_api::*;
use api::clipboard_file_api::*;
Expand All @@ -46,6 +52,8 @@ use api::storage_commands::*;
use api::subagent_api::*;
use api::system_api::*;
use api::tool_api::*;
use std::ffi::CString;
use std::ptr;

/// Agentic Coordinator state
#[derive(Clone)]
Expand Down Expand Up @@ -792,6 +800,16 @@ pub async fn _run() {
api::announcement_api::never_show_announcement,
api::announcement_api::trigger_announcement,
api::announcement_api::get_announcement_tips,
// ohos adater
open_oh_file_dialog,
handle_min_window,
handle_max_window,
handle_restore_window,
window_is_maximized,
window_is_minimized,
window_start_dragging,
close_window,

])
.run(tauri::generate_context!());
if let Err(e) = run_result {
Expand Down
3 changes: 1 addition & 2 deletions src/crates/core/src/agentic/execution/execution_engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1787,7 +1787,6 @@ impl ExecutionEngine {
}

let tool_name = tool.name().to_string();
if mode_allowed_tools.contains(&tool_name) {
let description = tool
.description_with_context(Some(&description_context))
.await
Expand All @@ -1802,7 +1801,7 @@ impl ExecutionEngine {
description,
parameters,
});
}

}

// Order tools for the model API: terminal → file-ish tools → **`ControlHub`**
Expand Down
151 changes: 151 additions & 0 deletions src/crates/core/src/agentic/tools/implementations/calendar_tool.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::agentic::tools::framework::{Tool, ToolResult, ToolUseContext};
use crate::util::errors::BitFunResult;
use crate::util::JS_THREADSAFE_FUNCTION;
use async_trait::async_trait;
use serde_json::{ Value,json};

pub struct CalendarTool;

impl CalendarTool {
pub fn new() -> CalendarTool {
Self
}
}

#[async_trait]
impl Tool for CalendarTool {
fn name(&self) -> &str {
"Calendar"
}

async fn description(&self) -> BitFunResult<String> {
Ok(r#"Manages all types of calendar schedules, including events, reminders, deadlines, and all-day entries.

Usage Guidelines:
- Supported actions: 'create' (new entry)
- You MUST extract the specific city or venue into the 'location' field (e.g, 'Beijing').
- DO NOT leave the primary location only inside the 'description' or 'title'.
- Time Format: Always use 'YYYY-MM-DD HH:mm'.
- Participants can include names or email address, Leave empty for personal tasks.
"#.to_string())
}

fn input_schema(&self) -> Value {
json!({
"type": "object",
"properties": {
"title": {
"type": "string",
"description": "Short title of the schedule (e.g., 'Flight to Tokyo'. 'Dentist Appointment')",
},
"description": {
"type": "string",
"description": "Detailed notes or additional information"
},
"start_time": {
"type": "string",
"description": "YYYY-MM-DD HH:mm format"
},
"end_time": {
"type": "string",
"description": "YYYY-MM-DD HH:mm"
},
"location": {
"type": "string",
"description": "The specific physical location, city, or address. E.G., 'Beijing' or 'Forbidden City'",
}
},
"required": ["action"],
"additionalProperties": false
})
}

fn is_readonly(&self) -> bool {
false
}

fn is_concurrency_safe(&self, _input: Option<&Value>) -> bool {
false
}

async fn call_impl(
&self,
input: &Value,
_context: &ToolUseContext
)-> BitFunResult<Vec<ToolResult>> {
let title = input.get("title").and_then(|v| v.as_str()).unwrap_or_default();
let description = input.get("description").and_then(|v| v.as_str()).unwrap_or_default();
let start_time = input.get("start_time").and_then(|v| v.as_str()).unwrap_or_default();
let end_time = input.get("end_time").and_then(|v| v.as_str()).unwrap_or_default();
let info = CalendarInfo::new(title.to_string(), description.to_string(), start_time.to_string(), end_time.to_string());

let res = call_calender(serde_json::to_string(&info).unwrap_or_default());
let action = "创建日程";

let result = ToolResult::Result {
data: json!({
"action": action,
"success": true
}),
result_for_assistant: Some(format!(
"Calendar {} operation executed successfully",
action
)),
image_attachments: None,
};
Ok(vec![result])
}
}

#[napi(object)]
#[derive(Debug,Clone,Serialize)]
#[serde(rename_all = "camelCase")]
pub struct CalendarInfo {
pub title: String,
pub start_time: String,
pub end_time: String,
pub description: String,
}

impl CalendarInfo {
pub fn new(title: String, start_time: String, end_time: String, description: String) -> Self {
Self {
title,
start_time,
end_time,
description
}
}
}

use napi_derive_ohos::napi;
use serde::Serialize;

use napi_ohos::threadsafe_function::ThreadsafeFunctionCallMode;

pub fn call_calender(args: String) -> Result<String, String>{
let result = Ok(args);
match JS_THREADSAFE_FUNCTION.write().get("call_calender") {
None => {
return Err("The Arkts has not register the functions".to_string());
}
Some(functions) => {
functions.call_with_return_value(
result,
ThreadsafeFunctionCallMode::Blocking,
move |result,_| {
match result {
Ok(_) => {
log::info!("Successfully called Arkts");
}
Err(err) => {
log::error!("call calender with error {:?}", err);
}
}
Ok(())
}
);
}
}
Ok("".to_string())
}
Loading
Loading