Skip to content

Commit e110c98

Browse files
committed
fix: complete CommandCode 1.3.1 contract alignment
1 parent 4a64fe5 commit e110c98

7 files changed

Lines changed: 153 additions & 10 deletions

File tree

src/commandcode.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,7 @@ export class CommandCodeClient implements CommandCodeUpstream {
433433
"x-project-slug": slugFromWorkingDir(body.config.workingDir),
434434
"x-taste-learning": "false",
435435
"x-co-flag": "false",
436-
"x-session-id": body.threadId,
436+
...(body.threadId ? { "x-session-id": body.threadId } : {}),
437437
},
438438
body: JSON.stringify(body),
439439
signal,

src/converter.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,10 @@ function formatDate(date: Date): string {
183183
return date.toISOString().slice(0, 10);
184184
}
185185

186+
function isUuid(value: string): boolean {
187+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
188+
}
189+
186190
export function buildCommandCodeGenerateBody(
187191
options: BuildCommandCodeBodyOptions,
188192
): CommandCodeGenerateBody {
@@ -203,6 +207,7 @@ export function buildCommandCodeGenerateBody(
203207
if (options.request.top_p !== undefined) params.top_p = options.request.top_p;
204208
if (options.request.stop !== undefined) params.stop = options.request.stop;
205209

210+
const threadId = options.threadId ?? randomUUID();
206211
return {
207212
config: {
208213
workingDir,
@@ -215,11 +220,11 @@ export function buildCommandCodeGenerateBody(
215220
gitStatus: "",
216221
recentCommits: [],
217222
},
218-
memory: "",
219-
taste: "",
220-
skills: "",
223+
memory: null,
224+
taste: null,
225+
skills: null,
221226
permissionMode: "standard",
222227
params,
223-
threadId: options.threadId ?? randomUUID(),
228+
...(isUuid(threadId) ? { threadId } : {}),
224229
};
225230
}

src/model-catalog.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,78 @@ export const COMMANDCODE_MODEL_DEFINITIONS: CommandCodeModelDefinition[] = [
407407
enabledByDefault: false,
408408
notes: "$3/M in · $10.25/M out",
409409
},
410+
{
411+
id: "xiaomi/mimo-v2.5-pro",
412+
label: "MiMo V2.5 Pro",
413+
provider: "Xiaomi",
414+
family: "mimo",
415+
aliases: ["mimo-v2.5-pro", "MiMo-V2.5-Pro"],
416+
enabledByDefault: false,
417+
notes: "$0.435/M in · $0.87/M out",
418+
},
419+
{
420+
id: "xiaomi/mimo-v2.5",
421+
label: "MiMo V2.5",
422+
provider: "Xiaomi",
423+
family: "mimo",
424+
aliases: ["mimo-v2.5", "MiMo-V2.5"],
425+
enabledByDefault: false,
426+
notes: "$0.14/M in · $0.28/M out",
427+
},
428+
{
429+
id: "nvidia/nemotron-3-ultra-550b-a55b",
430+
label: "Nemotron 3 Ultra",
431+
provider: "NVIDIA",
432+
family: "nemotron",
433+
aliases: ["nemotron-3-ultra-550b-a55b", "Nemotron-3-Ultra"],
434+
enabledByDefault: false,
435+
notes: "$0.60/M in · $2.40/M out",
436+
},
437+
{
438+
id: "thinkingmachines/inkling",
439+
label: "Inkling",
440+
provider: "Thinking Machines",
441+
family: "inkling",
442+
aliases: ["inkling"],
443+
enabledByDefault: false,
444+
notes: "$1/M in · $4.05/M out",
445+
},
446+
{
447+
id: "poolside/laguna-s-2.1-free",
448+
label: "Laguna S 2.1",
449+
provider: "Poolside",
450+
family: "laguna",
451+
aliases: ["laguna-s-2.1-free", "Laguna-S-2.1-Free"],
452+
enabledByDefault: false,
453+
notes: "$0/M in · $0/M out",
454+
},
455+
{
456+
id: "sakana/fugu-ultra",
457+
label: "Fugu Ultra",
458+
provider: "Sakana",
459+
family: "fugu",
460+
aliases: ["fugu-ultra", "Fugu-Ultra"],
461+
enabledByDefault: false,
462+
notes: "$5/M in · $30/M out",
463+
},
464+
{
465+
id: "meta/muse-spark-1.1",
466+
label: "Muse Spark 1.1",
467+
provider: "Meta",
468+
family: "muse",
469+
aliases: ["muse-spark-1.1", "Muse-Spark-1.1"],
470+
enabledByDefault: false,
471+
notes: "$1.25/M in · $4.25/M out",
472+
},
473+
{
474+
id: "xai/grok-4.5",
475+
label: "Grok 4.5",
476+
provider: "xAI",
477+
family: "grok",
478+
aliases: ["grok-4.5", "Grok-4.5"],
479+
enabledByDefault: false,
480+
notes: "$2/M in · $6/M out",
481+
},
410482
];
411483

412484
export function modelAliasMap(): Record<string, string> {

src/types.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ export interface CommandCodeMessage {
8787

8888
export interface CommandCodeGenerateBody {
8989
config: CommandCodeConfigContext;
90-
memory: string;
91-
taste: string;
90+
memory: string | null;
91+
taste: string | null;
9292
skills: string | null;
9393
permissionMode: "standard";
9494
params: {
@@ -102,7 +102,7 @@ export interface CommandCodeGenerateBody {
102102
stop?: string | string[];
103103
stream: true;
104104
};
105-
threadId: string;
105+
threadId?: string;
106106
}
107107

108108
export interface CommandCodeUsage {

tests/commandcode.test.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,8 @@ const generateBody: CommandCodeGenerateBody = {
6969
gitStatus: "",
7070
recentCommits: [],
7171
},
72-
memory: "",
73-
taste: "",
72+
memory: null,
73+
taste: null,
7474
skills: null,
7575
permissionMode: "standard",
7676
params: {
@@ -182,6 +182,11 @@ describe("CommandCode stream parsing", () => {
182182
expect(parseCommandCodeEventLine('{"type":"reasoning-end"}')).toEqual({
183183
type: "reasoning-end",
184184
});
185+
expect(
186+
parseCommandCodeEventLine(
187+
'data: {"type":"tool-call","toolCallId":"call_0","toolName":"read_file","input":{"path":"input.txt"}}',
188+
),
189+
).toMatchObject({ type: "tool-call", toolCallId: "call_0", input: { path: "input.txt" } });
185190
expect(
186191
parseCommandCodeEventLine(
187192
'data: {"type":"tool-call","toolCallId":"call_1","toolName":"read_file","args":{"path":"a.txt"}}',
@@ -203,6 +208,17 @@ describe("CommandCode stream parsing", () => {
203208
result: "ok",
204209
isError: false,
205210
});
211+
expect(
212+
parseCommandCodeEventLine(
213+
'data: {"type":"tool-result","toolCallId":"call_2","toolName":"read_file","output":"failed","isError":true,"providerExecuted":true}',
214+
),
215+
).toMatchObject({
216+
type: "tool-result",
217+
toolCallId: "call_2",
218+
output: "failed",
219+
isError: true,
220+
providerExecuted: true,
221+
});
206222
expect(parseCommandCodeEventLine('data: {"type":"error","error":"upstream failed"}')).toEqual({
207223
type: "error",
208224
error: "upstream failed",

tests/config.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,49 @@ describe("configuration and model aliases", () => {
7070
"gpt-5.6-terra",
7171
"tencent/hy3-paid",
7272
"zai-org/GLM-5.2-Fast",
73+
"xiaomi/mimo-v2.5-pro",
74+
"xiaomi/mimo-v2.5",
75+
"nvidia/nemotron-3-ultra-550b-a55b",
76+
"thinkingmachines/inkling",
77+
"poolside/laguna-s-2.1-free",
78+
"sakana/fugu-ultra",
79+
"meta/muse-spark-1.1",
80+
"xai/grok-4.5",
7381
]) {
7482
expect(catalog.has(id)).toBe(true);
7583
expect(catalog.get(id)?.enabled).toBe(false);
7684
}
7785
});
7886

87+
it("records exact CommandCode 1.3.1 prices for disabled candidates", () => {
88+
const catalog = new Map(
89+
loadBridgeConfig({ env: {} }).modelCatalog?.map((model) => [model.id, model]),
90+
);
91+
const prices = {
92+
"claude-sonnet-5": "$2/M in · $10/M out",
93+
"google/gemini-3.5-flash-lite": "$0.30/M in · $2.50/M out",
94+
"google/gemini-3.6-flash": "$1.50/M in · $7.50/M out",
95+
"inclusionai/ling-3.0-flash-free": "$0/M in · $0/M out",
96+
"moonshotai/Kimi-K3": "$3/M in · $15/M out",
97+
"gpt-5.6-luna": "$1/M in · $6/M out",
98+
"gpt-5.6-sol": "$5/M in · $30/M out",
99+
"gpt-5.6-terra": "$2.50/M in · $15/M out",
100+
"tencent/hy3-paid": "$0.14/M in · $0.58/M out",
101+
"zai-org/GLM-5.2-Fast": "$3/M in · $10.25/M out",
102+
"xiaomi/mimo-v2.5-pro": "$0.435/M in · $0.87/M out",
103+
"xiaomi/mimo-v2.5": "$0.14/M in · $0.28/M out",
104+
"nvidia/nemotron-3-ultra-550b-a55b": "$0.60/M in · $2.40/M out",
105+
"thinkingmachines/inkling": "$1/M in · $4.05/M out",
106+
"poolside/laguna-s-2.1-free": "$0/M in · $0/M out",
107+
"sakana/fugu-ultra": "$5/M in · $30/M out",
108+
"meta/muse-spark-1.1": "$1.25/M in · $4.25/M out",
109+
"xai/grok-4.5": "$2/M in · $6/M out",
110+
};
111+
for (const [id, notes] of Object.entries(prices)) {
112+
expect(catalog.get(id)).toMatchObject({ enabled: false, notes });
113+
}
114+
});
115+
79116
it("keeps balance alerts off by default while failing closed on empty length responses", () => {
80117
const config = loadBridgeConfig({ env: {} });
81118
expect(config.balanceAlerts.enabled).toBe(false);

tests/converter.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,19 @@ describe("OpenAI to CommandCode conversion", () => {
7676
{ role: "user", content: [{ type: "text", text: "Say hi" }] },
7777
]);
7878
expect(body.config.workingDir).toBe("/tmp/project");
79+
expect(body.memory).toBeNull();
80+
expect(body.taste).toBeNull();
81+
expect(body.skills).toBeNull();
82+
expect(body.threadId).toBe("00000000-0000-4000-8000-000000000000");
83+
});
84+
85+
it("omits invalid thread IDs instead of forwarding them upstream", () => {
86+
const body = buildCommandCodeGenerateBody({
87+
request: { model: "deepseek/deepseek-v4-pro", messages: [{ role: "user", content: "hi" }] },
88+
upstreamModel: "deepseek/deepseek-v4-pro",
89+
threadId: "not-a-uuid",
90+
});
91+
expect(body.threadId).toBeUndefined();
7992
});
8093

8194
it("treats OpenAI developer messages as system instructions for Hermes compatibility", () => {

0 commit comments

Comments
 (0)