Noir-Tor — Autonomous ReAct Intelligence Agent
Github Repository1. Project Overview & Architectural Goals
Crawling, indexing, and auditing the Tor network presents specific challenges: network instability, high latency, anti-bot mechanisms, and privacy requirements. **Noir-Tor** is an autonomous intelligence gathering system powered by a Reasoning + Action (ReAct) engine that automates multi-engine searches and deep web content retrieval through a secure, encrypted tunnel.
// CORE OBJECTIVE
"Implement a decoupled, modular AI agent capable of routing requests through SOCKS5h Tor proxies, parsing search engines (Torch, Ahmia, Phobos, TorDex, DuckDuckGo), and crawling onion pages without leaking identity, wasting tokens, or violating chat history protocols."
2. Technical Architecture & Component Design
Noir-Tor enforces strict Separation of Concerns (SOLID) and Dependency Injection (DI) to separate the reasoning engine from the underlying network layer, tools, and user interface.
SOCKS5h Network Layer
socks-proxy-agent client mapping to a local Tor SOCKS5h port (9150/9050). The 'h' extension is critical: it forces DNS resolution to occur remotely on the exit node, preventing local DNS leaks that would instantly compromise operational security. Decoupled Tool Matrix
torFetch network client via Constructor Injection, making it testable and mockable without active Tor daemon bindings. 3. ReAct Bounding & Parsing Optimization
Autonomous agents can fail due to parsing friction when LLMs output unexpected formatting. During testing, models like DeepSeek or Llama frequently wrapped ReAct keys in markdown bold tags (e.g. **Action:** instead of Action:). We implemented robust regex patterns to handle formatting variations seamlessly:
const finalAnswerRegex = /(?:\*?\*?Final\s+Answer\*?\*?\s*:?\s*\*?\*?)/i;
4. The Token-Efficiency & Context Retention Bug
An architectural issue was identified where the agent consumed up to 1.4 million tokens per hour. The root cause was diagnosed as **context loss** inside the ReAct execution loop:
Diagnosed Bug / Bug Diagnosticado
The agent previously replaced messages in the LLM call with a history that omitted the user's initial query and discarded previous tool outputs. Additionally, it appended consecutive assistant messages without alternating role structures. This forced the agent to lose its objectives, causing it to loop aimlessly until reaching the maximum iteration limit (6 times per prompt), bloating token usage.
The Mitigation: We refactored the execution loop to preserve the user's query and maintain a strict chronological alternation of roles (user for query/observations, assistant for thoughts/actions). This allowed the agent to leverage the system's *Efficiency Rule* and stop early, reducing the loop from 6 iterations to just 2 or 3.
// On loop tool execution:
history.push({ role: 'assistant', content: llmOutput });
history.push({ role: 'user', content: \`Observation: \${observation}\` });