diff --git a/src/agentsight/AGENTS.md b/src/agentsight/AGENTS.md
index 6fc894eb6..d460a3675 100644
--- a/src/agentsight/AGENTS.md
+++ b/src/agentsight/AGENTS.md
@@ -32,8 +32,8 @@ eBPF Probes → Event → Parser → ParsedMessage → Aggregator → Aggregated
| 模块 | 位置 | 职责 | 关键类型 |
|------|------|------|----------|
-| **Probes** | `src/probes/` | eBPF 探针管理 | `Probes`, `ProbesPoller`, `SslSniff`, `ProcMon`, `FileWatch` |
-| **Event** | `src/event.rs` | 统一事件枚举 | `Event::{Ssl, Proc, ProcMon, FileWatch}` |
+| **Probes** | `src/probes/` | eBPF 探针管理 | `Probes`, `ProbesPoller`, `SslSniff`, `ProcMon`, `FileWatch`, `FileWriteProbe`, `UdpDns`, `TcpSniff` |
+| **Event** | `src/event.rs` | 统一事件枚举 | `Event::{Ssl, Proc, ProcMon, FileWatch, FileWrite, UdpDns}` |
| **Parser** | `src/parser/` | 协议解析(HTTP/1.x, HTTP/2, SSE, ProcTrace) | `Parser`, `ParsedMessage` |
| **Aggregator** | `src/aggregator/` | 请求-响应关联 | `Aggregator`, `AggregatedResult` |
| **Analyzer** | `src/analyzer/` | Token/审计/消息分析 | `Analyzer`, `AnalysisResult` |
@@ -62,6 +62,9 @@ eBPF Probes → Event → Parser → ParsedMessage → Aggregator → Aggregated
| proctrace | `src/bpf/proctrace.bpf.c` | tracepoint on execve 捕获命令行参数 |
| procmon | `src/bpf/procmon.bpf.c` | 进程创建/退出事件(Agent 发现) |
| filewatch | `src/bpf/filewatch.bpf.c` | 监控 .jsonl 文件打开事件 |
+| filewrite | `src/bpf/filewrite.bpf.c` | fentry on vfs_write 捕获 .jsonl 写入内容 |
+| udpdns | `src/bpf/udpdns.bpf.c` | fentry on udp_sendmsg 捕获 DNS 查询(域名→IP)|
+| tcpsniff | `src/bpf/tcpsniff.bpf.c` | fentry on tcp_recvmsg/sendmsg 捕获明文 HTTP 流量 |
构建时 `build.rs` 通过 `libbpf-cargo` 自动生成 eBPF skeleton。
diff --git a/src/agentsight/docs/design-docs/ebpf-probes.md b/src/agentsight/docs/design-docs/ebpf-probes.md
index ad88f0dcb..53f2a8a6a 100644
--- a/src/agentsight/docs/design-docs/ebpf-probes.md
+++ b/src/agentsight/docs/design-docs/ebpf-probes.md
@@ -2,7 +2,7 @@
## Overview
-AgentSight 使用 4 个 eBPF 探针从内核态捕获数据,所有探针共享同一个 ring buffer 和 `traced_processes` BPF map,由 `Probes` 管理器统一协调。
+AgentSight 使用 7 个 eBPF 探针从内核态捕获数据,所有探针共享同一个 ring buffer 和 `traced_processes` BPF map,由 `Probes` 管理器统一协调。
## Probe Architecture
@@ -13,6 +13,9 @@ graph TB
PT[proctrace.bpf.c
tracepoint: sched_process_exec]
PM[procmon.bpf.c
tracepoint: sched_process_exec/fork/exit]
FW[filewatch.bpf.c
tracepoint: do_sys_open]
+ FWR[filewrite.bpf.c
fentry: vfs_write]
+ UD[udpdns.bpf.c
fentry: udp_sendmsg]
+ TS[tcpsniff.bpf.c
fentry: tcp_recvmsg/sendmsg]
end
subgraph Shared["Shared BPF Maps"]
@@ -24,8 +27,13 @@ graph TB
PT -->|write| RB
PM -->|write| RB
FW -->|write| RB
+ FWR -->|write| RB
+ UD -->|write| RB
+ TS -->|write| RB
SSL -->|lookup| TM
FW -->|lookup| TM
+ FWR -->|lookup| TM
+ UD -->|lookup| TM
subgraph Userspace["User Space"]
P[Probes Poller Thread]
@@ -87,6 +95,39 @@ graph TB
**Purpose**: Monitor Agent processes opening .jsonl files for auxiliary Agent session identification.
+### 5. filewrite — File Write Capture
+
+- **BPF Type**: fentry
+- **Attach Point**: `vfs_write`
+- **Filter**: Only PIDs in `traced_processes` writing to `.jsonl` files
+- **Output**: `filewrite_event_t` (pid, filename, written content)
+- **Source**: `src/bpf/filewrite.bpf.c`, `src/bpf/filewrite.h`
+- **Userspace**: `src/probes/filewrite.rs`
+
+**Purpose**: Capture written .jsonl content to recover responseId → sessionId mappings.
+
+### 6. udpdns — DNS Query Capture
+
+- **BPF Type**: fentry
+- **Attach Point**: `udp_sendmsg`
+- **Filter**: PIDs in `traced_processes`, UDP destination port 53
+- **Output**: `udpdns_event_t` (queried domain)
+- **Source**: `src/bpf/udpdns.bpf.c`, `src/bpf/udpdns.h`
+- **Userspace**: `src/probes/udpdns.rs`
+
+**Purpose**: Resolve configured HTTPS/HTTP domain patterns to IPs at runtime for SSL/TCP attach filtering.
+
+### 7. tcpsniff — Plaintext HTTP Capture
+
+- **BPF Type**: fentry/fexit
+- **Attach Point**: `tcp_recvmsg` / `tcp_sendmsg`
+- **Filter**: Configured destination IP/port targets (`tcp_targets`)
+- **Output**: reuses the sslsniff `probe_SSL_data_t` event format
+- **Source**: `src/bpf/tcpsniff.bpf.c`
+- **Userspace**: `src/probes/tcpsniff.rs`
+
+**Purpose**: Capture plaintext (non-TLS) HTTP traffic to configured endpoints, e.g. internal MaaS gateways.
+
## Shared Resource Design
### Ring Buffer (events_rb)
@@ -99,6 +140,8 @@ All probes share one ring buffer, distinguished by `common_event_hdr.source` fie
| 2 (EVENT_SOURCE_SSL) | sslsniff event | `SslEvent::from_bpf()` |
| 3 (EVENT_SOURCE_PROCMON) | procmon event | `procmon::Event::from_bytes()` |
| 4 (EVENT_SOURCE_FILEWATCH) | filewatch event | `FileWatchEvent::from_bytes()` |
+| 5 (EVENT_SOURCE_FILEWRITE) | filewrite event | `FileWriteEvent::from_bytes()` |
+| 6 (EVENT_SOURCE_UDPDNS) | udpdns event | `UdpDnsEvent::from_bytes()` |
**Implementation**: `src/probes/probes.rs:Probes::run()` lines 137-193 — single thread polls ring buffer, dispatches by source field into `Event` enum.
diff --git a/src/agentsight/integration-tests/README.md b/src/agentsight/integration-tests/README.md
index e683ee801..3a06b5e2e 100644
--- a/src/agentsight/integration-tests/README.md
+++ b/src/agentsight/integration-tests/README.md
@@ -10,6 +10,9 @@
|------|------|
| `RULES.md` | 测试环境、部署流程、通用规则 |
| `TEMPLATE.md` | 新建测试用例的模板 |
-| `test_sni.md` | TLS SNI 探针加载与域名匹配 |
-| `test_hermes_sni.md` | 通过 SNI 捕获 Hermes agent(dashscope.aliyuncs.com) |
+| `test_dns.md` | UDP DNS 探针:域名→IP 解析捕获 |
+| `test_hermes_dns.md` | 通过 DNS 捕获 Hermes agent(dashscope.aliyuncs.com) |
+| `test_http.md` | 明文 HTTP(tcpsniff)流量捕获 |
+| `test_connection_scanner.md` | 连接扫描器:活跃连接发现 |
+| `test_ffi_integration.md` | C FFI API 集成 |
| `test_claude_code.md` | Claude Code BoringSSL 探针、SSE thinking/tool_use 解析、msg_id 会话关联 |
diff --git a/src/agentsight/src/aggregator/http2.rs b/src/agentsight/src/aggregator/http2.rs
index d7ec15f6b..f65bb3f6d 100644
--- a/src/agentsight/src/aggregator/http2.rs
+++ b/src/agentsight/src/aggregator/http2.rs
@@ -4,12 +4,11 @@
//! by their stream_id and correlating request (client->server) with response (server->client)
//! to form complete HTTP/2 request/response pairs.
-use std::collections::HashMap;
use std::num::NonZeroUsize;
use lru::LruCache;
use crate::config::DEFAULT_CONNECTION_CAPACITY;
use crate::parser::http2::ParsedHttp2Frame;
-use crate::parser::sse::{SseParser, SSEParser};
+use crate::parser::sse::SSEParser;
use crate::aggregator::http::ConnectionId;
use crate::aggregator::result::AggregatedResult;
use crate::chrome_trace::{ChromeTraceEvent, ToChromeTraceEvent, ns_to_us};
diff --git a/src/agentsight/src/aggregator/unified.rs b/src/agentsight/src/aggregator/unified.rs
index 530827735..a2b628c1c 100644
--- a/src/agentsight/src/aggregator/unified.rs
+++ b/src/agentsight/src/aggregator/unified.rs
@@ -7,7 +7,7 @@ use super::http::{ConnectionId, ConnectionState, HttpConnectionAggregator};
use super::http2::Http2StreamAggregator;
use super::proctrace::ProcessEventAggregator;
use super::result::AggregatedResult;
-use crate::chrome_trace::{export_trace_events, ToChromeTraceEvent};
+use crate::chrome_trace::export_trace_events;
use crate::parser::{ParseResult, ParsedMessage};
/// Unified aggregator for all event types
diff --git a/src/agentsight/src/analyzer/message/mod.rs b/src/agentsight/src/analyzer/message/mod.rs
index 367fad4bb..5b5548153 100644
--- a/src/agentsight/src/analyzer/message/mod.rs
+++ b/src/agentsight/src/analyzer/message/mod.rs
@@ -390,7 +390,7 @@ mod tests {
#[test]
fn test_full_url_paths() {
- let parser = MessageParser::new();
+ let _parser = MessageParser::new();
// Should work with full URLs too
assert!(MessageParser::is_llm_api_path(
diff --git a/src/agentsight/src/analyzer/token/extractor/mod.rs b/src/agentsight/src/analyzer/token/extractor/mod.rs
index d81ac266b..11d63af73 100644
--- a/src/agentsight/src/analyzer/token/extractor/mod.rs
+++ b/src/agentsight/src/analyzer/token/extractor/mod.rs
@@ -18,7 +18,7 @@ mod anthropic;
mod utils;
use serde_json::Value;
-use super::data::{TokenData, MessageTokenData, ResponseTokenData};
+use super::data::TokenData;
/// Extract token data from JSON request/response bodies
///
@@ -79,4 +79,3 @@ pub enum Provider {
}
// Re-export utility functions for internal use
-pub use utils::extract_model_from_json;
diff --git a/src/agentsight/src/analyzer/unified.rs b/src/agentsight/src/analyzer/unified.rs
index d9a078807..2fec8d5a3 100644
--- a/src/agentsight/src/analyzer/unified.rs
+++ b/src/agentsight/src/analyzer/unified.rs
@@ -26,7 +26,7 @@ use crate::tokenizer::LlmTokenizer;
use crate::tokenizer::get_global_tokenizer;
use crate::analyzer::token::extract_response_content;
-use super::{AuditAnalyzer, TokenParser, MessageParser, AuditRecord, TokenRecord, TokenUsage, ParsedApiMessage, AnalysisResult, PromptTokenCount, HttpRecord};
+use super::{AuditAnalyzer, TokenParser, MessageParser, TokenRecord, TokenUsage, ParsedApiMessage, AnalysisResult, HttpRecord};
use super::result::{TokenConsumptionBreakdown, MessageTokenCount, OutputTokenCount};
/// Token count result for request messages
@@ -424,7 +424,7 @@ impl Analyzer {
let mut results = Vec::new();
// 1. Audit analysis for process actions (non-HTTP)
- if let AggregatedResult::ProcessComplete(process) = result {
+ if let AggregatedResult::ProcessComplete(_process) = result {
if let Some(record) = self.audit.analyze(result) {
results.push(AnalysisResult::Audit(record));
}
@@ -559,7 +559,7 @@ impl Analyzer {
let usage = sse_events.iter().rev()
.find_map(|e| self.token.parse_event(e))?;
- let mut record = TokenRecord::new(
+ let record = TokenRecord::new(
pid,
comm.to_string(),
usage.provider.to_string(),
@@ -926,78 +926,6 @@ impl Analyzer {
.map(AnalysisResult::Token)
}
- /// Compute prompt tokens for a parsed API message
- ///
- /// This method uses the tokenizer to compute the actual prompt token count
- /// from the request messages.
- fn compute_prompt_tokens(
- &self,
- msg_result: &AnalysisResult,
- tokenizer: &LlmTokenizer,
- chat_template: &LlmTokenizer,
- ) -> Option {
- let messages = match msg_result {
- AnalysisResult::Message(ParsedApiMessage::OpenAICompletion { request, .. }) => {
- request.as_ref()?.messages.clone()
- }
- _ => return None,
- };
-
- let provider = match msg_result {
- AnalysisResult::Message(msg) => msg.provider().to_string(),
- _ => "unknown".to_string(),
- };
-
- let model = match msg_result {
- AnalysisResult::Message(msg) => msg.model().unwrap_or("unknown").to_string(),
- _ => "unknown".to_string(),
- };
-
- let message_count = messages.len();
-
- // Convert messages to JSON values
- let messages_json: Vec = messages
- .iter()
- .filter_map(|m| serde_json::to_value(m).ok())
- .collect();
-
- // Apply chat template and count tokens
- match chat_template.apply_chat_template(&messages_json, true) {
- Ok(formatted_prompt) => {
- match tokenizer.count(&formatted_prompt) {
- Ok(prompt_tokens) => {
- // Compute per-message token counts
- let per_message_tokens: Vec = messages
- .iter()
- .filter_map(|m| {
- let msg_json = serde_json::to_value(m).ok()?;
- let content = msg_json.get("content")?.as_str()?.to_string();
- tokenizer.count(&content).ok()
- })
- .collect();
-
- Some(PromptTokenCount {
- provider,
- model,
- message_count,
- prompt_tokens,
- per_message_tokens,
- formatted_prompt,
- })
- }
- Err(e) => {
- log::warn!("Failed to count tokens: {}", e);
- None
- }
- }
- }
- Err(e) => {
- log::warn!("Failed to apply chat template: {}", e);
- None
- }
- }
- }
-
/// Get reference to the audit analyzer
pub fn audit_analyzer(&self) -> &AuditAnalyzer {
&self.audit
@@ -1049,199 +977,6 @@ impl Analyzer {
self.message.parse_by_path(path, request_body, response_body)
}
- /// Compute token consumption using apply_chat_template for accurate counting
- ///
- /// This function directly uses the Jinja2 template to format messages and count tokens,
- /// avoiding intermediate conversions and providing more accurate results.
- fn compute_token_consumption_with_template(
- &self,
- messages: &[serde_json::Value],
- model: &str,
- provider: &str,
- tools: Vec,
- system_prompt: Option,
- response_jsons: &[serde_json::Value],
- pid: u32,
- comm: String,
- ) -> Option {
- let (tokenizer, chat_template) = match (&self.tokenizer, &self.chat_template) {
- (Some(t), Some(ct)) => (t, ct),
- _ => {
- log::warn!("Tokenizer or chat template not available, cannot compute accurate token consumption");
- return None;
- }
- };
-
- let mut by_role: std::collections::HashMap = std::collections::HashMap::new();
- let mut per_message: Vec = Vec::new();
-
- // Prepare messages for apply_chat_template
- let mut template_messages: Vec = messages.to_vec();
-
- // Add system prompt as first message if present and not already in messages
- if let Some(ref system) = system_prompt {
- if !template_messages.is_empty() && template_messages[0].get("role") != Some(&serde_json::Value::String("system".to_string())) {
- let system_msg = serde_json::json!({
- "role": "system",
- "content": system
- });
- template_messages.insert(0, system_msg);
- }
- }
-
- // Count tools tokens
- let tools_tokens: usize = tools.iter()
- .filter_map(|tool| tokenizer.count(tool).ok())
- .sum();
-
- // Use apply_chat_template to format all messages and count total tokens
- let total_msg_tokens = match chat_template.apply_chat_template(&template_messages, true) {
- Ok(formatted) => tokenizer.count(&formatted).unwrap_or(0),
- Err(e) => {
- log::warn!("Failed to apply chat template: {}", e);
- // Fallback: count raw content
- messages.iter()
- .filter_map(|m| m.get("content").and_then(|c| c.as_str()))
- .filter_map(|c| tokenizer.count(c).ok())
- .sum()
- }
- };
-
- // Count per-message tokens using incremental approach
- for (i, msg) in messages.iter().enumerate() {
- let partial_messages: Vec = template_messages.iter().take(i + 1).cloned().collect();
- let tokens = match chat_template.apply_chat_template(&partial_messages, false) {
- Ok(formatted) => tokenizer.count(&formatted).unwrap_or(0),
- Err(_) => {
- // Fallback: count content only
- msg.get("content").and_then(|c| c.as_str())
- .and_then(|c| tokenizer.count(c).ok())
- .unwrap_or(0)
- }
- };
-
- // Calculate this message's tokens by subtracting previous total
- let prev_total: usize = per_message.iter().map(|m| m.tokens).sum();
- let msg_tokens = tokens.saturating_sub(prev_total);
-
- let role = msg.get("role").and_then(|r| r.as_str()).unwrap_or("unknown").to_string();
- *by_role.entry(role.clone()).or_insert(0) += msg_tokens;
-
- per_message.push(MessageTokenCount {
- role,
- tokens: msg_tokens,
- });
- }
-
- // Count system prompt tokens separately
- let system_prompt_tokens = if let Some(ref system) = system_prompt {
- tokenizer.count(system).unwrap_or(system.len() / 4)
- } else {
- 0
- };
-
- // Total input = tools + all messages (system is included in messages)
- let total_input = tools_tokens + total_msg_tokens;
-
- // Compute output token breakdown from response
- let (output_by_type, output_per_block) = self.compute_output_token_breakdown_from_json(
- response_jsons,
- tokenizer,
- chat_template,
- );
-
- let total_output_tokens: usize = output_by_type.values().sum();
-
- Some(TokenConsumptionBreakdown {
- timestamp_ns: std::time::SystemTime::now()
- .duration_since(std::time::UNIX_EPOCH)
- .map(|d| d.as_nanos() as u64)
- .unwrap_or(0),
- pid,
- comm,
- provider: provider.to_string(),
- model: model.to_string(),
- total_input_tokens: total_input,
- total_output_tokens,
- by_role,
- per_message,
- tools_tokens,
- system_prompt_tokens,
- output_by_type,
- output_per_block,
- })
- }
-
- /// Compute output token breakdown from SSE response JSONs
- ///
- /// Directly processes SSE chunks using extract_response_content which now supports
- /// both "message" and "delta" formats, eliminating the need for aggregate_sse_chunks.
- fn compute_output_token_breakdown_from_json(
- &self,
- response_jsons: &[serde_json::Value],
- tokenizer: &LlmTokenizer,
- _chat_template: &LlmTokenizer,
- ) -> (std::collections::HashMap, Vec) {
- let mut output_by_type: std::collections::HashMap = std::collections::HashMap::new();
- let mut output_per_block: Vec = Vec::new();
-
- // Accumulate content from all SSE chunks (extract_response_content now supports delta format)
- let mut all_content = String::new();
- let mut all_reasoning = String::new();
- let mut all_tool_calls = Vec::new();
-
- for chunk in response_jsons {
- if let Some((content, reasoning, tool_calls)) = extract_response_content(Some(chunk)) {
- if !content.is_empty() {
- all_content.push_str(&content);
- }
- if let Some(r) = reasoning {
- if !r.is_empty() {
- all_reasoning.push_str(&r);
- }
- }
- for tc in tool_calls {
- if !tc.is_empty() {
- all_tool_calls.push(tc);
- }
- }
- }
- }
-
- // Handle text content
- if !all_content.is_empty() {
- let tokens = tokenizer.count(&all_content).unwrap_or(all_content.len() / 4);
- *output_by_type.entry("text".to_string()).or_insert(0) += tokens;
- output_per_block.push(OutputTokenCount {
- content_type: "text".to_string(),
- tokens,
- });
- }
-
- // Handle reasoning content
- if !all_reasoning.is_empty() {
- let tokens = tokenizer.count(&all_reasoning).unwrap_or(all_reasoning.len() / 4);
- *output_by_type.entry("reasoning".to_string()).or_insert(0) += tokens;
- output_per_block.push(OutputTokenCount {
- content_type: "reasoning".to_string(),
- tokens,
- });
- }
-
- // Handle tool calls - aggregate all tool calls and count once
- if !all_tool_calls.is_empty() {
- let aggregated_tool_calls = all_tool_calls.join("");
- let tokens = tokenizer.count(&aggregated_tool_calls).unwrap_or(aggregated_tool_calls.len() / 4);
- *output_by_type.entry("tool_calls".to_string()).or_insert(0) += tokens;
- output_per_block.push(OutputTokenCount {
- content_type: "tool_calls".to_string(),
- tokens,
- });
- }
-
- (output_by_type, output_per_block)
- }
-
/// Analyze AggregatedResult and extract token consumption breakdown
///
/// This is a convenience method that combines extract_token_data and
diff --git a/src/agentsight/src/atif/converter.rs b/src/agentsight/src/atif/converter.rs
index 862b64f9c..34bd57548 100644
--- a/src/agentsight/src/atif/converter.rs
+++ b/src/agentsight/src/atif/converter.rs
@@ -746,7 +746,7 @@ fn ns_to_iso8601(ns: u64) -> String {
#[cfg(test)]
mod tests {
use super::*;
- use crate::genai::semantic::{InputMessage, OutputMessage, MessagePart};
+ use crate::genai::semantic::{InputMessage, MessagePart};
#[test]
fn test_ns_to_iso8601() {
diff --git a/src/agentsight/src/bin/cli/skill_metrics.rs b/src/agentsight/src/bin/cli/skill_metrics.rs
index d1dded6a6..df3081b30 100644
--- a/src/agentsight/src/bin/cli/skill_metrics.rs
+++ b/src/agentsight/src/bin/cli/skill_metrics.rs
@@ -367,19 +367,3 @@ fn format_timestamp_ns(ns: i64) -> String {
.naive_utc();
dt.format("%m-%d %H:%M").to_string()
}
-
-fn format_duration_ns(ns: i64) -> String {
- if ns == 0 {
- return "0s".to_string();
- }
- let secs = ns as f64 / 1_000_000_000.0;
- if secs < 60.0 {
- format!("{:.1}s", secs)
- } else if secs < 3600.0 {
- format!("{:.1}m", secs / 60.0)
- } else if secs < 86400.0 {
- format!("{:.1}h", secs / 3600.0)
- } else {
- format!("{:.1}d", secs / 86400.0)
- }
-}
diff --git a/src/agentsight/src/bin/cli/token.rs b/src/agentsight/src/bin/cli/token.rs
index ae620f621..634f3c1bb 100644
--- a/src/agentsight/src/bin/cli/token.rs
+++ b/src/agentsight/src/bin/cli/token.rs
@@ -5,7 +5,6 @@ use agentsight::{
SqliteConfig,
};
use structopt::StructOpt;
-use std::collections::HashMap;
/// Token query subcommand
#[derive(Debug, StructOpt, Clone)]
diff --git a/src/agentsight/src/genai/builder.rs b/src/agentsight/src/genai/builder.rs
index 9da392041..73fcc6392 100644
--- a/src/agentsight/src/genai/builder.rs
+++ b/src/agentsight/src/genai/builder.rs
@@ -1417,7 +1417,7 @@ impl GenAIBuilder {
log::debug!("[GenAI] Parsing SSE body with {} chunks", chunks.len());
- for (chunk_idx, chunk) in chunks.iter().enumerate() {
+ for (_chunk_idx, chunk) in chunks.iter().enumerate() {
let choices = chunk.get("choices").and_then(|c| c.as_array());
let choices = match choices {
Some(c) => c,
diff --git a/src/agentsight/src/health/checker.rs b/src/agentsight/src/health/checker.rs
index aa5553eaa..c0d84c46b 100644
--- a/src/agentsight/src/health/checker.rs
+++ b/src/agentsight/src/health/checker.rs
@@ -341,26 +341,6 @@ impl HealthChecker {
}
}
- /// Query pending LLM calls for a specific PID from genai_events.
- ///
- /// Returns a list of (call_id, session_id, trace_id, conversation_id) tuples.
- fn get_pending_calls_for_pid(
- &self,
- pid: u32,
- ) -> Vec<(String, Option, Option, Option)> {
- if let Some(ref genai_store) = self.genai_store {
- match genai_store.list_pending_for_pid(pid as i32) {
- Ok(calls) => calls,
- Err(e) => {
- log::warn!("Failed to query pending calls for pid={}: {}", pid, e);
- vec![]
- }
- }
- } else {
- vec![]
- }
- }
-
/// Query pending LLM calls for multiple PIDs at once.
///
/// Returns a list of (call_id, session_id, trace_id, conversation_id) tuples.
diff --git a/src/agentsight/src/parser/http/request.rs b/src/agentsight/src/parser/http/request.rs
index 6d070caba..e184c4f77 100644
--- a/src/agentsight/src/parser/http/request.rs
+++ b/src/agentsight/src/parser/http/request.rs
@@ -205,7 +205,7 @@ fn format_body(data: &[u8]) -> String {
format!("(text, {} bytes)\n{}", data.len(), text)
} else {
// Binary data - show as base64
- format!("(binary, {} bytes)\n{}", data.len(), base64::encode(data))
+ format!("(binary, {} bytes)\n{}", data.len(), base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data))
}
}
diff --git a/src/agentsight/src/parser/http/response.rs b/src/agentsight/src/parser/http/response.rs
index e3516521b..7f0fc337b 100644
--- a/src/agentsight/src/parser/http/response.rs
+++ b/src/agentsight/src/parser/http/response.rs
@@ -151,6 +151,6 @@ fn format_body(data: &[u8]) -> String {
format!("(text, {} bytes)\n{}", data.len(), text)
} else {
// Binary data - show as base64
- format!("(binary, {} bytes)\n{}", data.len(), base64::encode(data))
+ format!("(binary, {} bytes)\n{}", data.len(), base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data))
}
}
diff --git a/src/agentsight/src/parser/proctrace.rs b/src/agentsight/src/parser/proctrace.rs
index ba90ed7c2..be9837253 100644
--- a/src/agentsight/src/parser/proctrace.rs
+++ b/src/agentsight/src/parser/proctrace.rs
@@ -47,7 +47,7 @@ impl ProcTraceParser {
/// Parse a variable-length process event
pub fn parse_variable(event: &VariableEvent) -> Option {
match event {
- VariableEvent::Exec { header, filename, args } => {
+ VariableEvent::Exec { header, filename: _, args } => {
Some(ParsedProcEvent {
event_type: ProcEventType::Exec,
pid: header.pid,
diff --git a/src/agentsight/src/parser/sse/event.rs b/src/agentsight/src/parser/sse/event.rs
index d7d512f98..dd4e8865a 100644
--- a/src/agentsight/src/parser/sse/event.rs
+++ b/src/agentsight/src/parser/sse/event.rs
@@ -182,7 +182,7 @@ fn format_sse_data(data: &[u8]) -> String {
format!("(text, {} bytes)\n{}", data.len(), text)
} else {
// Binary data - show as base64
- format!("(binary, {} bytes)\n{}", data.len(), base64::encode(data))
+ format!("(binary, {} bytes)\n{}", data.len(), base64::Engine::encode(&base64::engine::general_purpose::STANDARD, data))
}
}
diff --git a/src/agentsight/src/parser/unified.rs b/src/agentsight/src/parser/unified.rs
index 12409adfc..70e62ff8b 100644
--- a/src/agentsight/src/parser/unified.rs
+++ b/src/agentsight/src/parser/unified.rs
@@ -50,7 +50,7 @@ impl Parser {
pub fn parse_ssl_event(&self, ssl_event: Rc) -> ParseResult {
log::debug!("parse_ssl_event: length={}", ssl_event.buf_size());
- let comm = ssl_event.comm.trim_end_matches('\0');
+ let _comm = ssl_event.comm.trim_end_matches('\0');
// 1. HTTP/1.x detection (text-based protocols)
if ssl_event.is_http() {
diff --git a/src/agentsight/src/probes/filewatch.rs b/src/agentsight/src/probes/filewatch.rs
index e96f44626..acedb7971 100644
--- a/src/agentsight/src/probes/filewatch.rs
+++ b/src/agentsight/src/probes/filewatch.rs
@@ -15,6 +15,7 @@ use std::{
};
// ─── Generated skeleton ───────────────────────────────────────────────────────
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/filewatch.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/filewatch.rs"));
diff --git a/src/agentsight/src/probes/filewrite.rs b/src/agentsight/src/probes/filewrite.rs
index 741abe524..e1dfefed1 100644
--- a/src/agentsight/src/probes/filewrite.rs
+++ b/src/agentsight/src/probes/filewrite.rs
@@ -15,6 +15,7 @@ use std::{
};
// ─── Generated skeleton ───────────────────────────────────────────────────────
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/filewrite.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/filewrite.rs"));
diff --git a/src/agentsight/src/probes/procmon.rs b/src/agentsight/src/probes/procmon.rs
index e84c0b5ff..c1ea16046 100644
--- a/src/agentsight/src/probes/procmon.rs
+++ b/src/agentsight/src/probes/procmon.rs
@@ -15,6 +15,7 @@ use std::{
};
// ─── Generated skeleton ───────────────────────────────────────────────────────
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/procmon.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/procmon.rs"));
diff --git a/src/agentsight/src/probes/proctrace.rs b/src/agentsight/src/probes/proctrace.rs
index 3f5d8d121..e4aca139f 100644
--- a/src/agentsight/src/probes/proctrace.rs
+++ b/src/agentsight/src/probes/proctrace.rs
@@ -11,7 +11,7 @@ use libbpf_rs::{
};
use std::{
mem::MaybeUninit,
- os::fd::{AsFd, AsRawFd},
+ os::fd::AsFd,
sync::{
Arc,
atomic::{AtomicBool, Ordering},
@@ -21,6 +21,7 @@ use std::{
};
// ─── Generated skeleton ───────────────────────────────────────────────────────
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/proctrace.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/proctrace.rs"));
diff --git a/src/agentsight/src/probes/sslsniff.rs b/src/agentsight/src/probes/sslsniff.rs
index 0b5a0d599..b8bff9c0a 100644
--- a/src/agentsight/src/probes/sslsniff.rs
+++ b/src/agentsight/src/probes/sslsniff.rs
@@ -5,7 +5,7 @@
// Exposes a `SslSniff` struct with a builder-style API.
use crate::config;
-use anyhow::{Context, Result, bail};
+use anyhow::{Context, Result};
use libbpf_rs::{
Link, MapHandle, RingBufferBuilder, UprobeOpts,
skel::{OpenSkel, SkelBuilder},
@@ -15,7 +15,6 @@ use procfs::process::Process;
use std::{
collections::{HashMap, HashSet},
fs,
- io::Write,
mem::{self, MaybeUninit},
path::Path,
slice,
@@ -28,6 +27,7 @@ use std::{
};
// ─── Generated skeleton ───────────────────────────────────────────────────────
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
pub mod bpf {
include!(concat!(env!("OUT_DIR"), "/sslsniff.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/sslsniff.rs"));
@@ -684,16 +684,6 @@ fn ssl_libs_from_maps(pid: i32) -> Result> {
Ok(results)
}
-/// Convert a null-terminated byte array (from C `char comm[TASK_COMM_LEN]`) to a `String`.
-fn comm_to_string(comm: &[u8]) -> String {
- let bytes: Vec = comm
- .iter()
- .copied()
- .take_while(|&b| b != 0)
- .collect();
- String::from_utf8_lossy(&bytes).into_owned()
-}
-
// ─── uprobe helpers ───────────────────────────────────────────────────────────
fn make_sym_opts(sym: &str, retprobe: bool) -> UprobeOpts {
diff --git a/src/agentsight/src/probes/tcpsniff.rs b/src/agentsight/src/probes/tcpsniff.rs
index 3f72422a7..5650f7d89 100644
--- a/src/agentsight/src/probes/tcpsniff.rs
+++ b/src/agentsight/src/probes/tcpsniff.rs
@@ -26,6 +26,7 @@ use std::{
};
// --- Generated skeleton ---
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/tcpsniff.skel.rs"));
}
diff --git a/src/agentsight/src/probes/udpdns.rs b/src/agentsight/src/probes/udpdns.rs
index d522b5b0d..f0bb9e7cb 100644
--- a/src/agentsight/src/probes/udpdns.rs
+++ b/src/agentsight/src/probes/udpdns.rs
@@ -19,6 +19,7 @@ use std::{
};
// --- Generated skeleton ---
+#[allow(non_camel_case_types, non_upper_case_globals, dead_code, non_snake_case)]
mod bpf {
include!(concat!(env!("OUT_DIR"), "/udpdns.skel.rs"));
include!(concat!(env!("OUT_DIR"), "/udpdns.rs"));
diff --git a/src/agentsight/src/server/handlers.rs b/src/agentsight/src/server/handlers.rs
index 75247d452..002ab2c60 100644
--- a/src/agentsight/src/server/handlers.rs
+++ b/src/agentsight/src/server/handlers.rs
@@ -1,12 +1,12 @@
//! API request handlers
-use actix_web::{delete, get, post, web, HttpResponse, Responder};
+use actix_web::{get, post, web, HttpResponse, Responder};
use serde::{Deserialize, Serialize};
use super::AppState;
use crate::health::AgentHealthStatus;
use crate::storage::sqlite::{GenAISqliteStore};
-use crate::storage::sqlite::genai::{TimeseriesBucket, ModelTimeseriesBucket, ToolCallTurnInfo};
+use crate::storage::sqlite::genai::{TimeseriesBucket, ModelTimeseriesBucket};
use crate::storage::sqlite::tokenless::{self, TokenlessStatsStore};
// ─── Prometheus helpers ───────────────────────────────────────────────────────
diff --git a/src/agentsight/src/storage/sqlite/http.rs b/src/agentsight/src/storage/sqlite/http.rs
index d14a25a8f..da3349513 100644
--- a/src/agentsight/src/storage/sqlite/http.rs
+++ b/src/agentsight/src/storage/sqlite/http.rs
@@ -2,7 +2,7 @@
//!
//! Handles table creation, record insertion, and querying for HTTP request/response records.
-use anyhow::{Context, Result};
+use anyhow::Result;
use rusqlite::{params, Connection};
use std::path::Path;
diff --git a/src/agentsight/src/storage/sqlite/interruption.rs b/src/agentsight/src/storage/sqlite/interruption.rs
index 246da97f3..3abf680eb 100644
--- a/src/agentsight/src/storage/sqlite/interruption.rs
+++ b/src/agentsight/src/storage/sqlite/interruption.rs
@@ -3,7 +3,7 @@
use rusqlite::{params, Connection};
use std::sync::Mutex;
-use crate::interruption::{InterruptionEvent, InterruptionType, Severity};
+use crate::interruption::{InterruptionEvent, InterruptionType};
use super::connection::create_connection;
// ─── API response types ────────────────────────────────────────────────────────
diff --git a/src/agentsight/src/storage/sqlite/token_consumption.rs b/src/agentsight/src/storage/sqlite/token_consumption.rs
index 8e49811cb..a78abffc4 100644
--- a/src/agentsight/src/storage/sqlite/token_consumption.rs
+++ b/src/agentsight/src/storage/sqlite/token_consumption.rs
@@ -213,7 +213,6 @@ impl TokenConsumptionStore {
}
if filter.model.is_some() {
conditions.push(format!("model = ?{}", bind_idx));
- bind_idx += 1;
}
let where_clause = if conditions.is_empty() {
diff --git a/src/agentsight/src/tokenizer/llm_tok.rs b/src/agentsight/src/tokenizer/llm_tok.rs
index 206f59f7b..f20f3fc0e 100644
--- a/src/agentsight/src/tokenizer/llm_tok.rs
+++ b/src/agentsight/src/tokenizer/llm_tok.rs
@@ -9,7 +9,6 @@ use serde_json::Value;
use std::path::Path;
use std::sync::Arc;
-use crate::analyzer::{MessageRole, OpenAIChatMessage};
use llm_tokenizer::{Decoder as _, Encoder as _, HuggingFaceTokenizer, TokenizerTrait, chat_template::ChatTemplateParams};
/// Unified tokenizer + chat template adapter wrapping `llm-tokenizer` crate.
@@ -63,16 +62,6 @@ impl LlmTokenizer {
})
}
- /// Create a tokenizer from a URL (backward compatibility).
- ///
- /// This is deprecated in favor of `from_hf` which uses HuggingFace Hub directly.
- /// For URLs pointing to HuggingFace (e.g., huggingface.co/...), consider using
- /// `from_hf` with the model ID instead.
- #[deprecated]
- pub fn from_url(url: &str, model_name: &str) -> Result {
- todo!()
- }
-
/// Encode text with special tokens.
pub fn encode_with_special_tokens(&self, text: &str) -> Result> {
let encoding = self.inner.encode(text, true)
@@ -111,11 +100,6 @@ impl LlmTokenizer {
.map_err(|e| anyhow!("Failed to apply chat template: {}", e))
}
- /// Convert OpenAIChatMessage to serde_json::Value for template rendering.
- pub fn messages_to_json(messages: &[OpenAIChatMessage]) -> Vec {
- todo!()
- }
-
/// Count tokens in text
pub fn count(&self, text: &str) -> Result {
let encoding = self.inner.encode(text, false)
diff --git a/src/agentsight/src/tokenizer/multi_model.rs b/src/agentsight/src/tokenizer/multi_model.rs
index 02d2e3769..779da7462 100644
--- a/src/agentsight/src/tokenizer/multi_model.rs
+++ b/src/agentsight/src/tokenizer/multi_model.rs
@@ -10,7 +10,6 @@ use anyhow::{Result, anyhow};
use hf_hub::api::sync::{Api, ApiBuilder};
use once_cell::sync::OnceCell;
use std::collections::HashMap;
-use std::path::PathBuf;
use std::sync::{Arc, Mutex, MutexGuard};
static GLOBAL_TOKENIZER: OnceCell> = OnceCell::new();
diff --git a/src/agentsight/src/unified.rs b/src/agentsight/src/unified.rs
index f1b612ab1..50b3a8ed9 100644
--- a/src/agentsight/src/unified.rs
+++ b/src/agentsight/src/unified.rs
@@ -738,7 +738,9 @@ impl AgentSight {
/// Install an FFI event sender for C API mode.
/// When set, completed events are pushed through this channel.
- pub fn set_ffi_sender(&mut self, sender: FfiEventSender) {
+ /// `pub(crate)` because `FfiEventSender` is a crate-internal type and the
+ /// only caller lives in this crate's FFI layer.
+ pub(crate) fn set_ffi_sender(&mut self, sender: FfiEventSender) {
self.ffi_sender = Some(sender);
}
@@ -831,7 +833,7 @@ impl AgentSight {
for (conn_id, state) in drained {
// Destructure to capture both request AND sse_events
- let (state_name, request, sse_events) = match state {
+ let (_state_name, request, sse_events) = match state {
ConnectionState::RequestPending { request } => ("RequestPending", request, vec![]),
ConnectionState::SseActive {
request: Some(req),