Skip to content

Commit c7699de

Browse files
authored
feat(llm): support Kimi Code models (kimi-for-coding, k3) (#117)
Kimi Code's OpenAI-compatible endpoint (https://api.kimi.com/coding/v1) rejects any explicit temperature other than the default (1) with a 400 "invalid temperature: only 1 is allowed for this model". Add the kimi-for-coding* and k3* model ID prefixes to modelForbidsTemperature so the client omits the field, matching the existing handling for OpenAI reasoning models. Also wire the documented --temperature CLI flag into the agent config: it was parsed into flags.Temp but never consumed, so every run kept the hardcoded deterministic default (0). The continue command takes no CLI flags and keeps the fixed default.
1 parent b748e50 commit c7699de

3 files changed

Lines changed: 17 additions & 8 deletions

File tree

cmd/odek/main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1332,7 +1332,7 @@ func run(args []string) error {
13321332
NoProjectFile: resolved.NoAgents,
13331333
Thinking: resolved.Thinking,
13341334
ThinkingBudget: f.ThinkingBudget,
1335-
Temperature: 0, // deterministic by default; override with --temperature
1335+
Temperature: f.Temp, // 0 = deterministic default; negative = omit from request
13361336
Tools: tools,
13371337
ToolFilter: odek.ToolFilterConfig{Enabled: resolved.Tools.Enabled, Disabled: resolved.Tools.Disabled},
13381338
SandboxCleanup: sandboxCleanup,
@@ -2404,7 +2404,7 @@ func continueCmd(args []string) error {
24042404
UntrustedWrapper: func(source, content string) string { return wrapUntrusted(context.Background(), source, content) },
24052405
NoProjectFile: resolved.NoAgents,
24062406
Thinking: resolved.Thinking,
2407-
Temperature: 0, // deterministic by default; override with --temperature
2407+
Temperature: 0, // deterministic by default; continue takes no CLI flags
24082408
Tools: tools,
24092409
ToolFilter: odek.ToolFilterConfig{Enabled: resolved.Tools.Enabled, Disabled: resolved.Tools.Disabled},
24102410
SandboxCleanup: sandboxCleanup,

internal/llm/client.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,14 @@ func (c *Client) sendsThinkingObject() bool {
8181
// temperature parameter. OpenAI reasoning models (o1/o3/o4 families and the
8282
// gpt-5 series) only accept the default temperature (1); sending any other
8383
// value — including odek's deterministic default 0 — returns a 400
84-
// "unsupported_value" error. Matching is model-name-based and
84+
// "unsupported_value" error. Kimi Code models (kimi-for-coding*, k3*) behave
85+
// the same way: the endpoint answers 400 "invalid temperature: only 1 is
86+
// allowed for this model". Matching is model-name-based and
8587
// provider-agnostic, since OpenAI-compatible proxies serving these model
8688
// IDs enforce the same constraint.
8789
func modelForbidsTemperature(model string) bool {
8890
m := strings.ToLower(model)
89-
for _, prefix := range []string{"o1", "o3", "o4", "gpt-5"} {
91+
for _, prefix := range []string{"o1", "o3", "o4", "gpt-5", "kimi-for-coding", "k3"} {
9092
if strings.HasPrefix(m, prefix) {
9193
return true
9294
}

internal/llm/client_test.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1038,10 +1038,11 @@ func TestClient_IsAnthropic(t *testing.T) {
10381038
}
10391039
}
10401040

1041-
// OpenAI reasoning models (o1/o3/o4, gpt-5 family) reject any explicit
1042-
// temperature other than the default (1) with a 400. The client must omit
1043-
// the field for those models while still sending odek's deterministic
1044-
// default (0) to models that accept it.
1041+
// OpenAI reasoning models (o1/o3/o4, gpt-5 family) and Kimi Code models
1042+
// (kimi-for-coding*, k3*) reject any explicit temperature other than the
1043+
// default (1) with a 400. The client must omit the field for those models
1044+
// while still sending odek's deterministic default (0) to models that
1045+
// accept it.
10451046
func TestCall_OmitsTemperatureForReasoningModels(t *testing.T) {
10461047
cases := []struct {
10471048
model string
@@ -1053,9 +1054,15 @@ func TestCall_OmitsTemperatureForReasoningModels(t *testing.T) {
10531054
{"o1-preview", false},
10541055
{"o4-mini", false},
10551056
{"GPT-5-MINI", false}, // case-insensitive
1057+
{"kimi-for-coding", false},
1058+
{"kimi-for-coding-highspeed", false},
1059+
{"k3", false},
1060+
{"k3-256k", false},
1061+
{"Kimi-For-Coding", false}, // case-insensitive
10561062
{"gpt-4o-mini", true},
10571063
{"deepseek-chat", true},
10581064
{"claude-sonnet-4-5", true},
1065+
{"kimi-latest", true}, // Moonshot platform models accept temperature
10591066
}
10601067

10611068
for _, tc := range cases {

0 commit comments

Comments
 (0)