add context.md, strip LLM timestamps, clippy fixes, simplify deploy target

This commit is contained in:
Fam Zheng
2026-04-10 22:43:52 +01:00
parent c0e12798ee
commit 9d2d2af33f
8 changed files with 91 additions and 23 deletions

View File

@@ -16,6 +16,7 @@ pub struct Config {
}
#[derive(Deserialize, Clone)]
#[allow(dead_code)]
pub struct GiteaConfig {
pub url: String,
/// Direct token or read from token_file at startup

View File

@@ -6,6 +6,25 @@ use teloxide::types::ParseMode;
use crate::stream::{CURSOR, TG_MSG_LIMIT};
/// Strip leading timestamps that LLM copies from our injected message timestamps.
/// Matches patterns like `[2026-04-10 21:13:15]` or `[2026-04-10 21:13]` at the start.
pub fn strip_leading_timestamp(s: &str) -> &str {
let trimmed = s.trim_start();
if trimmed.starts_with('[') {
if let Some(end) = trimmed.find(']') {
let inside = &trimmed[1..end];
// check if it looks like a timestamp: starts with 20xx-
if inside.len() >= 16 && inside.starts_with("20") && inside.contains('-') {
let after = trimmed[end + 1..].trim_start();
if !after.is_empty() {
return after;
}
}
}
}
s
}
pub fn truncate_for_display(s: &str) -> String {
let budget = TG_MSG_LIMIT - CURSOR.len() - 1;
if s.len() <= budget {

View File

@@ -6,7 +6,7 @@ use axum::http::StatusCode;
use axum::response::IntoResponse;
use axum::routing::post;
use axum::Json;
use tracing::{error, info, warn};
use tracing::{error, info};
use crate::config::GiteaConfig;

View File

@@ -36,6 +36,7 @@ use crate::stream::{send_message_draft, DRAFT_INTERVAL_MS, EDIT_INTERVAL_MS, TG_
pub struct TelegramOutput {
pub bot: Bot,
pub chat_id: ChatId,
#[allow(dead_code)]
pub is_private: bool,
// internal state
msg_id: Option<teloxide::types::MessageId>,
@@ -140,6 +141,7 @@ impl Output for TelegramOutput {
use crate::gitea::GiteaClient;
#[allow(dead_code)]
pub struct GiteaOutput {
pub client: GiteaClient,
pub owner: String,
@@ -173,10 +175,12 @@ impl Output for GiteaOutput {
// ── Buffer (for Worker, tests) ─────────────────────────────────────
#[allow(dead_code)]
pub struct BufferOutput {
pub text: String,
}
#[allow(dead_code)]
impl BufferOutput {
pub fn new() -> Self {
Self {

View File

@@ -4,7 +4,7 @@ use anyhow::Result;
use tracing::{error, info, warn};
use crate::config::Config;
use crate::display::truncate_at_char_boundary;
use crate::display::{strip_leading_timestamp, truncate_at_char_boundary};
use crate::output::Output;
use crate::state::AppState;
use crate::tools::{discover_tools, execute_tool, ToolCall};
@@ -209,11 +209,14 @@ pub async fn run_openai_with_tools(
continue;
}
if !accumulated.is_empty() {
let _ = output.finalize(&accumulated).await;
// strip timestamps that LLM copies from our message format
let cleaned = strip_leading_timestamp(&accumulated).to_string();
if !cleaned.is_empty() {
let _ = output.finalize(&cleaned).await;
}
return Ok(accumulated);
return Ok(cleaned);
}
}
@@ -257,6 +260,19 @@ pub fn build_system_prompt(summary: &str, persona: &str, memory_slots: &[(i32, S
text.push_str(inner_state);
}
// inject context file if present (e.g. /data/noc/context.md)
let config_path = std::env::var("NOC_CONFIG").unwrap_or_else(|_| "config.yaml".into());
let context_path = std::path::Path::new(&config_path)
.parent()
.unwrap_or(std::path::Path::new("."))
.join("context.md");
if let Ok(ctx) = std::fs::read_to_string(&context_path) {
if !ctx.trim().is_empty() {
text.push_str("\n\n## 运行环境\n");
text.push_str(ctx.trim());
}
}
if !summary.is_empty() {
text.push_str("\n\n## 之前的对话总结\n");
text.push_str(summary);

View File

@@ -7,7 +7,7 @@ use anyhow::Result;
use tokio::io::AsyncBufReadExt;
use tokio::process::Command;
use tokio::sync::RwLock;
use tracing::{error, info, warn};
use tracing::{info, warn};
use crate::config::Config;
use crate::display::truncate_at_char_boundary;