Skip to content

Commit b416bf4

Browse files
committed
critical fixes
1 parent 1cd47d3 commit b416bf4

File tree

30 files changed

+229
-93
lines changed

30 files changed

+229
-93
lines changed

Cargo.lock

Lines changed: 14 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -412,7 +412,7 @@ MIT — use it however you want.
412412
<p align="center">
413413
<a href="https://www.rightnowai.co/">Website</a> &bull;
414414
<a href="https://x.com/Akashi203">Twitter / X</a> &bull;
415-
<a href="https://github.com/sponsors/RightNow-AI">Sponsor</a>
415+
<a href="https://www.buymeacoffee.com/openfang" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>
416416
</p>
417417

418418
---

crates/openfang-api/src/channel_bridge.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -893,11 +893,7 @@ impl ChannelBridgeHandle for KernelBridgeAdapter {
893893
msg.push_str(&format!(" {} — {}\n", card.name, url));
894894
let desc = &card.description;
895895
if !desc.is_empty() {
896-
let short = if desc.len() > 60 {
897-
&desc[..60]
898-
} else {
899-
desc.as_str()
900-
};
896+
let short = openfang_types::truncate_str(desc, 60);
901897
msg.push_str(&format!(" {short}\n"));
902898
}
903899
}

crates/openfang-api/src/routes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ pub async fn send_message(
285285
input_tokens: result.total_usage.input_tokens,
286286
output_tokens: result.total_usage.output_tokens,
287287
iterations: result.iterations,
288+
cost_usd: result.cost_usd,
288289
})),
289290
)
290291
}
@@ -3639,10 +3640,9 @@ pub async fn hand_instance_browser(
36393640
url = data["url"].as_str().unwrap_or("").to_string();
36403641
title = data["title"].as_str().unwrap_or("").to_string();
36413642
content = data["content"].as_str().unwrap_or("").to_string();
3642-
// Truncate content to avoid huge payloads (keep first 2000 chars)
3643+
// Truncate content to avoid huge payloads (UTF-8 safe)
36433644
if content.len() > 2000 {
3644-
content.truncate(2000);
3645-
content.push_str("... (truncated)");
3645+
content = format!("{}... (truncated)", openfang_types::truncate_str(&content, 2000));
36463646
}
36473647
}
36483648
}

crates/openfang-api/src/types.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ pub struct MessageResponse {
4646
pub input_tokens: u64,
4747
pub output_tokens: u64,
4848
pub iterations: u32,
49+
#[serde(skip_serializing_if = "Option::is_none")]
50+
pub cost_usd: Option<f64>,
4951
}
5052

5153
/// Request to install a skill from the marketplace.

crates/openfang-channels/src/types.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,9 @@ pub fn split_message(text: &str, max_len: usize) -> Vec<&str> {
278278
chunks.push(remaining);
279279
break;
280280
}
281-
// Try to split at a newline near the boundary
282-
let split_at = remaining[..max_len].rfind('\n').unwrap_or(max_len);
281+
// Try to split at a newline near the boundary (UTF-8 safe)
282+
let safe_end = openfang_types::truncate_str(remaining, max_len).len();
283+
let split_at = remaining[..safe_end].rfind('\n').unwrap_or(safe_end);
283284
let (chunk, rest) = remaining.split_at(split_at);
284285
chunks.push(chunk);
285286
// Skip the newline (and optional \r) we split on

crates/openfang-cli/src/tui/chat_runner.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ impl StandaloneChat {
175175
self.chat.last_tokens =
176176
Some((r.total_usage.input_tokens, r.total_usage.output_tokens));
177177
}
178+
self.chat.last_cost_usd = r.cost_usd;
178179
}
179180
Err(e) => {
180181
self.chat.status_msg = Some(format!("Error: {e}"));
@@ -227,6 +228,7 @@ impl StandaloneChat {
227228
self.chat.thinking = true;
228229
self.chat.streaming_chars = 0;
229230
self.chat.last_tokens = None;
231+
self.chat.last_cost_usd = None;
230232
self.chat.status_msg = None;
231233

232234
match &self.backend {

crates/openfang-cli/src/tui/screens/agents.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,6 @@ fn truncate(s: &str, max: usize) -> String {
15241524
if s.len() <= max {
15251525
s.to_string()
15261526
} else {
1527-
format!("{}\u{2026}", &s[..max - 1])
1527+
format!("{}\u{2026}", openfang_types::truncate_str(s, max.saturating_sub(1)))
15281528
}
15291529
}

crates/openfang-cli/src/tui/screens/audit.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -341,6 +341,6 @@ fn truncate(s: &str, max: usize) -> String {
341341
if s.len() <= max {
342342
s.to_string()
343343
} else {
344-
format!("{}\u{2026}", &s[..max - 1])
344+
format!("{}\u{2026}", openfang_types::truncate_str(s, max.saturating_sub(1)))
345345
}
346346
}

crates/openfang-cli/src/tui/screens/chat.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ pub struct ChatState {
5858
pub scroll_offset: u16,
5959
/// Token usage from last response.
6060
pub last_tokens: Option<(u64, u64)>,
61+
/// Cost in USD from last response.
62+
pub last_cost_usd: Option<f64>,
6163
/// Characters received during current stream (~4 chars ≈ 1 token).
6264
pub streaming_chars: usize,
6365
/// Status message (errors, etc.)
@@ -90,6 +92,7 @@ impl ChatState {
9092
input: String::new(),
9193
scroll_offset: 0,
9294
last_tokens: None,
95+
last_cost_usd: None,
9396
streaming_chars: 0,
9497
status_msg: None,
9598
staged_messages: Vec::new(),
@@ -107,6 +110,7 @@ impl ChatState {
107110
self.input.clear();
108111
self.scroll_offset = 0;
109112
self.last_tokens = None;
113+
self.last_cost_usd = None;
110114
self.streaming_chars = 0;
111115
self.status_msg = None;
112116
self.staged_messages.clear();
@@ -547,11 +551,15 @@ fn draw_messages(f: &mut Frame, area: Rect, state: &ChatState) {
547551
)]));
548552
}
549553

550-
// Add token usage if available
554+
// Add token usage and cost if available
551555
if let Some((input, output)) = state.last_tokens {
552556
if input > 0 || output > 0 {
557+
let cost_str = match state.last_cost_usd {
558+
Some(c) if c > 0.0 => format!(" | ${:.4}", c),
559+
_ => String::new(),
560+
};
553561
lines.push(Line::from(vec![Span::styled(
554-
format!(" [tokens: {} in / {} out]", input, output),
562+
format!(" [tokens: {} in / {} out{}]", input, output, cost_str),
555563
theme::dim_style(),
556564
)]));
557565
}
@@ -653,6 +661,6 @@ fn truncate_line(s: &str, max_len: usize) -> String {
653661
if s.len() <= max_len {
654662
s.to_string()
655663
} else {
656-
format!("{}\u{2026}", &s[..max_len.saturating_sub(1)])
664+
format!("{}\u{2026}", openfang_types::truncate_str(s, max_len.saturating_sub(1)))
657665
}
658666
}

0 commit comments

Comments
 (0)