magi-code 0.104.0

Repository-aware CLI coding agent for terminal work
Documentation
use crate::providers::error::{ProviderError, ToolArgumentWhitespaceRunaway};

const MAX_JSON_WHITESPACE_RUN_BYTES: usize = 4 * 1024;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub(in crate::providers) struct ToolArgumentWhitespaceState {
    in_string: bool,
    escaped: bool,
    whitespace_run: usize,
}

impl ToolArgumentWhitespaceState {
    pub(in crate::providers) fn observe(
        &mut self,
        delta: &str,
        previous_bytes: usize,
        tool_name: Option<&str>,
    ) -> anyhow::Result<bool> {
        let mut semantic_progress = false;
        for (offset, byte) in delta.bytes().enumerate() {
            if self.in_string {
                semantic_progress = true;
                if self.escaped {
                    self.escaped = false;
                } else if byte == b'\\' {
                    self.escaped = true;
                } else if byte == b'"' {
                    self.in_string = false;
                }
            } else if matches!(byte, b' ' | b'\t' | b'\n' | b'\r') {
                self.whitespace_run += 1;
                if self.whitespace_run > MAX_JSON_WHITESPACE_RUN_BYTES {
                    let runaway = ToolArgumentWhitespaceRunaway {
                        tool_name: crate::output::redact_sensitive_text(
                            tool_name.unwrap_or("unknown"),
                        )
                        .chars()
                        .take(256)
                        .collect(),
                        argument_bytes: previous_bytes + offset + 1,
                        whitespace_run_bytes: self.whitespace_run,
                    };
                    return Err(anyhow::Error::new(runaway).context(
                        ProviderError::stream_terminal(
                            "provider tool call arguments degenerated into whitespace",
                        ),
                    ));
                }
            } else {
                self.whitespace_run = 0;
                self.in_string = byte == b'"';
                semantic_progress = true;
            }
        }
        Ok(semantic_progress)
    }
}