merge: integrate origin/master (v0.5.50) into gitea/new_feature
- Resolve conflicts in chatCore handlers: keep apiKey/streamErrorPatterns from the details-filters feature, adopt origin's stripContinuityFields, customToolNames, cache-inclusive usage accounting, and Responses-API SSE→JSON conversion - Adopt origin's provider usage handlers (codebuddy-intl, qoder creds) and modality detection (audio/video inputs) - Keep requestDetails apiKey column (schema v2) + masked key persistence Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
@@ -20,9 +20,7 @@ describe("Codex CLI Responses → OpenAI", () => {
|
||||
expect(asst?.tool_calls?.length ?? 0, "empty tool_calls[] produced").toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
// openai-responses.js:109-110 — arguments passed through without ensuring string type
|
||||
// KNOWN BUG
|
||||
it.fails("function_call arguments end up as a string", () => {
|
||||
it("function_call arguments end up as a string", () => {
|
||||
const out = R2O({
|
||||
input: [{ type: "function_call", call_id: "c1", name: "f", arguments: { a: 1 } }],
|
||||
});
|
||||
|
||||
@@ -67,6 +67,27 @@ describe("OpenAI → Claude context mapping", () => {
|
||||
expect(JSON.stringify(out), "remote image dropped").toContain("pic.png");
|
||||
});
|
||||
|
||||
// claude.js hasValidContent() — a user message whose content is only an
|
||||
// image (no text block) was filtered out by prepareClaudeRequest's
|
||||
// "drop empty messages" pass, so an image-only turn (e.g. a vision
|
||||
// describe request with no accompanying prompt text in the user message)
|
||||
// produced an empty `messages` array and Anthropic rejected the request
|
||||
// with "messages: at least one message is required".
|
||||
it("user message with only an image is not dropped as empty", () => {
|
||||
const out = T({
|
||||
messages: [
|
||||
{ role: "system", content: "Describe the image." },
|
||||
{ role: "user", content: [
|
||||
{ type: "image_url", image_url: { url: "data:image/png;base64,AAAA" } },
|
||||
] },
|
||||
],
|
||||
});
|
||||
expect(out.messages.length, "image-only user message was dropped").toBeGreaterThan(0);
|
||||
expect(out.messages[0].content).toEqual(
|
||||
expect.arrayContaining([expect.objectContaining({ type: "image" })])
|
||||
);
|
||||
});
|
||||
|
||||
// prepareClaudeRequest reconciles max_tokens vs thinking.budget_tokens.
|
||||
// applyThinking runs after adjustMaxTokens caps max_tokens, so a claude-budget
|
||||
// model at "max" effort (budget 128000) can exceed the clamped max_tokens and
|
||||
|
||||
@@ -18,7 +18,7 @@ const SPECIAL_CRED = {
|
||||
// Chúng được lock riêng ở 11-provider edge tests / unit test chuyên biệt.
|
||||
const SPECIALIZED = new Set([
|
||||
"antigravity", "azure", "gemini-cli", "github", "iflow", "qoder", "kiro",
|
||||
"codex", "cursor", "vertex", "vertex-partner", "qwen", "opencode",
|
||||
"codex", "cursor", "vertex", "vertex-partner", "opencode",
|
||||
"opencode-go", "grok-web", "perplexity-web", "ollama-local", "commandcode",
|
||||
"xiaomi-tokenplan", "mimo-free",
|
||||
]);
|
||||
|
||||
@@ -18,6 +18,12 @@ describe("parseSuffix", () => {
|
||||
it("parses level suffix", () => {
|
||||
expect(parseSuffix("gpt-5(high)")).toEqual({ cleanModel: "gpt-5", override: { mode: "level", level: "high" } });
|
||||
});
|
||||
it("parses ultra suffix", () => {
|
||||
expect(parseSuffix("gpt-5.6-sol(ultra)")).toEqual({
|
||||
cleanModel: "gpt-5.6-sol",
|
||||
override: { mode: "level", level: "ultra" },
|
||||
});
|
||||
});
|
||||
it("parses numeric budget suffix", () => {
|
||||
expect(parseSuffix("model(8192)")).toEqual({ cleanModel: "model", override: { mode: "budget", budget: 8192 } });
|
||||
});
|
||||
@@ -157,6 +163,25 @@ describe("applyThinking per provider format", () => {
|
||||
const out = apply("openai", "gpt-5.3-codex", { reasoning_effort: "xhigh" }, "codex");
|
||||
expect(out.reasoning_effort).toBe("xhigh");
|
||||
});
|
||||
it.each([
|
||||
["gpt-5.6-sol", "max", "max"],
|
||||
["gpt-5.6-sol", "ultra", "ultra"],
|
||||
["gpt-5.6-terra", "max", "max"],
|
||||
["gpt-5.6-terra", "ultra", "ultra"],
|
||||
["gpt-5.6-luna", "max", "max"],
|
||||
["gpt-5.6-luna", "ultra", "max"],
|
||||
])("normalizes Codex %s effort %s to %s", (model, effort, expected) => {
|
||||
const out = apply("openai-responses", model, { reasoning: { effort } }, "codex");
|
||||
expect(out.reasoning_effort).toBe(expected);
|
||||
});
|
||||
it("applies a supported Codex Ultra suffix", () => {
|
||||
const out = apply("openai-responses", "gpt-5.6-sol(ultra)", {}, "codex");
|
||||
expect(out.reasoning_effort).toBe("ultra");
|
||||
});
|
||||
it("keeps Codex-only GPT-5.6 levels out of Kiro translation", () => {
|
||||
const out = apply("openai", "gpt-5.6-sol", { reasoning_effort: "max" }, "kiro");
|
||||
expect(out.reasoning_effort).toBe("xhigh");
|
||||
});
|
||||
});
|
||||
|
||||
describe("extractReasoningText (response shapes)", () => {
|
||||
|
||||
Reference in New Issue
Block a user