mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-14 02:31:24 +00:00
This commit is contained in:
@@ -89,6 +89,7 @@ Docs: https://docs.openclaw.ai
|
||||
- iMessage (imsg): strip an accidental protobuf length-delimited UTF-8 field wrapper from inbound `text` and `reply_to_text` when it fully consumes the field, fixing leading garbage before the real message. (#63868) Thanks @neeravmakwana.
|
||||
- Gateway/pairing: fail closed for paired device records that have no device tokens, and reject pairing approvals whose requested scopes do not match the requested device roles.
|
||||
- ACP/gateway chat: classify lifecycle errors before forwarding them to ACP clients so refusals use ACP's refusal stop reason while transient backend errors continue to finish as normal turns.
|
||||
- Commands/btw: keep tool-less side questions from sending injected empty `tools` arrays on strict OpenAI-compatible providers, so `/btw` continues working after prior tool-call history. (#64219) Thanks @ngutman.
|
||||
|
||||
## 2026.4.9
|
||||
|
||||
|
||||
@@ -297,6 +297,21 @@ describe("runBtwSideQuestion", () => {
|
||||
expect(result).toEqual({ text: "Final answer." });
|
||||
});
|
||||
|
||||
it("strips injected empty tools arrays from BTW payloads before sending", async () => {
|
||||
mockDoneAnswer("Final answer.");
|
||||
|
||||
await runSideQuestion();
|
||||
|
||||
const [, , options] = streamSimpleMock.mock.calls[0] ?? [];
|
||||
const onPayload = (options as { onPayload?: (payload: unknown) => void })?.onPayload;
|
||||
const payloadWithEmptyTools = { messages: [], tools: [] as unknown[] };
|
||||
|
||||
const result = onPayload?.(payloadWithEmptyTools);
|
||||
|
||||
expect(payloadWithEmptyTools).not.toHaveProperty("tools");
|
||||
expect(result).toBeUndefined();
|
||||
});
|
||||
|
||||
it("forces provider reasoning off even when the session think level is adaptive", async () => {
|
||||
streamSimpleMock.mockImplementation((_model, _input, options?: { reasoning?: unknown }) => {
|
||||
return options?.reasoning === undefined
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ensureOpenClawModelsJson } from "./models-config.js";
|
||||
import { EmbeddedBlockChunker, type BlockReplyChunking } from "./pi-embedded-block-chunker.js";
|
||||
import { resolveModelWithRegistry } from "./pi-embedded-runner/model.js";
|
||||
import { getActiveEmbeddedRunSnapshot } from "./pi-embedded-runner/runs.js";
|
||||
import { streamWithPayloadPatch } from "./pi-embedded-runner/stream-payload-utils.js";
|
||||
import { discoverAuthStorage, discoverModels } from "./pi-model-discovery.js";
|
||||
import { stripToolResultDetails } from "./session-transcript-repair.js";
|
||||
|
||||
@@ -283,7 +284,8 @@ export async function runBtwSideQuestion(
|
||||
await blockEmitChain;
|
||||
};
|
||||
|
||||
const stream = streamSimple(
|
||||
const stream = await streamWithPayloadPatch(
|
||||
streamSimple,
|
||||
model,
|
||||
{
|
||||
systemPrompt: buildBtwSystemPrompt(),
|
||||
@@ -308,6 +310,13 @@ export async function runBtwSideQuestion(
|
||||
reasoning: undefined,
|
||||
signal: params.opts?.abortSignal,
|
||||
},
|
||||
(payloadObj) => {
|
||||
// BTW is intentionally tool-less. Some OpenAI-compatible providers reject
|
||||
// the empty tools arrays injected for generic tool-history replay.
|
||||
if (Array.isArray(payloadObj.tools) && payloadObj.tools.length === 0) {
|
||||
delete payloadObj.tools;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let finalEvent:
|
||||
|
||||
Reference in New Issue
Block a user