opencode-copilot-cost-override 0.1.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/README.md +98 -0
- package/package.json +37 -0
- package/src/index.ts +27 -0
- package/src/models.ts +129 -0
package/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# opencode-copilot-cost-override
|
|
2
|
+
|
|
3
|
+
> 修复 OpenCode v1.4.0+ GitHub Copilot provider cost 被硬编码为 0 的问题
|
|
4
|
+
|
|
5
|
+
## 问题
|
|
6
|
+
|
|
7
|
+
OpenCode v1.4.0+ 的内部 Copilot 插件 (`packages/opencode/src/plugin/github-copilot/models.ts`) **将所有模型的 cost 硬编码为 0**,忽略用户在 `opencode.jsonc` 中配置的值。
|
|
8
|
+
|
|
9
|
+
## 解决方案
|
|
10
|
+
|
|
11
|
+
一个用户侧插件,完全绕过内部的 `/models` API 调用,直接返回硬编码的模型定义(包含正确的 cost 值)。不依赖外部 API,不读外部配置。
|
|
12
|
+
|
|
13
|
+
## 安装与使用
|
|
14
|
+
|
|
15
|
+
### 方式一:直接从 npm 安装(推荐)
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
opencode plugin install opencode-copilot-cost-override@latest
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
或手动在 `~/.config/opencode/opencode.jsonc` 中添加:
|
|
22
|
+
|
|
23
|
+
```jsonc
|
|
24
|
+
{
|
|
25
|
+
"plugin": ["opencode-copilot-cost-override@latest"]
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### 方式二:从 git 路径加载
|
|
30
|
+
|
|
31
|
+
```jsonc
|
|
32
|
+
{
|
|
33
|
+
"plugin": [
|
|
34
|
+
"file:///path/to/opencode-github-copilot-provider"
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 验证
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
opencode models github-copilot
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
应该看到正确的 cost 值(不是 0)。例如 `gpt-5.4` 应显示 `input: 2.5, output: 15, cache_read: 0.25`。
|
|
46
|
+
|
|
47
|
+
## 当前模型列表
|
|
48
|
+
|
|
49
|
+
| 模型 | input | output | cache_read | cache_write | context |
|
|
50
|
+
|------|-------|--------|------------|-------------|---------|
|
|
51
|
+
| gemini-3.1-pro-preview | 2 | 12 | 0.2 | 0 | 1,000,000 |
|
|
52
|
+
| claude-haiku-4.5 | 1 | 5 | 0.1 | 1.25 | 200,000 |
|
|
53
|
+
| gpt-5.4 | 2.5 | 15 | 0.25 | 0 | 1,050,000 |
|
|
54
|
+
| claude-sonnet-4.6 | 3 | 15 | 0.3 | 3.75 | 200,000 |
|
|
55
|
+
| claude-opus-4.6 | 5 | 25 | 0.5 | 6.25 | 1,000,000 |
|
|
56
|
+
|
|
57
|
+
## 工作原理
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
1. 内部插件加载 (CopilotAuthPlugin)
|
|
61
|
+
└── provider(id="github-copilot", models=API fetch, costs=0)
|
|
62
|
+
2. 外部插件加载 (本插件)
|
|
63
|
+
└── provider(id="github-copilot", models=硬编码, costs=正确值)
|
|
64
|
+
3. Provider 初始化时按顺序执行所有 models hooks
|
|
65
|
+
└── 本插件最后执行,覆盖内部插件的结果 ✅
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
**不受影响的钩子**: auth / chat.params / chat.headers 仍由内部 CopilotAuthPlugin 提供。
|
|
69
|
+
|
|
70
|
+
## 自定义模型
|
|
71
|
+
|
|
72
|
+
要添加/修改/删除模型,编辑 `src/models.ts`。每个模型需要包含完整字段:
|
|
73
|
+
|
|
74
|
+
- `id`, `providerID` (`"github-copilot"`)
|
|
75
|
+
- `api` (`{ id, url, npm: "@ai-sdk/github-copilot" }`)
|
|
76
|
+
- `name`, `family`, `release_date`
|
|
77
|
+
- `cost` (`{ input, output, cache: { read, write } }`)
|
|
78
|
+
- `limit` (`{ context, input, output }`)
|
|
79
|
+
- `capabilities` (temperature, reasoning, attachment, toolcall, input/output, interleaved)
|
|
80
|
+
- `options`, `headers`, `variants`
|
|
81
|
+
|
|
82
|
+
本地开发用 `file://` 路径加载即可,opencode 直接读取 `.ts` 源码。
|
|
83
|
+
|
|
84
|
+
## 发布到 npm
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# 1. 更新版本号
|
|
88
|
+
pnpm version patch # 或 minor / major
|
|
89
|
+
|
|
90
|
+
# 2. 发布(从 src 直接发布,opencode 加载 .ts 无需编译)
|
|
91
|
+
npm publish --access public
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
> opencode 的插件加载器直接通过 `import()` 加载 `.ts` 源文件,不需要 build 步骤。
|
|
95
|
+
|
|
96
|
+
## License
|
|
97
|
+
|
|
98
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "opencode-copilot-cost-override",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Override GitHub Copilot provider models with hard-coded cost values, bypassing the internal models.ts which hardcodes all costs to 0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.ts"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"src"
|
|
12
|
+
],
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/yee88/opencode-copilot-cost-override"
|
|
16
|
+
},
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"engines": {
|
|
19
|
+
"opencode": ">=1.4.0"
|
|
20
|
+
},
|
|
21
|
+
"peerDependencies": {
|
|
22
|
+
"@opencode-ai/plugin": "*",
|
|
23
|
+
"@opencode-ai/sdk": "*"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@opencode-ai/plugin": "1.4.0",
|
|
27
|
+
"@opencode-ai/sdk": "1.4.0",
|
|
28
|
+
"typescript": "^6.0.2"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"opencode",
|
|
32
|
+
"plugin",
|
|
33
|
+
"github-copilot",
|
|
34
|
+
"cost"
|
|
35
|
+
],
|
|
36
|
+
"scripts": {}
|
|
37
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Plugin, PluginInput, Hooks } from "@opencode-ai/plugin"
|
|
2
|
+
import type { Provider as ProviderV2 } from "@opencode-ai/sdk/v2"
|
|
3
|
+
import { models as hardcodedModels } from "./models.js"
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* GitHub Copilot Cost Override Plugin
|
|
7
|
+
*
|
|
8
|
+
* Replaces the internal Copilot plugin's models hook (which hardcodes all costs to 0)
|
|
9
|
+
* with hard-coded model definitions that respect user-configured cost values.
|
|
10
|
+
*
|
|
11
|
+
* To add/update models, edit `src/models.ts` directly.
|
|
12
|
+
*/
|
|
13
|
+
export default {
|
|
14
|
+
id: "copilot-cost-override",
|
|
15
|
+
server: async function CopilotCostPlugin(_input: PluginInput): Promise<Hooks> {
|
|
16
|
+
return {
|
|
17
|
+
provider: {
|
|
18
|
+
id: "github-copilot",
|
|
19
|
+
async models(_provider: ProviderV2): Promise<Record<string, typeof hardcodedModels[string]>> {
|
|
20
|
+
// Return hard-coded models with correct cost values
|
|
21
|
+
// This completely bypasses the internal Copilot plugin's /models API call
|
|
22
|
+
return { ...hardcodedModels }
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
}
|
package/src/models.ts
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Model } from "@opencode-ai/sdk/v2"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Hard-coded Copilot model definitions.
|
|
5
|
+
* This completely bypasses the internal Copilot plugin's models.ts API call
|
|
6
|
+
* (packages/opencode/src/plugin/github-copilot/models.ts) which hardcodes all costs to 0.
|
|
7
|
+
*
|
|
8
|
+
* To add/update models, edit this file directly.
|
|
9
|
+
*/
|
|
10
|
+
const BASE_URL = "https://api.githubcopilot.com"
|
|
11
|
+
const NPM_SDK = "@ai-sdk/github-copilot"
|
|
12
|
+
|
|
13
|
+
export const models: Record<string, Model> = {
|
|
14
|
+
"gemini-3.1-pro-preview": {
|
|
15
|
+
id: "gemini-3.1-pro-preview",
|
|
16
|
+
providerID: "github-copilot",
|
|
17
|
+
api: { id: "gemini-3.1-pro-preview", url: BASE_URL, npm: NPM_SDK },
|
|
18
|
+
status: "active",
|
|
19
|
+
name: "Gemini 3.1 Pro Preview",
|
|
20
|
+
family: "gemini-pro",
|
|
21
|
+
release_date: "2026-02-19",
|
|
22
|
+
cost: { input: 2, output: 12, cache: { read: 0.2, write: 0 } },
|
|
23
|
+
limit: { context: 1000000, input: 1000000, output: 64000 },
|
|
24
|
+
capabilities: {
|
|
25
|
+
temperature: true,
|
|
26
|
+
reasoning: true,
|
|
27
|
+
attachment: true,
|
|
28
|
+
toolcall: true,
|
|
29
|
+
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
|
30
|
+
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
|
31
|
+
interleaved: false,
|
|
32
|
+
},
|
|
33
|
+
options: {},
|
|
34
|
+
headers: {},
|
|
35
|
+
variants: {},
|
|
36
|
+
},
|
|
37
|
+
"claude-haiku-4.5": {
|
|
38
|
+
id: "claude-haiku-4.5",
|
|
39
|
+
providerID: "github-copilot",
|
|
40
|
+
api: { id: "claude-haiku-4.5", url: BASE_URL, npm: NPM_SDK },
|
|
41
|
+
status: "active",
|
|
42
|
+
name: "Claude Haiku 4.5",
|
|
43
|
+
family: undefined as any,
|
|
44
|
+
release_date: "2025-10-15",
|
|
45
|
+
cost: { input: 1, output: 5, cache: { read: 0.1, write: 1.25 } },
|
|
46
|
+
limit: { context: 200000, input: 136000, output: 64000 },
|
|
47
|
+
capabilities: {
|
|
48
|
+
temperature: true,
|
|
49
|
+
reasoning: false,
|
|
50
|
+
attachment: true,
|
|
51
|
+
toolcall: true,
|
|
52
|
+
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
|
53
|
+
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
|
54
|
+
interleaved: false,
|
|
55
|
+
},
|
|
56
|
+
options: {},
|
|
57
|
+
headers: {},
|
|
58
|
+
variants: {},
|
|
59
|
+
},
|
|
60
|
+
"gpt-5.4": {
|
|
61
|
+
id: "gpt-5.4",
|
|
62
|
+
providerID: "github-copilot",
|
|
63
|
+
api: { id: "gpt-5.4", url: BASE_URL, npm: NPM_SDK },
|
|
64
|
+
status: "active",
|
|
65
|
+
name: "GPT 5.4",
|
|
66
|
+
family: "gpt",
|
|
67
|
+
release_date: "2026-03-05",
|
|
68
|
+
cost: { input: 2.5, output: 15, cache: { read: 0.25, write: 0 } },
|
|
69
|
+
limit: { context: 1050000, input: 922000, output: 128000 },
|
|
70
|
+
capabilities: {
|
|
71
|
+
temperature: true,
|
|
72
|
+
reasoning: true,
|
|
73
|
+
attachment: true,
|
|
74
|
+
toolcall: true,
|
|
75
|
+
input: { text: true, audio: false, image: true, video: false, pdf: true },
|
|
76
|
+
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
|
77
|
+
interleaved: false,
|
|
78
|
+
},
|
|
79
|
+
options: {},
|
|
80
|
+
headers: {},
|
|
81
|
+
variants: {},
|
|
82
|
+
},
|
|
83
|
+
"claude-sonnet-4.6": {
|
|
84
|
+
id: "claude-sonnet-4.6",
|
|
85
|
+
providerID: "github-copilot",
|
|
86
|
+
api: { id: "claude-sonnet-4.6", url: BASE_URL, npm: NPM_SDK },
|
|
87
|
+
status: "active",
|
|
88
|
+
name: "Claude Sonnet 4.6",
|
|
89
|
+
family: undefined as any,
|
|
90
|
+
release_date: "2026-02-17",
|
|
91
|
+
cost: { input: 3, output: 15, cache: { read: 0.3, write: 3.75 } },
|
|
92
|
+
limit: { context: 200000, input: 200000, output: 64000 },
|
|
93
|
+
capabilities: {
|
|
94
|
+
temperature: true,
|
|
95
|
+
reasoning: true,
|
|
96
|
+
attachment: true,
|
|
97
|
+
toolcall: true,
|
|
98
|
+
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
|
99
|
+
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
|
100
|
+
interleaved: false,
|
|
101
|
+
},
|
|
102
|
+
options: {},
|
|
103
|
+
headers: {},
|
|
104
|
+
variants: {},
|
|
105
|
+
},
|
|
106
|
+
"claude-opus-4.6": {
|
|
107
|
+
id: "claude-opus-4.6",
|
|
108
|
+
providerID: "github-copilot",
|
|
109
|
+
api: { id: "claude-opus-4.6", url: BASE_URL, npm: NPM_SDK },
|
|
110
|
+
status: "active",
|
|
111
|
+
name: "Claude Opus 4.6",
|
|
112
|
+
family: "claude-opus",
|
|
113
|
+
release_date: "2026-02-05",
|
|
114
|
+
cost: { input: 5, output: 25, cache: { read: 0.5, write: 6.25 } },
|
|
115
|
+
limit: { context: 1000000, input: 1000000, output: 128000 },
|
|
116
|
+
capabilities: {
|
|
117
|
+
temperature: true,
|
|
118
|
+
reasoning: true,
|
|
119
|
+
attachment: true,
|
|
120
|
+
toolcall: true,
|
|
121
|
+
input: { text: true, audio: false, image: true, video: false, pdf: false },
|
|
122
|
+
output: { text: true, audio: false, image: false, video: false, pdf: false },
|
|
123
|
+
interleaved: false,
|
|
124
|
+
},
|
|
125
|
+
options: {},
|
|
126
|
+
headers: {},
|
|
127
|
+
variants: {},
|
|
128
|
+
},
|
|
129
|
+
}
|