mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 00:35:27 +08:00
fix(coding-agent): remove explicit tool choice from compaction calls
Fixes #8649\n\nFixes #8638
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed OpenAI-compatible Chat Completions requests sending `tool_choice` without tools, which gateways can reject during compaction ([#8607](https://github.com/earendil-works/pi/issues/8607)).
|
||||
- Fixed OpenAI-compatible Chat Completions ignoring an explicitly requested `toolChoice` when no tools are defined.
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
||||
@@ -835,7 +835,7 @@ function buildParams(
|
||||
applyAnthropicCacheControl(messages, params.tools, cacheControl);
|
||||
}
|
||||
|
||||
if (options?.toolChoice && params.tools?.length) {
|
||||
if (options?.toolChoice) {
|
||||
params.tool_choice = options.toolChoice;
|
||||
}
|
||||
|
||||
|
||||
@@ -312,7 +312,7 @@ export interface AnthropicAllowedFallbackModel {
|
||||
|
||||
// Unified options with reasoning passed to streamSimple() and completeSimple()
|
||||
export interface SimpleStreamOptions extends StreamOptions {
|
||||
/** Provider-neutral tool selection for simple requests. Default: "auto". */
|
||||
/** Provider-neutral tool selection for simple requests. When omitted, adapters use provider-specific behavior. */
|
||||
toolChoice?: ToolChoice;
|
||||
reasoning?: ThinkingLevel;
|
||||
/** Ask a capable provider to return a durable handle and continue the request asynchronously. */
|
||||
|
||||
@@ -150,7 +150,7 @@ describe("openai-completions tool_choice", () => {
|
||||
expect(params.tools?.length ?? 0).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
it("omits toolChoice when no tools are provided", async () => {
|
||||
it("includes toolChoice when no tools are provided", async () => {
|
||||
const { compat: _compat, ...baseModel } = getModel("openai", "gpt-4o-mini")!;
|
||||
const model = { ...baseModel, api: "openai-completions" } as const;
|
||||
let payload: unknown;
|
||||
@@ -170,7 +170,7 @@ describe("openai-completions tool_choice", () => {
|
||||
).result();
|
||||
|
||||
const params = (payload ?? mockState.lastParams) as { tool_choice?: string; tools?: unknown[] };
|
||||
expect(params).not.toHaveProperty("tool_choice");
|
||||
expect(params.tool_choice).toBe("none");
|
||||
expect(params).not.toHaveProperty("tools");
|
||||
});
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
- Fixed Windows shell aborts crashing Pi when `taskkill.exe` is unavailable on `PATH` ([#6596](https://github.com/earendil-works/pi/issues/6596)).
|
||||
- Fixed extension messages sent with `triggerTurn: false` while the agent is running being inserted between a tool call and its result, which made providers that validate message order reject the replayed history. They are now appended once the turn's tool results are in ([#8537](https://github.com/earendil-works/pi/issues/8537)).
|
||||
- Fixed compaction and branch summaries forcing `toolChoice: "none"` ([#8649](https://github.com/earendil-works/pi/issues/8649), [#8638](https://github.com/earendil-works/pi/issues/8638)).
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
||||
@@ -590,7 +590,6 @@ export async function completeSummarization(
|
||||
...options,
|
||||
cacheRetention: "none",
|
||||
sessionId: options.sessionId ?? uuidv7(),
|
||||
toolChoice: "none",
|
||||
};
|
||||
const produce = async (): Promise<AssistantMessage> =>
|
||||
streamFn
|
||||
|
||||
@@ -44,7 +44,7 @@ function response(content: AssistantMessage["content"]): AssistantMessage {
|
||||
}
|
||||
|
||||
describe("branch summarization", () => {
|
||||
it("disables tools for branch summaries", async () => {
|
||||
it("does not override tool choice for branch summaries", async () => {
|
||||
let requestOptions: SimpleStreamOptions | undefined;
|
||||
const streamFn: StreamFn = (_model, _context, options) => {
|
||||
requestOptions = options;
|
||||
@@ -61,7 +61,7 @@ describe("branch summarization", () => {
|
||||
streamFn,
|
||||
});
|
||||
|
||||
expect(requestOptions?.toolChoice).toBe("none");
|
||||
expect(requestOptions?.toolChoice).toBeUndefined();
|
||||
});
|
||||
|
||||
it("rejects tool calls from branch summaries", async () => {
|
||||
|
||||
@@ -109,13 +109,12 @@ describe("generateSummary reasoning options", () => {
|
||||
const requestOptions = completeSimpleMock.mock.calls.map((call) => call[2]);
|
||||
expect(requestOptions).toHaveLength(2);
|
||||
expect(requestOptions.every((options) => options?.cacheRetention === "none")).toBe(true);
|
||||
expect(requestOptions.every((options) => options?.toolChoice === "none")).toBe(true);
|
||||
|
||||
const sessionIds = requestOptions.map((options) => options?.sessionId);
|
||||
expect(sessionIds[0]).not.toBe(sessionIds[1]);
|
||||
});
|
||||
|
||||
it("honors a caller-supplied routing session without prompt caching", async () => {
|
||||
it("honors caller-supplied routing session and tool choice without prompt caching", async () => {
|
||||
await completeSummarization(
|
||||
createModel(false),
|
||||
{ systemPrompt: "Summarize", messages: [] },
|
||||
@@ -125,7 +124,7 @@ describe("generateSummary reasoning options", () => {
|
||||
expect(completeSimpleMock.mock.calls[0][2]).toMatchObject({
|
||||
sessionId: "current-routing-session",
|
||||
cacheRetention: "none",
|
||||
toolChoice: "none",
|
||||
toolChoice: "auto",
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user