@x-all-in-one/coding-helper 0.4.6 → 0.4.7
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/dist/lib/tools/opencode-tool.d.ts +5 -5
- package/dist/lib/tools/opencode-tool.js +82 -52
- package/dist/lib/utils/fetch-models.d.ts +1 -0
- package/dist/lib/utils/fetch-models.js +1 -0
- package/dist/lib/wizard/menus/plugin-menu.js +2 -2
- package/dist/lib/wizard/menus/tool-menu.js +1 -1
- package/package.json +2 -1
|
@@ -38,6 +38,9 @@ export interface OpenCodeModelEntry {
|
|
|
38
38
|
interleaved?: {
|
|
39
39
|
field: string;
|
|
40
40
|
};
|
|
41
|
+
provider?: {
|
|
42
|
+
npm: string;
|
|
43
|
+
};
|
|
41
44
|
}
|
|
42
45
|
export interface OpenCodeProviderConfig {
|
|
43
46
|
npm: string;
|
|
@@ -62,6 +65,7 @@ export interface OpenCodeModelConfig {
|
|
|
62
65
|
smallModel: string;
|
|
63
66
|
baseUrl?: string;
|
|
64
67
|
}
|
|
68
|
+
export declare function buildOpenCodeModelEntry(info: ModelInfo): OpenCodeModelEntry;
|
|
65
69
|
/**
|
|
66
70
|
* OpenCode 工具实现
|
|
67
71
|
* 实现 ITool 接口,管理 OpenCode 的配置和生命周期
|
|
@@ -92,10 +96,6 @@ export declare class OpenCodeTool extends BaseTool {
|
|
|
92
96
|
* Fetch available models from API
|
|
93
97
|
*/
|
|
94
98
|
fetchAvailableModels(): Promise<string[]>;
|
|
95
|
-
private hasTag;
|
|
96
|
-
private isVisionModelByTag;
|
|
97
|
-
private isReasoningModel;
|
|
98
|
-
private isInterleavedReasoningModel;
|
|
99
99
|
private buildModelsConfig;
|
|
100
100
|
/**
|
|
101
101
|
* Save model config to OpenCode (merge, not overwrite)
|
|
@@ -133,7 +133,7 @@ export declare class OpenCodeTool extends BaseTool {
|
|
|
133
133
|
* Update oh-my-opencode agent and category models
|
|
134
134
|
* Only updates the model field, preserves other configurations
|
|
135
135
|
*/
|
|
136
|
-
updateOhMyOpenCodeModels(model: string): void;
|
|
136
|
+
updateOhMyOpenCodeModels(model: string, smallModel: string): void;
|
|
137
137
|
/**
|
|
138
138
|
* 获取所有已注册的插件
|
|
139
139
|
*/
|
|
@@ -10,6 +10,7 @@ const XAIO_PROVIDER_ID = 'xaio';
|
|
|
10
10
|
// oh-my-opencode agent names (latest version)
|
|
11
11
|
const OH_MY_OPENCODE_AGENTS = [
|
|
12
12
|
'sisyphus',
|
|
13
|
+
'hephaestus',
|
|
13
14
|
'oracle',
|
|
14
15
|
'librarian',
|
|
15
16
|
'explore',
|
|
@@ -18,17 +19,30 @@ const OH_MY_OPENCODE_AGENTS = [
|
|
|
18
19
|
'metis',
|
|
19
20
|
'momus',
|
|
20
21
|
'atlas',
|
|
22
|
+
'frontend-ui-ux-engineer',
|
|
23
|
+
'document-writer',
|
|
24
|
+
];
|
|
25
|
+
const OH_MY_OPENCODE_SMALL_AGENTS = [
|
|
26
|
+
'librarian',
|
|
27
|
+
'explore',
|
|
28
|
+
'document-writer',
|
|
21
29
|
];
|
|
22
30
|
// oh-my-opencode category names
|
|
23
31
|
const OH_MY_OPENCODE_CATEGORIES = [
|
|
24
32
|
'visual-engineering',
|
|
25
33
|
'ultrabrain',
|
|
34
|
+
'deep',
|
|
26
35
|
'artistry',
|
|
27
36
|
'quick',
|
|
28
37
|
'unspecified-low',
|
|
29
38
|
'unspecified-high',
|
|
30
39
|
'writing',
|
|
31
40
|
];
|
|
41
|
+
const OH_MY_OPENCODE_SMALL_CATEGORIES = [
|
|
42
|
+
'quick',
|
|
43
|
+
'unspecified-low',
|
|
44
|
+
'writing',
|
|
45
|
+
];
|
|
32
46
|
// Unified output token limit for all models
|
|
33
47
|
const OUTPUT_TOKEN_LIMIT = 32000;
|
|
34
48
|
// Model tag constants
|
|
@@ -36,6 +50,18 @@ const TAG_VISION = '视觉';
|
|
|
36
50
|
const TAG_REASONING = '推理';
|
|
37
51
|
const TAG_INTERLEAVED_REASONING = '交替推理';
|
|
38
52
|
const deepmerge = deepmergeCustom({ mergeArrays: false });
|
|
53
|
+
function hasTag(tags, tag) {
|
|
54
|
+
return Array.isArray(tags) && tags.includes(tag);
|
|
55
|
+
}
|
|
56
|
+
function isVisionModelByTag(tags) {
|
|
57
|
+
return hasTag(tags, TAG_VISION);
|
|
58
|
+
}
|
|
59
|
+
function isReasoningModel(tags) {
|
|
60
|
+
return hasTag(tags, TAG_REASONING) && !hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
61
|
+
}
|
|
62
|
+
function isInterleavedReasoningModel(tags) {
|
|
63
|
+
return hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
64
|
+
}
|
|
39
65
|
// Default configuration
|
|
40
66
|
export const OPENCODE_DEFAULT_CONFIG = {
|
|
41
67
|
BASE_URL: 'https://code-api.x-aio.com/v1',
|
|
@@ -49,6 +75,45 @@ export const OPENCODE_DEFAULT_CONFIG = {
|
|
|
49
75
|
VISION_CONTEXT: 64000,
|
|
50
76
|
VISION_OUTPUT: OUTPUT_TOKEN_LIMIT,
|
|
51
77
|
};
|
|
78
|
+
export function buildOpenCodeModelEntry(info) {
|
|
79
|
+
const entry = {};
|
|
80
|
+
const isVision = isVisionModelByTag(info.tags);
|
|
81
|
+
const isReasoning = isReasoningModel(info.tags);
|
|
82
|
+
const isInterleavedReasoning = isInterleavedReasoningModel(info.tags);
|
|
83
|
+
if (info.name && info.name !== info.id) {
|
|
84
|
+
entry.name = info.name;
|
|
85
|
+
}
|
|
86
|
+
if (isVision) {
|
|
87
|
+
entry.limit = {
|
|
88
|
+
context: info.context_length || OPENCODE_DEFAULT_CONFIG.VISION_CONTEXT,
|
|
89
|
+
output: OUTPUT_TOKEN_LIMIT,
|
|
90
|
+
};
|
|
91
|
+
entry.modalities = {
|
|
92
|
+
input: ['text', 'image', 'video'],
|
|
93
|
+
output: ['text'],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
entry.limit = {
|
|
98
|
+
context: info.context_length || OPENCODE_DEFAULT_CONFIG.DEFAULT_CONTEXT,
|
|
99
|
+
output: OUTPUT_TOKEN_LIMIT,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const isResponsesModel = info.upstream_type === 'responses';
|
|
103
|
+
if (isInterleavedReasoning) {
|
|
104
|
+
entry.reasoning = true;
|
|
105
|
+
if (!isResponsesModel) {
|
|
106
|
+
entry.interleaved = { field: 'reasoning_content' };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (isReasoning) {
|
|
110
|
+
entry.reasoning = true;
|
|
111
|
+
}
|
|
112
|
+
if (isResponsesModel) {
|
|
113
|
+
entry.provider = { npm: '@ai-sdk/openai' };
|
|
114
|
+
}
|
|
115
|
+
return entry;
|
|
116
|
+
}
|
|
52
117
|
/**
|
|
53
118
|
* OpenCode 工具实现
|
|
54
119
|
* 实现 ITool 接口,管理 OpenCode 的配置和生命周期
|
|
@@ -119,52 +184,10 @@ export class OpenCodeTool extends BaseTool {
|
|
|
119
184
|
async fetchAvailableModels() {
|
|
120
185
|
return modelService.fetchModels();
|
|
121
186
|
}
|
|
122
|
-
hasTag(tags, tag) {
|
|
123
|
-
return Array.isArray(tags) && tags.includes(tag);
|
|
124
|
-
}
|
|
125
|
-
isVisionModelByTag(tags) {
|
|
126
|
-
return this.hasTag(tags, TAG_VISION);
|
|
127
|
-
}
|
|
128
|
-
isReasoningModel(tags) {
|
|
129
|
-
return this.hasTag(tags, TAG_REASONING) && !this.hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
130
|
-
}
|
|
131
|
-
isInterleavedReasoningModel(tags) {
|
|
132
|
-
return this.hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
133
|
-
}
|
|
134
187
|
buildModelsConfig(modelInfos) {
|
|
135
188
|
const models = {};
|
|
136
189
|
for (const info of modelInfos) {
|
|
137
|
-
|
|
138
|
-
const isVision = this.isVisionModelByTag(info.tags);
|
|
139
|
-
const isReasoning = this.isReasoningModel(info.tags);
|
|
140
|
-
const isInterleavedReasoning = this.isInterleavedReasoningModel(info.tags);
|
|
141
|
-
if (info.name && info.name !== info.id) {
|
|
142
|
-
entry.name = info.name;
|
|
143
|
-
}
|
|
144
|
-
if (isVision) {
|
|
145
|
-
entry.limit = {
|
|
146
|
-
context: info.context_length || OPENCODE_DEFAULT_CONFIG.VISION_CONTEXT,
|
|
147
|
-
output: OUTPUT_TOKEN_LIMIT,
|
|
148
|
-
};
|
|
149
|
-
entry.modalities = {
|
|
150
|
-
input: ['text', 'image', 'video'],
|
|
151
|
-
output: ['text'],
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
else {
|
|
155
|
-
entry.limit = {
|
|
156
|
-
context: info.context_length || OPENCODE_DEFAULT_CONFIG.DEFAULT_CONTEXT,
|
|
157
|
-
output: OUTPUT_TOKEN_LIMIT,
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
if (isInterleavedReasoning) {
|
|
161
|
-
entry.reasoning = true;
|
|
162
|
-
entry.interleaved = { field: 'reasoning_content' };
|
|
163
|
-
}
|
|
164
|
-
else if (isReasoning) {
|
|
165
|
-
entry.reasoning = true;
|
|
166
|
-
}
|
|
167
|
-
models[info.id] = entry;
|
|
190
|
+
models[info.id] = buildOpenCodeModelEntry(info);
|
|
168
191
|
}
|
|
169
192
|
return models;
|
|
170
193
|
}
|
|
@@ -333,29 +356,35 @@ export class OpenCodeTool extends BaseTool {
|
|
|
333
356
|
throw new Error(`Failed to save oh-my-opencode config: ${error}`);
|
|
334
357
|
}
|
|
335
358
|
}
|
|
336
|
-
updateOhMyOpenCodeAgents(config, model) {
|
|
359
|
+
updateOhMyOpenCodeAgents(config, model, smallModel) {
|
|
337
360
|
if (!config.agents) {
|
|
338
361
|
config.agents = {};
|
|
339
362
|
}
|
|
340
363
|
for (const agentName of OH_MY_OPENCODE_AGENTS) {
|
|
364
|
+
const targetModel = OH_MY_OPENCODE_SMALL_AGENTS.includes(agentName)
|
|
365
|
+
? smallModel
|
|
366
|
+
: model;
|
|
341
367
|
if (config.agents[agentName]) {
|
|
342
|
-
config.agents[agentName].model =
|
|
368
|
+
config.agents[agentName].model = targetModel;
|
|
343
369
|
}
|
|
344
370
|
else {
|
|
345
|
-
config.agents[agentName] = { model };
|
|
371
|
+
config.agents[agentName] = { model: targetModel };
|
|
346
372
|
}
|
|
347
373
|
}
|
|
348
374
|
}
|
|
349
|
-
updateOhMyOpenCodeCategories(config, model) {
|
|
375
|
+
updateOhMyOpenCodeCategories(config, model, smallModel) {
|
|
350
376
|
if (!config.categories) {
|
|
351
377
|
config.categories = {};
|
|
352
378
|
}
|
|
353
379
|
for (const categoryName of OH_MY_OPENCODE_CATEGORIES) {
|
|
380
|
+
const targetModel = OH_MY_OPENCODE_SMALL_CATEGORIES.includes(categoryName)
|
|
381
|
+
? smallModel
|
|
382
|
+
: model;
|
|
354
383
|
if (config.categories[categoryName]) {
|
|
355
|
-
config.categories[categoryName].model =
|
|
384
|
+
config.categories[categoryName].model = targetModel;
|
|
356
385
|
}
|
|
357
386
|
else {
|
|
358
|
-
config.categories[categoryName] = { model };
|
|
387
|
+
config.categories[categoryName] = { model: targetModel };
|
|
359
388
|
}
|
|
360
389
|
}
|
|
361
390
|
}
|
|
@@ -363,11 +392,12 @@ export class OpenCodeTool extends BaseTool {
|
|
|
363
392
|
* Update oh-my-opencode agent and category models
|
|
364
393
|
* Only updates the model field, preserves other configurations
|
|
365
394
|
*/
|
|
366
|
-
updateOhMyOpenCodeModels(model) {
|
|
395
|
+
updateOhMyOpenCodeModels(model, smallModel) {
|
|
367
396
|
const prefixedModel = `${XAIO_PROVIDER_ID}/${model}`;
|
|
397
|
+
const prefixedSmallModel = `${XAIO_PROVIDER_ID}/${smallModel}`;
|
|
368
398
|
const currentConfig = this.getOhMyOpenCodeConfig();
|
|
369
|
-
this.updateOhMyOpenCodeAgents(currentConfig, prefixedModel);
|
|
370
|
-
this.updateOhMyOpenCodeCategories(currentConfig, prefixedModel);
|
|
399
|
+
this.updateOhMyOpenCodeAgents(currentConfig, prefixedModel, prefixedSmallModel);
|
|
400
|
+
this.updateOhMyOpenCodeCategories(currentConfig, prefixedModel, prefixedSmallModel);
|
|
371
401
|
if (!currentConfig.$schema) {
|
|
372
402
|
currentConfig.$schema = 'https://raw.githubusercontent.com/code-yeongyu/oh-my-opencode/master/assets/oh-my-opencode.schema.json';
|
|
373
403
|
}
|
|
@@ -20,6 +20,7 @@ export async function fetchModelsFromApi() {
|
|
|
20
20
|
context_length: m.context ? m.context * 1000 : undefined,
|
|
21
21
|
max_output_tokens: m.context ? m.context * 500 : undefined,
|
|
22
22
|
tags: Array.isArray(m.tags) ? m.tags : null,
|
|
23
|
+
upstream_type: typeof m.upstream_type === 'string' ? m.upstream_type : undefined,
|
|
23
24
|
}));
|
|
24
25
|
}
|
|
25
26
|
return [];
|
|
@@ -117,8 +117,8 @@ export class PluginMenu {
|
|
|
117
117
|
const result = await modelService.refreshAndSyncToOpenCode();
|
|
118
118
|
if (result.success) {
|
|
119
119
|
const modelConfig = openCodeTool.getModelConfig();
|
|
120
|
-
if (modelConfig?.model) {
|
|
121
|
-
openCodeTool.updateOhMyOpenCodeModels(modelConfig.model);
|
|
120
|
+
if (modelConfig?.model && modelConfig.smallModel) {
|
|
121
|
+
openCodeTool.updateOhMyOpenCodeModels(modelConfig.model, modelConfig.smallModel);
|
|
122
122
|
}
|
|
123
123
|
spinner.succeed(chalk.green(i18n.t('wizard.models_refreshed', { count: String(result.count) })));
|
|
124
124
|
}
|
|
@@ -364,7 +364,7 @@ export class ToolMenu {
|
|
|
364
364
|
// Update oh-my-opencode agent models if plugin is installed
|
|
365
365
|
if (toolName === 'opencode' && openCodeTool.hasOhMyOpenCodePlugin()) {
|
|
366
366
|
spinner.text = i18n.t('wizard.oh_my_opencode_detected');
|
|
367
|
-
openCodeTool.updateOhMyOpenCodeModels(openCodeModel);
|
|
367
|
+
openCodeTool.updateOhMyOpenCodeModels(openCodeModel, openCodeSmallModel);
|
|
368
368
|
await new Promise(resolve => setTimeout(resolve, 500));
|
|
369
369
|
console.log(chalk.gray(` ${i18n.t('wizard.oh_my_opencode_models_updated')}`));
|
|
370
370
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-all-in-one/coding-helper",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.4.
|
|
4
|
+
"version": "0.4.7",
|
|
5
5
|
"description": "X All In One Coding Helper",
|
|
6
6
|
"author": "X.AIO",
|
|
7
7
|
"homepage": "https://docs.x-aio.com/zh/docs",
|
|
@@ -69,6 +69,7 @@
|
|
|
69
69
|
"lint": "eslint .",
|
|
70
70
|
"lint:fix": "eslint . --fix",
|
|
71
71
|
"type-check": "tsc --noEmit",
|
|
72
|
+
"verify:opencode-provider": "tsx scripts/verify-opencode-responses-provider.ts",
|
|
72
73
|
"changeset": "changeset",
|
|
73
74
|
"version": "changeset version",
|
|
74
75
|
"release": "pnpm run build && changeset publish"
|