@arnilo/prism-provider-kimi 0.0.1 → 0.0.2
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 +2 -0
- package/README.md +6 -0
- package/dist/cache.d.ts +16 -0
- package/dist/cache.js +41 -0
- package/dist/provider.js +19 -10
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -20,3 +20,9 @@ Security defaults:
|
|
|
20
20
|
- No automatic environment, file, keychain, or shell credential lookup.
|
|
21
21
|
- Kimi credentials are resolved per request from caller-supplied values or resolvers.
|
|
22
22
|
- Moonshot/Open Platform model metadata is registered only with `includeMoonshotModels: true`.
|
|
23
|
+
|
|
24
|
+
Cache behavior:
|
|
25
|
+
- Default catalog models use implicit caching (no `cache_control`); opt in via `ModelConfig.cache.kind: "cache_control"` on the Anthropic route.
|
|
26
|
+
- When opted in, `cache_control` markers apply only to selected `cache.breakpoints` (`"long"` → `ttl: "1h"`); Moonshot OpenAI route sends none.
|
|
27
|
+
- `cache_read_input_tokens`/`cache_creation_input_tokens` map to `Usage.cacheReadTokens`/`cacheWriteTokens`.
|
|
28
|
+
- Provider-owned headers (`content-type`, `user-agent`, `authorization`) win over caller headers.
|
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Message, ProviderRequest } from "@arnilo/prism";
|
|
2
|
+
/**
|
|
3
|
+
* Whether Anthropic-style content `cache_control` markers may be emitted on the
|
|
4
|
+
* Kimi coding (`/messages`) endpoint. Default catalog models use implicit
|
|
5
|
+
* caching and do not declare this; hosts opt in per-model via
|
|
6
|
+
* `ModelConfig.cache.kind: "cache_control"` (or force `cache.mode: "on"`).
|
|
7
|
+
* The Moonshot OpenAI-compatible route never receives Anthropic `cache_control`.
|
|
8
|
+
*/
|
|
9
|
+
export declare function kimiAnthropicCacheEnabled(request: ProviderRequest): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Apply Anthropic-style `cache_control` markers only to the caller-selected Prism
|
|
12
|
+
* breakpoints on the Kimi Anthropic route, using the shared `applyCacheControl`
|
|
13
|
+
* helper. Markers land on the last content block of each selected message; with
|
|
14
|
+
* no breakpoints, no markers are emitted and the endpoint relies on implicit caching.
|
|
15
|
+
*/
|
|
16
|
+
export declare function applyKimiAnthropicCacheControl(request: ProviderRequest): readonly Message[];
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { applyCacheControl } from "@arnilo/prism";
|
|
2
|
+
/**
|
|
3
|
+
* Whether Anthropic-style content `cache_control` markers may be emitted on the
|
|
4
|
+
* Kimi coding (`/messages`) endpoint. Default catalog models use implicit
|
|
5
|
+
* caching and do not declare this; hosts opt in per-model via
|
|
6
|
+
* `ModelConfig.cache.kind: "cache_control"` (or force `cache.mode: "on"`).
|
|
7
|
+
* The Moonshot OpenAI-compatible route never receives Anthropic `cache_control`.
|
|
8
|
+
*/
|
|
9
|
+
export function kimiAnthropicCacheEnabled(request) {
|
|
10
|
+
if (request.options?.cacheRetention === "none")
|
|
11
|
+
return false;
|
|
12
|
+
if (request.options?.cache?.mode === "off")
|
|
13
|
+
return false;
|
|
14
|
+
if (request.model.cache?.kind === "none")
|
|
15
|
+
return false;
|
|
16
|
+
return request.model.cache?.kind === "cache_control" || request.options?.cache?.mode === "on";
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Apply Anthropic-style `cache_control` markers only to the caller-selected Prism
|
|
20
|
+
* breakpoints on the Kimi Anthropic route, using the shared `applyCacheControl`
|
|
21
|
+
* helper. Markers land on the last content block of each selected message; with
|
|
22
|
+
* no breakpoints, no markers are emitted and the endpoint relies on implicit caching.
|
|
23
|
+
*/
|
|
24
|
+
export function applyKimiAnthropicCacheControl(request) {
|
|
25
|
+
if (!kimiAnthropicCacheEnabled(request))
|
|
26
|
+
return request.messages;
|
|
27
|
+
const breakpoints = request.options?.cache?.breakpoints;
|
|
28
|
+
if (!breakpoints?.length)
|
|
29
|
+
return request.messages;
|
|
30
|
+
const options = {
|
|
31
|
+
ttl: kimiAnthropicCacheTtl(request) ? "1h" : undefined,
|
|
32
|
+
maxBreakpoints: request.model.cache?.maxBreakpoints,
|
|
33
|
+
};
|
|
34
|
+
return applyCacheControl(request.messages, breakpoints, options);
|
|
35
|
+
}
|
|
36
|
+
function kimiAnthropicCacheTtl(request) {
|
|
37
|
+
if (request.options?.cacheRetention !== "long" && request.options?.cache?.retention !== "long")
|
|
38
|
+
return false;
|
|
39
|
+
return request.model.cache?.longRetention !== false;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=cache.js.map
|
package/dist/provider.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { providerDone, providerError, providerTextDelta, providerThinkingDelta, providerToolCall, providerToolCallDelta, providerUsage, resolveCredentialValue, toolCallContent } from "@arnilo/prism";
|
|
2
|
+
import { applyKimiAnthropicCacheControl } from "./cache.js";
|
|
2
3
|
import { readSseData } from "./sse.js";
|
|
3
4
|
export function createKimiCodingProvider(options = {}) {
|
|
4
5
|
const id = options.id ?? "kimi-coding";
|
|
@@ -14,9 +15,9 @@ export function createKimiCodingProvider(options = {}) {
|
|
|
14
15
|
const response = await (options.fetch ?? fetch)(`${baseUrl}/messages`, {
|
|
15
16
|
method: "POST",
|
|
16
17
|
headers: {
|
|
18
|
+
...request.options?.headers,
|
|
17
19
|
"content-type": "application/json",
|
|
18
20
|
"user-agent": options.userAgent ?? "KimiCLI/1.5",
|
|
19
|
-
...request.options?.headers,
|
|
20
21
|
...(token ? { authorization: `Bearer ${token}` } : {}),
|
|
21
22
|
},
|
|
22
23
|
body: JSON.stringify(kimiAnthropicBody(request)),
|
|
@@ -36,14 +37,16 @@ export function createKimiCodingProvider(options = {}) {
|
|
|
36
37
|
}
|
|
37
38
|
export function kimiAnthropicBody(request) {
|
|
38
39
|
const preserveThinking = request.model.compat?.preserveThinking === true;
|
|
40
|
+
const { maxTokens, ...parameters } = request.model.parameters ?? {};
|
|
41
|
+
const messages = applyKimiAnthropicCacheControl(request);
|
|
39
42
|
return clean({
|
|
40
43
|
model: request.model.model,
|
|
41
|
-
messages:
|
|
42
|
-
system:
|
|
44
|
+
messages: messages.filter((m) => m.role !== "system").map((message) => toMessage(message, request.model.capabilities ?? {}, preserveThinking)),
|
|
45
|
+
system: messages.filter((m) => m.role === "system").map((m) => text(m, preserveThinking)).join("\n\n") || undefined,
|
|
43
46
|
tools: request.tools?.map(toTool),
|
|
44
47
|
stream: true,
|
|
45
|
-
|
|
46
|
-
|
|
48
|
+
...parameters,
|
|
49
|
+
max_tokens: maxTokens ?? request.model.limits?.maxOutputTokens ?? 4096,
|
|
47
50
|
...request.options?.compat,
|
|
48
51
|
...request.options?.extra,
|
|
49
52
|
});
|
|
@@ -83,26 +86,29 @@ export async function* kimiAnthropicEvents(body) {
|
|
|
83
86
|
function toMessage(message, capabilities = {}, preserveThinking = false) {
|
|
84
87
|
if (message.role === "tool") {
|
|
85
88
|
const result = message.content.find((part) => part.type === "tool_result");
|
|
89
|
+
const last = message.content[message.content.length - 1];
|
|
86
90
|
return {
|
|
87
91
|
role: "user",
|
|
88
92
|
content: [{
|
|
89
93
|
type: "tool_result",
|
|
90
94
|
tool_use_id: result?.toolCallId ?? "",
|
|
91
95
|
content: result ? JSON.stringify(result.result ?? result.error ?? null) : "",
|
|
96
|
+
...(last?.cache_control ? { cache_control: last.cache_control } : {}),
|
|
92
97
|
}],
|
|
93
98
|
};
|
|
94
99
|
}
|
|
95
100
|
const content = [];
|
|
96
101
|
for (const part of message.content) {
|
|
102
|
+
const marker = (part.cache_control ?? undefined);
|
|
97
103
|
if (part.type === "text") {
|
|
98
|
-
content.push({ type: "text", text: part.text });
|
|
104
|
+
content.push(withMarker({ type: "text", text: part.text }, marker));
|
|
99
105
|
}
|
|
100
106
|
else if (part.type === "thinking") {
|
|
101
107
|
if (preserveThinking) {
|
|
102
|
-
content.push(part.signature ? { type: "thinking", thinking: part.text, signature: part.signature } : { type: "thinking", thinking: part.text });
|
|
108
|
+
content.push(withMarker(part.signature ? { type: "thinking", thinking: part.text, signature: part.signature } : { type: "thinking", thinking: part.text }, marker));
|
|
103
109
|
}
|
|
104
110
|
else {
|
|
105
|
-
content.push({ type: "text", text: part.text });
|
|
111
|
+
content.push(withMarker({ type: "text", text: part.text }, marker));
|
|
106
112
|
}
|
|
107
113
|
}
|
|
108
114
|
else if (part.type === "image") {
|
|
@@ -112,10 +118,10 @@ function toMessage(message, capabilities = {}, preserveThinking = false) {
|
|
|
112
118
|
const source = part.url
|
|
113
119
|
? { type: "url", url: part.url }
|
|
114
120
|
: { type: "base64", media_type: part.mimeType ?? "image/png", data: part.data ?? "" };
|
|
115
|
-
content.push({ type: "image", source });
|
|
121
|
+
content.push(withMarker({ type: "image", source }, marker));
|
|
116
122
|
}
|
|
117
123
|
else if (part.type === "tool_call") {
|
|
118
|
-
content.push({ type: "tool_use", id: part.id, name: part.name, input: part.arguments });
|
|
124
|
+
content.push(withMarker({ type: "tool_use", id: part.id, name: part.name, input: part.arguments }, marker));
|
|
119
125
|
}
|
|
120
126
|
else if (part.type === "tool_result") {
|
|
121
127
|
throw new Error("Kimi tool_result blocks must appear in role=tool messages");
|
|
@@ -123,6 +129,9 @@ function toMessage(message, capabilities = {}, preserveThinking = false) {
|
|
|
123
129
|
}
|
|
124
130
|
return { role: message.role === "assistant" ? "assistant" : "user", content: content.length > 0 ? content : [{ type: "text", text: "" }] };
|
|
125
131
|
}
|
|
132
|
+
function withMarker(item, marker) {
|
|
133
|
+
return marker ? { ...item, cache_control: marker } : item;
|
|
134
|
+
}
|
|
126
135
|
function toTool(tool) {
|
|
127
136
|
return clean({ name: tool.name, description: tool.description, input_schema: tool.parameters ?? { type: "object" } });
|
|
128
137
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arnilo/prism-provider-kimi",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.2",
|
|
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.
|
|
28
|
+
"@arnilo/prism": "0.0.2"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@arnilo/prism": "file:../.."
|