MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / run_tool_loop

Function run_tool_loop

atomic-repository/src/ai/tools.rs:531–669  ·  view source on GitHub ↗

Run the agentic tool-use loop. The LLM can invoke tools up to `config.max_turns` times before a final text response is forced.

(
    provider: &LlmProvider,
    executor: &dyn ToolExecutor,
    query: &str,
    config: &AgentConfig,
)

Source from the content-addressed store, hash-verified

529/// Run the agentic tool-use loop. The LLM can invoke tools up to
530/// `config.max_turns` times before a final text response is forced.
531pub async fn run_tool_loop(
532 provider: &LlmProvider,
533 executor: &dyn ToolExecutor,
534 query: &str,
535 config: &AgentConfig,
536) -> Result<AgentResult, AiError> {
537 let tool_defs = executor.tool_definitions();
538
539 let mut messages: Vec<ToolMessage> = Vec::new();
540 if !config.system_prompt.is_empty() {
541 messages.push(ToolMessage::System {
542 content: config.system_prompt.clone(),
543 });
544 }
545 messages.push(ToolMessage::User {
546 content: query.to_string(),
547 });
548
549 let mut total_usage = TokenUsage::default();
550 let mut tool_trace: Vec<ToolTraceEntry> = Vec::new();
551 let mut turn: u8 = 0;
552 let mut last_text = String::new(); // accumulate text across turns
553
554 loop {
555 turn += 1;
556 let at_limit = turn > config.max_turns;
557
558 // If we've exhausted turns, inject a prompt telling the LLM to
559 // answer now with what it has, rather than removing tools (which
560 // confuses the conversation flow after tool_use/tool_result pairs).
561 if at_limit {
562 messages.push(ToolMessage::User {
563 content: "You have used all available tool turns. Please provide your \
564 answer now based on what you have found so far. Be concise \
565 and cite file paths and line numbers."
566 .to_string(),
567 });
568 }
569 let tools_for_call = &tool_defs; // always provide tools
570 let tokens_for_call = if at_limit {
571 config.max_tokens.max(8192)
572 } else {
573 config.max_tokens
574 };
575
576 debug!(
577 "tool loop turn {turn}/{} (tools={})",
578 config.max_turns,
579 tools_for_call.len()
580 );
581
582 let resp = provider
583 .chat_with_tools(&messages, tools_for_call, tokens_for_call)
584 .await?;
585
586 total_usage.input_tokens += resp.usage.input_tokens;
587 total_usage.output_tokens += resp.usage.output_tokens;
588 total_usage.cache_read_tokens += resp.usage.cache_read_tokens;

Callers 1

run_tool_loop_syncFunction · 0.85

Calls 10

format_tool_as_commandFunction · 0.85
truncate_resultFunction · 0.85
previewFunction · 0.85
tool_definitionsMethod · 0.80
chat_with_toolsMethod · 0.80
is_emptyMethod · 0.45
pushMethod · 0.45
cloneMethod · 0.45
executeMethod · 0.45
countMethod · 0.45

Tested by

no test coverage detected