Skip to content

Commit 6be74cc

Browse files
committed
move to fork() and exec() + cargo fmt
1 parent b2ca851 commit 6be74cc

20 files changed

Lines changed: 467 additions & 152 deletions

src/agent.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,15 +167,15 @@ pub async fn process_message(
167167
db: &Arc<BrainDb>,
168168
) -> Result<String, AgentError> {
169169
let mut session = Session::load(Arc::clone(db), chat_id).await?;
170-
170+
171171
// Check if summarization is needed (before building context so summary is included)
172172
if session.history().len() > summarize::SUMMARIZE_THRESHOLD {
173173
if let Err(e) = summarize::summarize_if_needed(llm, &mut session, model).await {
174174
eprintln!("Warning: summarization failed: {}", e);
175175
// Continue anyway — summarization is optimization
176176
}
177177
}
178-
178+
179179
let skills_summary = skills::build_skills_summary(workspace_path)?;
180180
let tool_summaries = registry.summaries();
181181

src/agent/context.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,13 @@ mod tests {
135135
use super::*;
136136

137137
const WEEKDAYS: &[&str] = &[
138-
"Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday",
138+
"Monday",
139+
"Tuesday",
140+
"Wednesday",
141+
"Thursday",
142+
"Friday",
143+
"Saturday",
144+
"Sunday",
139145
];
140146

141147
#[test]

src/agent/session.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,11 @@ impl Session {
5959
let db_clone = Arc::clone(&db);
6060
let chat_id_clone = chat_id.clone();
6161

62-
let (stored, summary) = tokio::task::spawn_blocking(move || {
63-
db_clone.load_session(&chat_id_clone)
64-
})
65-
.await
66-
.map_err(|e| SessionError::Db(format!("spawn_blocking: {e}")))?
67-
.map_err(SessionError::from)?;
62+
let (stored, summary) =
63+
tokio::task::spawn_blocking(move || db_clone.load_session(&chat_id_clone))
64+
.await
65+
.map_err(|e| SessionError::Db(format!("spawn_blocking: {e}")))?
66+
.map_err(SessionError::from)?;
6867

6968
let history = stored
7069
.into_iter()
@@ -193,10 +192,7 @@ fn message_to_stored(msg: &Message) -> Result<StoredMessage, SessionError> {
193192
let tool_calls = msg
194193
.tool_calls
195194
.as_ref()
196-
.map(|tc| {
197-
serde_json::to_string(tc)
198-
.map_err(|e| SessionError::Serialize(e.to_string()))
199-
})
195+
.map(|tc| serde_json::to_string(tc).map_err(|e| SessionError::Serialize(e.to_string())))
200196
.transpose()?;
201197

202198
Ok(StoredMessage {

src/agent/summarize.rs

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,12 @@ pub async fn summarize_if_needed(
7777

7878
let s1 = summarize_batch(llm, part1, "", model).await?;
7979
let s2 = summarize_batch(llm, part2, "", model).await?;
80-
merge_summaries(llm, &s1, &s2, model).await.unwrap_or_else(|_| {
81-
// Fallback: concatenate
82-
format!("{}\n\n{}", s1, s2)
83-
})
80+
merge_summaries(llm, &s1, &s2, model)
81+
.await
82+
.unwrap_or_else(|_| {
83+
// Fallback: concatenate
84+
format!("{}\n\n{}", s1, s2)
85+
})
8486
} else {
8587
// Single-pass
8688
summarize_batch(llm, &valid_messages, &existing_summary, model).await?
@@ -121,10 +123,7 @@ fn estimate_tokens(text: &str) -> usize {
121123
text.chars().count() / 3
122124
}
123125

124-
fn filter_valid_messages(
125-
messages: &[Message],
126-
max_tokens: usize,
127-
) -> (Vec<Message>, bool) {
126+
fn filter_valid_messages(messages: &[Message], max_tokens: usize) -> (Vec<Message>, bool) {
128127
let mut valid = Vec::new();
129128
let mut omitted = false;
130129

@@ -205,7 +204,13 @@ async fn summarize_batch(
205204
];
206205

207206
let response = llm
208-
.chat_with_params(&msgs, &[], model, Some(SUMMARY_TEMPERATURE), Some(SUMMARY_MAX_TOKENS))
207+
.chat_with_params(
208+
&msgs,
209+
&[],
210+
model,
211+
Some(SUMMARY_TEMPERATURE),
212+
Some(SUMMARY_MAX_TOKENS),
213+
)
209214
.await?;
210215

211216
Ok(response.content.trim().to_string())
@@ -230,7 +235,13 @@ async fn merge_summaries(
230235
}];
231236

232237
let response = llm
233-
.chat_with_params(&msgs, &[], model, Some(SUMMARY_TEMPERATURE), Some(SUMMARY_MAX_TOKENS))
238+
.chat_with_params(
239+
&msgs,
240+
&[],
241+
model,
242+
Some(SUMMARY_TEMPERATURE),
243+
Some(SUMMARY_MAX_TOKENS),
244+
)
234245
.await?;
235246

236247
Ok(response.content.trim().to_string())
@@ -242,23 +253,29 @@ mod tests {
242253

243254
#[test]
244255
fn should_summarize_returns_false_when_below_threshold() {
245-
let history = vec![Message {
246-
role: Role::User,
247-
content: "test".to_string(),
248-
tool_call_id: None,
249-
tool_calls: None,
250-
}; SUMMARIZE_THRESHOLD];
256+
let history = vec![
257+
Message {
258+
role: Role::User,
259+
content: "test".to_string(),
260+
tool_call_id: None,
261+
tool_calls: None,
262+
};
263+
SUMMARIZE_THRESHOLD
264+
];
251265
assert!(!should_summarize(&history));
252266
}
253267

254268
#[test]
255269
fn should_summarize_returns_true_when_above_threshold() {
256-
let history = vec![Message {
257-
role: Role::User,
258-
content: "test".to_string(),
259-
tool_call_id: None,
260-
tool_calls: None,
261-
}; SUMMARIZE_THRESHOLD + 1];
270+
let history = vec![
271+
Message {
272+
role: Role::User,
273+
content: "test".to_string(),
274+
tool_call_id: None,
275+
tool_calls: None,
276+
};
277+
SUMMARIZE_THRESHOLD + 1
278+
];
262279
assert!(should_summarize(&history));
263280
}
264281

src/bin/test_reqwest.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[tokio::main]
2+
async fn main() {
3+
println!("Testing reqwest TLS...");
4+
match reqwest::Client::builder().build() {
5+
Ok(client) => match client.get("https://api.telegram.org").send().await {
6+
Ok(res) => println!("reqwest ok, status: {}", res.status()),
7+
Err(e) => println!("reqwest send err: {}", e),
8+
},
9+
Err(e) => println!("reqwest builder err: {}", e),
10+
}
11+
}

src/bin/test_tokio_process.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#[tokio::main]
2+
async fn main() {
3+
println!("Testing tokio::process...");
4+
match tokio::process::Command::new("echo")
5+
.arg("hello from tokio::process")
6+
.output()
7+
.await
8+
{
9+
Ok(out) => println!(
10+
"tokio::process ok: {:?}",
11+
String::from_utf8_lossy(&out.stdout)
12+
),
13+
Err(e) => println!("tokio::process err: {}", e),
14+
}
15+
16+
println!("Testing std::process in spawn_blocking...");
17+
match tokio::task::spawn_blocking(|| {
18+
std::process::Command::new("echo")
19+
.arg("hello from std::process")
20+
.output()
21+
})
22+
.await
23+
{
24+
Ok(Ok(out)) => println!(
25+
"std::process ok: {:?}",
26+
String::from_utf8_lossy(&out.stdout)
27+
),
28+
Ok(Err(e)) => println!("std::process err: {}", e),
29+
Err(e) => println!("spawn_blocking err: {}", e),
30+
}
31+
}

src/cron_runner.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ pub async fn tick_once(
3232
channel: "cron".to_string(),
3333
};
3434
if inbound_tx.try_send(msg).is_err() {
35-
eprintln!("cron runner: inbound channel full, dropping agent job {}", job.id);
35+
eprintln!(
36+
"cron runner: inbound channel full, dropping agent job {}",
37+
job.id
38+
);
3639
}
3740
}
3841
JobAction::Direct => {
@@ -42,7 +45,10 @@ pub async fn tick_once(
4245
channel: "cron".to_string(),
4346
};
4447
if outbound_tx.try_send(msg).is_err() {
45-
eprintln!("cron runner: outbound channel full, dropping direct job {}", job.id);
48+
eprintln!(
49+
"cron runner: outbound channel full, dropping direct job {}",
50+
job.id
51+
);
4652
}
4753
}
4854
}
@@ -157,7 +163,9 @@ mod tests {
157163
None,
158164
"Later".to_string(),
159165
JobAction::Direct,
160-
Schedule::Once { at_unix: base + 1000 },
166+
Schedule::Once {
167+
at_unix: base + 1000,
168+
},
161169
1,
162170
)
163171
.unwrap();

src/heartbeat.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
//! `channel == "heartbeat"` to call `process_heartbeat_message` instead of `process_message`.
66
77
use std::path::{Path, PathBuf};
8-
use std::sync::atomic::{AtomicI64, Ordering};
98
use std::sync::Arc;
9+
use std::sync::atomic::{AtomicI64, Ordering};
1010
use std::time::Duration;
1111

1212
use tokio::sync::mpsc;
@@ -60,7 +60,10 @@ pub fn spawn_heartbeat_runner(
6060
inbound_tx: mpsc::Sender<InboundMsg>,
6161
last_chat_id: Arc<AtomicI64>,
6262
) -> tokio::task::JoinHandle<()> {
63-
assert!(interval_minutes >= 1, "heartbeat interval_minutes must be >= 1");
63+
assert!(
64+
interval_minutes >= 1,
65+
"heartbeat interval_minutes must be >= 1"
66+
);
6467
tokio::spawn(async move {
6568
let mut interval = tokio::time::interval(Duration::from_secs(interval_minutes * 60));
6669
// Skip the immediately-firing first tick so the first real tick is one full interval out.

src/llm.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,8 @@ impl HttpProvider {
200200
tools: &[ToolDef],
201201
model: &str,
202202
) -> Result<LlmResponse, LlmError> {
203-
self.chat_with_params(messages, tools, model, None, None).await
203+
self.chat_with_params(messages, tools, model, None, None)
204+
.await
204205
}
205206

206207
/// Send chat request with optional temperature and max_tokens. Returns content and tool_calls.

src/main.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
//! Single binary: runs Telegram poller + agent loop. Config: `~/.icrab/config.toml` or env.
44
55
use std::path::PathBuf;
6-
use std::sync::atomic::{AtomicI64, Ordering};
76
use std::sync::Arc;
7+
use std::sync::atomic::{AtomicI64, Ordering};
88

99
use tokio::sync::mpsc;
1010

@@ -17,12 +17,12 @@ use icrab::llm::HttpProvider;
1717
use icrab::memory::db::BrainDb;
1818
use icrab::memory::indexer::VaultIndexer;
1919
use icrab::sync;
20-
use icrab::tools::{GitSyncTool, GrepDirTool, SearchChatTool, SearchVaultTool};
2120
use icrab::telegram::{self, OutboundMsg};
2221
use icrab::tools;
2322
use icrab::tools::cron::{CronStore, CronTool};
2423
use icrab::tools::spawn::SpawnTool;
2524
use icrab::tools::subagent::SubagentTool;
25+
use icrab::tools::{GitSyncTool, GrepDirTool, SearchChatTool, SearchVaultTool};
2626

2727
const SUBAGENT_MAX_ITERATIONS: u32 = 10;
2828

@@ -67,7 +67,10 @@ async fn main() {
6767
std::process::exit(1);
6868
}
6969
};
70-
eprintln!("brain db opened: {}", icrab::workspace::brain_db_path(&workspace).display());
70+
eprintln!(
71+
"brain db opened: {}",
72+
icrab::workspace::brain_db_path(&workspace).display()
73+
);
7174

7275
// Kick off the vault indexer in a background task so startup isn't blocked.
7376
// The indexer walks the workspace and upserts any new/modified .md files
@@ -128,12 +131,10 @@ async fn main() {
128131
let outbound_tx = telegram::spawn_telegram(&cfg, inbound_tx.clone());
129132
eprintln!("Telegram poller and sender started");
130133

131-
let cron_store = Arc::new(
132-
CronStore::load(&workspace).unwrap_or_else(|e| {
133-
eprintln!("cron store: {}", e);
134-
CronStore::empty(&workspace)
135-
}),
136-
);
134+
let cron_store = Arc::new(CronStore::load(&workspace).unwrap_or_else(|e| {
135+
eprintln!("cron store: {}", e);
136+
CronStore::empty(&workspace)
137+
}));
137138
cron_runner::spawn_cron_runner(
138139
Arc::clone(&cron_store),
139140
inbound_tx.clone(),
@@ -158,7 +159,10 @@ async fn main() {
158159
inbound_tx.clone(),
159160
Arc::clone(&last_chat_id),
160161
);
161-
eprintln!("heartbeat runner started (interval: {} min)", heartbeat_interval);
162+
eprintln!(
163+
"heartbeat runner started (interval: {} min)",
164+
heartbeat_interval
165+
);
162166
}
163167

164168
drop(inbound_tx);

0 commit comments

Comments
 (0)