docs(code): add decision-point comments to agent loop, security policy, and reliable provider
Adds section markers and decision-point comments to the three most complex control-flow modules. Comments explain loop invariants, retry/fallback strategy, security policy precedence rules, and error handling rationale. This improves maintainability by making the reasoning behind complex branches explicit for reviewers and future contributors. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
bec1dc7b8c
commit
dd541bd7e4
3 changed files with 97 additions and 1 deletions
|
|
@ -590,6 +590,17 @@ fn parse_glm_style_tool_calls(text: &str) -> Vec<(String, serde_json::Value, Opt
|
|||
calls
|
||||
}
|
||||
|
||||
// ── Tool-Call Parsing ─────────────────────────────────────────────────────
|
||||
// LLM responses may contain tool calls in multiple formats depending on
|
||||
// the provider. Parsing follows a priority chain:
|
||||
// 1. OpenAI-style JSON with `tool_calls` array (native API)
|
||||
// 2. XML tags: <tool_call>, <toolcall>, <tool-call>, <invoke>
|
||||
// 3. Markdown code blocks with `tool_call` language
|
||||
// 4. GLM-style line-based format (e.g. `shell/command>ls`)
|
||||
// SECURITY: We never fall back to extracting arbitrary JSON from the
|
||||
// response body, because that would enable prompt-injection attacks where
|
||||
// malicious content in emails/files/web pages mimics a tool call.
|
||||
|
||||
/// Parse tool calls from an LLM response that uses XML-style function calling.
|
||||
///
|
||||
/// Expected format (common with system-prompt-guided tool use):
|
||||
|
|
@ -874,6 +885,18 @@ pub(crate) async fn agent_turn(
|
|||
.await
|
||||
}
|
||||
|
||||
// ── Agent Tool-Call Loop ──────────────────────────────────────────────────
|
||||
// Core agentic iteration: send conversation to the LLM, parse any tool
|
||||
// calls from the response, execute them, append results to history, and
|
||||
// repeat until the LLM produces a final text-only answer.
|
||||
//
|
||||
// Loop invariant: at the start of each iteration, `history` contains the
|
||||
// full conversation so far (system prompt + user messages + prior tool
|
||||
// results). The loop exits when:
|
||||
// • the LLM returns no tool calls (final answer), or
|
||||
// • max_iterations is reached (runaway safety), or
|
||||
// • the cancellation token fires (external abort).
|
||||
|
||||
/// Execute a single turn of the agent loop: send messages, parse tool calls,
|
||||
/// execute tools, and loop until the LLM produces a final text response.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
|
|
@ -972,6 +995,10 @@ pub(crate) async fn run_tool_call_loop(
|
|||
});
|
||||
|
||||
let response_text = resp.text_or_empty().to_string();
|
||||
// First try native structured tool calls (OpenAI-format).
|
||||
// Fall back to text-based parsing (XML tags, markdown blocks,
|
||||
// GLM format) only if the provider returned no native calls —
|
||||
// this ensures we support both native and prompt-guided models.
|
||||
let mut calls = parse_structured_tool_calls(&resp.tool_calls);
|
||||
let mut parsed_text = String::new();
|
||||
|
||||
|
|
@ -1190,6 +1217,12 @@ pub(crate) fn build_tool_instructions(tools_registry: &[Box<dyn Tool>]) -> Strin
|
|||
instructions
|
||||
}
|
||||
|
||||
// ── CLI Entrypoint ───────────────────────────────────────────────────────
|
||||
// Wires up all subsystems (observer, runtime, security, memory, tools,
|
||||
// provider, hardware RAG, peripherals) and enters either single-shot or
|
||||
// interactive REPL mode. The interactive loop manages history compaction
|
||||
// and hard trimming to keep the context window bounded.
|
||||
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub async fn run(
|
||||
config: Config,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue