feat: add lesson export and import functionality
- Implemented `LessonExport` and `LessonImport` actions in the action module. - Added corresponding command parsing for lesson export and import. - Created functions to handle lesson export and import in the memory module. - Updated state management to reflect changes after lesson operations. - Introduced deferred operations for handling asynchronous tasks in the event loop. - Enhanced the tool execution context to include graduated checks for file operations. - Added OAuth support with PKCE for secure authorization flows. - Implemented a loopback server for handling OAuth redirects. - Refactored various modules to improve code organization and maintainability.
This commit is contained in:
@@ -1,2 +1,4 @@
|
||||
#[expect(dead_code)]
|
||||
pub mod tools;
|
||||
#[expect(dead_code)]
|
||||
pub mod turn;
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
use crate::tool::{ToolCtx, all_tools};
|
||||
use serde_json::Value;
|
||||
use anyhow::Result;
|
||||
|
||||
pub fn execute_tool_call(name: &str, args: &Value, ctx: &ToolCtx) -> Result<String> {
|
||||
let tools = all_tools();
|
||||
for tool in &tools {
|
||||
if tool.name() == name {
|
||||
return tool.run(ctx, args);
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!("tool not found: {}", name))
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn execute_deferred_tool(name: &str, args: &Value, ctx: &ToolCtx) -> Result<String> {
|
||||
let tools = all_tools();
|
||||
for tool in &tools {
|
||||
if tool.name() == name {
|
||||
return tool.run(ctx, args);
|
||||
}
|
||||
}
|
||||
Err(anyhow::anyhow!("deferred tool not found: {}", name))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
use crate::app::state::rest::AppStateRest;
|
||||
use crate::app::runtime::actions::{Action, apply_action};
|
||||
|
||||
pub fn advance_turn(state: &mut AppStateRest) {
|
||||
if state.session_runtime.is_none() {
|
||||
return;
|
||||
}
|
||||
let rt = state.session_runtime.as_mut().unwrap();
|
||||
if rt.messages.is_empty() {
|
||||
return;
|
||||
}
|
||||
let api_key = state.settings.api_key.clone();
|
||||
let model = state.settings.model.clone();
|
||||
let msgs = rt.messages.clone();
|
||||
let pending = state.pending_api_response.clone();
|
||||
if let Some(key) = api_key {
|
||||
if !key.is_empty() {
|
||||
std::thread::spawn(move || {
|
||||
let client = crate::service::openrouter::OpenRouterClient::new(key, model);
|
||||
match client.chat(&msgs) {
|
||||
Ok(response) => {
|
||||
if let Ok(mut guard) = pending.lock() {
|
||||
*guard = Some(response);
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
if let Ok(mut guard) = pending.lock() {
|
||||
*guard = Some(format!("Error: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn process_tools(state: &mut AppStateRest) {
|
||||
let tool_calls: Vec<_> = {
|
||||
let rt = match state.session_runtime.as_ref() {
|
||||
Some(r) => r,
|
||||
None => return,
|
||||
};
|
||||
rt.pending_tool_queue.clone()
|
||||
};
|
||||
if tool_calls.is_empty() {
|
||||
return;
|
||||
}
|
||||
for tool_call in &tool_calls {
|
||||
let _result = format!("processing tool: {}", tool_call.tool_name);
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn finish_tool_round(state: &mut AppStateRest) {
|
||||
let tool_count = {
|
||||
let rt = match state.session_runtime.as_ref() {
|
||||
Some(r) => r,
|
||||
None => return,
|
||||
};
|
||||
rt.tool_call_results.len()
|
||||
};
|
||||
if tool_count > 0 {
|
||||
let note = format!("{} tool calls completed", tool_count);
|
||||
apply_action(state, Action::SystemNote {
|
||||
kind: "tool_round".to_string(),
|
||||
message: note,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user