Limit `delegate` to one tool call per user turn.

afea5551fa79 · AtlantisPleb · · parent c06badb472e3

Limit `delegate` to one tool call per user turn.

The ATIF you exported showed 24 consecutive `delegate` calls for a single
"do a test delegation" message. `execute_turn` now sets `tool_choice: none`
for the follow-up request after the first `delegate` is processed, so the
model can only emit text afterward instead of calling `delegate` again and
again.

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By
Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified crates/coder-lite/src/runtime.rs

Diff

1 file changed, +10 -0

crates/coder-lite/src/runtime.rs modified +10

@@ -3,6 +3,7 @@

3 3
use futures::StreamExt;
4 4
use openresponses_rust::{
5 5
    CreateResponseBody, FunctionOutput, Input, Item, StreamingClient, StreamingEvent, Tool,
6
    ToolChoice, ToolChoiceParam,
6 7
};
7 8
use std::env;
8 9
use std::path::PathBuf;

@@ -61,12 +62,19 @@ impl CoderRuntimeSession {

61 62
62 63
        let client = StreamingClient::with_base_url(&self.api_key, &self.base_url);
63 64
        let tools = self.delegate_tool();
65
        let mut post_tool = false;
64 66
65 67
        loop {
68
            let tool_choice = if post_tool {
69
                Some(ToolChoiceParam::Simple(ToolChoice::None))
70
            } else {
71
                Some(ToolChoiceParam::Simple(ToolChoice::Auto))
72
            };
66 73
            let request = CreateResponseBody {
67 74
                model: env::var("OPENAGENTS_MODEL").ok(),
68 75
                input: Some(Input::Items(self.history.clone())),
69 76
                tools: tools.clone(),
77
                tool_choice,
70 78
                stream: Some(true),
71 79
                ..Default::default()
72 80
            };

@@ -194,6 +202,7 @@ impl CoderRuntimeSession {

194 202
                    if turn_failed {
195 203
                        break;
196 204
                    }
205
                    post_tool = true;
197 206
                    continue;
198 207
                } else {
199 208
                    let msg = format!("unknown ACP agent: {}", agent_id);

@@ -204,6 +213,7 @@ impl CoderRuntimeSession {

204 213
                        output: FunctionOutput::Text(msg),
205 214
                        status: None,
206 215
                    });
216
                    post_tool = true;
207 217
                    continue;
208 218
                }
209 219
            }

This page updates live while a promote is in flight · changelog