@arnilo/prism-provider-kimi 0.0.6 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.0.8] - 2026-07-20
4
+
5
+ - Released with the exact 0.0.8 first-party package graph.
6
+
7
+ ### Added
8
+
9
+ - Featured Moonshot catalog adds `kimi-k2.7-code-highspeed`, `kimi-k2.6`, and `kimi-k2.5` with official thinking defaults (K2.5 intentionally without Preserved Thinking).
10
+
11
+ ### Fixed
12
+
13
+ - Featured Coding `k3` defaults `reasoning_effort: "high"` per official Kimi Code docs (Open Platform `kimi-k3` keeps `"max"`); 256K-class featured context windows corrected to the exact official `262_144`.
14
+ - `stripKimiThinkingCompat()` also strips `route` and `preserve_thinking`, so provider-owned routing/serialization keys no longer leak into Anthropic or Chat Completions request bodies.
15
+ - Coding route sends provider-owned `x-api-key` and `anthropic-version: 2023-06-01` headers alongside Bearer per the official third-party setup; caller headers cannot override them.
16
+ - Both stream parsers require protocol completion evidence (`message_stop` on the Coding route, `[DONE]` + terminal `finish_reason` on the Moonshot route) and complete tool-call accumulators; truncated streams end with a terminal `error` instead of a false `done`.
17
+
18
+ ## [0.0.7] - 2026-07-19
19
+
20
+ - Released with the exact 0.0.7 first-party package graph.
21
+
3
22
  All notable changes to @arnilo/prism-provider-kimi will be documented in this file.
4
23
 
5
24
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
package/dist/models.d.ts CHANGED
@@ -6,7 +6,7 @@ export interface KimiModelConfig extends Omit<ModelConfig, "provider" | "compat"
6
6
  readonly preserveThinking?: boolean;
7
7
  /** Official K2.x `thinking` object (`type`, optional `keep`). */
8
8
  readonly thinking?: boolean | JsonObject;
9
- /** Official K3 `reasoning_effort` (`"max"` on Open Platform; Coding `k3` also `low`/`high`). */
9
+ /** Official K3 `reasoning_effort` (`"low"`/`"high"`/`"max"`; Open Platform default `"max"`, Coding default `"high"`). */
10
10
  readonly reasoning_effort?: string;
11
11
  };
12
12
  }
