@x-all-in-one/coding-helper 0.4.2 → 0.4.4
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.
|
@@ -30,6 +30,10 @@ export interface OpenCodeModelEntry {
|
|
|
30
30
|
input?: string[];
|
|
31
31
|
output?: string[];
|
|
32
32
|
};
|
|
33
|
+
reasoning?: boolean;
|
|
34
|
+
interleaved?: {
|
|
35
|
+
field: string;
|
|
36
|
+
};
|
|
33
37
|
}
|
|
34
38
|
export interface OpenCodeProviderConfig {
|
|
35
39
|
npm: string;
|
|
@@ -84,13 +88,10 @@ export declare class OpenCodeTool extends BaseTool {
|
|
|
84
88
|
* Fetch available models from API
|
|
85
89
|
*/
|
|
86
90
|
fetchAvailableModels(): Promise<string[]>;
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
private
|
|
91
|
-
/**
|
|
92
|
-
* Build models object from fetched model list
|
|
93
|
-
*/
|
|
91
|
+
private hasTag;
|
|
92
|
+
private isVisionModelByTag;
|
|
93
|
+
private isReasoningModel;
|
|
94
|
+
private isInterleavedReasoningModel;
|
|
94
95
|
private buildModelsConfig;
|
|
95
96
|
/**
|
|
96
97
|
* Save model config to OpenCode (merge, not overwrite)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { homedir } from 'node:os';
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
|
+
import { deepmergeCustom } from 'deepmerge-ts';
|
|
4
5
|
import { configManager } from '../config.js';
|
|
5
6
|
import { modelService } from '../model-service.js';
|
|
6
7
|
import { BaseTool } from './base-tool.js';
|
|
@@ -18,6 +19,11 @@ const OH_MY_OPENCODE_AGENTS = [
|
|
|
18
19
|
];
|
|
19
20
|
// Unified output token limit for all models
|
|
20
21
|
const OUTPUT_TOKEN_LIMIT = 32000;
|
|
22
|
+
// Model tag constants
|
|
23
|
+
const TAG_VISION = '视觉';
|
|
24
|
+
const TAG_REASONING = '推理';
|
|
25
|
+
const TAG_INTERLEAVED_REASONING = '交替推理';
|
|
26
|
+
const deepmerge = deepmergeCustom({ mergeArrays: false });
|
|
21
27
|
// Default configuration
|
|
22
28
|
export const OPENCODE_DEFAULT_CONFIG = {
|
|
23
29
|
BASE_URL: 'https://code-api.x-aio.com/v1',
|
|
@@ -101,32 +107,33 @@ export class OpenCodeTool extends BaseTool {
|
|
|
101
107
|
async fetchAvailableModels() {
|
|
102
108
|
return modelService.fetchModels();
|
|
103
109
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
+
hasTag(tags, tag) {
|
|
111
|
+
return Array.isArray(tags) && tags.includes(tag);
|
|
112
|
+
}
|
|
113
|
+
isVisionModelByTag(tags) {
|
|
114
|
+
return this.hasTag(tags, TAG_VISION);
|
|
115
|
+
}
|
|
116
|
+
isReasoningModel(tags) {
|
|
117
|
+
return this.hasTag(tags, TAG_REASONING) && !this.hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
118
|
+
}
|
|
119
|
+
isInterleavedReasoningModel(tags) {
|
|
120
|
+
return this.hasTag(tags, TAG_INTERLEAVED_REASONING);
|
|
110
121
|
}
|
|
111
|
-
/**
|
|
112
|
-
* Build models object from fetched model list
|
|
113
|
-
*/
|
|
114
122
|
buildModelsConfig(modelInfos) {
|
|
115
123
|
const models = {};
|
|
116
124
|
for (const info of modelInfos) {
|
|
117
125
|
const entry = {};
|
|
118
|
-
const isVision = this.
|
|
119
|
-
|
|
126
|
+
const isVision = this.isVisionModelByTag(info.tags);
|
|
127
|
+
const isReasoning = this.isReasoningModel(info.tags);
|
|
128
|
+
const isInterleavedReasoning = this.isInterleavedReasoningModel(info.tags);
|
|
120
129
|
if (info.name && info.name !== info.id) {
|
|
121
130
|
entry.name = info.name;
|
|
122
131
|
}
|
|
123
|
-
// Set limits (context from API, output always use unified limit)
|
|
124
132
|
if (isVision) {
|
|
125
133
|
entry.limit = {
|
|
126
134
|
context: info.context_length || OPENCODE_DEFAULT_CONFIG.VISION_CONTEXT,
|
|
127
135
|
output: OUTPUT_TOKEN_LIMIT,
|
|
128
136
|
};
|
|
129
|
-
// Add modalities for vision models
|
|
130
137
|
entry.modalities = {
|
|
131
138
|
input: ['text', 'image', 'video'],
|
|
132
139
|
output: ['text'],
|
|
@@ -138,6 +145,13 @@ export class OpenCodeTool extends BaseTool {
|
|
|
138
145
|
output: OUTPUT_TOKEN_LIMIT,
|
|
139
146
|
};
|
|
140
147
|
}
|
|
148
|
+
if (isInterleavedReasoning) {
|
|
149
|
+
entry.reasoning = true;
|
|
150
|
+
entry.interleaved = { field: 'reasoning_content' };
|
|
151
|
+
}
|
|
152
|
+
else if (isReasoning) {
|
|
153
|
+
entry.reasoning = true;
|
|
154
|
+
}
|
|
141
155
|
models[info.id] = entry;
|
|
142
156
|
}
|
|
143
157
|
return models;
|
|
@@ -160,7 +174,8 @@ export class OpenCodeTool extends BaseTool {
|
|
|
160
174
|
}
|
|
161
175
|
// Read current config (preserve user's other settings)
|
|
162
176
|
const currentConfig = this.getConfig();
|
|
163
|
-
|
|
177
|
+
const existingModels = currentConfig.provider?.[XAIO_PROVIDER_ID]?.models || {};
|
|
178
|
+
const mergedModels = deepmerge(existingModels, modelsConfig);
|
|
164
179
|
const xaioProvider = {
|
|
165
180
|
npm: '@ai-sdk/openai-compatible',
|
|
166
181
|
name: OPENCODE_DEFAULT_CONFIG.PROVIDER_NAME,
|
|
@@ -168,7 +183,7 @@ export class OpenCodeTool extends BaseTool {
|
|
|
168
183
|
baseURL: `https://${configManager.baseUrl}/v1`,
|
|
169
184
|
apiKey: modelConfig.apiKey,
|
|
170
185
|
},
|
|
171
|
-
models:
|
|
186
|
+
models: mergedModels,
|
|
172
187
|
};
|
|
173
188
|
// Merge config: only update xaio provider, preserve other providers
|
|
174
189
|
const newConfig = {
|
|
@@ -259,9 +274,8 @@ export class OpenCodeTool extends BaseTool {
|
|
|
259
274
|
}
|
|
260
275
|
currentConfig.provider[XAIO_PROVIDER_ID] = xaioProvider;
|
|
261
276
|
}
|
|
262
|
-
// 更新 models 部分
|
|
263
277
|
const modelsConfig = this.buildModelsConfig(modelInfos);
|
|
264
|
-
xaioProvider.models = modelsConfig;
|
|
278
|
+
xaioProvider.models = deepmerge(xaioProvider.models || {}, modelsConfig);
|
|
265
279
|
this.saveConfig(currentConfig);
|
|
266
280
|
}
|
|
267
281
|
// ==================== Oh My OpenCode 相关方法 ====================
|
|
@@ -19,6 +19,7 @@ export async function fetchModelsFromApi() {
|
|
|
19
19
|
name: m.real_model_name,
|
|
20
20
|
context_length: m.context ? m.context * 1000 : undefined,
|
|
21
21
|
max_output_tokens: m.context ? m.context * 500 : undefined,
|
|
22
|
+
tags: Array.isArray(m.tags) ? m.tags : null,
|
|
22
23
|
}));
|
|
23
24
|
}
|
|
24
25
|
return [];
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
|
+
import { configManager } from '../../config.js';
|
|
3
4
|
import { i18n } from '../../i18n.js';
|
|
4
5
|
import { promptHelper } from '../ui/prompt-helper.js';
|
|
5
6
|
import { uiRenderer } from '../ui/ui-renderer.js';
|
|
@@ -51,7 +52,8 @@ export class LanguageFlow {
|
|
|
51
52
|
if (language === 'back') {
|
|
52
53
|
return 'back';
|
|
53
54
|
}
|
|
54
|
-
|
|
55
|
+
configManager.setLang(language);
|
|
56
|
+
i18n.loadFromConfig(language);
|
|
55
57
|
console.log(chalk.green(`\n✨ ${i18n.t('wizard.language_set')}`));
|
|
56
58
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
|
57
59
|
}
|
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.4",
|
|
5
5
|
"description": "X All In One Coding Helper",
|
|
6
6
|
"author": "X.AIO",
|
|
7
7
|
"homepage": "https://docs.x-aio.com/zh/docs",
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"dependencies": {
|
|
34
34
|
"chalk": "^5.3.0",
|
|
35
35
|
"commander": "^12.1.0",
|
|
36
|
+
"deepmerge-ts": "^7.1.5",
|
|
36
37
|
"inquirer": "^9.2.12",
|
|
37
38
|
"js-yaml": "^4.1.0",
|
|
38
39
|
"open": "^11.0.0",
|