auto analysis = p.ref("analysis");
auto preamble = p.rule("preamble", p.literal("<|channel|>commentary<|message|>") + p.content(content) + end);
auto final_msg = p.rule("final", p.literal("<|channel|>final<|message|>") + p.content(content));
+
+ // Consume any unsolicited tool calls, e.g. builtin functions
+ auto unsolicited = p.rule("unsolicited", p.atomic(p.optional(channel) + p.literal(" to=") + content + end));
+
auto any = p.rule("any", preamble | analysis);
if (has_response_format) {
return p.zero_or_more(start + any) + start + (tool_call | final_msg);
}
- return p.zero_or_more(start + any) + start + final_msg;
+ return p.zero_or_more(start + any) + start + (final_msg | unsolicited);
});
data.parser = parser.save();
.expect_reasoning("I need to output the invoice details in JSON")
.expect_content(R"({"amount": 123.45, "date": "2025-12-03"})")
.run();
+
+
+ // Unsolicited tool calls. There is no good way to handle these, so we return empty content.
+
+ // Builtin function - recipient in role
+ tst.test(
+ "<|channel|>analysis<|message|>I will execute python to say hello<|end|>"
+ "<|start|>assistant to=container.exec<|channel|>commentary<|message|>python3 -c 'print(\"hello\")'")
+ .reasoning_format(COMMON_REASONING_FORMAT_AUTO)
+ .expect_reasoning("I will execute python to say hello")
+ .expect_content("")
+ .run();
+
+ // Builtin function - recipient in channel
+ tst.test(
+ "<|channel|>analysis<|message|>I will execute python to say hello<|end|>"
+ "<|start|>assistant<|channel|>commentary to=python <|constrain|>code<|message|>print(\"hello\")")
+ .reasoning_format(COMMON_REASONING_FORMAT_AUTO)
+ .expect_reasoning("I will execute python to say hello")
+ .expect_content("")
+ .run();
}
{