Refactor session ID handling and improve error management
- Introduced `SessionId` newtype for validated session identifiers, ensuring safety against path traversal attacks. - Updated session repository methods to accept `SessionId` instead of raw strings, enhancing type safety. - Removed redundant error handling in repository methods by leveraging the new `Error` type from `zesdex_utils`. - Simplified atomic JSON write operations by eliminating unnecessary error conversions. - Enhanced integer casting with a new `CastOr` trait for safer narrowing conversions. - Removed deprecated error handling code and consolidated error types across the codebase. - Updated HTTP handlers to utilize the new session ID validation, improving overall robustness.
This commit is contained in:
@@ -84,7 +84,9 @@ pub fn bash_kill(id: &str) -> anyhow::Result<()> {
|
||||
// SAFETY: job.child_pid is the real PID of the spawned child;
|
||||
// SIGTERM is safe and the process may already be dead.
|
||||
unsafe {
|
||||
let pid_signed: i32 = job.child_pid.try_into().unwrap_or(0);
|
||||
// SAFETY: Linux PID fits in i32 (pid_max ≤ 2^22 by default).
|
||||
let pid_signed: i32 = job.child_pid.try_into()
|
||||
.expect("child_pid exceeds i32 range — kernel pid_max > 2^31");
|
||||
libc::kill(pid_signed, libc::SIGTERM);
|
||||
}
|
||||
debug!(%id, pid = job.child_pid, "bash_kill: SIGTERM sent");
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn generation_params(level: usize, base_max_tokens: Option<u32>) -> (f32, Op
|
||||
};
|
||||
scaled.max(256)
|
||||
});
|
||||
(temperature, max_tokens.map(|t| t.max(256)))
|
||||
(temperature, max_tokens)
|
||||
}
|
||||
|
||||
/// Return the current effort level index, clamped to a valid `EFFORT_LEVELS` slot.
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::app::state::rest::AppStateRest;
|
||||
use sha2::Digest;
|
||||
use tracing::{debug, info};
|
||||
use zesdex_cms::domain::repository::EditLogRepository;
|
||||
use zesdex_utils::CastOr;
|
||||
|
||||
/// Returns the number of stored pre-edit blobs (snapshots) for this session.
|
||||
///
|
||||
@@ -108,7 +109,7 @@ pub fn rewind_to(state: &mut AppStateRest, index: usize) {
|
||||
path: restore_path.to_string_lossy().to_string(),
|
||||
reason: format!("rewind_to({index})"),
|
||||
content_sha256: hex::encode(sha2::Sha256::digest(&bytes)),
|
||||
bytes_delta: i64::try_from(bytes.len()).unwrap_or(0),
|
||||
bytes_delta: bytes.len().cast_or(0i64),
|
||||
origin: crate::app::state::types::Origin::Main.tag(),
|
||||
session_id: state.session_id.clone(),
|
||||
};
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
//! Build/test probing: running a verification command and capturing its
|
||||
//! pass/fail/timeout outcome for the review subagent.
|
||||
|
||||
use std::convert::TryInto;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zesdex_utils::CastOr;
|
||||
use std::process::Command;
|
||||
|
||||
/// Outcome of running a build/test probe command against a workspace.
|
||||
@@ -59,7 +58,7 @@ pub fn probe_build_test(
|
||||
|
||||
let start = std::time::Instant::now();
|
||||
let timed_out = loop {
|
||||
let elapsed: u64 = start.elapsed().as_millis().try_into().unwrap_or(u64::MAX);
|
||||
let elapsed: u64 = start.elapsed().as_millis().cast_or(u64::MAX);
|
||||
if elapsed >= timeout_ms {
|
||||
let _ = child.kill();
|
||||
break true;
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
//! `execute_one_tool`, `build_memory_section`, and `archive_message`.
|
||||
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryFrom;
|
||||
use std::fmt::Write;
|
||||
use zesdex_utils::CastOr;
|
||||
|
||||
use crate::app::guard::Verdict;
|
||||
use crate::app::runtime::context::tokens::count_tokens;
|
||||
@@ -200,11 +200,11 @@ pub(super) fn run_agent_turn(
|
||||
Ok((reply, usage_opt)) => {
|
||||
let (mut tok_in, mut tok_out) = usage_opt.unwrap_or((0, 0));
|
||||
if tok_in == 0 {
|
||||
tok_in = u64::try_from((planner_prompt_chars / 4).max(1)).unwrap_or(1);
|
||||
tok_in = ((planner_prompt_chars / 4).max(1)).cast_or(1u64);
|
||||
}
|
||||
if tok_out == 0 {
|
||||
let response_chars = reply.content.as_deref().map_or(0, str::len);
|
||||
tok_out = u64::try_from((response_chars / 4).max(1)).unwrap_or(1);
|
||||
tok_out = ((response_chars / 4).max(1)).cast_or(1u64);
|
||||
}
|
||||
push_event(&events_q, TurnEvent::Usage {
|
||||
tokens_in: tok_in,
|
||||
@@ -478,11 +478,11 @@ pub(super) fn run_agent_turn(
|
||||
.filter_map(|m| m.content.as_deref())
|
||||
.map(count_tokens)
|
||||
.sum();
|
||||
tok_in = u64::try_from(total_tokens.max(1)).unwrap_or(1);
|
||||
tok_in = total_tokens.max(1).cast_or(1u64);
|
||||
}
|
||||
if tok_out == 0 {
|
||||
let response_chars = response.content.as_deref().map_or(0, str::len);
|
||||
tok_out = u64::try_from((response_chars / 4).max(1)).unwrap_or(1);
|
||||
tok_out = ((response_chars / 4).max(1)).cast_or(1u64);
|
||||
}
|
||||
push_event(&events_q, TurnEvent::Usage {
|
||||
tokens_in: tok_in,
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
//! `FAST_POLL_MS` (8 ms) or `SLOW_POLL_MS` (100 ms). `is_idle()` reports
|
||||
//! whether the deadline has expired.
|
||||
use std::collections::VecDeque;
|
||||
use std::convert::TryInto;
|
||||
use std::time::{Duration, Instant};
|
||||
use zesdex_utils::CastOr;
|
||||
|
||||
use crate::app::state::runtime::TurnEvent;
|
||||
use tracing;
|
||||
@@ -62,7 +62,7 @@ impl EventLoop {
|
||||
|
||||
/// Return `true` if the app has been idle for more than `IDLE_THRESHOLD_MS`.
|
||||
pub fn is_idle(&self) -> bool {
|
||||
let elapsed: u64 = self.last_activity.elapsed().as_millis().try_into().unwrap_or(u64::MAX);
|
||||
let elapsed: u64 = self.last_activity.elapsed().as_millis().cast_or(u64::MAX);
|
||||
elapsed > IDLE_THRESHOLD_MS
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
//! These types are used across multiple sub-modules in `state/` and are
|
||||
//! also consumed by the view layer, tool harness, and IPC transport.
|
||||
use serde::{Deserialize, Serialize};
|
||||
use zesdex_utils::CastOr;
|
||||
|
||||
/// Severity/category of a toast notification, used to pick its color.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -48,7 +49,7 @@ impl Toast {
|
||||
|
||||
/// Whether this toast's lifetime has elapsed as of `now_ms`.
|
||||
pub fn expired(&self, now_ms: i64) -> bool {
|
||||
let lifetime = i64::try_from(self.lifetime_ms).unwrap_or(i64::MAX);
|
||||
let lifetime = self.lifetime_ms.cast_or(i64::MAX);
|
||||
let expired = now_ms - self.created_at > lifetime;
|
||||
if expired {
|
||||
tracing::debug!("Toast::expired — toast aged {}ms expired (lifetime={}ms)", now_ms - self.created_at, self.lifetime_ms);
|
||||
|
||||
@@ -19,8 +19,8 @@
|
||||
//! async event loop is not blocked. All I/O inside tool calls is
|
||||
//! synchronous (`ureq`, `std::fs`, etc.).
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use super::context::SubagentContext;
|
||||
use zesdex_utils::CastOr;
|
||||
use super::event::SubagentEvent;
|
||||
use super::gating::gate_subagent_tool_call;
|
||||
use super::provider::{require_api_key, resolve_provider_config};
|
||||
@@ -305,11 +305,11 @@ pub fn run_subagent(
|
||||
.filter_map(|m| m.content.as_deref())
|
||||
.map(str::len)
|
||||
.sum();
|
||||
tok_in = u64::try_from((prompt_chars / 4).max(1)).unwrap_or(1);
|
||||
tok_in = ((prompt_chars / 4).max(1)).cast_or(1u64);
|
||||
}
|
||||
if tok_out == 0 {
|
||||
let response_chars = response.content.as_deref().map_or(0, str::len);
|
||||
tok_out = u64::try_from((response_chars / 4).max(1)).unwrap_or(1);
|
||||
tok_out = ((response_chars / 4).max(1)).cast_or(1u64);
|
||||
}
|
||||
let _ = tx.blocking_send(SubagentEvent::Usage {
|
||||
tokens_in: tok_in,
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
//! Three use cases (subagent, provider, workflow) all share the same formula
|
||||
//! with different caps. This module provides a single implementation.
|
||||
|
||||
use std::convert::TryInto;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
use zesdex_utils::CastOr;
|
||||
|
||||
/// Compute an exponential backoff with ±25% jitter.
|
||||
///
|
||||
@@ -31,6 +31,6 @@ fn jitter_ns(range_ns: u64) -> u64 {
|
||||
let dur = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap_or_default();
|
||||
let nanos: u64 = dur.as_nanos().try_into().unwrap_or(u64::MAX);
|
||||
let nanos: u64 = dur.as_nanos().cast_or(u64::MAX);
|
||||
nanos % range_ns
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user