@@ -62,4 +62,4 @@ export declare const kimiCodingModels: readonly [ModelConfig, ModelConfig, Model
62
62
  * ids from https://platform.kimi.ai/docs/models. Callable via `createMoonshotProvider`
63
63
  * when `includeMoonshotModels: true`. Refresh via `listKimiModels()`.
64
64
  */
65
- export declare const moonshotKimiModels: readonly [ModelConfig, ModelConfig];
65
+ export declare const moonshotKimiModels: readonly [ModelConfig, ModelConfig, ModelConfig, ModelConfig, ModelConfig];
package/dist/models.js CHANGED
@@ -89,7 +89,7 @@ export const kimiCodingModels = [
89
89
  model: "kimi-for-coding",
90
90
  displayName: "Kimi For Coding (K2.7 Code)",
91
91
  capabilities: { input: ["text", "document", "file"] },
92
- limits: { contextWindow: 256_000, maxOutputTokens: 64_000 },
92
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
93
93
  compat: {
94
94
  route: "anthropic",
95
95
  // Official: thinking always on — omit `thinking` on the wire unless the host sets it.
@@ -101,7 +101,7 @@ export const kimiCodingModels = [
101
101
  model: "kimi-for-coding-highspeed",
102
102
  displayName: "Kimi For Coding Highspeed",
103
103
  capabilities: { input: ["text", "document", "file"] },
104
- limits: { contextWindow: 256_000, maxOutputTokens: 64_000 },
104
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
105
105
  compat: {
106
106
  route: "anthropic",
107
107
  preserveThinking: true,
@@ -116,8 +116,8 @@ export const kimiCodingModels = [
116
116
  compat: {
117
117
  route: "anthropic",
118
118
  preserveThinking: true,
119
- // Coding docs: low / high / max (default max).
120
- reasoning_effort: "max",
119
+ // Official Kimi Code docs: low / high / max; unset effort maps to "high".
120
+ reasoning_effort: "high",
121
121
  },
122
122
  }),
123
123
  ];
@@ -132,13 +132,49 @@ export const moonshotKimiModels = [
132
132
  model: "kimi-k2.7-code",
133
133
  displayName: "Kimi K2.7 Code",
134
134
  capabilities: { input: ["text"] },
135
- limits: { contextWindow: 256_000, maxOutputTokens: 64_000 },
135
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
136
136
  compat: {
137
137
  route: "openai",
138
138
  // Official: omit `thinking` for K2.7-code; Preserved Thinking still required on replay.
139
139
  preserveThinking: true,
140
140
  },
141
141
  }),
142
+ defineKimiModel({
143
+ provider: "moonshot",
144
+ model: "kimi-k2.7-code-highspeed",
145
+ displayName: "Kimi K2.7 Code Highspeed",
146
+ capabilities: { input: ["text"] },
147
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
148
+ compat: {
149
+ route: "openai",
150
+ // Official: same model as kimi-k2.7-code with identical constraints; only output speed differs.
151
+ preserveThinking: true,
152
+ },
153
+ }),
154
+ defineKimiModel({
155
+ provider: "moonshot",
156
+ model: "kimi-k2.6",
157
+ displayName: "Kimi K2.6",
158
+ capabilities: { input: ["text"] },
159
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
160
+ compat: {
161
+ route: "openai",
162
+ // Official: thinking `{"type":"enabled"}` default; `keep: "all"` opt-in.
163
+ thinking: { type: "enabled" },
164
+ },
165
+ }),
166
+ defineKimiModel({
167
+ provider: "moonshot",
168
+ model: "kimi-k2.5",
169
+ displayName: "Kimi K2.5",
170
+ capabilities: { input: ["text"] },
171
+ limits: { contextWindow: 262_144, maxOutputTokens: 64_000 },
172
+ compat: {
173
+ route: "openai",
174
+ // Official: thinking `{"type":"enabled"}` default; no Preserved Thinking support.
175
+ thinking: { type: "enabled" },
176
+ },
177
+ }),
142
178
  defineKimiModel({
143
179
  provider: "moonshot",
144
180
  model: "kimi-k3",
@@ -148,7 +184,7 @@ export const moonshotKimiModels = [
148
184
  compat: {
149
185
  route: "openai",
150
186
  preserveThinking: true,
151
- // Open Platform currently documents only `"max"`.
187
+ // Official Open Platform: low / high / max (default max).
152
188
  reasoning_effort: "max",
153
189
  },
154
190
  }),
package/dist/moonshot.js CHANGED
@@ -68,9 +68,13 @@ export function moonshotBody(request) {
68
68
  export async function* moonshotEvents(body, signal) {
69
69
  const tools = new Map();
70
70
  let usage;
71
+ let sawDoneMarker = false;
72
+ let sawFinishReason = false;
71
73
  for await (const data of readSseData(body, { signal })) {
72
- if (data === "[DONE]")
74
+ if (data === "[DONE]") {
75
+ sawDoneMarker = true;
73
76
  break;
77
+ }
74
78
  const chunk = JSON.parse(data);
75
79
  usage = mapOpenAIChatUsage(chunk.usage) ?? usage;
76
80
  if (chunk.usage) {
@@ -79,6 +83,8 @@ export async function* moonshotEvents(body, signal) {
79
83
  yield providerUsage(mapped);
80
84
  }
81
85
  for (const choice of chunk.choices ?? []) {
86
+ if (choice.finish_reason)
87
+ sawFinishReason = true;
82
88
  const delta = choice.delta ?? {};
83
89
  if (delta.content)
84
90
  yield providerTextDelta(delta.content);
@@ -100,10 +106,17 @@ export async function* moonshotEvents(body, signal) {
100
106
  }
101
107
  }
102
108
  }
109
+ const danglingToolCall = [...tools.values()].some((call) => !call.id || !call.name);
110
+ if (!sawDoneMarker || !sawFinishReason || danglingToolCall) {
111
+ // Truncated streams must fail loudly — emitting done would mark partial output as succeeded.
112
+ yield providerError(new Error(`Moonshot chat stream ended without completion evidence `
113
+ + `([DONE]: ${sawDoneMarker ? "received" : "missing"}, `
114
+ + `finish_reason: ${sawFinishReason ? "received" : "missing"}, `
115
+ + `tool calls complete: ${danglingToolCall ? "no" : "yes"})`));
116
+ return;
117
+ }
103
118
  for (const call of tools.values()) {
104
- if (call.id && call.name) {
105
- yield providerToolCall(toolCallContent(call.id, call.name, parseJsonObjectArguments(call.argumentsText, { toolName: call.name })));
106
- }
119
+ yield providerToolCall(toolCallContent(call.id, call.name, parseJsonObjectArguments(call.argumentsText, { toolName: call.name })));
107
120
  }
108
121
  yield providerDone(usage);
109
122
  }
package/dist/provider.js CHANGED
@@ -24,6 +24,9 @@ export function createKimiCodingProvider(options = {}) {
24
24
  "content-type": "application/json",
25
25
  "user-agent": options.userAgent ?? "KimiCLI/1.5",
26
26
  ...(token ? { authorization: `Bearer ${token}` } : {}),
27
+ // Provider-owned Anthropic-route auth: official third-party setup uses
28
+ // ANTHROPIC_API_KEY semantics (x-api-key + anthropic-version).
29
+ ...(token ? { "x-api-key": token, "anthropic-version": "2023-06-01" } : {}),
27
30
  },
28
31
  body: JSON.stringify(body),
29
32
  signal: request.signal,
@@ -66,12 +69,20 @@ export async function kimiAnthropicBody(request) {
66
69
  export async function* kimiAnthropicEvents(body, signal) {
67
70
  const blocks = new Map();
68
71
  let usage;
72
+ let sawMessageStop = false;
69
73
  for await (const data of readSseData(body, { signal })) {
70
74
  if (data === "[DONE]")
71
75
  break;
72
76
  const event = JSON.parse(data);
77
+ if (event.type === "message_stop")
78
+ sawMessageStop = true;
73
79
  if (event.type === "content_block_start" && event.content_block?.type === "tool_use")
74
80
  blocks.set(event.index ?? 0, { id: event.content_block.id, name: event.content_block.name, argumentsText: "" });
81
+ if (event.type === "content_block_stop") {
82
+ const current = blocks.get(event.index ?? 0);
83
+ if (current)
84
+ current.complete = true;
85
+ }
75
86
  if (event.type === "content_block_delta") {
76
87
  const delta = event.delta;
77
88
  if (delta?.type === "text_delta" && delta.text)
@@ -90,10 +101,16 @@ export async function* kimiAnthropicEvents(body, signal) {
90
101
  if (event.type === "message_delta" && usage)
91
102
  yield providerUsage(usage);
92
103
  }
104
+ const danglingBlock = [...blocks.values()].some((call) => !call.id || !call.name || !call.complete);
105
+ if (!sawMessageStop || danglingBlock) {
106
+ // Truncated streams must fail loudly — emitting done would mark partial output as succeeded.
107
+ yield providerError(new Error(`Kimi messages stream ended without completion evidence `
108
+ + `(message_stop: ${sawMessageStop ? "received" : "missing"}, `
109
+ + `content blocks complete: ${danglingBlock ? "no" : "yes"})`));
110
+ return;
111
+ }
93
112
  for (const call of blocks.values()) {
94
- if (call.id && call.name) {
95
- yield providerToolCall(toolCallContent(call.id, call.name, parseJsonObjectArguments(call.argumentsText, { toolName: call.name })));
96
- }
113
+ yield providerToolCall(toolCallContent(call.id, call.name, parseJsonObjectArguments(call.argumentsText, { toolName: call.name })));
97
114
  }
98
115
  yield providerDone(usage);
99
116
  }
@@ -6,8 +6,8 @@ import type { JsonObject, ProviderRequest } from "@arnilo/prism";
6
6
  */
7
7
  export declare function kimiThinking(request: ProviderRequest): JsonObject | undefined;
8
8
  /**
9
- * Official K3 top-level `reasoning_effort` (Open Platform currently documents `"max"`;
10
- * Kimi Code additionally maps `low` / `high` / `max` for model id `k3`).
9
+ * Official K3 top-level `reasoning_effort`: `"low"` / `"high"` / `"max"`.
10
+ * Open Platform default is `"max"`; Kimi Code default is `"high"`.
11
11
  * Request wins over model default.
12
12
  * @see https://platform.kimi.ai/docs/guide/use-thinking-effort
13
13
  */
@@ -18,5 +18,8 @@ export declare function kimiReasoningEffort(request: ProviderRequest): string |
18
18
  * Request `compat.preserveThinking` wins over model default.
19
19
  */
20
20
  export declare function kimiPreserveThinking(request: ProviderRequest): boolean;
21
- /** Strip thinking-owned keys so opaque compat spread cannot invert explicit resolvers. */
21
+ /**
22
+ * Strip provider-owned compat keys so the opaque compat spread cannot leak
23
+ * routing/serialization directives (or inverted thinking values) into wire bodies.
24
+ */
22
25
  export declare function stripKimiThinkingCompat(compat: JsonObject | undefined): JsonObject;
package/dist/thinking.js CHANGED
@@ -12,8 +12,8 @@ export function kimiThinking(request) {
12
12
  return value === true ? { type: "enabled" } : undefined;
13
13
  }
14
14
  /**
15
- * Official K3 top-level `reasoning_effort` (Open Platform currently documents `"max"`;
16
- * Kimi Code additionally maps `low` / `high` / `max` for model id `k3`).
15
+ * Official K3 top-level `reasoning_effort`: `"low"` / `"high"` / `"max"`.
16
+ * Open Platform default is `"max"`; Kimi Code default is `"high"`.
17
17
  * Request wins over model default.
18
18
  * @see https://platform.kimi.ai/docs/guide/use-thinking-effort
19
19
  */
@@ -32,11 +32,14 @@ export function kimiPreserveThinking(request) {
32
32
  const value = request.options?.compat?.preserveThinking ?? request.model.compat?.preserveThinking;
33
33
  return value === true;
34
34
  }
35
- /** Strip thinking-owned keys so opaque compat spread cannot invert explicit resolvers. */
35
+ /**
36
+ * Strip provider-owned compat keys so the opaque compat spread cannot leak
37
+ * routing/serialization directives (or inverted thinking values) into wire bodies.
38
+ */
36
39
  export function stripKimiThinkingCompat(compat) {
37
40
  if (!compat)
38
41
  return {};
39
- const { thinking: _thinking, reasoning_effort: _effort, reasoningEffort: _effortCamel, preserveThinking: _preserve, ...rest } = compat;
42
+ const { thinking: _thinking, reasoning_effort: _effort, reasoningEffort: _effortCamel, preserveThinking: _preserve, preserve_thinking: _preserveSnake, route: _route, ...rest } = compat;
40
43
  return rest;
41
44
  }
42
45
  //# sourceMappingURL=thinking.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arnilo/prism-provider-kimi",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Kimi provider package for Prism.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,7 +25,7 @@
25
25
  "pack:dry-run": "npm pack --dry-run"
26
26
  },
27
27
  "peerDependencies": {
28
- "@arnilo/prism": "0.0.6"
28
+ "@arnilo/prism": "0.0.8"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@arnilo/prism": "file:../.."