mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 14:54:46 +00:00
test(agents): surface live OpenAI replay auth failures
This commit is contained in:
@@ -545,6 +545,34 @@ async function completeSimpleWithTimeout<TApi extends Api>(
|
||||
}
|
||||
}
|
||||
|
||||
function requireToolChoicePayload(payload: unknown): unknown | undefined {
|
||||
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
|
||||
return undefined;
|
||||
}
|
||||
const candidate = payload as { tools?: unknown; tool_choice?: unknown };
|
||||
if (!Array.isArray(candidate.tools) || candidate.tools.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
...candidate,
|
||||
tool_choice: { type: "function", name: "noop" },
|
||||
};
|
||||
}
|
||||
|
||||
describe("requireToolChoicePayload", () => {
|
||||
it("requires tool use when a Responses payload has tools", () => {
|
||||
expect(requireToolChoicePayload({ model: "gpt", tools: [{ name: "noop" }] })).toEqual({
|
||||
model: "gpt",
|
||||
tools: [{ name: "noop" }],
|
||||
tool_choice: { type: "function", name: "noop" },
|
||||
});
|
||||
});
|
||||
|
||||
it("leaves payloads without tools unchanged", () => {
|
||||
expect(requireToolChoicePayload({ model: "gpt", tools: [] })).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
async function completeOkWithRetry(params: {
|
||||
model: Model<Api>;
|
||||
apiKey: string;
|
||||
@@ -982,6 +1010,7 @@ describeLive("live models (profile keys)", () => {
|
||||
apiKey,
|
||||
reasoning: resolveTestReasoning(model),
|
||||
maxTokens: 128,
|
||||
onPayload: requireToolChoicePayload,
|
||||
},
|
||||
perModelTimeoutMs,
|
||||
`${progressLabel}: tool-only regression first call`,
|
||||
@@ -1012,6 +1041,7 @@ describeLive("live models (profile keys)", () => {
|
||||
apiKey,
|
||||
reasoning: resolveTestReasoning(model),
|
||||
maxTokens: 128,
|
||||
onPayload: requireToolChoicePayload,
|
||||
},
|
||||
perModelTimeoutMs,
|
||||
`${progressLabel}: tool-only regression retry ${i + 1}`,
|
||||
@@ -1025,6 +1055,11 @@ describeLive("live models (profile keys)", () => {
|
||||
.trim();
|
||||
}
|
||||
|
||||
if (first.stopReason === "error") {
|
||||
throw new Error(
|
||||
first.errorMessage || "tool-only regression returned error with no message",
|
||||
);
|
||||
}
|
||||
expect(firstText.length).toBe(0);
|
||||
if (!toolCall || toolCall.type !== "toolCall") {
|
||||
throw new Error("expected tool call");
|
||||
|
||||
@@ -2314,6 +2314,37 @@ describe("openai transport stream", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("passes explicit Responses tool_choice when tools are present", () => {
|
||||
const params = buildOpenAIResponsesParams(
|
||||
{
|
||||
id: "gpt-5.4",
|
||||
name: "GPT-5.4",
|
||||
api: "openai-responses",
|
||||
provider: "openai",
|
||||
baseUrl: "https://api.openai.com/v1",
|
||||
reasoning: true,
|
||||
input: ["text"],
|
||||
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
||||
contextWindow: 200000,
|
||||
maxTokens: 8192,
|
||||
} satisfies Model<"openai-responses">,
|
||||
{
|
||||
systemPrompt: "system",
|
||||
messages: [],
|
||||
tools: [
|
||||
{
|
||||
name: "lookup_weather",
|
||||
description: "Get forecast",
|
||||
parameters: { type: "object", properties: {}, additionalProperties: false },
|
||||
},
|
||||
],
|
||||
} as never,
|
||||
{ toolChoice: "required" } as never,
|
||||
) as { tool_choice?: string };
|
||||
|
||||
expect(params.tool_choice).toBe("required");
|
||||
});
|
||||
|
||||
it("falls back to strict:false when a native OpenAI tool schema is not strict-compatible", () => {
|
||||
const params = buildOpenAIResponsesParams(
|
||||
{
|
||||
|
||||
@@ -94,6 +94,7 @@ type OpenAIResponsesOptions = BaseStreamOptions & {
|
||||
reasoningEffort?: OpenAIReasoningEffort;
|
||||
reasoningSummary?: "auto" | "detailed" | "concise" | null;
|
||||
serviceTier?: ResponseCreateParamsStreaming["service_tier"];
|
||||
toolChoice?: ResponseCreateParamsStreaming["tool_choice"];
|
||||
};
|
||||
|
||||
type OpenAICompletionsOptions = BaseStreamOptions & {
|
||||
@@ -1364,6 +1365,9 @@ export function buildOpenAIResponsesParams(
|
||||
transport: "stream",
|
||||
}),
|
||||
});
|
||||
if (options?.toolChoice) {
|
||||
params.tool_choice = options.toolChoice;
|
||||
}
|
||||
}
|
||||
if (model.reasoning) {
|
||||
if (options?.reasoningEffort || options?.reasoning || options?.reasoningSummary) {
|
||||
@@ -2188,6 +2192,7 @@ type OpenAIResponsesRequestParams = {
|
||||
top_p?: number;
|
||||
service_tier?: ResponseCreateParamsStreaming["service_tier"];
|
||||
tools?: FunctionTool[];
|
||||
tool_choice?: ResponseCreateParamsStreaming["tool_choice"];
|
||||
reasoning?:
|
||||
| { effort: OpenAIApiReasoningEffort }
|
||||
| {
|
||||
|
||||
Reference in New Issue
Block a user