chad-code 1.3.1 → 1.3.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/README.md +55 -6
- package/package.json +36 -98
- package/AGENTS.md +0 -27
- package/Dockerfile +0 -18
- package/README.npm.md +0 -64
- package/bunfig.toml +0 -7
- package/eslint.config.js +0 -29
- package/parsers-config.ts +0 -253
- package/script/build.ts +0 -167
- package/script/publish-registries.ts +0 -187
- package/script/publish.ts +0 -93
- package/script/schema.ts +0 -47
- package/src/acp/README.md +0 -164
- package/src/acp/agent.ts +0 -1086
- package/src/acp/session.ts +0 -101
- package/src/acp/types.ts +0 -22
- package/src/agent/agent.ts +0 -253
- package/src/agent/generate.txt +0 -75
- package/src/agent/prompt/compaction.txt +0 -12
- package/src/agent/prompt/explore.txt +0 -18
- package/src/agent/prompt/summary.txt +0 -11
- package/src/agent/prompt/title.txt +0 -36
- package/src/auth/index.ts +0 -70
- package/src/bun/index.ts +0 -130
- package/src/bus/bus-event.ts +0 -43
- package/src/bus/global.ts +0 -10
- package/src/bus/index.ts +0 -105
- package/src/cli/bootstrap.ts +0 -17
- package/src/cli/cmd/acp.ts +0 -69
- package/src/cli/cmd/agent.ts +0 -257
- package/src/cli/cmd/auth.ts +0 -132
- package/src/cli/cmd/cmd.ts +0 -7
- package/src/cli/cmd/debug/agent.ts +0 -28
- package/src/cli/cmd/debug/config.ts +0 -15
- package/src/cli/cmd/debug/file.ts +0 -91
- package/src/cli/cmd/debug/index.ts +0 -45
- package/src/cli/cmd/debug/lsp.ts +0 -48
- package/src/cli/cmd/debug/ripgrep.ts +0 -83
- package/src/cli/cmd/debug/scrap.ts +0 -15
- package/src/cli/cmd/debug/skill.ts +0 -15
- package/src/cli/cmd/debug/snapshot.ts +0 -48
- package/src/cli/cmd/export.ts +0 -88
- package/src/cli/cmd/generate.ts +0 -38
- package/src/cli/cmd/github.ts +0 -32
- package/src/cli/cmd/import.ts +0 -98
- package/src/cli/cmd/mcp.ts +0 -670
- package/src/cli/cmd/models.ts +0 -42
- package/src/cli/cmd/pr.ts +0 -112
- package/src/cli/cmd/run.ts +0 -374
- package/src/cli/cmd/serve.ts +0 -16
- package/src/cli/cmd/session.ts +0 -135
- package/src/cli/cmd/stats.ts +0 -402
- package/src/cli/cmd/tui/app.tsx +0 -705
- package/src/cli/cmd/tui/attach.ts +0 -32
- package/src/cli/cmd/tui/component/border.tsx +0 -21
- package/src/cli/cmd/tui/component/dialog-agent.tsx +0 -31
- package/src/cli/cmd/tui/component/dialog-command.tsx +0 -124
- package/src/cli/cmd/tui/component/dialog-mcp.tsx +0 -86
- package/src/cli/cmd/tui/component/dialog-model.tsx +0 -232
- package/src/cli/cmd/tui/component/dialog-provider.tsx +0 -228
- package/src/cli/cmd/tui/component/dialog-session-list.tsx +0 -115
- package/src/cli/cmd/tui/component/dialog-session-rename.tsx +0 -31
- package/src/cli/cmd/tui/component/dialog-stash.tsx +0 -86
- package/src/cli/cmd/tui/component/dialog-status.tsx +0 -162
- package/src/cli/cmd/tui/component/dialog-tag.tsx +0 -44
- package/src/cli/cmd/tui/component/dialog-theme-list.tsx +0 -50
- package/src/cli/cmd/tui/component/did-you-know.tsx +0 -85
- package/src/cli/cmd/tui/component/logo.tsx +0 -43
- package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +0 -654
- package/src/cli/cmd/tui/component/prompt/history.tsx +0 -108
- package/src/cli/cmd/tui/component/prompt/index.tsx +0 -1078
- package/src/cli/cmd/tui/component/prompt/stash.tsx +0 -101
- package/src/cli/cmd/tui/component/textarea-keybindings.ts +0 -73
- package/src/cli/cmd/tui/component/tips.ts +0 -92
- package/src/cli/cmd/tui/component/todo-item.tsx +0 -32
- package/src/cli/cmd/tui/context/args.tsx +0 -14
- package/src/cli/cmd/tui/context/directory.ts +0 -13
- package/src/cli/cmd/tui/context/exit.tsx +0 -23
- package/src/cli/cmd/tui/context/helper.tsx +0 -25
- package/src/cli/cmd/tui/context/keybind.tsx +0 -101
- package/src/cli/cmd/tui/context/kv.tsx +0 -49
- package/src/cli/cmd/tui/context/local.tsx +0 -392
- package/src/cli/cmd/tui/context/prompt.tsx +0 -18
- package/src/cli/cmd/tui/context/route.tsx +0 -46
- package/src/cli/cmd/tui/context/sdk.tsx +0 -75
- package/src/cli/cmd/tui/context/sync.tsx +0 -384
- package/src/cli/cmd/tui/context/theme/aura.json +0 -69
- package/src/cli/cmd/tui/context/theme/ayu.json +0 -80
- package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +0 -233
- package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +0 -233
- package/src/cli/cmd/tui/context/theme/catppuccin.json +0 -112
- package/src/cli/cmd/tui/context/theme/chad.json +0 -245
- package/src/cli/cmd/tui/context/theme/cobalt2.json +0 -228
- package/src/cli/cmd/tui/context/theme/cursor.json +0 -249
- package/src/cli/cmd/tui/context/theme/dracula.json +0 -219
- package/src/cli/cmd/tui/context/theme/everforest.json +0 -241
- package/src/cli/cmd/tui/context/theme/flexoki.json +0 -237
- package/src/cli/cmd/tui/context/theme/github.json +0 -233
- package/src/cli/cmd/tui/context/theme/gruvbox.json +0 -95
- package/src/cli/cmd/tui/context/theme/kanagawa.json +0 -77
- package/src/cli/cmd/tui/context/theme/lucent-orng.json +0 -227
- package/src/cli/cmd/tui/context/theme/material.json +0 -235
- package/src/cli/cmd/tui/context/theme/matrix.json +0 -77
- package/src/cli/cmd/tui/context/theme/mercury.json +0 -252
- package/src/cli/cmd/tui/context/theme/monokai.json +0 -221
- package/src/cli/cmd/tui/context/theme/nightowl.json +0 -221
- package/src/cli/cmd/tui/context/theme/nord.json +0 -223
- package/src/cli/cmd/tui/context/theme/one-dark.json +0 -84
- package/src/cli/cmd/tui/context/theme/orng.json +0 -245
- package/src/cli/cmd/tui/context/theme/osaka-jade.json +0 -93
- package/src/cli/cmd/tui/context/theme/palenight.json +0 -222
- package/src/cli/cmd/tui/context/theme/rosepine.json +0 -234
- package/src/cli/cmd/tui/context/theme/solarized.json +0 -223
- package/src/cli/cmd/tui/context/theme/synthwave84.json +0 -226
- package/src/cli/cmd/tui/context/theme/tokyonight.json +0 -243
- package/src/cli/cmd/tui/context/theme/vercel.json +0 -245
- package/src/cli/cmd/tui/context/theme/vesper.json +0 -218
- package/src/cli/cmd/tui/context/theme/zenburn.json +0 -223
- package/src/cli/cmd/tui/context/theme.tsx +0 -1137
- package/src/cli/cmd/tui/event.ts +0 -46
- package/src/cli/cmd/tui/routes/home.tsx +0 -138
- package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +0 -64
- package/src/cli/cmd/tui/routes/session/dialog-message.tsx +0 -109
- package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +0 -26
- package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +0 -47
- package/src/cli/cmd/tui/routes/session/footer.tsx +0 -88
- package/src/cli/cmd/tui/routes/session/header.tsx +0 -125
- package/src/cli/cmd/tui/routes/session/index.tsx +0 -1814
- package/src/cli/cmd/tui/routes/session/permission.tsx +0 -416
- package/src/cli/cmd/tui/routes/session/sidebar.tsx +0 -318
- package/src/cli/cmd/tui/spawn.ts +0 -48
- package/src/cli/cmd/tui/thread.ts +0 -111
- package/src/cli/cmd/tui/ui/dialog-alert.tsx +0 -57
- package/src/cli/cmd/tui/ui/dialog-confirm.tsx +0 -83
- package/src/cli/cmd/tui/ui/dialog-export-options.tsx +0 -204
- package/src/cli/cmd/tui/ui/dialog-help.tsx +0 -38
- package/src/cli/cmd/tui/ui/dialog-prompt.tsx +0 -77
- package/src/cli/cmd/tui/ui/dialog-select.tsx +0 -345
- package/src/cli/cmd/tui/ui/dialog.tsx +0 -171
- package/src/cli/cmd/tui/ui/link.tsx +0 -28
- package/src/cli/cmd/tui/ui/spinner.ts +0 -368
- package/src/cli/cmd/tui/ui/toast.tsx +0 -100
- package/src/cli/cmd/tui/util/clipboard.ts +0 -127
- package/src/cli/cmd/tui/util/editor.ts +0 -32
- package/src/cli/cmd/tui/util/signal.ts +0 -7
- package/src/cli/cmd/tui/util/terminal.ts +0 -114
- package/src/cli/cmd/tui/util/transcript.ts +0 -98
- package/src/cli/cmd/tui/worker.ts +0 -68
- package/src/cli/cmd/uninstall.ts +0 -344
- package/src/cli/cmd/upgrade.ts +0 -67
- package/src/cli/cmd/web.ts +0 -73
- package/src/cli/error.ts +0 -56
- package/src/cli/network.ts +0 -53
- package/src/cli/ui.ts +0 -87
- package/src/cli/upgrade.ts +0 -25
- package/src/command/index.ts +0 -131
- package/src/command/template/initialize.txt +0 -10
- package/src/command/template/review.txt +0 -97
- package/src/config/config.ts +0 -1124
- package/src/config/markdown.ts +0 -41
- package/src/env/index.ts +0 -26
- package/src/file/ignore.ts +0 -83
- package/src/file/index.ts +0 -411
- package/src/file/ripgrep.ts +0 -402
- package/src/file/time.ts +0 -64
- package/src/file/watcher.ts +0 -117
- package/src/flag/flag.ts +0 -52
- package/src/format/formatter.ts +0 -359
- package/src/format/index.ts +0 -137
- package/src/global/index.ts +0 -55
- package/src/id/id.ts +0 -73
- package/src/ide/index.ts +0 -77
- package/src/index.ts +0 -159
- package/src/installation/index.ts +0 -198
- package/src/lsp/client.ts +0 -252
- package/src/lsp/index.ts +0 -485
- package/src/lsp/language.ts +0 -119
- package/src/lsp/server.ts +0 -2023
- package/src/mcp/auth.ts +0 -135
- package/src/mcp/index.ts +0 -874
- package/src/mcp/oauth-callback.ts +0 -200
- package/src/mcp/oauth-provider.ts +0 -154
- package/src/patch/index.ts +0 -622
- package/src/permission/arity.ts +0 -163
- package/src/permission/index.ts +0 -210
- package/src/permission/next.ts +0 -268
- package/src/plugin/index.ts +0 -106
- package/src/project/bootstrap.ts +0 -31
- package/src/project/instance.ts +0 -78
- package/src/project/project.ts +0 -263
- package/src/project/state.ts +0 -65
- package/src/project/vcs.ts +0 -76
- package/src/provider/auth.ts +0 -143
- package/src/provider/models-macro.ts +0 -4
- package/src/provider/models.ts +0 -77
- package/src/provider/provider.ts +0 -516
- package/src/provider/transform.ts +0 -114
- package/src/pty/index.ts +0 -212
- package/src/server/error.ts +0 -36
- package/src/server/mdns.ts +0 -57
- package/src/server/project.ts +0 -79
- package/src/server/server.ts +0 -2866
- package/src/server/tui.ts +0 -71
- package/src/session/compaction.ts +0 -225
- package/src/session/index.ts +0 -469
- package/src/session/llm.ts +0 -213
- package/src/session/message-v2.ts +0 -742
- package/src/session/message.ts +0 -189
- package/src/session/processor.ts +0 -402
- package/src/session/prompt/anthropic-20250930.txt +0 -166
- package/src/session/prompt/anthropic.txt +0 -105
- package/src/session/prompt/anthropic_spoof.txt +0 -1
- package/src/session/prompt/beast.txt +0 -147
- package/src/session/prompt/build-switch.txt +0 -5
- package/src/session/prompt/codex.txt +0 -318
- package/src/session/prompt/copilot-gpt-5.txt +0 -143
- package/src/session/prompt/gemini.txt +0 -155
- package/src/session/prompt/max-steps.txt +0 -16
- package/src/session/prompt/plan-reminder-anthropic.txt +0 -67
- package/src/session/prompt/plan.txt +0 -26
- package/src/session/prompt/qwen.txt +0 -109
- package/src/session/prompt.ts +0 -1621
- package/src/session/retry.ts +0 -90
- package/src/session/revert.ts +0 -108
- package/src/session/status.ts +0 -76
- package/src/session/summary.ts +0 -194
- package/src/session/system.ts +0 -108
- package/src/session/todo.ts +0 -37
- package/src/share/share-next.ts +0 -194
- package/src/share/share.ts +0 -23
- package/src/shell/shell.ts +0 -67
- package/src/skill/index.ts +0 -1
- package/src/skill/skill.ts +0 -124
- package/src/snapshot/index.ts +0 -197
- package/src/storage/storage.ts +0 -226
- package/src/tool/bash.ts +0 -262
- package/src/tool/bash.txt +0 -116
- package/src/tool/batch.ts +0 -175
- package/src/tool/batch.txt +0 -24
- package/src/tool/codesearch.ts +0 -132
- package/src/tool/codesearch.txt +0 -12
- package/src/tool/edit.ts +0 -655
- package/src/tool/edit.txt +0 -10
- package/src/tool/glob.ts +0 -75
- package/src/tool/glob.txt +0 -6
- package/src/tool/grep.ts +0 -132
- package/src/tool/grep.txt +0 -8
- package/src/tool/invalid.ts +0 -17
- package/src/tool/ls.ts +0 -119
- package/src/tool/ls.txt +0 -1
- package/src/tool/lsp.ts +0 -94
- package/src/tool/lsp.txt +0 -19
- package/src/tool/multiedit.ts +0 -46
- package/src/tool/multiedit.txt +0 -41
- package/src/tool/patch.ts +0 -210
- package/src/tool/patch.txt +0 -1
- package/src/tool/read.ts +0 -191
- package/src/tool/read.txt +0 -12
- package/src/tool/registry.ts +0 -137
- package/src/tool/skill.ts +0 -77
- package/src/tool/task.ts +0 -167
- package/src/tool/task.txt +0 -60
- package/src/tool/todo.ts +0 -53
- package/src/tool/todoread.txt +0 -14
- package/src/tool/todowrite.txt +0 -167
- package/src/tool/tool.ts +0 -73
- package/src/tool/webfetch.ts +0 -182
- package/src/tool/webfetch.txt +0 -13
- package/src/tool/websearch.ts +0 -144
- package/src/tool/websearch.txt +0 -11
- package/src/tool/write.ts +0 -84
- package/src/tool/write.txt +0 -8
- package/src/util/archive.ts +0 -16
- package/src/util/color.ts +0 -19
- package/src/util/context.ts +0 -25
- package/src/util/defer.ts +0 -12
- package/src/util/eventloop.ts +0 -20
- package/src/util/filesystem.ts +0 -83
- package/src/util/fn.ts +0 -11
- package/src/util/iife.ts +0 -3
- package/src/util/keybind.ts +0 -102
- package/src/util/lazy.ts +0 -18
- package/src/util/locale.ts +0 -81
- package/src/util/lock.ts +0 -98
- package/src/util/log.ts +0 -180
- package/src/util/queue.ts +0 -32
- package/src/util/rpc.ts +0 -42
- package/src/util/scrap.ts +0 -10
- package/src/util/signal.ts +0 -12
- package/src/util/timeout.ts +0 -14
- package/src/util/token.ts +0 -7
- package/src/util/wildcard.ts +0 -54
- package/src/worktree/index.ts +0 -217
- package/sst-env.d.ts +0 -9
- package/test/agent/agent.test.ts +0 -448
- package/test/bun.test.ts +0 -53
- package/test/cli/github-action.test.ts +0 -129
- package/test/cli/github-remote.test.ts +0 -80
- package/test/cli/tui/transcript.test.ts +0 -297
- package/test/config/agent-color.test.ts +0 -66
- package/test/config/config.test.ts +0 -870
- package/test/config/markdown.test.ts +0 -89
- package/test/file/ignore.test.ts +0 -10
- package/test/file/path-traversal.test.ts +0 -115
- package/test/fixture/fixture.ts +0 -45
- package/test/fixture/lsp/fake-lsp-server.js +0 -77
- package/test/ide/ide.test.ts +0 -82
- package/test/keybind.test.ts +0 -421
- package/test/lsp/client.test.ts +0 -95
- package/test/mcp/headers.test.ts +0 -153
- package/test/patch/patch.test.ts +0 -348
- package/test/permission/arity.test.ts +0 -33
- package/test/permission/next.test.ts +0 -652
- package/test/preload.ts +0 -63
- package/test/project/project.test.ts +0 -120
- package/test/provider/amazon-bedrock.test.ts +0 -236
- package/test/provider/provider.test.ts +0 -2127
- package/test/provider/transform.test.ts +0 -980
- package/test/server/session-select.test.ts +0 -78
- package/test/session/compaction.test.ts +0 -251
- package/test/session/message-v2.test.ts +0 -570
- package/test/session/retry.test.ts +0 -131
- package/test/session/revert-compact.test.ts +0 -285
- package/test/session/session.test.ts +0 -71
- package/test/skill/skill.test.ts +0 -185
- package/test/snapshot/snapshot.test.ts +0 -939
- package/test/tool/__snapshots__/tool.test.ts.snap +0 -9
- package/test/tool/bash.test.ts +0 -232
- package/test/tool/grep.test.ts +0 -109
- package/test/tool/patch.test.ts +0 -261
- package/test/tool/read.test.ts +0 -167
- package/test/util/iife.test.ts +0 -36
- package/test/util/lazy.test.ts +0 -50
- package/test/util/timeout.test.ts +0 -21
- package/test/util/wildcard.test.ts +0 -55
- package/tsconfig.json +0 -16
- /package/{script/postinstall.mjs → postinstall.mjs} +0 -0
package/src/provider/provider.ts
DELETED
|
@@ -1,516 +0,0 @@
|
|
|
1
|
-
import z from "zod"
|
|
2
|
-
import { Config } from "../config/config"
|
|
3
|
-
import { mapValues, mergeDeep } from "remeda"
|
|
4
|
-
import { NoSuchModelError, type Provider as SDK } from "ai"
|
|
5
|
-
import { Log } from "../util/log"
|
|
6
|
-
import { NamedError } from "@opencode-ai/util/error"
|
|
7
|
-
import { Env } from "../env"
|
|
8
|
-
import { Instance } from "../project/instance"
|
|
9
|
-
import { createOpenAICompatible } from "@ai-sdk/openai-compatible"
|
|
10
|
-
import type { LanguageModelV2 } from "@ai-sdk/provider"
|
|
11
|
-
import { Auth } from "../auth"
|
|
12
|
-
|
|
13
|
-
export namespace Provider {
|
|
14
|
-
const log = Log.create({ service: "provider" })
|
|
15
|
-
|
|
16
|
-
// Corethink API configuration
|
|
17
|
-
const CORETHINK_API_URL = "https://api.corethink.ai/v1/code"
|
|
18
|
-
const CORETHINK_ENV_KEY = "CORETHINK_API_KEY"
|
|
19
|
-
|
|
20
|
-
export const Model = z
|
|
21
|
-
.object({
|
|
22
|
-
id: z.string(),
|
|
23
|
-
providerID: z.string(),
|
|
24
|
-
api: z.object({
|
|
25
|
-
id: z.string(),
|
|
26
|
-
url: z.string(),
|
|
27
|
-
npm: z.string(),
|
|
28
|
-
}),
|
|
29
|
-
name: z.string(),
|
|
30
|
-
family: z.string().optional(),
|
|
31
|
-
capabilities: z.object({
|
|
32
|
-
temperature: z.boolean(),
|
|
33
|
-
reasoning: z.boolean(),
|
|
34
|
-
attachment: z.boolean(),
|
|
35
|
-
toolcall: z.boolean(),
|
|
36
|
-
input: z.object({
|
|
37
|
-
text: z.boolean(),
|
|
38
|
-
audio: z.boolean(),
|
|
39
|
-
image: z.boolean(),
|
|
40
|
-
video: z.boolean(),
|
|
41
|
-
pdf: z.boolean(),
|
|
42
|
-
}),
|
|
43
|
-
output: z.object({
|
|
44
|
-
text: z.boolean(),
|
|
45
|
-
audio: z.boolean(),
|
|
46
|
-
image: z.boolean(),
|
|
47
|
-
video: z.boolean(),
|
|
48
|
-
pdf: z.boolean(),
|
|
49
|
-
}),
|
|
50
|
-
interleaved: z.union([
|
|
51
|
-
z.boolean(),
|
|
52
|
-
z.object({
|
|
53
|
-
field: z.enum(["reasoning_content", "reasoning_details"]),
|
|
54
|
-
}),
|
|
55
|
-
]),
|
|
56
|
-
}),
|
|
57
|
-
cost: z.object({
|
|
58
|
-
input: z.number(),
|
|
59
|
-
output: z.number(),
|
|
60
|
-
cache: z.object({
|
|
61
|
-
read: z.number(),
|
|
62
|
-
write: z.number(),
|
|
63
|
-
}),
|
|
64
|
-
experimentalOver200K: z
|
|
65
|
-
.object({
|
|
66
|
-
input: z.number(),
|
|
67
|
-
output: z.number(),
|
|
68
|
-
cache: z.object({
|
|
69
|
-
read: z.number(),
|
|
70
|
-
write: z.number(),
|
|
71
|
-
}),
|
|
72
|
-
})
|
|
73
|
-
.optional(),
|
|
74
|
-
}),
|
|
75
|
-
limit: z.object({
|
|
76
|
-
context: z.number(),
|
|
77
|
-
output: z.number(),
|
|
78
|
-
}),
|
|
79
|
-
status: z.enum(["alpha", "beta", "deprecated", "active"]),
|
|
80
|
-
options: z.record(z.string(), z.any()),
|
|
81
|
-
headers: z.record(z.string(), z.string()),
|
|
82
|
-
release_date: z.string(),
|
|
83
|
-
variants: z.record(z.string(), z.record(z.string(), z.any())).optional(),
|
|
84
|
-
})
|
|
85
|
-
.meta({
|
|
86
|
-
ref: "Model",
|
|
87
|
-
})
|
|
88
|
-
export type Model = z.infer<typeof Model>
|
|
89
|
-
|
|
90
|
-
export const Info = z
|
|
91
|
-
.object({
|
|
92
|
-
id: z.string(),
|
|
93
|
-
name: z.string(),
|
|
94
|
-
source: z.enum(["env", "config", "custom", "api"]),
|
|
95
|
-
env: z.string().array(),
|
|
96
|
-
key: z.string().optional(),
|
|
97
|
-
options: z.record(z.string(), z.any()),
|
|
98
|
-
models: z.record(z.string(), Model),
|
|
99
|
-
})
|
|
100
|
-
.meta({
|
|
101
|
-
ref: "Provider",
|
|
102
|
-
})
|
|
103
|
-
export type Info = z.infer<typeof Info>
|
|
104
|
-
|
|
105
|
-
// Stub function for compatibility with server.ts
|
|
106
|
-
export function fromModelsDevProvider(provider: any): Info {
|
|
107
|
-
return {
|
|
108
|
-
id: provider.id,
|
|
109
|
-
source: "custom",
|
|
110
|
-
name: provider.name,
|
|
111
|
-
env: provider.env ?? [],
|
|
112
|
-
options: {},
|
|
113
|
-
models: {},
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
// Create the corethink model definition
|
|
118
|
-
function createCorethinkModel(): Model {
|
|
119
|
-
return {
|
|
120
|
-
id: "corethink",
|
|
121
|
-
providerID: "corethink",
|
|
122
|
-
name: "Chadcode",
|
|
123
|
-
api: {
|
|
124
|
-
id: "corethink",
|
|
125
|
-
url: CORETHINK_API_URL,
|
|
126
|
-
npm: "@ai-sdk/openai-compatible",
|
|
127
|
-
},
|
|
128
|
-
status: "active",
|
|
129
|
-
headers: {},
|
|
130
|
-
options: {},
|
|
131
|
-
cost: {
|
|
132
|
-
input: 1.5, // $1.50 per 1M input tokens
|
|
133
|
-
output: 2.0, // $2.00 per 1M output tokens
|
|
134
|
-
cache: {
|
|
135
|
-
read: 0,
|
|
136
|
-
write: 0,
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
limit: {
|
|
140
|
-
context: 200000,
|
|
141
|
-
output: 8000,
|
|
142
|
-
},
|
|
143
|
-
capabilities: {
|
|
144
|
-
temperature: true,
|
|
145
|
-
reasoning: false,
|
|
146
|
-
attachment: true,
|
|
147
|
-
toolcall: true,
|
|
148
|
-
input: {
|
|
149
|
-
text: true,
|
|
150
|
-
audio: false,
|
|
151
|
-
image: true,
|
|
152
|
-
video: false,
|
|
153
|
-
pdf: true,
|
|
154
|
-
},
|
|
155
|
-
output: {
|
|
156
|
-
text: true,
|
|
157
|
-
audio: false,
|
|
158
|
-
image: false,
|
|
159
|
-
video: false,
|
|
160
|
-
pdf: false,
|
|
161
|
-
},
|
|
162
|
-
interleaved: false,
|
|
163
|
-
},
|
|
164
|
-
release_date: "2025-01-01",
|
|
165
|
-
variants: {},
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// Create the corethink provider definition
|
|
170
|
-
function createCorethinkProvider(apiKey?: string): Info {
|
|
171
|
-
return {
|
|
172
|
-
id: "corethink",
|
|
173
|
-
name: "Chadcode",
|
|
174
|
-
source: apiKey ? "env" : "config",
|
|
175
|
-
env: [CORETHINK_ENV_KEY],
|
|
176
|
-
key: apiKey,
|
|
177
|
-
options: {
|
|
178
|
-
baseURL: CORETHINK_API_URL,
|
|
179
|
-
},
|
|
180
|
-
models: {
|
|
181
|
-
corethink: createCorethinkModel(),
|
|
182
|
-
},
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const state = Instance.state(async () => {
|
|
187
|
-
using _ = log.time("state")
|
|
188
|
-
const config = await Config.get()
|
|
189
|
-
|
|
190
|
-
const providers: { [providerID: string]: Info } = {}
|
|
191
|
-
const languages = new Map<string, LanguageModelV2>()
|
|
192
|
-
const sdk = new Map<number, SDK>()
|
|
193
|
-
|
|
194
|
-
log.info("init")
|
|
195
|
-
|
|
196
|
-
// Get API key from multiple sources (in order of priority):
|
|
197
|
-
// 1. Environment variable
|
|
198
|
-
// 2. Auth storage (from UI input)
|
|
199
|
-
// 3. Config file
|
|
200
|
-
let apiKey = Env.get(CORETHINK_ENV_KEY)
|
|
201
|
-
|
|
202
|
-
// Check auth storage if no env var
|
|
203
|
-
if (!apiKey) {
|
|
204
|
-
const authData = await Auth.get("corethink")
|
|
205
|
-
if (authData?.type === "api") {
|
|
206
|
-
apiKey = authData.key
|
|
207
|
-
log.info("found API key in auth storage")
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
if (!apiKey) {
|
|
212
|
-
log.warn("CORETHINK_API_KEY not set - corethink provider will not be available")
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
// Create the corethink provider
|
|
216
|
-
const corethinkProvider = createCorethinkProvider(apiKey)
|
|
217
|
-
|
|
218
|
-
// Apply any config overrides
|
|
219
|
-
if (config.provider?.corethink) {
|
|
220
|
-
const configProvider = config.provider.corethink
|
|
221
|
-
if (configProvider.options) {
|
|
222
|
-
corethinkProvider.options = mergeDeep(corethinkProvider.options, configProvider.options)
|
|
223
|
-
}
|
|
224
|
-
if (configProvider.options?.apiKey) {
|
|
225
|
-
corethinkProvider.key = configProvider.options.apiKey
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Only add provider if we have an API key
|
|
230
|
-
if (corethinkProvider.key) {
|
|
231
|
-
providers["corethink"] = corethinkProvider
|
|
232
|
-
log.info("found", { providerID: "corethink" })
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
return {
|
|
236
|
-
models: languages,
|
|
237
|
-
providers,
|
|
238
|
-
sdk,
|
|
239
|
-
}
|
|
240
|
-
})
|
|
241
|
-
|
|
242
|
-
export async function list() {
|
|
243
|
-
return state().then((state) => state.providers)
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
async function getSDK(model: Model) {
|
|
247
|
-
try {
|
|
248
|
-
using _ = log.time("getSDK", {
|
|
249
|
-
providerID: model.providerID,
|
|
250
|
-
})
|
|
251
|
-
const s = await state()
|
|
252
|
-
const provider = s.providers[model.providerID]
|
|
253
|
-
const options: Record<string, any> = { ...provider.options }
|
|
254
|
-
|
|
255
|
-
// Enable usage tracking for OpenAI-compatible providers
|
|
256
|
-
options["includeUsage"] = true
|
|
257
|
-
|
|
258
|
-
if (!options["baseURL"]) options["baseURL"] = model.api.url
|
|
259
|
-
if (options["apiKey"] === undefined && provider.key) options["apiKey"] = provider.key
|
|
260
|
-
if (model.headers) {
|
|
261
|
-
options["headers"] = {
|
|
262
|
-
...options["headers"],
|
|
263
|
-
...model.headers,
|
|
264
|
-
}
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
const key = Bun.hash.xxHash32(JSON.stringify({ npm: model.api.npm, options }))
|
|
268
|
-
const existing = s.sdk.get(key)
|
|
269
|
-
if (existing) return existing
|
|
270
|
-
|
|
271
|
-
options["fetch"] = async (input: any, init?: BunFetchRequestInit) => {
|
|
272
|
-
const opts = init ?? {}
|
|
273
|
-
|
|
274
|
-
if (options["timeout"] !== undefined && options["timeout"] !== null) {
|
|
275
|
-
const signals: AbortSignal[] = []
|
|
276
|
-
if (opts.signal) signals.push(opts.signal)
|
|
277
|
-
if (options["timeout"] !== false) signals.push(AbortSignal.timeout(options["timeout"]))
|
|
278
|
-
|
|
279
|
-
const combined = signals.length > 1 ? AbortSignal.any(signals) : signals[0]
|
|
280
|
-
|
|
281
|
-
opts.signal = combined
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
// Clean up messages for API compatibility
|
|
285
|
-
if (opts.body) {
|
|
286
|
-
try {
|
|
287
|
-
const bodyStr = typeof opts.body === "string" ? opts.body : new TextDecoder().decode(opts.body as ArrayBuffer)
|
|
288
|
-
const parsed = JSON.parse(bodyStr)
|
|
289
|
-
|
|
290
|
-
if (parsed.messages) {
|
|
291
|
-
for (const msg of parsed.messages) {
|
|
292
|
-
// When assistant has tool_calls, set empty content to null (some APIs require this)
|
|
293
|
-
if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0) {
|
|
294
|
-
if (msg.content && msg.content.trim() === "") {
|
|
295
|
-
msg.content = null
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
opts.body = JSON.stringify(parsed)
|
|
300
|
-
}
|
|
301
|
-
} catch {
|
|
302
|
-
// Ignore parse errors
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
const response = await fetch(input, {
|
|
307
|
-
...opts,
|
|
308
|
-
// @ts-ignore see here: https://github.com/oven-sh/bun/issues/16682
|
|
309
|
-
timeout: false,
|
|
310
|
-
})
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
// For streaming responses, we need to filter out usage-only events that CoreThink sends
|
|
314
|
-
// These events don't have 'choices' and cause validation errors in the AI SDK
|
|
315
|
-
const contentType = response.headers.get("content-type") || ""
|
|
316
|
-
if (contentType.includes("text/event-stream") && response.body) {
|
|
317
|
-
const reader = response.body.getReader()
|
|
318
|
-
const encoder = new TextEncoder()
|
|
319
|
-
|
|
320
|
-
const transformedStream = new ReadableStream({
|
|
321
|
-
async start(controller) {
|
|
322
|
-
const decoder = new TextDecoder()
|
|
323
|
-
let buffer = ""
|
|
324
|
-
|
|
325
|
-
while (true) {
|
|
326
|
-
const { done, value } = await reader.read()
|
|
327
|
-
if (done) {
|
|
328
|
-
controller.close()
|
|
329
|
-
break
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
buffer += decoder.decode(value, { stream: true })
|
|
333
|
-
const lines = buffer.split("\n")
|
|
334
|
-
buffer = lines.pop() || ""
|
|
335
|
-
|
|
336
|
-
for (const line of lines) {
|
|
337
|
-
const trimmed = line.trim()
|
|
338
|
-
if (!trimmed) {
|
|
339
|
-
controller.enqueue(encoder.encode("\n"))
|
|
340
|
-
continue
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
if (trimmed.startsWith("data:")) {
|
|
344
|
-
const data = trimmed.slice(5).trim()
|
|
345
|
-
if (data === "[DONE]") {
|
|
346
|
-
controller.enqueue(encoder.encode(line + "\n"))
|
|
347
|
-
continue
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
try {
|
|
351
|
-
const parsed = JSON.parse(data)
|
|
352
|
-
// Skip events that only have usage (no choices) - these cause validation errors
|
|
353
|
-
if (parsed.usage && !parsed.choices) {
|
|
354
|
-
continue
|
|
355
|
-
}
|
|
356
|
-
// CoreThink uses 'reasoning' field - map it to 'content' for compatibility
|
|
357
|
-
if (parsed.choices?.[0]?.delta?.reasoning && !parsed.choices?.[0]?.delta?.content) {
|
|
358
|
-
parsed.choices[0].delta.content = parsed.choices[0].delta.reasoning
|
|
359
|
-
delete parsed.choices[0].delta.reasoning
|
|
360
|
-
controller.enqueue(encoder.encode("data: " + JSON.stringify(parsed) + "\n"))
|
|
361
|
-
continue
|
|
362
|
-
}
|
|
363
|
-
} catch {
|
|
364
|
-
// If JSON parsing fails, pass through as-is
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
controller.enqueue(encoder.encode(line + "\n"))
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
},
|
|
372
|
-
})
|
|
373
|
-
|
|
374
|
-
return new Response(transformedStream, {
|
|
375
|
-
status: response.status,
|
|
376
|
-
statusText: response.statusText,
|
|
377
|
-
headers: response.headers,
|
|
378
|
-
})
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
return response
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
log.info("creating corethink provider", { providerID: model.providerID })
|
|
385
|
-
const loaded = createOpenAICompatible({
|
|
386
|
-
name: model.providerID,
|
|
387
|
-
baseURL: options["baseURL"],
|
|
388
|
-
apiKey: options["apiKey"],
|
|
389
|
-
headers: options["headers"],
|
|
390
|
-
fetch: options["fetch"],
|
|
391
|
-
})
|
|
392
|
-
s.sdk.set(key, loaded)
|
|
393
|
-
return loaded as SDK
|
|
394
|
-
} catch (e) {
|
|
395
|
-
throw new InitError({ providerID: model.providerID }, { cause: e })
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export async function getProvider(providerID: string) {
|
|
400
|
-
return state().then((s) => s.providers[providerID])
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
export async function getModel(providerID: string, modelID: string) {
|
|
404
|
-
const s = await state()
|
|
405
|
-
const provider = s.providers[providerID]
|
|
406
|
-
if (!provider) {
|
|
407
|
-
throw new ModelNotFoundError({ providerID, modelID, suggestions: ["corethink"] })
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
const info = provider.models[modelID]
|
|
411
|
-
if (!info) {
|
|
412
|
-
const availableModels = Object.keys(provider.models)
|
|
413
|
-
throw new ModelNotFoundError({ providerID, modelID, suggestions: availableModels })
|
|
414
|
-
}
|
|
415
|
-
return info
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
export async function getLanguage(model: Model): Promise<LanguageModelV2> {
|
|
419
|
-
const s = await state()
|
|
420
|
-
const key = `${model.providerID}/${model.id}`
|
|
421
|
-
if (s.models.has(key)) return s.models.get(key)!
|
|
422
|
-
|
|
423
|
-
const sdk = await getSDK(model)
|
|
424
|
-
|
|
425
|
-
try {
|
|
426
|
-
const language = sdk.languageModel(model.api.id) as LanguageModelV2
|
|
427
|
-
s.models.set(key, language)
|
|
428
|
-
return language
|
|
429
|
-
} catch (e) {
|
|
430
|
-
if (e instanceof NoSuchModelError)
|
|
431
|
-
throw new ModelNotFoundError(
|
|
432
|
-
{
|
|
433
|
-
modelID: model.id,
|
|
434
|
-
providerID: model.providerID,
|
|
435
|
-
},
|
|
436
|
-
{ cause: e },
|
|
437
|
-
)
|
|
438
|
-
throw e
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
export async function closest(providerID: string, query: string[]) {
|
|
443
|
-
const s = await state()
|
|
444
|
-
const provider = s.providers[providerID]
|
|
445
|
-
if (!provider) return undefined
|
|
446
|
-
for (const item of query) {
|
|
447
|
-
for (const modelID of Object.keys(provider.models)) {
|
|
448
|
-
if (modelID.includes(item))
|
|
449
|
-
return {
|
|
450
|
-
providerID,
|
|
451
|
-
modelID,
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
export async function getSmallModel(providerID: string) {
|
|
458
|
-
const cfg = await Config.get()
|
|
459
|
-
|
|
460
|
-
if (cfg.small_model) {
|
|
461
|
-
const parsed = parseModel(cfg.small_model)
|
|
462
|
-
return getModel(parsed.providerID, parsed.modelID)
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
// For corethink, just return the main model
|
|
466
|
-
const provider = await state().then((state) => state.providers[providerID])
|
|
467
|
-
if (provider && provider.models["corethink"]) {
|
|
468
|
-
return provider.models["corethink"]
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
return undefined
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
export function sort(models: Model[]) {
|
|
475
|
-
// For corethink, just return as-is since there's only one model
|
|
476
|
-
return models
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
export async function defaultModel() {
|
|
480
|
-
const cfg = await Config.get()
|
|
481
|
-
if (cfg.model) return parseModel(cfg.model)
|
|
482
|
-
|
|
483
|
-
const providers = await list()
|
|
484
|
-
const provider = providers["corethink"]
|
|
485
|
-
if (!provider) throw new Error("Chad provider not found. Please set CORETHINK_API_KEY environment variable.")
|
|
486
|
-
|
|
487
|
-
return {
|
|
488
|
-
providerID: "corethink",
|
|
489
|
-
modelID: "corethink",
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
export function parseModel(model: string) {
|
|
494
|
-
const [providerID, ...rest] = model.split("/")
|
|
495
|
-
return {
|
|
496
|
-
providerID: providerID,
|
|
497
|
-
modelID: rest.join("/"),
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
export const ModelNotFoundError = NamedError.create(
|
|
502
|
-
"ProviderModelNotFoundError",
|
|
503
|
-
z.object({
|
|
504
|
-
providerID: z.string(),
|
|
505
|
-
modelID: z.string(),
|
|
506
|
-
suggestions: z.array(z.string()).optional(),
|
|
507
|
-
}),
|
|
508
|
-
)
|
|
509
|
-
|
|
510
|
-
export const InitError = NamedError.create(
|
|
511
|
-
"ProviderInitError",
|
|
512
|
-
z.object({
|
|
513
|
-
providerID: z.string(),
|
|
514
|
-
}),
|
|
515
|
-
)
|
|
516
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import type { APICallError, ModelMessage } from "ai"
|
|
2
|
-
import type { JSONSchema } from "zod/v4/core"
|
|
3
|
-
import type { Provider } from "./provider"
|
|
4
|
-
|
|
5
|
-
export namespace ProviderTransform {
|
|
6
|
-
function unsupportedParts(msgs: ModelMessage[], model: Provider.Model): ModelMessage[] {
|
|
7
|
-
return msgs.map((msg) => {
|
|
8
|
-
if (msg.role !== "user" || !Array.isArray(msg.content)) return msg
|
|
9
|
-
|
|
10
|
-
const filtered = msg.content.map((part) => {
|
|
11
|
-
if (part.type !== "file" && part.type !== "image") return part
|
|
12
|
-
|
|
13
|
-
// Check for empty base64 image data
|
|
14
|
-
if (part.type === "image") {
|
|
15
|
-
const imageStr = part.image.toString()
|
|
16
|
-
if (imageStr.startsWith("data:")) {
|
|
17
|
-
const match = imageStr.match(/^data:([^;]+);base64,(.*)$/)
|
|
18
|
-
if (match && (!match[2] || match[2].length === 0)) {
|
|
19
|
-
return {
|
|
20
|
-
type: "text" as const,
|
|
21
|
-
text: "ERROR: Image file is empty or corrupted. Please provide a valid image.",
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType
|
|
28
|
-
const filename = part.type === "file" ? part.filename : undefined
|
|
29
|
-
const modality = mimeToModality(mime)
|
|
30
|
-
if (!modality) return part
|
|
31
|
-
if (model.capabilities.input[modality]) return part
|
|
32
|
-
|
|
33
|
-
const name = filename ? `"${filename}"` : modality
|
|
34
|
-
return {
|
|
35
|
-
type: "text" as const,
|
|
36
|
-
text: `ERROR: Cannot read ${name} (this model does not support ${modality} input). Inform the user.`,
|
|
37
|
-
}
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
return { ...msg, content: filtered }
|
|
41
|
-
})
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function mimeToModality(mime: string): "image" | "audio" | "video" | "pdf" | undefined {
|
|
45
|
-
if (mime.startsWith("image/")) return "image"
|
|
46
|
-
if (mime.startsWith("audio/")) return "audio"
|
|
47
|
-
if (mime.startsWith("video/")) return "video"
|
|
48
|
-
if (mime === "application/pdf") return "pdf"
|
|
49
|
-
return undefined
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export function message(msgs: ModelMessage[], model: Provider.Model) {
|
|
53
|
-
msgs = unsupportedParts(msgs, model)
|
|
54
|
-
return msgs
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export function temperature(_model: Provider.Model) {
|
|
58
|
-
// Default temperature for corethink
|
|
59
|
-
return undefined
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export function topP(_model: Provider.Model) {
|
|
63
|
-
return undefined
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export function topK(_model: Provider.Model) {
|
|
67
|
-
return undefined
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
export function variants(_model: Provider.Model): Record<string, Record<string, any>> {
|
|
71
|
-
// Corethink doesn't have reasoning variants
|
|
72
|
-
return {}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export function options(
|
|
76
|
-
_model: Provider.Model,
|
|
77
|
-
_sessionID: string,
|
|
78
|
-
_providerOptions?: Record<string, any>,
|
|
79
|
-
): Record<string, any> {
|
|
80
|
-
return {}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
export function smallOptions(_model: Provider.Model) {
|
|
84
|
-
return {}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
export function providerOptions(model: Provider.Model, options: { [x: string]: any }) {
|
|
88
|
-
return {
|
|
89
|
-
[model.providerID]: options,
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function maxOutputTokens(
|
|
94
|
-
_npm: string,
|
|
95
|
-
_options: Record<string, any>,
|
|
96
|
-
modelLimit: number,
|
|
97
|
-
globalLimit: number,
|
|
98
|
-
): number {
|
|
99
|
-
return Math.min(modelLimit || globalLimit, globalLimit)
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function schema(_model: Provider.Model, schema: JSONSchema.BaseSchema) {
|
|
103
|
-
// Strip fields that some APIs don't handle well
|
|
104
|
-
const cleaned = { ...schema } as Record<string, any>
|
|
105
|
-
delete cleaned["$schema"]
|
|
106
|
-
// Some APIs don't like strict additionalProperties
|
|
107
|
-
delete cleaned["additionalProperties"]
|
|
108
|
-
return cleaned as JSONSchema.BaseSchema
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export function error(_providerID: string, error: APICallError) {
|
|
112
|
-
return error.message
|
|
113
|
-
}
|
|
114
|
-
}
|