cerebras-cli 1.0.0
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/AGENTS.md +27 -0
- package/Dockerfile +10 -0
- package/README.md +15 -0
- package/bin/opencode +84 -0
- package/bunfig.toml +4 -0
- package/package.json +128 -0
- package/parsers-config.ts +239 -0
- package/script/build.ts +151 -0
- package/script/postinstall.mjs +122 -0
- package/script/publish.ts +256 -0
- package/script/schema.ts +47 -0
- package/src/acp/README.md +164 -0
- package/src/acp/agent.ts +812 -0
- package/src/acp/session.ts +70 -0
- package/src/acp/types.ts +22 -0
- package/src/agent/agent.ts +310 -0
- package/src/agent/generate.txt +75 -0
- package/src/auth/index.ts +70 -0
- package/src/bun/index.ts +152 -0
- package/src/bus/global.ts +10 -0
- package/src/bus/index.ts +142 -0
- package/src/cli/bootstrap.ts +17 -0
- package/src/cli/cmd/acp.ts +88 -0
- package/src/cli/cmd/agent.ts +165 -0
- package/src/cli/cmd/auth.ts +369 -0
- package/src/cli/cmd/cmd.ts +7 -0
- package/src/cli/cmd/debug/config.ts +15 -0
- package/src/cli/cmd/debug/file.ts +91 -0
- package/src/cli/cmd/debug/index.ts +41 -0
- package/src/cli/cmd/debug/lsp.ts +47 -0
- package/src/cli/cmd/debug/ripgrep.ts +83 -0
- package/src/cli/cmd/debug/scrap.ts +15 -0
- package/src/cli/cmd/debug/snapshot.ts +48 -0
- package/src/cli/cmd/export.ts +88 -0
- package/src/cli/cmd/generate.ts +38 -0
- package/src/cli/cmd/github.ts +1200 -0
- package/src/cli/cmd/import.ts +98 -0
- package/src/cli/cmd/mcp.ts +400 -0
- package/src/cli/cmd/models.ts +77 -0
- package/src/cli/cmd/pr.ts +112 -0
- package/src/cli/cmd/run.ts +342 -0
- package/src/cli/cmd/serve.ts +31 -0
- package/src/cli/cmd/session.ts +106 -0
- package/src/cli/cmd/stats.ts +298 -0
- package/src/cli/cmd/tui/app.tsx +732 -0
- package/src/cli/cmd/tui/attach.ts +25 -0
- package/src/cli/cmd/tui/component/border.tsx +21 -0
- package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-command.tsx +124 -0
- package/src/cli/cmd/tui/component/dialog-feedback.tsx +160 -0
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
- package/src/cli/cmd/tui/component/dialog-model.tsx +223 -0
- package/src/cli/cmd/tui/component/dialog-notification.tsx +78 -0
- package/src/cli/cmd/tui/component/dialog-provider.tsx +222 -0
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +97 -0
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
- package/src/cli/cmd/tui/component/dialog-status.tsx +114 -0
- package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +50 -0
- package/src/cli/cmd/tui/component/logo.tsx +37 -0
- package/src/cli/cmd/tui/component/notification-banner.tsx +58 -0
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +530 -0
- package/src/cli/cmd/tui/component/prompt/history.tsx +107 -0
- package/src/cli/cmd/tui/component/prompt/index.tsx +931 -0
- package/src/cli/cmd/tui/context/args.tsx +14 -0
- package/src/cli/cmd/tui/context/directory.ts +12 -0
- package/src/cli/cmd/tui/context/exit.tsx +23 -0
- package/src/cli/cmd/tui/context/helper.tsx +25 -0
- package/src/cli/cmd/tui/context/keybind.tsx +111 -0
- package/src/cli/cmd/tui/context/kv.tsx +49 -0
- package/src/cli/cmd/tui/context/local.tsx +339 -0
- package/src/cli/cmd/tui/context/prompt.tsx +18 -0
- package/src/cli/cmd/tui/context/route.tsx +45 -0
- package/src/cli/cmd/tui/context/sdk.tsx +75 -0
- package/src/cli/cmd/tui/context/sync.tsx +374 -0
- package/src/cli/cmd/tui/context/theme/aura.json +69 -0
- package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
- package/src/cli/cmd/tui/context/theme/catppuccin.json +112 -0
- package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
- package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
- package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
- package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
- package/src/cli/cmd/tui/context/theme/github.json +233 -0
- package/src/cli/cmd/tui/context/theme/gruvbox.json +95 -0
- package/src/cli/cmd/tui/context/theme/kanagawa.json +77 -0
- package/src/cli/cmd/tui/context/theme/material.json +235 -0
- package/src/cli/cmd/tui/context/theme/matrix.json +77 -0
- package/src/cli/cmd/tui/context/theme/mercury.json +252 -0
- package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
- package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
- package/src/cli/cmd/tui/context/theme/nord.json +223 -0
- package/src/cli/cmd/tui/context/theme/one-dark.json +84 -0
- package/src/cli/cmd/tui/context/theme/orng.json +245 -0
- package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
- package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
- package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
- package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
- package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
- package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
- package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
- package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
- package/src/cli/cmd/tui/context/theme.tsx +1077 -0
- package/src/cli/cmd/tui/event.ts +39 -0
- package/src/cli/cmd/tui/routes/home.tsx +104 -0
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +93 -0
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +37 -0
- package/src/cli/cmd/tui/routes/session/footer.tsx +76 -0
- package/src/cli/cmd/tui/routes/session/header.tsx +183 -0
- package/src/cli/cmd/tui/routes/session/index.tsx +1703 -0
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +586 -0
- package/src/cli/cmd/tui/spawn.ts +60 -0
- package/src/cli/cmd/tui/thread.ts +120 -0
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +55 -0
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +81 -0
- package/src/cli/cmd/tui/ui/dialog-help.tsx +36 -0
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +75 -0
- package/src/cli/cmd/tui/ui/dialog-select.tsx +317 -0
- package/src/cli/cmd/tui/ui/dialog.tsx +170 -0
- package/src/cli/cmd/tui/ui/spinner.ts +368 -0
- package/src/cli/cmd/tui/ui/toast.tsx +100 -0
- package/src/cli/cmd/tui/util/clipboard.ts +127 -0
- package/src/cli/cmd/tui/util/editor.ts +32 -0
- package/src/cli/cmd/tui/util/terminal.ts +114 -0
- package/src/cli/cmd/tui/worker.ts +63 -0
- package/src/cli/cmd/uninstall.ts +344 -0
- package/src/cli/cmd/upgrade.ts +67 -0
- package/src/cli/cmd/web.ts +84 -0
- package/src/cli/error.ts +55 -0
- package/src/cli/ui.ts +84 -0
- package/src/cli/upgrade.ts +25 -0
- package/src/command/index.ts +79 -0
- package/src/command/template/initialize.txt +10 -0
- package/src/command/template/review.txt +73 -0
- package/src/config/config.ts +886 -0
- package/src/config/markdown.ts +41 -0
- package/src/env/index.ts +26 -0
- package/src/file/fzf.ts +124 -0
- package/src/file/ignore.ts +83 -0
- package/src/file/index.ts +326 -0
- package/src/file/ripgrep.ts +391 -0
- package/src/file/time.ts +38 -0
- package/src/file/watcher.ts +89 -0
- package/src/flag/flag.ts +28 -0
- package/src/format/formatter.ts +277 -0
- package/src/format/index.ts +137 -0
- package/src/global/index.ts +52 -0
- package/src/id/id.ts +73 -0
- package/src/ide/index.ts +75 -0
- package/src/index.ts +158 -0
- package/src/installation/index.ts +194 -0
- package/src/lsp/client.ts +215 -0
- package/src/lsp/index.ts +370 -0
- package/src/lsp/language.ts +111 -0
- package/src/lsp/server.ts +1327 -0
- package/src/mcp/auth.ts +82 -0
- package/src/mcp/index.ts +576 -0
- package/src/mcp/oauth-callback.ts +203 -0
- package/src/mcp/oauth-provider.ts +132 -0
- package/src/notification/index.ts +101 -0
- package/src/patch/index.ts +622 -0
- package/src/permission/index.ts +198 -0
- package/src/plugin/index.ts +95 -0
- package/src/project/bootstrap.ts +31 -0
- package/src/project/instance.ts +68 -0
- package/src/project/project.ts +133 -0
- package/src/project/state.ts +65 -0
- package/src/project/vcs.ts +77 -0
- package/src/provider/auth.ts +143 -0
- package/src/provider/models-macro.ts +11 -0
- package/src/provider/models.ts +93 -0
- package/src/provider/provider.ts +996 -0
- package/src/provider/sdk/openai-compatible/src/README.md +5 -0
- package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
- package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
- package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
- package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +27 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1713 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
- package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
- package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
- package/src/provider/transform.ts +406 -0
- package/src/pty/index.ts +226 -0
- package/src/ratelimit/index.ts +185 -0
- package/src/server/error.ts +36 -0
- package/src/server/project.ts +50 -0
- package/src/server/server.ts +2463 -0
- package/src/server/tui.ts +71 -0
- package/src/session/compaction.ts +257 -0
- package/src/session/index.ts +470 -0
- package/src/session/message-v2.ts +641 -0
- package/src/session/message.ts +189 -0
- package/src/session/processor.ts +443 -0
- package/src/session/prompt/anthropic-20250930.txt +166 -0
- package/src/session/prompt/anthropic.txt +105 -0
- package/src/session/prompt/anthropic_spoof.txt +1 -0
- package/src/session/prompt/beast.txt +147 -0
- package/src/session/prompt/build-switch.txt +5 -0
- package/src/session/prompt/codex.txt +318 -0
- package/src/session/prompt/compaction.txt +12 -0
- package/src/session/prompt/copilot-gpt-5.txt +143 -0
- package/src/session/prompt/gemini.txt +155 -0
- package/src/session/prompt/max-steps.txt +16 -0
- package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
- package/src/session/prompt/plan.txt +26 -0
- package/src/session/prompt/polaris.txt +107 -0
- package/src/session/prompt/qwen.txt +109 -0
- package/src/session/prompt/summarize.txt +4 -0
- package/src/session/prompt/title.txt +36 -0
- package/src/session/prompt.ts +1541 -0
- package/src/session/retry.ts +82 -0
- package/src/session/revert.ts +108 -0
- package/src/session/status.ts +75 -0
- package/src/session/summary.ts +203 -0
- package/src/session/system.ts +148 -0
- package/src/session/todo.ts +36 -0
- package/src/share/share-next.ts +195 -0
- package/src/share/share.ts +87 -0
- package/src/snapshot/index.ts +197 -0
- package/src/storage/storage.ts +226 -0
- package/src/telemetry/index.ts +232 -0
- package/src/tool/bash.ts +365 -0
- package/src/tool/bash.txt +128 -0
- package/src/tool/batch.ts +173 -0
- package/src/tool/batch.txt +28 -0
- package/src/tool/codesearch.ts +138 -0
- package/src/tool/codesearch.txt +12 -0
- package/src/tool/edit.ts +674 -0
- package/src/tool/edit.txt +10 -0
- package/src/tool/glob.ts +65 -0
- package/src/tool/glob.txt +6 -0
- package/src/tool/grep.ts +120 -0
- package/src/tool/grep.txt +8 -0
- package/src/tool/invalid.ts +17 -0
- package/src/tool/ls.ts +110 -0
- package/src/tool/ls.txt +1 -0
- package/src/tool/lsp-diagnostics.ts +26 -0
- package/src/tool/lsp-diagnostics.txt +1 -0
- package/src/tool/lsp-hover.ts +31 -0
- package/src/tool/lsp-hover.txt +1 -0
- package/src/tool/multiedit.ts +46 -0
- package/src/tool/multiedit.txt +41 -0
- package/src/tool/patch.ts +233 -0
- package/src/tool/patch.txt +1 -0
- package/src/tool/read.ts +217 -0
- package/src/tool/read.txt +12 -0
- package/src/tool/registry.ts +148 -0
- package/src/tool/task.ts +135 -0
- package/src/tool/task.txt +60 -0
- package/src/tool/todo.ts +39 -0
- package/src/tool/todoread.txt +14 -0
- package/src/tool/todowrite.txt +167 -0
- package/src/tool/tool.ts +66 -0
- package/src/tool/webfetch.ts +187 -0
- package/src/tool/webfetch.txt +14 -0
- package/src/tool/websearch.ts +150 -0
- package/src/tool/websearch.txt +11 -0
- package/src/tool/write.ts +99 -0
- package/src/tool/write.txt +8 -0
- package/src/types/shims.d.ts +3 -0
- package/src/util/color.ts +19 -0
- package/src/util/context.ts +25 -0
- package/src/util/defer.ts +12 -0
- package/src/util/eventloop.ts +20 -0
- package/src/util/filesystem.ts +69 -0
- package/src/util/fn.ts +11 -0
- package/src/util/iife.ts +3 -0
- package/src/util/keybind.ts +79 -0
- package/src/util/lazy.ts +11 -0
- package/src/util/locale.ts +81 -0
- package/src/util/lock.ts +98 -0
- package/src/util/log.ts +177 -0
- package/src/util/queue.ts +32 -0
- package/src/util/rpc.ts +42 -0
- package/src/util/scrap.ts +10 -0
- package/src/util/signal.ts +12 -0
- package/src/util/timeout.ts +14 -0
- package/src/util/token.ts +7 -0
- package/src/util/wildcard.ts +54 -0
- package/sst-env.d.ts +9 -0
- package/test/bun.test.ts +53 -0
- package/test/config/agent-color.test.ts +66 -0
- package/test/config/config.test.ts +503 -0
- package/test/config/markdown.test.ts +89 -0
- package/test/file/ignore.test.ts +10 -0
- package/test/fixture/fixture.ts +28 -0
- package/test/fixture/lsp/fake-lsp-server.js +77 -0
- package/test/ide/ide.test.ts +82 -0
- package/test/keybind.test.ts +317 -0
- package/test/lsp/client.test.ts +95 -0
- package/test/patch/patch.test.ts +348 -0
- package/test/preload.ts +38 -0
- package/test/project/project.test.ts +42 -0
- package/test/provider/provider.test.ts +1809 -0
- package/test/provider/transform.test.ts +305 -0
- package/test/session/retry.test.ts +61 -0
- package/test/session/session.test.ts +71 -0
- package/test/snapshot/snapshot.test.ts +939 -0
- package/test/tool/__snapshots__/tool.test.ts.snap +9 -0
- package/test/tool/bash.test.ts +55 -0
- package/test/tool/patch.test.ts +259 -0
- package/test/util/iife.test.ts +36 -0
- package/test/util/lazy.test.ts +50 -0
- package/test/util/timeout.test.ts +21 -0
- package/test/util/wildcard.test.ts +55 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createProviderDefinedToolFactory } from "@ai-sdk/provider-utils"
|
|
2
|
+
import { z } from "zod/v4"
|
|
3
|
+
|
|
4
|
+
export const webSearchArgsSchema = z.object({
|
|
5
|
+
filters: z
|
|
6
|
+
.object({
|
|
7
|
+
allowedDomains: z.array(z.string()).optional(),
|
|
8
|
+
})
|
|
9
|
+
.optional(),
|
|
10
|
+
|
|
11
|
+
searchContextSize: z.enum(["low", "medium", "high"]).optional(),
|
|
12
|
+
|
|
13
|
+
userLocation: z
|
|
14
|
+
.object({
|
|
15
|
+
type: z.literal("approximate"),
|
|
16
|
+
country: z.string().optional(),
|
|
17
|
+
city: z.string().optional(),
|
|
18
|
+
region: z.string().optional(),
|
|
19
|
+
timezone: z.string().optional(),
|
|
20
|
+
})
|
|
21
|
+
.optional(),
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
export const webSearchToolFactory = createProviderDefinedToolFactory<
|
|
25
|
+
{
|
|
26
|
+
// Web search doesn't take input parameters - it's controlled by the prompt
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
/**
|
|
30
|
+
* Filters for the search.
|
|
31
|
+
*/
|
|
32
|
+
filters?: {
|
|
33
|
+
/**
|
|
34
|
+
* Allowed domains for the search.
|
|
35
|
+
* If not provided, all domains are allowed.
|
|
36
|
+
* Subdomains of the provided domains are allowed as well.
|
|
37
|
+
*/
|
|
38
|
+
allowedDomains?: string[]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Search context size to use for the web search.
|
|
43
|
+
* - high: Most comprehensive context, highest cost, slower response
|
|
44
|
+
* - medium: Balanced context, cost, and latency (default)
|
|
45
|
+
* - low: Least context, lowest cost, fastest response
|
|
46
|
+
*/
|
|
47
|
+
searchContextSize?: "low" | "medium" | "high"
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* User location information to provide geographically relevant search results.
|
|
51
|
+
*/
|
|
52
|
+
userLocation?: {
|
|
53
|
+
/**
|
|
54
|
+
* Type of location (always 'approximate')
|
|
55
|
+
*/
|
|
56
|
+
type: "approximate"
|
|
57
|
+
/**
|
|
58
|
+
* Two-letter ISO country code (e.g., 'US', 'GB')
|
|
59
|
+
*/
|
|
60
|
+
country?: string
|
|
61
|
+
/**
|
|
62
|
+
* City name (free text, e.g., 'Minneapolis')
|
|
63
|
+
*/
|
|
64
|
+
city?: string
|
|
65
|
+
/**
|
|
66
|
+
* Region name (free text, e.g., 'Minnesota')
|
|
67
|
+
*/
|
|
68
|
+
region?: string
|
|
69
|
+
/**
|
|
70
|
+
* IANA timezone (e.g., 'America/Chicago')
|
|
71
|
+
*/
|
|
72
|
+
timezone?: string
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
>({
|
|
76
|
+
id: "openai.web_search",
|
|
77
|
+
name: "web_search",
|
|
78
|
+
inputSchema: z.object({
|
|
79
|
+
action: z
|
|
80
|
+
.discriminatedUnion("type", [
|
|
81
|
+
z.object({
|
|
82
|
+
type: z.literal("search"),
|
|
83
|
+
query: z.string().nullish(),
|
|
84
|
+
}),
|
|
85
|
+
z.object({
|
|
86
|
+
type: z.literal("open_page"),
|
|
87
|
+
url: z.string(),
|
|
88
|
+
}),
|
|
89
|
+
z.object({
|
|
90
|
+
type: z.literal("find"),
|
|
91
|
+
url: z.string(),
|
|
92
|
+
pattern: z.string(),
|
|
93
|
+
}),
|
|
94
|
+
])
|
|
95
|
+
.nullish(),
|
|
96
|
+
}),
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
export const webSearch = (
|
|
100
|
+
args: Parameters<typeof webSearchToolFactory>[0] = {}, // default
|
|
101
|
+
) => {
|
|
102
|
+
return webSearchToolFactory(args)
|
|
103
|
+
}
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
import type { APICallError, ModelMessage } from "ai"
|
|
2
|
+
import { unique } from "remeda"
|
|
3
|
+
import type { JSONSchema } from "zod/v4/core"
|
|
4
|
+
import type { Provider } from "./provider"
|
|
5
|
+
import type { ModelsDev } from "./models"
|
|
6
|
+
|
|
7
|
+
type Modality = NonNullable<ModelsDev.Model["modalities"]>["input"][number]
|
|
8
|
+
|
|
9
|
+
function mimeToModality(mime: string): Modality | undefined {
|
|
10
|
+
if (mime.startsWith("image/")) return "image"
|
|
11
|
+
if (mime.startsWith("audio/")) return "audio"
|
|
12
|
+
if (mime.startsWith("video/")) return "video"
|
|
13
|
+
if (mime === "application/pdf") return "pdf"
|
|
14
|
+
return undefined
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export namespace ProviderTransform {
|
|
18
|
+
function normalizeMessages(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
|
19
|
+
if (model.api.id.includes("claude")) {
|
|
20
|
+
return msgs.map((msg) => {
|
|
21
|
+
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
|
|
22
|
+
msg.content = msg.content.map((part) => {
|
|
23
|
+
if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
|
|
24
|
+
return {
|
|
25
|
+
...part,
|
|
26
|
+
toolCallId: part.toolCallId.replace(/[^a-zA-Z0-9_-]/g, "_"),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return part
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
return msg
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
if (model.providerID === "mistral" || model.api.id.toLowerCase().includes("mistral")) {
|
|
36
|
+
const result: ModelMessage[] = []
|
|
37
|
+
for (let i = 0; i < msgs.length; i++) {
|
|
38
|
+
const msg = msgs[i]
|
|
39
|
+
const nextMsg = msgs[i + 1]
|
|
40
|
+
|
|
41
|
+
if ((msg.role === "assistant" || msg.role === "tool") && Array.isArray(msg.content)) {
|
|
42
|
+
msg.content = msg.content.map((part) => {
|
|
43
|
+
if ((part.type === "tool-call" || part.type === "tool-result") && "toolCallId" in part) {
|
|
44
|
+
// Mistral requires alphanumeric tool call IDs with exactly 9 characters
|
|
45
|
+
const normalizedId = part.toolCallId
|
|
46
|
+
.replace(/[^a-zA-Z0-9]/g, "") // Remove non-alphanumeric characters
|
|
47
|
+
.substring(0, 9) // Take first 9 characters
|
|
48
|
+
.padEnd(9, "0") // Pad with zeros if less than 9 characters
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
...part,
|
|
52
|
+
toolCallId: normalizedId,
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return part
|
|
56
|
+
})
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
result.push(msg)
|
|
60
|
+
|
|
61
|
+
// Fix message sequence: tool messages cannot be followed by user messages
|
|
62
|
+
if (msg.role === "tool" && nextMsg?.role === "user") {
|
|
63
|
+
result.push({
|
|
64
|
+
role: "assistant",
|
|
65
|
+
content: [
|
|
66
|
+
{
|
|
67
|
+
type: "text",
|
|
68
|
+
text: "Done.",
|
|
69
|
+
},
|
|
70
|
+
],
|
|
71
|
+
})
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return result
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// DeepSeek: Handle reasoning_content for tool call continuations
|
|
78
|
+
// - With tool calls: Include reasoning_content in providerOptions so model can continue reasoning
|
|
79
|
+
// - Without tool calls: Strip reasoning (new turn doesn't need previous reasoning)
|
|
80
|
+
// See: https://api-docs.deepseek.com/guides/thinking_mode
|
|
81
|
+
if (model.providerID === "deepseek" || model.api.id.toLowerCase().includes("deepseek")) {
|
|
82
|
+
return msgs.map((msg) => {
|
|
83
|
+
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
84
|
+
const reasoningParts = msg.content.filter((part: any) => part.type === "reasoning")
|
|
85
|
+
const hasToolCalls = msg.content.some((part: any) => part.type === "tool-call")
|
|
86
|
+
const reasoningText = reasoningParts.map((part: any) => part.text).join("")
|
|
87
|
+
|
|
88
|
+
// Filter out reasoning parts from content
|
|
89
|
+
const filteredContent = msg.content.filter((part: any) => part.type !== "reasoning")
|
|
90
|
+
|
|
91
|
+
// If this message has tool calls and reasoning, include reasoning_content
|
|
92
|
+
// so DeepSeek can continue reasoning after tool execution
|
|
93
|
+
if (hasToolCalls && reasoningText) {
|
|
94
|
+
return {
|
|
95
|
+
...msg,
|
|
96
|
+
content: filteredContent,
|
|
97
|
+
providerOptions: {
|
|
98
|
+
...msg.providerOptions,
|
|
99
|
+
openaiCompatible: {
|
|
100
|
+
...(msg.providerOptions as any)?.openaiCompatible,
|
|
101
|
+
reasoning_content: reasoningText,
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// For final answers (no tool calls), just strip reasoning
|
|
108
|
+
return {
|
|
109
|
+
...msg,
|
|
110
|
+
content: filteredContent,
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return msg
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return msgs
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function applyCaching(msgs: ModelMessage[], providerID: string): ModelMessage[] {
|
|
121
|
+
const system = msgs.filter((msg) => msg.role === "system").slice(0, 2)
|
|
122
|
+
const final = msgs.filter((msg) => msg.role !== "system").slice(-2)
|
|
123
|
+
|
|
124
|
+
const providerOptions = {
|
|
125
|
+
anthropic: {
|
|
126
|
+
cacheControl: { type: "ephemeral" },
|
|
127
|
+
},
|
|
128
|
+
openrouter: {
|
|
129
|
+
cache_control: { type: "ephemeral" },
|
|
130
|
+
},
|
|
131
|
+
bedrock: {
|
|
132
|
+
cachePoint: { type: "ephemeral" },
|
|
133
|
+
},
|
|
134
|
+
openaiCompatible: {
|
|
135
|
+
cache_control: { type: "ephemeral" },
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
for (const msg of unique([...system, ...final])) {
|
|
140
|
+
const shouldUseContentOptions = providerID !== "anthropic" && Array.isArray(msg.content) && msg.content.length > 0
|
|
141
|
+
|
|
142
|
+
if (shouldUseContentOptions) {
|
|
143
|
+
const lastContent = msg.content[msg.content.length - 1]
|
|
144
|
+
if (lastContent && typeof lastContent === "object") {
|
|
145
|
+
lastContent.providerOptions = {
|
|
146
|
+
...lastContent.providerOptions,
|
|
147
|
+
...providerOptions,
|
|
148
|
+
}
|
|
149
|
+
continue
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
msg.providerOptions = {
|
|
154
|
+
...msg.providerOptions,
|
|
155
|
+
...providerOptions,
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return msgs
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
|
163
|
+
return msgs.map((msg) => {
|
|
164
|
+
if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
|
|
165
|
+
|
|
166
|
+
const filtered = msg.content.map((part) => {
|
|
167
|
+
if (part.type !== "file" && part.type !== "image") return part
|
|
168
|
+
|
|
169
|
+
const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
|
|
170
|
+
const filename = part.type === "file" ? part.filename : undefined
|
|
171
|
+
const modality = mimeToModality(mime)
|
|
172
|
+
if (!modality) return part
|
|
173
|
+
if (model.capabilities.input[modality]) return part
|
|
174
|
+
|
|
175
|
+
const name = filename ? `"${filename}"` : modality
|
|
176
|
+
return {
|
|
177
|
+
type: "text" as const,
|
|
178
|
+
text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
|
|
179
|
+
}
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
return { ...msg, content: filtered }
|
|
183
|
+
})
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function message(msgs: ModelMessage[], model: Provider.Model) {
|
|
187
|
+
msgs = unsupportedParts(msgs, model)
|
|
188
|
+
msgs = normalizeMessages(msgs, model)
|
|
189
|
+
if (model.providerID === "anthropic" || model.api.id.includes("anthropic") || model.api.id.includes("claude")) {
|
|
190
|
+
msgs = applyCaching(msgs, model.providerID)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return msgs
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
export function temperature(model: Provider.Model) {
|
|
197
|
+
if (model.api.id.toLowerCase().includes("qwen")) return 0.55
|
|
198
|
+
if (model.api.id.toLowerCase().includes("claude")) return undefined
|
|
199
|
+
if (model.api.id.toLowerCase().includes("gemini-3-pro")) return 1.0
|
|
200
|
+
return 0
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export function topP(model: Provider.Model) {
|
|
204
|
+
if (model.api.id.toLowerCase().includes("qwen")) return 1
|
|
205
|
+
return undefined
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function options(
|
|
209
|
+
model: Provider.Model,
|
|
210
|
+
sessionID: string,
|
|
211
|
+
providerOptions?: Record<string, any>,
|
|
212
|
+
): Record<string, any> {
|
|
213
|
+
const result: Record<string, any> = {}
|
|
214
|
+
|
|
215
|
+
// switch to providerID later, for now use this
|
|
216
|
+
if (model.api.npm === "@openrouter/ai-sdk-provider") {
|
|
217
|
+
result["usage"] = {
|
|
218
|
+
include: true,
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (model.providerID === "openai" || providerOptions?.setCacheKey) {
|
|
223
|
+
result["promptCacheKey"] = sessionID
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (
|
|
227
|
+
model.providerID === "google" ||
|
|
228
|
+
(model.providerID.startsWith("opencode") && model.api.id.includes("gemini-3"))
|
|
229
|
+
) {
|
|
230
|
+
result["thinkingConfig"] = {
|
|
231
|
+
includeThoughts: true,
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (model.api.id.includes("gpt-5") && !model.api.id.includes("gpt-5-chat")) {
|
|
236
|
+
if (model.providerID.includes("codex")) {
|
|
237
|
+
result["store"] = false
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (!model.api.id.includes("codex") && !model.api.id.includes("gpt-5-pro")) {
|
|
241
|
+
result["reasoningEffort"] = "medium"
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (model.api.id.endsWith("gpt-5.1") && model.providerID !== "azure") {
|
|
245
|
+
result["textVerbosity"] = "low"
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if (model.providerID.startsWith("opencode")) {
|
|
249
|
+
result["promptCacheKey"] = sessionID
|
|
250
|
+
result["include"] = ["reasoning.encrypted_content"]
|
|
251
|
+
result["reasoningSummary"] = "auto"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return result
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function smallOptions(model: Provider.Model) {
|
|
258
|
+
const options: Record<string, any> = {}
|
|
259
|
+
|
|
260
|
+
if (model.providerID === "openai" || model.api.id.includes("gpt-5")) {
|
|
261
|
+
if (model.api.id.includes("5.1")) {
|
|
262
|
+
options["reasoningEffort"] = "low"
|
|
263
|
+
} else {
|
|
264
|
+
options["reasoningEffort"] = "minimal"
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if (model.providerID === "google") {
|
|
268
|
+
options["thinkingConfig"] = {
|
|
269
|
+
thinkingBudget: 0,
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
return options
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export function providerOptions(npm: string | undefined, providerID: string, options: { [x: string]: any }) {
|
|
277
|
+
switch (npm) {
|
|
278
|
+
case "@ai-sdk/openai":
|
|
279
|
+
case "@ai-sdk/azure":
|
|
280
|
+
return {
|
|
281
|
+
["openai" as string]: options,
|
|
282
|
+
}
|
|
283
|
+
case "@ai-sdk/amazon-bedrock":
|
|
284
|
+
return {
|
|
285
|
+
["bedrock" as string]: options,
|
|
286
|
+
}
|
|
287
|
+
case "@ai-sdk/anthropic":
|
|
288
|
+
return {
|
|
289
|
+
["anthropic" as string]: options,
|
|
290
|
+
}
|
|
291
|
+
case "@ai-sdk/google":
|
|
292
|
+
return {
|
|
293
|
+
["google" as string]: options,
|
|
294
|
+
}
|
|
295
|
+
case "@ai-sdk/gateway":
|
|
296
|
+
return {
|
|
297
|
+
["gateway" as string]: options,
|
|
298
|
+
}
|
|
299
|
+
case "@openrouter/ai-sdk-provider":
|
|
300
|
+
return {
|
|
301
|
+
["openrouter" as string]: options,
|
|
302
|
+
}
|
|
303
|
+
default:
|
|
304
|
+
return {
|
|
305
|
+
[providerID]: options,
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function maxOutputTokens(
|
|
311
|
+
npm: string,
|
|
312
|
+
options: Record<string, any>,
|
|
313
|
+
modelLimit: number,
|
|
314
|
+
globalLimit: number,
|
|
315
|
+
): number {
|
|
316
|
+
const modelCap = modelLimit || globalLimit
|
|
317
|
+
const standardLimit = Math.min(modelCap, globalLimit)
|
|
318
|
+
|
|
319
|
+
if (npm === "@ai-sdk/anthropic") {
|
|
320
|
+
const thinking = options?.["thinking"]
|
|
321
|
+
const budgetTokens = typeof thinking?.["budgetTokens"] === "number" ? thinking["budgetTokens"] : 0
|
|
322
|
+
const enabled = thinking?.["type"] === "enabled"
|
|
323
|
+
if (enabled && budgetTokens > 0) {
|
|
324
|
+
// Return text tokens so that text + thinking <= model cap, preferring 32k text when possible.
|
|
325
|
+
if (budgetTokens + standardLimit <= modelCap) {
|
|
326
|
+
return standardLimit
|
|
327
|
+
}
|
|
328
|
+
return modelCap - budgetTokens
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
return standardLimit
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
export function schema(model: Provider.Model, schema: JSONSchema.BaseSchema) {
|
|
336
|
+
/*
|
|
337
|
+
if (["openai", "azure"].includes(providerID)) {
|
|
338
|
+
if (schema.type === "object" && schema.properties) {
|
|
339
|
+
for (const [key, value] of Object.entries(schema.properties)) {
|
|
340
|
+
if (schema.required?.includes(key)) continue
|
|
341
|
+
schema.properties[key] = {
|
|
342
|
+
anyOf: [
|
|
343
|
+
value as JSONSchema.JSONSchema,
|
|
344
|
+
{
|
|
345
|
+
type: "null",
|
|
346
|
+
},
|
|
347
|
+
],
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
*/
|
|
353
|
+
|
|
354
|
+
// Convert integer enums to string enums for Google/Gemini
|
|
355
|
+
if (model.providerID === "google" || model.api.id.includes("gemini")) {
|
|
356
|
+
const sanitizeGemini = (obj: any): any => {
|
|
357
|
+
if (obj === null || typeof obj !== "object") {
|
|
358
|
+
return obj
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
if (Array.isArray(obj)) {
|
|
362
|
+
return obj.map(sanitizeGemini)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const result: any = {}
|
|
366
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
367
|
+
if (key === "enum" && Array.isArray(value)) {
|
|
368
|
+
// Convert all enum values to strings
|
|
369
|
+
result[key] = value.map((v) => String(v))
|
|
370
|
+
// If we have integer type with enum, change type to string
|
|
371
|
+
if (result.type === "integer" || result.type === "number") {
|
|
372
|
+
result.type = "string"
|
|
373
|
+
}
|
|
374
|
+
} else if (typeof value === "object" && value !== null) {
|
|
375
|
+
result[key] = sanitizeGemini(value)
|
|
376
|
+
} else {
|
|
377
|
+
result[key] = value
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Filter required array to only include fields that exist in properties
|
|
382
|
+
if (result.type === "object" && result.properties && Array.isArray(result.required)) {
|
|
383
|
+
result.required = result.required.filter((field: any) => field in result.properties)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return result
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
schema = sanitizeGemini(schema)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
return schema
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function error(providerID: string, error: APICallError) {
|
|
396
|
+
let message = error.message
|
|
397
|
+
if (providerID === "github-copilot" && message.includes("The requested model is not supported")) {
|
|
398
|
+
return (
|
|
399
|
+
message +
|
|
400
|
+
"\n\nMake sure the model is enabled in your copilot settings: https://github.com/settings/copilot/features"
|
|
401
|
+
)
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
return message
|
|
405
|
+
}
|
|
406
|
+
}
|