@ottocode/sdk 0.1.313 → 0.1.315
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/package.json +1 -1
- package/src/config/src/index.ts +38 -8
- package/src/config/src/manager.ts +2 -0
- package/src/config/src/paths.ts +221 -3
- package/src/core/src/providers/resolver.ts +1 -2
- package/src/core/src/tools/builtin/fs/copy-attachment.ts +28 -13
- package/src/core/src/tools/builtin/fs/edit.txt +1 -1
- package/src/core/src/tools/builtin/fs/index.ts +2 -0
- package/src/core/src/tools/builtin/fs/multiedit.txt +1 -1
- package/src/core/src/tools/builtin/git-identity.ts +37 -3
- package/src/core/src/tools/builtin/git.ts +8 -2
- package/src/core/src/tools/builtin/glob.txt +4 -0
- package/src/core/src/tools/builtin/patch/indentation.ts +8 -1
- package/src/core/src/tools/builtin/patch/normalize.ts +4 -0
- package/src/core/src/tools/builtin/patch/repair.ts +42 -0
- package/src/core/src/tools/builtin/patch.txt +2 -0
- package/src/core/src/tools/builtin/search.txt +4 -0
- package/src/core/src/tools/builtin/shell.ts +54 -12
- package/src/core/src/tools/builtin/shell.txt +5 -0
- package/src/core/src/tools/builtin/terminal.ts +11 -3
- package/src/core/src/tools/loader.ts +8 -4
- package/src/index.ts +17 -5
- package/src/prompts/src/agents/build.txt +2 -2
- package/src/prompts/src/providers/{moonshot.txt → kimi.txt} +1 -1
- package/src/prompts/src/providers.ts +5 -5
- package/src/providers/src/catalog-manual.ts +53 -8
- package/src/providers/src/catalog.ts +74 -34
- package/src/providers/src/env.ts +4 -7
- package/src/providers/src/index.ts +3 -9
- package/src/providers/src/{moonshot-client.ts → kimi-client.ts} +131 -15
- package/src/providers/src/model-merge.ts +7 -1
- package/src/providers/src/pricing.ts +1 -1
- package/src/providers/src/registry.ts +8 -19
- package/src/providers/src/utils.ts +11 -8
- package/src/types/src/config.ts +12 -1
- package/src/types/src/provider.ts +4 -4
|
@@ -13,10 +13,30 @@ import {
|
|
|
13
13
|
|
|
14
14
|
export function repairPatchContent(patch: string): string {
|
|
15
15
|
patch = extractPatchFromWrappedJson(patch);
|
|
16
|
+
patch = extractEnvelopedPatchFromText(patch);
|
|
17
|
+
patch = stripTrailingMarkdownFenceBeforeMissingEndMarker(patch);
|
|
16
18
|
patch = appendMissingEndMarker(patch);
|
|
19
|
+
patch = trimAfterEndMarker(patch);
|
|
17
20
|
return patch;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
function looksLikeUnifiedPatch(patch: string): boolean {
|
|
24
|
+
const trimmed = patch.trimStart();
|
|
25
|
+
return (
|
|
26
|
+
trimmed.startsWith('diff --git ') ||
|
|
27
|
+
trimmed.startsWith('--- ') ||
|
|
28
|
+
trimmed.startsWith('Index: ')
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function extractEnvelopedPatchFromText(patch: string): string {
|
|
33
|
+
const beginIndex = patch.indexOf(PATCH_BEGIN_MARKER);
|
|
34
|
+
if (beginIndex === -1) return patch;
|
|
35
|
+
if (beginIndex === patch.search(/\S/)) return patch;
|
|
36
|
+
if (looksLikeUnifiedPatch(patch)) return patch;
|
|
37
|
+
return patch.slice(beginIndex);
|
|
38
|
+
}
|
|
39
|
+
|
|
20
40
|
function extractPatchFromWrappedJson(patch: string): string {
|
|
21
41
|
if (patch.includes(PATCH_BEGIN_MARKER)) return patch;
|
|
22
42
|
|
|
@@ -61,3 +81,25 @@ function appendMissingEndMarker(patch: string): string {
|
|
|
61
81
|
|
|
62
82
|
return patch;
|
|
63
83
|
}
|
|
84
|
+
|
|
85
|
+
function stripTrailingMarkdownFenceBeforeMissingEndMarker(
|
|
86
|
+
patch: string,
|
|
87
|
+
): string {
|
|
88
|
+
const trimmed = patch.trimEnd();
|
|
89
|
+
if (!trimmed.trimStart().startsWith(PATCH_BEGIN_MARKER)) return patch;
|
|
90
|
+
if (trimmed.includes(PATCH_END_MARKER)) return patch;
|
|
91
|
+
const lines = trimmed.split('\n');
|
|
92
|
+
const last = lines.at(-1)?.trim();
|
|
93
|
+
if (last !== '```') return patch;
|
|
94
|
+
return lines.slice(0, -1).join('\n');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function trimAfterEndMarker(patch: string): string {
|
|
98
|
+
if (!patch.trimStart().startsWith(PATCH_BEGIN_MARKER)) return patch;
|
|
99
|
+
const endIndex = patch.indexOf(PATCH_END_MARKER);
|
|
100
|
+
if (endIndex === -1) return patch;
|
|
101
|
+
const endOfMarker = endIndex + PATCH_END_MARKER.length;
|
|
102
|
+
const suffix = patch.slice(endOfMarker);
|
|
103
|
+
if (suffix.trim().length === 0) return patch;
|
|
104
|
+
return patch.slice(0, endOfMarker);
|
|
105
|
+
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
Apply a patch to modify one or more files.
|
|
2
2
|
|
|
3
|
+
Prefer this as the first-choice editing tool for code and text changes when it is available. Use exact-replacement tools (`edit`/`multiedit`) when a patch would be awkward, when you only need a precise old/new string replacement, or after patch attempts fail.
|
|
4
|
+
|
|
3
5
|
Use the **enveloped format** by default. Standard unified diffs (`---` / `+++`) are also accepted.
|
|
4
6
|
|
|
5
7
|
## Fastest / safest mode (recommended): Replace
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
|
|
6
6
|
Use this for text/code search across the codebase. It is the primary tool for repository content discovery.
|
|
7
7
|
|
|
8
|
+
Think of `search` as the repository's fast local `rg`/`grep` replacement: use it for exact string and regex searches before reaching for shell commands.
|
|
9
|
+
|
|
8
10
|
## Usage tips
|
|
9
11
|
|
|
10
12
|
- Narrow broad searches with `path` and `glob` values.
|
|
@@ -12,3 +14,5 @@ Use this for text/code search across the codebase. It is the primary tool for re
|
|
|
12
14
|
- Batch independent searches (e.g. multiple function names) in a single turn for parallel execution.
|
|
13
15
|
- Use `ignoreCase: true` for case-insensitive matching; pass `glob` patterns (e.g. `["*.ts", "*.tsx"]`) to limit file types.
|
|
14
16
|
- For filename/path discovery, use `glob` first when you already know the file pattern.
|
|
17
|
+
- Instead of `grep -r "workspace:" packages apps`, call `search` with `query: "workspace:"`, `path: "."`, and `glob: ["**/package.json"]`.
|
|
18
|
+
- Instead of `rg "function foo" src`, call `search` with `query: "function foo"` and `path: "src"`.
|
|
@@ -5,7 +5,10 @@ import { z } from 'zod/v3';
|
|
|
5
5
|
import DESCRIPTION from './shell.txt' with { type: 'text' };
|
|
6
6
|
import { getShellExecutionConfig } from '../bin-manager.ts';
|
|
7
7
|
import { createToolError, type ToolResponse } from '../error.ts';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
injectCoAuthorIntoGitCommit,
|
|
10
|
+
shouldCoAuthorCommits,
|
|
11
|
+
} from './git-identity.ts';
|
|
9
12
|
|
|
10
13
|
function normalizePath(p: string) {
|
|
11
14
|
const normalized = p.replace(/\\/g, '/');
|
|
@@ -43,6 +46,7 @@ function killProcessTree(pid: number) {
|
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
const REDIRECTED_SEARCH_COMMANDS = new Set(['grep', 'egrep', 'fgrep', 'rg']);
|
|
49
|
+
const REDIRECTED_GLOB_COMMANDS = new Set(['find', 'fd']);
|
|
46
50
|
|
|
47
51
|
/**
|
|
48
52
|
* Detect commands that start with a standalone grep-style search binary.
|
|
@@ -50,23 +54,55 @@ const REDIRECTED_SEARCH_COMMANDS = new Set(['grep', 'egrep', 'fgrep', 'rg']);
|
|
|
50
54
|
* with grep/rg are redirected to the dedicated `search` tool.
|
|
51
55
|
*/
|
|
52
56
|
export function findRedirectedSearchCommand(cmd: string): string | null {
|
|
57
|
+
return findRepositoryDiscoveryCommand(cmd, 'search')?.command ?? null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function commandTokens(segment: string): string[] {
|
|
61
|
+
const tokens = segment.trim().split(/\s+/).filter(Boolean);
|
|
62
|
+
let index = 0;
|
|
63
|
+
while (
|
|
64
|
+
index < tokens.length &&
|
|
65
|
+
/^[A-Za-z_][A-Za-z0-9_]*=/.test(tokens[index] ?? '')
|
|
66
|
+
) {
|
|
67
|
+
index++;
|
|
68
|
+
}
|
|
69
|
+
if (tokens[index] === 'command') index++;
|
|
70
|
+
return tokens.slice(index);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function findRepositoryDiscoveryCommand(
|
|
74
|
+
cmd: string,
|
|
75
|
+
kind?: 'search' | 'glob',
|
|
76
|
+
): { command: string; tool: 'search' | 'glob' } | null {
|
|
53
77
|
const segments = cmd.split(/&&|\|\||;|\n/);
|
|
54
78
|
for (const segment of segments) {
|
|
55
|
-
const tokens = segment
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
79
|
+
const tokens = commandTokens(segment);
|
|
80
|
+
const bin = tokens[0]?.split('/').pop() ?? '';
|
|
81
|
+
const second = tokens[1] ?? '';
|
|
82
|
+
if ((!kind || kind === 'search') && bin === 'git' && second === 'grep') {
|
|
83
|
+
return { command: 'git grep', tool: 'search' };
|
|
84
|
+
}
|
|
85
|
+
if ((!kind || kind === 'search') && REDIRECTED_SEARCH_COMMANDS.has(bin)) {
|
|
86
|
+
return { command: bin, tool: 'search' };
|
|
87
|
+
}
|
|
88
|
+
if ((!kind || kind === 'glob') && REDIRECTED_GLOB_COMMANDS.has(bin)) {
|
|
89
|
+
return { command: bin, tool: 'glob' };
|
|
90
|
+
}
|
|
91
|
+
if ((!kind || kind === 'glob') && bin === 'ls' && segment.includes('**')) {
|
|
92
|
+
return { command: 'ls **', tool: 'glob' };
|
|
62
93
|
}
|
|
63
|
-
if (tokens[index] === 'command') index++;
|
|
64
|
-
const bin = tokens[index]?.split('/').pop() ?? '';
|
|
65
|
-
if (REDIRECTED_SEARCH_COMMANDS.has(bin)) return bin;
|
|
66
94
|
}
|
|
67
95
|
return null;
|
|
68
96
|
}
|
|
69
97
|
|
|
98
|
+
function repositoryDiscoveryHint(cmd: string): string | undefined {
|
|
99
|
+
const discovery = findRepositoryDiscoveryCommand(cmd);
|
|
100
|
+
if (!discovery) return undefined;
|
|
101
|
+
return discovery.tool === 'search'
|
|
102
|
+
? `Tip: For repository content search, prefer the search tool instead of shelling out to ${discovery.command}. It is indexed, faster, and returns structured file:line matches.`
|
|
103
|
+
: `Tip: For repository file discovery, prefer the glob tool instead of shelling out to ${discovery.command}. It returns structured paths and skips common build/cache folders.`;
|
|
104
|
+
}
|
|
105
|
+
|
|
70
106
|
export type ShellOutputMode = 'auto' | 'full' | 'tail';
|
|
71
107
|
|
|
72
108
|
const DEFAULT_TAIL_LINES = 100;
|
|
@@ -133,6 +169,7 @@ type ShellResult = ToolResponse<{
|
|
|
133
169
|
stderrTruncated?: boolean;
|
|
134
170
|
stderrOriginalBytes?: number;
|
|
135
171
|
stderrShownBytes?: number;
|
|
172
|
+
discoveryHint?: string;
|
|
136
173
|
}>;
|
|
137
174
|
|
|
138
175
|
type ShellStreamChunk =
|
|
@@ -248,7 +285,10 @@ export function buildShellTool(projectRoot: string): {
|
|
|
248
285
|
}
|
|
249
286
|
|
|
250
287
|
const absCwd = resolveSafePath(projectRoot, cwd || '.');
|
|
251
|
-
const finalCmd = injectCoAuthorIntoGitCommit(
|
|
288
|
+
const finalCmd = injectCoAuthorIntoGitCommit(
|
|
289
|
+
cmd,
|
|
290
|
+
shouldCoAuthorCommits(projectRoot),
|
|
291
|
+
);
|
|
252
292
|
const shellExecutor = shellExecutorContext.getStore();
|
|
253
293
|
if (shellExecutor) {
|
|
254
294
|
return shellExecutor(
|
|
@@ -440,11 +480,13 @@ export function buildShellTool(projectRoot: string): {
|
|
|
440
480
|
return;
|
|
441
481
|
}
|
|
442
482
|
|
|
483
|
+
const discoveryHint = repositoryDiscoveryHint(finalCmd);
|
|
443
484
|
settle({
|
|
444
485
|
ok: true,
|
|
445
486
|
exitCode: exitCode ?? 0,
|
|
446
487
|
stdout,
|
|
447
488
|
stderr,
|
|
489
|
+
...(discoveryHint ? { discoveryHint } : {}),
|
|
448
490
|
...(outputMode === 'tail' || outputMode === 'auto'
|
|
449
491
|
? { outputMode, tailLines, maxOutputBytes }
|
|
450
492
|
: { outputMode, maxOutputBytes }),
|
|
@@ -8,6 +8,11 @@ For repository discovery, use `search` for content/code search and `glob` for fi
|
|
|
8
8
|
|
|
9
9
|
**Strongly prefer the `search` tool over `grep`/`rg`, and `glob` over `find`.** The `search` tool is indexed and faster, returns structured `file:line` matches, and supports regex, `glob` includes, `path` scoping, and `ignoreCase` — use it for all repository content search. Only fall back to `grep`/`rg` via shell for cases `search` cannot handle (e.g. gitignored files like node_modules or build output). Pipelines that filter program output (e.g. `ps aux | grep node`) are fine.
|
|
10
10
|
|
|
11
|
+
Mapping from common shell habits:
|
|
12
|
+
- `grep -r` / `rg` / `git grep` over repo files → use `search`.
|
|
13
|
+
- `find` / `fd` / recursive `ls` for filenames → use `glob`.
|
|
14
|
+
- Build, test, package manager, diagnostics, process inspection → use `shell`.
|
|
15
|
+
|
|
11
16
|
## Usage tips
|
|
12
17
|
|
|
13
18
|
- Chain commands with `&&` to fail-fast.
|
|
@@ -5,7 +5,10 @@ import { createToolError } from '../error.ts';
|
|
|
5
5
|
import type { TerminalManager } from '../../terminals/index.ts';
|
|
6
6
|
import type { TerminalStatus } from '../../terminals/terminal.ts';
|
|
7
7
|
import { normalizeTerminalLine } from '../../utils/ansi.ts';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
injectCoAuthorIntoGitCommit,
|
|
10
|
+
shouldCoAuthorCommits,
|
|
11
|
+
} from './git-identity.ts';
|
|
9
12
|
|
|
10
13
|
function shellQuote(segment: string): string {
|
|
11
14
|
if (/^[a-zA-Z0-9._-]+$/.test(segment)) {
|
|
@@ -108,6 +111,7 @@ export function buildTerminalTool(
|
|
|
108
111
|
execute: async (params) => {
|
|
109
112
|
try {
|
|
110
113
|
const { operation } = params;
|
|
114
|
+
const coAuthorCommits = shouldCoAuthorCommits(projectRoot);
|
|
111
115
|
|
|
112
116
|
switch (operation) {
|
|
113
117
|
case 'start': {
|
|
@@ -169,7 +173,9 @@ export function buildTerminalTool(
|
|
|
169
173
|
|
|
170
174
|
if (initialCommand) {
|
|
171
175
|
queueMicrotask(() => {
|
|
172
|
-
term.write(
|
|
176
|
+
term.write(
|
|
177
|
+
`${injectCoAuthorIntoGitCommit(initialCommand, coAuthorCommits)}\n`,
|
|
178
|
+
);
|
|
173
179
|
});
|
|
174
180
|
}
|
|
175
181
|
|
|
@@ -243,7 +249,9 @@ export function buildTerminalTool(
|
|
|
243
249
|
return createToolError(`Terminal ${params.terminalId} not found`);
|
|
244
250
|
}
|
|
245
251
|
|
|
246
|
-
term.write(
|
|
252
|
+
term.write(
|
|
253
|
+
injectCoAuthorIntoGitCommit(params.input, coAuthorCommits),
|
|
254
|
+
);
|
|
247
255
|
|
|
248
256
|
return {
|
|
249
257
|
ok: true,
|
|
@@ -142,7 +142,14 @@ async function discoverStaticProjectTools(
|
|
|
142
142
|
|
|
143
143
|
const discoveryPromise = (async () => {
|
|
144
144
|
const tools = new Map<string, Tool>();
|
|
145
|
-
|
|
145
|
+
const fsTools = buildFsTools(projectRoot);
|
|
146
|
+
for (const { name, tool } of fsTools.filter(({ name }) => name === 'read'))
|
|
147
|
+
tools.set(name, tool);
|
|
148
|
+
// Put apply_patch before exact replacement tools so models see it as the
|
|
149
|
+
// default editing path after reading files.
|
|
150
|
+
const ap = buildApplyPatchTool(projectRoot);
|
|
151
|
+
tools.set(ap.name, ap.tool);
|
|
152
|
+
for (const { name, tool } of fsTools.filter(({ name }) => name !== 'read'))
|
|
146
153
|
tools.set(name, tool);
|
|
147
154
|
for (const { name, tool } of buildGitTools(projectRoot))
|
|
148
155
|
tools.set(name, tool);
|
|
@@ -155,9 +162,6 @@ async function discoverStaticProjectTools(
|
|
|
155
162
|
tools.set(search.name, search.tool);
|
|
156
163
|
const glob = buildGlobTool(projectRoot);
|
|
157
164
|
tools.set(glob.name, glob.tool);
|
|
158
|
-
// Patch/apply
|
|
159
|
-
const ap = buildApplyPatchTool(projectRoot);
|
|
160
|
-
tools.set(ap.name, ap.tool);
|
|
161
165
|
// Todo tracking
|
|
162
166
|
tools.set('update_todos', updateTodosTool);
|
|
163
167
|
// Web search
|
package/src/index.ts
CHANGED
|
@@ -81,6 +81,7 @@ export type {
|
|
|
81
81
|
} from './providers/src/index.ts';
|
|
82
82
|
export {
|
|
83
83
|
isBuiltInProviderId,
|
|
84
|
+
resolveBuiltInProviderCatalogId,
|
|
84
85
|
getProviderSettings,
|
|
85
86
|
getProviderDefinition,
|
|
86
87
|
hasConfiguredProvider,
|
|
@@ -162,13 +163,9 @@ export { createOpencodeModel } from './providers/src/index.ts';
|
|
|
162
163
|
export type { OpencodeProviderConfig } from './providers/src/index.ts';
|
|
163
164
|
export {
|
|
164
165
|
createKimiModel,
|
|
165
|
-
createMoonshotModel,
|
|
166
166
|
readKimiApiKeyFromEnv,
|
|
167
167
|
} from './providers/src/index.ts';
|
|
168
|
-
export type {
|
|
169
|
-
KimiProviderConfig,
|
|
170
|
-
MoonshotProviderConfig,
|
|
171
|
-
} from './providers/src/index.ts';
|
|
168
|
+
export type { KimiProviderConfig } from './providers/src/index.ts';
|
|
172
169
|
export { createMinimaxModel } from './providers/src/index.ts';
|
|
173
170
|
export type { MinimaxProviderConfig } from './providers/src/index.ts';
|
|
174
171
|
export {
|
|
@@ -253,6 +250,20 @@ export type {
|
|
|
253
250
|
export { loadConfig, read as readConfig } from './config/src/index.ts';
|
|
254
251
|
export {
|
|
255
252
|
getLocalDataDir,
|
|
253
|
+
getLegacyProjectDataDir,
|
|
254
|
+
getOttoHomeDir,
|
|
255
|
+
getProjectsStateRoot,
|
|
256
|
+
getProjectId,
|
|
257
|
+
getProjectConfigDir,
|
|
258
|
+
getProjectConfigPath,
|
|
259
|
+
getProjectStateDir,
|
|
260
|
+
getProjectDbPath,
|
|
261
|
+
getProjectAttachmentsDir,
|
|
262
|
+
getProjectDebugDir,
|
|
263
|
+
getProjectDebugDumpsDir,
|
|
264
|
+
getProjectLogsDir,
|
|
265
|
+
getProjectTmpDir,
|
|
266
|
+
getProjectCacheDir,
|
|
256
267
|
getGlobalConfigDir,
|
|
257
268
|
getGlobalConfigPath,
|
|
258
269
|
getGlobalSkillsConfigPath,
|
|
@@ -334,6 +345,7 @@ export {
|
|
|
334
345
|
export {
|
|
335
346
|
appendCoAuthorTrailer,
|
|
336
347
|
injectCoAuthorIntoGitCommit,
|
|
348
|
+
shouldCoAuthorCommits,
|
|
337
349
|
OTTOCODE_BOT_NAME,
|
|
338
350
|
OTTOCODE_BOT_EMAIL,
|
|
339
351
|
OTTOCODE_CO_AUTHOR,
|
|
@@ -8,8 +8,8 @@ You help with coding and build tasks.
|
|
|
8
8
|
|
|
9
9
|
Pick the right tool for the job (each tool's description has its full contract):
|
|
10
10
|
|
|
11
|
-
-
|
|
12
|
-
- Use
|
|
11
|
+
- Prefer `apply_patch` for code and text changes when it is available. It gives the clearest diff preview and handles targeted, structural, and multi-file edits.
|
|
12
|
+
- Use exact-replacement tools (`edit`/`multiedit`) when a patch would be awkward, when you have a precise replacement block, or after patch attempts fail.
|
|
13
13
|
- Use `write` only for NEW files or >70% full-file rewrites. Never use it for targeted edits.
|
|
14
14
|
|
|
15
15
|
**Always read a file immediately before editing it.** Memory and earlier context are not reliable — the file may have changed.
|
|
@@ -14,7 +14,7 @@ import PROVIDER_ANTHROPIC from './providers/anthropic.txt' with {
|
|
|
14
14
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
15
15
|
import PROVIDER_GOOGLE from './providers/google.txt' with { type: 'text' };
|
|
16
16
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
17
|
-
import
|
|
17
|
+
import PROVIDER_KIMI from './providers/kimi.txt' with { type: 'text' };
|
|
18
18
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
19
19
|
import PROVIDER_DEFAULT from './providers/default.txt' with { type: 'text' };
|
|
20
20
|
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
|
|
@@ -24,7 +24,7 @@ const FAMILY_PROMPTS: Record<string, string> = {
|
|
|
24
24
|
openai: PROVIDER_OPENAI,
|
|
25
25
|
anthropic: PROVIDER_ANTHROPIC,
|
|
26
26
|
google: PROVIDER_GOOGLE,
|
|
27
|
-
|
|
27
|
+
kimi: PROVIDER_KIMI,
|
|
28
28
|
glm: PROVIDER_GLM,
|
|
29
29
|
minimax: PROVIDER_DEFAULT,
|
|
30
30
|
};
|
|
@@ -142,9 +142,9 @@ export async function providerBasePrompt(
|
|
|
142
142
|
const result = PROVIDER_GOOGLE.trim();
|
|
143
143
|
return { prompt: result, resolvedType: 'google' };
|
|
144
144
|
}
|
|
145
|
-
if (id === '
|
|
146
|
-
const result =
|
|
147
|
-
return { prompt: result, resolvedType: '
|
|
145
|
+
if (id === 'kimi') {
|
|
146
|
+
const result = PROVIDER_KIMI.trim();
|
|
147
|
+
return { prompt: result, resolvedType: 'kimi' };
|
|
148
148
|
}
|
|
149
149
|
if (id === 'zai' || id === 'zai-coding') {
|
|
150
150
|
const result = PROVIDER_GLM.trim();
|
|
@@ -46,7 +46,7 @@ const OWNER_NPM: Record<ModelOwner, string> = {
|
|
|
46
46
|
google: '@ai-sdk/google',
|
|
47
47
|
openrouter: '@openrouter/ai-sdk-provider',
|
|
48
48
|
xai: '@ai-sdk/xai',
|
|
49
|
-
|
|
49
|
+
kimi: '@ai-sdk/openai-compatible',
|
|
50
50
|
qwen: '@ai-sdk/openai-compatible',
|
|
51
51
|
zai: '@ai-sdk/openai-compatible',
|
|
52
52
|
minimax: '@ai-sdk/anthropic',
|
|
@@ -154,16 +154,61 @@ export function appendXaiGrokCliModels<T extends { models: ModelInfo[] }>(
|
|
|
154
154
|
return { ...entry, models: [...mergedModels, ...missingModels] };
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
+
const DEPRECATED_KIMI_MODEL_IDS = new Set([
|
|
158
|
+
'kimi-k2-0711-preview',
|
|
159
|
+
'kimi-k2-0905-preview',
|
|
160
|
+
'kimi-k2-thinking',
|
|
161
|
+
'kimi-k2-thinking-turbo',
|
|
162
|
+
'kimi-k2-turbo-preview',
|
|
163
|
+
]);
|
|
164
|
+
|
|
165
|
+
const KIMI_MANUAL_MODELS: ModelInfo[] = [
|
|
166
|
+
{
|
|
167
|
+
id: 'kimi-k2.7-code-highspeed',
|
|
168
|
+
ownedBy: 'kimi',
|
|
169
|
+
label: 'Kimi K2.7 Code Highspeed',
|
|
170
|
+
modalities: { input: ['text', 'image', 'video'], output: ['text'] },
|
|
171
|
+
toolCall: true,
|
|
172
|
+
reasoningText: true,
|
|
173
|
+
attachment: true,
|
|
174
|
+
temperature: false,
|
|
175
|
+
knowledge: '2025-01',
|
|
176
|
+
openWeights: true,
|
|
177
|
+
cost: { input: 1.9, output: 8, cacheRead: 0.38 },
|
|
178
|
+
limit: { context: 262_144, output: 262_144 },
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
export function filterAvailableKimiModels(models: ModelInfo[]): ModelInfo[] {
|
|
183
|
+
return models.filter((model) => !DEPRECATED_KIMI_MODEL_IDS.has(model.id));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function appendKimiManualModels(models: ModelInfo[]): ModelInfo[] {
|
|
187
|
+
const manualById = new Map(
|
|
188
|
+
KIMI_MANUAL_MODELS.map((model) => [model.id, model]),
|
|
189
|
+
);
|
|
190
|
+
const mergedModels = models.map((model) => {
|
|
191
|
+
const override = manualById.get(model.id);
|
|
192
|
+
return override ? { ...model, ...override } : model;
|
|
193
|
+
});
|
|
194
|
+
const existingIds = new Set(mergedModels.map((model) => model.id));
|
|
195
|
+
const missingModels = KIMI_MANUAL_MODELS.filter(
|
|
196
|
+
(model) => !existingIds.has(model.id),
|
|
197
|
+
);
|
|
198
|
+
return missingModels.length
|
|
199
|
+
? [...mergedModels, ...missingModels]
|
|
200
|
+
: mergedModels;
|
|
201
|
+
}
|
|
202
|
+
|
|
157
203
|
export function applyOfficialKimiCatalogMetadata<
|
|
158
204
|
T extends ProviderCatalogEntry,
|
|
159
205
|
>(entry: T | undefined): T | undefined {
|
|
160
206
|
if (!entry) return undefined;
|
|
161
|
-
const env = Array.from(
|
|
162
|
-
new Set(['KIMI_API_KEY', 'MOONSHOT_API_KEY', ...(entry.env ?? [])]),
|
|
163
|
-
);
|
|
207
|
+
const env = Array.from(new Set(['KIMI_API_KEY', ...(entry.env ?? [])]));
|
|
164
208
|
return {
|
|
165
209
|
...entry,
|
|
166
|
-
|
|
210
|
+
models: appendKimiManualModels(filterAvailableKimiModels(entry.models)),
|
|
211
|
+
label: 'Kimi',
|
|
167
212
|
env,
|
|
168
213
|
doc: 'https://platform.kimi.ai/docs/api/overview.md',
|
|
169
214
|
};
|
|
@@ -182,9 +227,9 @@ export function mergeManualCatalog(
|
|
|
182
227
|
if (xaiEntry) {
|
|
183
228
|
merged.xai = xaiEntry;
|
|
184
229
|
}
|
|
185
|
-
const
|
|
186
|
-
if (
|
|
187
|
-
merged.
|
|
230
|
+
const kimiEntry = applyOfficialKimiCatalogMetadata(merged.kimi);
|
|
231
|
+
if (kimiEntry) {
|
|
232
|
+
merged.kimi = kimiEntry;
|
|
188
233
|
}
|
|
189
234
|
if (manualEntry) {
|
|
190
235
|
merged[OTTOROUTER_ID] = manualEntry;
|