@x-all-in-one/coding-helper 0.4.3 → 0.4.5

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
- * Check if model is a vision model (contains "VL" or ends with "V")
89
- */
90
- private isVisionModel;
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';
@@ -15,9 +16,15 @@ const OH_MY_OPENCODE_AGENTS = [
15
16
  'frontend-ui-ux-engineer',
16
17
  'document-writer',
17
18
  'multimodal-looker',
19
+ 'atlas',
18
20
  ];
19
21
  // Unified output token limit for all models
20
22
  const OUTPUT_TOKEN_LIMIT = 32000;
23
+ // Model tag constants
24
+ const TAG_VISION = '视觉';
25
+ const TAG_REASONING = '推理';
26
+ const TAG_INTERLEAVED_REASONING = '交替推理';
27
+ const deepmerge = deepmergeCustom({ mergeArrays: false });
21
28
  // Default configuration
22
29
  export const OPENCODE_DEFAULT_CONFIG = {
23
30
  BASE_URL: 'https://code-api.x-aio.com/v1',
@@ -101,32 +108,33 @@ export class OpenCodeTool extends BaseTool {
101
108
  async fetchAvailableModels() {
102
109
  return modelService.fetchModels();
103
110
  }
104
- /**
105
- * Check if model is a vision model (contains "VL" or ends with "V")
106
- */
107
- isVisionModel(modelId) {
108
- const upperCaseId = modelId.toUpperCase();
109
- return upperCaseId.includes('VL') || upperCaseId.endsWith('V');
111
+ hasTag(tags, tag) {
112
+ return Array.isArray(tags) && tags.includes(tag);
113
+ }
114
+ isVisionModelByTag(tags) {
115
+ return this.hasTag(tags, TAG_VISION);
116
+ }
117
+ isReasoningModel(tags) {
118
+ return this.hasTag(tags, TAG_REASONING) && !this.hasTag(tags, TAG_INTERLEAVED_REASONING);
119
+ }
120
+ isInterleavedReasoningModel(tags) {
121
+ return this.hasTag(tags, TAG_INTERLEAVED_REASONING);
110
122
  }
111
- /**
112
- * Build models object from fetched model list
113
- */
114
123
  buildModelsConfig(modelInfos) {
115
124
  const models = {};
116
125
  for (const info of modelInfos) {
117
126
  const entry = {};
118
- const isVision = this.isVisionModel(info.id);
119
- // Set display name
127
+ const isVision = this.isVisionModelByTag(info.tags);
128
+ const isReasoning = this.isReasoningModel(info.tags);
129
+ const isInterleavedReasoning = this.isInterleavedReasoningModel(info.tags);
120
130
  if (info.name && info.name !== info.id) {
121
131
  entry.name = info.name;
122
132
  }
123
- // Set limits (context from API, output always use unified limit)
124
133
  if (isVision) {
125
134
  entry.limit = {
126
135
  context: info.context_length || OPENCODE_DEFAULT_CONFIG.VISION_CONTEXT,
127
136
  output: OUTPUT_TOKEN_LIMIT,
128
137
  };
129
- // Add modalities for vision models
130
138
  entry.modalities = {
131
139
  input: ['text', 'image', 'video'],
132
140
  output: ['text'],
@@ -138,6 +146,13 @@ export class OpenCodeTool extends BaseTool {
138
146
  output: OUTPUT_TOKEN_LIMIT,
139
147
  };
140
148
  }
149
+ if (isInterleavedReasoning) {
150
+ entry.reasoning = true;
151
+ entry.interleaved = { field: 'reasoning_content' };
152
+ }
153
+ else if (isReasoning) {
154
+ entry.reasoning = true;
155
+ }
141
156
  models[info.id] = entry;
142
157
  }
143
158
  return models;
@@ -160,7 +175,8 @@ export class OpenCodeTool extends BaseTool {
160
175
  }
161
176
  // Read current config (preserve user's other settings)
162
177
  const currentConfig = this.getConfig();
163
- // Build xaio provider config
178
+ const existingModels = currentConfig.provider?.[XAIO_PROVIDER_ID]?.models || {};
179
+ const mergedModels = deepmerge(existingModels, modelsConfig);
164
180
  const xaioProvider = {
165
181
  npm: '@ai-sdk/openai-compatible',
166
182
  name: OPENCODE_DEFAULT_CONFIG.PROVIDER_NAME,
@@ -168,7 +184,7 @@ export class OpenCodeTool extends BaseTool {
168
184
  baseURL: `https://${configManager.baseUrl}/v1`,
169
185
  apiKey: modelConfig.apiKey,
170
186
  },
171
- models: modelsConfig,
187
+ models: mergedModels,
172
188
  };
173
189
  // Merge config: only update xaio provider, preserve other providers
174
190
  const newConfig = {
@@ -259,9 +275,8 @@ export class OpenCodeTool extends BaseTool {
259
275
  }
260
276
  currentConfig.provider[XAIO_PROVIDER_ID] = xaioProvider;
261
277
  }
262
- // 更新 models 部分
263
278
  const modelsConfig = this.buildModelsConfig(modelInfos);
264
- xaioProvider.models = modelsConfig;
279
+ xaioProvider.models = deepmerge(xaioProvider.models || {}, modelsConfig);
265
280
  this.saveConfig(currentConfig);
266
281
  }
267
282
  // ==================== Oh My OpenCode 相关方法 ====================
@@ -4,5 +4,6 @@ export interface ModelInfo {
4
4
  name?: string;
5
5
  context_length?: number;
6
6
  max_output_tokens?: number;
7
+ tags?: string[] | null;
7
8
  }
8
9
  export declare function fetchModelsFromApi(): Promise<ModelInfo[]>;
@@ -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 [];
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.3",
4
+ "version": "0.4.5",
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",