@lutery/vision-mcp 1.0.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.
Files changed (122) hide show
  1. package/README.md +428 -0
  2. package/dist/adapters/base-adapter.d.ts +69 -0
  3. package/dist/adapters/base-adapter.d.ts.map +1 -0
  4. package/dist/adapters/base-adapter.js +143 -0
  5. package/dist/adapters/base-adapter.js.map +1 -0
  6. package/dist/adapters/claude-adapter.d.ts +38 -0
  7. package/dist/adapters/claude-adapter.d.ts.map +1 -0
  8. package/dist/adapters/claude-adapter.js +251 -0
  9. package/dist/adapters/claude-adapter.js.map +1 -0
  10. package/dist/adapters/glm-adapter.d.ts +15 -0
  11. package/dist/adapters/glm-adapter.d.ts.map +1 -0
  12. package/dist/adapters/glm-adapter.js +131 -0
  13. package/dist/adapters/glm-adapter.js.map +1 -0
  14. package/dist/adapters/modelscope-adapter.d.ts +20 -0
  15. package/dist/adapters/modelscope-adapter.d.ts.map +1 -0
  16. package/dist/adapters/modelscope-adapter.js +142 -0
  17. package/dist/adapters/modelscope-adapter.js.map +1 -0
  18. package/dist/adapters/openai-adapter.d.ts +20 -0
  19. package/dist/adapters/openai-adapter.d.ts.map +1 -0
  20. package/dist/adapters/openai-adapter.js +194 -0
  21. package/dist/adapters/openai-adapter.js.map +1 -0
  22. package/dist/adapters/siliconflow-adapter.d.ts +21 -0
  23. package/dist/adapters/siliconflow-adapter.d.ts.map +1 -0
  24. package/dist/adapters/siliconflow-adapter.js +145 -0
  25. package/dist/adapters/siliconflow-adapter.js.map +1 -0
  26. package/dist/config/model-config.d.ts +39 -0
  27. package/dist/config/model-config.d.ts.map +1 -0
  28. package/dist/config/model-config.js +115 -0
  29. package/dist/config/model-config.js.map +1 -0
  30. package/dist/index.d.ts +17 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +186 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/prompts/system.d.ts +75 -0
  35. package/dist/prompts/system.d.ts.map +1 -0
  36. package/dist/prompts/system.js +272 -0
  37. package/dist/prompts/system.js.map +1 -0
  38. package/dist/providers/provider-registry.d.ts +58 -0
  39. package/dist/providers/provider-registry.d.ts.map +1 -0
  40. package/dist/providers/provider-registry.js +173 -0
  41. package/dist/providers/provider-registry.js.map +1 -0
  42. package/dist/src/adapters/base-adapter.d.ts +59 -0
  43. package/dist/src/adapters/base-adapter.d.ts.map +1 -0
  44. package/dist/src/adapters/base-adapter.js +83 -0
  45. package/dist/src/adapters/base-adapter.js.map +1 -0
  46. package/dist/src/adapters/glm-adapter.d.ts +15 -0
  47. package/dist/src/adapters/glm-adapter.d.ts.map +1 -0
  48. package/dist/src/adapters/glm-adapter.js +116 -0
  49. package/dist/src/adapters/glm-adapter.js.map +1 -0
  50. package/dist/src/adapters/siliconflow-adapter.d.ts +21 -0
  51. package/dist/src/adapters/siliconflow-adapter.d.ts.map +1 -0
  52. package/dist/src/adapters/siliconflow-adapter.js +130 -0
  53. package/dist/src/adapters/siliconflow-adapter.js.map +1 -0
  54. package/dist/src/config/model-config.d.ts +40 -0
  55. package/dist/src/config/model-config.d.ts.map +1 -0
  56. package/dist/src/config/model-config.js +126 -0
  57. package/dist/src/config/model-config.js.map +1 -0
  58. package/dist/src/index.d.ts +17 -0
  59. package/dist/src/index.d.ts.map +1 -0
  60. package/dist/src/index.js +188 -0
  61. package/dist/src/index.js.map +1 -0
  62. package/dist/src/prompts/system.d.ts +75 -0
  63. package/dist/src/prompts/system.d.ts.map +1 -0
  64. package/dist/src/prompts/system.js +272 -0
  65. package/dist/src/prompts/system.js.map +1 -0
  66. package/dist/src/tools/vision-tool.d.ts +91 -0
  67. package/dist/src/tools/vision-tool.d.ts.map +1 -0
  68. package/dist/src/tools/vision-tool.js +171 -0
  69. package/dist/src/tools/vision-tool.js.map +1 -0
  70. package/dist/src/utils/errors.d.ts +65 -0
  71. package/dist/src/utils/errors.d.ts.map +1 -0
  72. package/dist/src/utils/errors.js +146 -0
  73. package/dist/src/utils/errors.js.map +1 -0
  74. package/dist/src/utils/image-input.d.ts +45 -0
  75. package/dist/src/utils/image-input.d.ts.map +1 -0
  76. package/dist/src/utils/image-input.js +226 -0
  77. package/dist/src/utils/image-input.js.map +1 -0
  78. package/dist/src/utils/logger.d.ts +63 -0
  79. package/dist/src/utils/logger.d.ts.map +1 -0
  80. package/dist/src/utils/logger.js +157 -0
  81. package/dist/src/utils/logger.js.map +1 -0
  82. package/dist/test/integration.test.d.ts +10 -0
  83. package/dist/test/integration.test.d.ts.map +1 -0
  84. package/dist/test/integration.test.js +270 -0
  85. package/dist/test/integration.test.js.map +1 -0
  86. package/dist/test/test-utils.d.ts +45 -0
  87. package/dist/test/test-utils.d.ts.map +1 -0
  88. package/dist/test/test-utils.js +107 -0
  89. package/dist/test/test-utils.js.map +1 -0
  90. package/dist/test/vision-tool.test.d.ts +9 -0
  91. package/dist/test/vision-tool.test.d.ts.map +1 -0
  92. package/dist/test/vision-tool.test.js +167 -0
  93. package/dist/test/vision-tool.test.js.map +1 -0
  94. package/dist/tools/vision-tool.d.ts +91 -0
  95. package/dist/tools/vision-tool.d.ts.map +1 -0
  96. package/dist/tools/vision-tool.js +167 -0
  97. package/dist/tools/vision-tool.js.map +1 -0
  98. package/dist/utils/data-url-parser.d.ts +27 -0
  99. package/dist/utils/data-url-parser.d.ts.map +1 -0
  100. package/dist/utils/data-url-parser.js +53 -0
  101. package/dist/utils/data-url-parser.js.map +1 -0
  102. package/dist/utils/errors.d.ts +65 -0
  103. package/dist/utils/errors.d.ts.map +1 -0
  104. package/dist/utils/errors.js +146 -0
  105. package/dist/utils/errors.js.map +1 -0
  106. package/dist/utils/image-input.d.ts +45 -0
  107. package/dist/utils/image-input.d.ts.map +1 -0
  108. package/dist/utils/image-input.js +238 -0
  109. package/dist/utils/image-input.js.map +1 -0
  110. package/dist/utils/logger.d.ts +63 -0
  111. package/dist/utils/logger.d.ts.map +1 -0
  112. package/dist/utils/logger.js +157 -0
  113. package/dist/utils/logger.js.map +1 -0
  114. package/dist/utils/thinking-extractors.d.ts +34 -0
  115. package/dist/utils/thinking-extractors.d.ts.map +1 -0
  116. package/dist/utils/thinking-extractors.js +83 -0
  117. package/dist/utils/thinking-extractors.js.map +1 -0
  118. package/dist/utils/thinking-filter.d.ts +32 -0
  119. package/dist/utils/thinking-filter.d.ts.map +1 -0
  120. package/dist/utils/thinking-filter.js +147 -0
  121. package/dist/utils/thinking-filter.js.map +1 -0
  122. package/package.json +41 -0
@@ -0,0 +1,194 @@
1
+ /**
2
+ * OpenAI Adapter
3
+ *
4
+ * @description OpenAI API 适配器实现,支持 GPT-4o、GPT-4 Vision 等视觉模型
5
+ */
6
+ import { BaseVisionModelAdapter } from './base-adapter.js';
7
+ import { ModelAPIError, ModelConfigError } from '../utils/errors.js';
8
+ import { logger } from '../utils/logger.js';
9
+ export class OpenAIAdapter extends BaseVisionModelAdapter {
10
+ options;
11
+ constructor(config, options = {}) {
12
+ super(config);
13
+ if (config.type !== 'openai') {
14
+ throw new ModelConfigError('Invalid model type. Expected: openai', { expected: 'openai', received: config.type });
15
+ }
16
+ this.options = {
17
+ maxTokens: 2048,
18
+ temperature: 0.7,
19
+ ...options
20
+ };
21
+ logger.info('Initialized OpenAI adapter', {
22
+ model: config.name,
23
+ baseUrl: config.baseUrl,
24
+ options: this.options
25
+ });
26
+ }
27
+ async analyze(imageData, prompt) {
28
+ logger.logRequest('Analyzing image with OpenAI', {
29
+ modelType: 'openai',
30
+ model: this.config.name,
31
+ imageLength: imageData.length
32
+ });
33
+ try {
34
+ return await this.withRetry(async (signal) => {
35
+ const response = await this.callOpenAIAPI(imageData, prompt, signal);
36
+ logger.logRequest('OpenAI analysis completed', {
37
+ modelType: 'openai',
38
+ model: this.config.name,
39
+ responseLength: response.content.length
40
+ });
41
+ return response.content;
42
+ });
43
+ }
44
+ catch (error) {
45
+ logger.error('OpenAI analysis failed', error);
46
+ throw error;
47
+ }
48
+ }
49
+ async analyzeWithResponse(imageData, prompt) {
50
+ logger.logRequest('Analyzing image with OpenAI (full response)', {
51
+ modelType: 'openai',
52
+ model: this.config.name,
53
+ imageLength: imageData.length
54
+ });
55
+ try {
56
+ return await this.withRetry(async (signal) => {
57
+ const response = await this.callOpenAIAPI(imageData, prompt, signal);
58
+ logger.logRequest('OpenAI analysis completed', {
59
+ modelType: 'openai',
60
+ model: this.config.name,
61
+ responseLength: response.content.length,
62
+ usage: response.usage
63
+ });
64
+ return response;
65
+ });
66
+ }
67
+ catch (error) {
68
+ logger.error('OpenAI analysis failed', error);
69
+ throw error;
70
+ }
71
+ }
72
+ async callOpenAIAPI(imageData, prompt, signal) {
73
+ // 构建 API 端点(移除末尾斜杠后添加 /chat/completions)
74
+ const baseUrl = this.config.baseUrl.replace(/\/$/, '');
75
+ const apiUrl = `${baseUrl}/chat/completions`;
76
+ // 构建请求体(OpenAI Chat Completions 格式)
77
+ const requestBody = {
78
+ model: this.config.name,
79
+ messages: [
80
+ {
81
+ role: 'user',
82
+ content: [
83
+ {
84
+ type: 'text',
85
+ text: prompt
86
+ },
87
+ {
88
+ type: 'image_url',
89
+ image_url: {
90
+ url: imageData
91
+ }
92
+ }
93
+ ]
94
+ }
95
+ ],
96
+ stream: false, // 强制非流式响应
97
+ // 注意:使用 max_tokens 参数
98
+ // - 适用于 gpt-4o、gpt-4-vision-preview 等主流模型
99
+ // - 对于 reasoning/o 系列模型,可能需要使用 max_completion_tokens
100
+ // - 未来可根据模型名称动态选择参数
101
+ max_tokens: this.options.maxTokens,
102
+ temperature: this.options.temperature
103
+ };
104
+ logger.debug('Calling OpenAI API', {
105
+ apiUrl,
106
+ model: this.config.name,
107
+ maxTokens: this.options.maxTokens,
108
+ temperature: this.options.temperature
109
+ });
110
+ const response = await fetch(apiUrl, {
111
+ method: 'POST',
112
+ headers: {
113
+ 'Authorization': `Bearer ${this.config.apiKey}`,
114
+ 'Content-Type': 'application/json',
115
+ 'Accept': 'application/json'
116
+ },
117
+ body: JSON.stringify(requestBody),
118
+ signal
119
+ });
120
+ if (!response.ok) {
121
+ const rawErrorText = await response.text().catch(() => 'Failed to get error details');
122
+ // 截断过长的错误信息(最多 500 字符)
123
+ const MAX_ERROR_LENGTH = 500;
124
+ const errorText = rawErrorText.length > MAX_ERROR_LENGTH
125
+ ? `${rawErrorText.slice(0, MAX_ERROR_LENGTH)}... (truncated)`
126
+ : rawErrorText;
127
+ // 尝试解析 OpenAI 标准错误格式
128
+ let errorMessage = `OpenAI API request failed: ${response.status} ${response.statusText}`;
129
+ let errorCode;
130
+ let guidance;
131
+ try {
132
+ const errorJson = JSON.parse(rawErrorText);
133
+ if (errorJson.error) {
134
+ errorMessage = errorJson.error.message || errorMessage;
135
+ errorCode = errorJson.error.code;
136
+ guidance = errorJson.error.type;
137
+ }
138
+ }
139
+ catch {
140
+ // 不是 JSON 格式,使用原始文本
141
+ }
142
+ // 特殊处理 429 限流
143
+ if (response.status === 429) {
144
+ const retryAfter = response.headers.get('retry-after');
145
+ const retryAfterText = retryAfter ? `Retry after ${retryAfter}s. ` : '';
146
+ throw new ModelAPIError(`Rate limit exceeded (429). ${retryAfterText}Please check your API quota or wait before retrying.`, {
147
+ status: response.status,
148
+ statusText: response.statusText,
149
+ errorCode,
150
+ errorDetails: errorText,
151
+ endpoint: apiUrl,
152
+ retryAfter: retryAfter,
153
+ guidance: guidance || 'Check your API quota or wait before retrying'
154
+ });
155
+ }
156
+ // 其他错误
157
+ throw new ModelAPIError(errorMessage, {
158
+ status: response.status,
159
+ statusText: response.statusText,
160
+ errorCode,
161
+ errorDetails: errorText,
162
+ endpoint: apiUrl,
163
+ guidance
164
+ });
165
+ }
166
+ // JSON 解析带兜底处理
167
+ let responseData;
168
+ const rawText = await response.text();
169
+ try {
170
+ responseData = JSON.parse(rawText);
171
+ }
172
+ catch (parseError) {
173
+ // 截断原始响应体用于诊断(最多 500 字符)
174
+ const truncatedBody = rawText.slice(0, 500);
175
+ const bodyPreview = rawText.length > 500
176
+ ? `${truncatedBody}... (truncated, total length: ${rawText.length})`
177
+ : rawText;
178
+ logger.error('Failed to parse successful response as JSON', parseError, {
179
+ contentType: response.headers.get('content-type'),
180
+ bodyLength: rawText.length,
181
+ bodyPreview
182
+ });
183
+ throw new ModelAPIError('Invalid JSON response from successful request', {
184
+ status: response.status,
185
+ statusText: response.statusText,
186
+ endpoint: apiUrl,
187
+ errorDetails: bodyPreview,
188
+ parseError: parseError instanceof Error ? parseError.message : String(parseError)
189
+ });
190
+ }
191
+ return this.parseResponse(responseData, 'openai');
192
+ }
193
+ }
194
+ //# sourceMappingURL=openai-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-adapter.js","sourceRoot":"","sources":["../../src/adapters/openai-adapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * SiliconFlow Adapter
3
+ *
4
+ * @description SiliconFlow 模型适配器实现,支持多种视觉模型(Qwen2-VL、InternVL 等)
5
+ */
6
+ import { BaseVisionModelAdapter } from './base-adapter.js';
7
+ import { ModelConfig } from '../config/model-config.js';
8
+ import { VisionModelResponse } from './base-adapter.js';
9
+ export interface SiliconFlowAdapterOptions {
10
+ detail?: 'low' | 'high' | 'auto';
11
+ maxTokens?: number;
12
+ temperature?: number;
13
+ }
14
+ export declare class SiliconFlowAdapter extends BaseVisionModelAdapter {
15
+ private options;
16
+ constructor(config: ModelConfig, options?: SiliconFlowAdapterOptions);
17
+ analyze(imageData: string, prompt: string): Promise<string>;
18
+ analyzeWithResponse(imageData: string, prompt: string): Promise<VisionModelResponse>;
19
+ private callSiliconFlowAPI;
20
+ }
21
+ //# sourceMappingURL=siliconflow-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siliconflow-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/siliconflow-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAGxD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAExD,MAAM,WAAW,yBAAyB;IACxC,MAAM,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qBAAa,kBAAmB,SAAQ,sBAAsB;IAC5D,OAAO,CAAC,OAAO,CAA4B;gBAE/B,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,yBAA8B;IAqBlE,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAyB3D,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;YA0B5E,kBAAkB;CAsFjC"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * SiliconFlow Adapter
3
+ *
4
+ * @description SiliconFlow 模型适配器实现,支持多种视觉模型(Qwen2-VL、InternVL 等)
5
+ */
6
+ import { BaseVisionModelAdapter } from './base-adapter.js';
7
+ import { ModelAPIError } from '../utils/errors.js';
8
+ import { logger } from '../utils/logger.js';
9
+ export class SiliconFlowAdapter extends BaseVisionModelAdapter {
10
+ options;
11
+ constructor(config, options = {}) {
12
+ super(config);
13
+ if (config.type !== 'siliconflow') {
14
+ throw new Error('Invalid model type. Expected: siliconflow');
15
+ }
16
+ this.options = {
17
+ detail: 'auto',
18
+ maxTokens: 2048,
19
+ temperature: 0.7,
20
+ ...options
21
+ };
22
+ logger.info('Initialized SiliconFlow adapter', {
23
+ model: config.name,
24
+ baseUrl: config.baseUrl,
25
+ options: this.options
26
+ });
27
+ }
28
+ async analyze(imageData, prompt) {
29
+ logger.logRequest('Analyzing image with SiliconFlow', {
30
+ modelType: 'siliconflow',
31
+ model: this.config.name,
32
+ imageLength: imageData.length
33
+ });
34
+ try {
35
+ return await this.withRetry(async (signal) => {
36
+ const response = await this.callSiliconFlowAPI(imageData, prompt, signal);
37
+ logger.logRequest('SiliconFlow analysis completed', {
38
+ modelType: 'siliconflow',
39
+ model: this.config.name,
40
+ responseLength: response.content.length
41
+ });
42
+ return response.content;
43
+ });
44
+ }
45
+ catch (error) {
46
+ logger.error('SiliconFlow analysis failed', error);
47
+ throw error;
48
+ }
49
+ }
50
+ async analyzeWithResponse(imageData, prompt) {
51
+ logger.logRequest('Analyzing image with SiliconFlow (full response)', {
52
+ modelType: 'siliconflow',
53
+ model: this.config.name,
54
+ imageLength: imageData.length
55
+ });
56
+ try {
57
+ return await this.withRetry(async (signal) => {
58
+ const response = await this.callSiliconFlowAPI(imageData, prompt, signal);
59
+ logger.logRequest('SiliconFlow analysis completed', {
60
+ modelType: 'siliconflow',
61
+ model: this.config.name,
62
+ responseLength: response.content.length,
63
+ usage: response.usage
64
+ });
65
+ return response;
66
+ });
67
+ }
68
+ catch (error) {
69
+ logger.error('SiliconFlow analysis failed', error);
70
+ throw error;
71
+ }
72
+ }
73
+ async callSiliconFlowAPI(imageData, prompt, signal) {
74
+ // 构建请求 URL
75
+ const apiUrl = `${this.config.baseUrl}/chat/completions`;
76
+ // 构建请求体(OpenAI 兼容格式)
77
+ const requestBody = {
78
+ model: this.config.name,
79
+ messages: [
80
+ {
81
+ role: 'user',
82
+ content: [
83
+ {
84
+ type: 'text',
85
+ text: prompt
86
+ },
87
+ {
88
+ type: 'image_url',
89
+ image_url: {
90
+ url: imageData,
91
+ detail: this.options.detail || 'auto'
92
+ }
93
+ }
94
+ ]
95
+ }
96
+ ],
97
+ stream: false, // 显式禁用流式响应
98
+ max_tokens: this.options.maxTokens,
99
+ temperature: this.options.temperature
100
+ };
101
+ logger.debug('Calling SiliconFlow API', {
102
+ apiUrl,
103
+ model: this.config.name,
104
+ detail: this.options.detail,
105
+ maxTokens: this.options.maxTokens,
106
+ temperature: this.options.temperature
107
+ });
108
+ const response = await fetch(apiUrl, {
109
+ method: 'POST',
110
+ headers: {
111
+ 'Authorization': `Bearer ${this.config.apiKey}`,
112
+ 'Content-Type': 'application/json',
113
+ 'Accept': 'application/json'
114
+ },
115
+ body: JSON.stringify(requestBody),
116
+ signal
117
+ });
118
+ if (!response.ok) {
119
+ const errorText = await response.text().catch(() => 'Failed to get error details');
120
+ // Special handling for rate limiting
121
+ if (response.status === 429) {
122
+ const retryAfter = response.headers.get('retry-after');
123
+ const retryAfterText = retryAfter ? `Retry after ${retryAfter}s. ` : '';
124
+ throw new ModelAPIError(`Rate limit exceeded (429). ${retryAfterText}Please check your API quota or wait before retrying.`, {
125
+ status: response.status,
126
+ statusText: response.statusText,
127
+ errorDetails: errorText,
128
+ endpoint: apiUrl,
129
+ retryAfter: retryAfter,
130
+ guidance: 'Check your API quota or wait before retrying'
131
+ });
132
+ }
133
+ // Handle other errors normally
134
+ throw new ModelAPIError(`SiliconFlow API request failed: ${response.status} ${response.statusText}`, {
135
+ status: response.status,
136
+ statusText: response.statusText,
137
+ errorDetails: errorText,
138
+ endpoint: apiUrl
139
+ });
140
+ }
141
+ const responseData = await response.json();
142
+ return this.parseResponse(responseData, 'siliconflow');
143
+ }
144
+ }
145
+ //# sourceMappingURL=siliconflow-adapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"siliconflow-adapter.js","sourceRoot":"","sources":["../../src/adapters/siliconflow-adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAE3D,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAS5C,MAAM,OAAO,kBAAmB,SAAQ,sBAAsB;IACpD,OAAO,CAA4B;IAE3C,YAAY,MAAmB,EAAE,UAAqC,EAAE;QACtE,KAAK,CAAC,MAAM,CAAC,CAAC;QAEd,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;QAC/D,CAAC;QAED,IAAI,CAAC,OAAO,GAAG;YACb,MAAM,EAAE,MAAM;YACd,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,GAAG;YAChB,GAAG,OAAO;SACX,CAAC;QAEF,MAAM,CAAC,IAAI,CAAC,iCAAiC,EAAE;YAC7C,KAAK,EAAE,MAAM,CAAC,IAAI;YAClB,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;SACtB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,SAAiB,EAAE,MAAc;QAC7C,MAAM,CAAC,UAAU,CAAC,kCAAkC,EAAE;YACpD,SAAS,EAAE,aAAa;YACxB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACvB,WAAW,EAAE,SAAS,CAAC,MAAM;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE1E,MAAM,CAAC,UAAU,CAAC,gCAAgC,EAAE;oBAClD,SAAS,EAAE,aAAa;oBACxB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;oBACvB,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;iBACxC,CAAC,CAAC;gBAEH,OAAO,QAAQ,CAAC,OAAO,CAAC;YAC1B,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,SAAiB,EAAE,MAAc;QACzD,MAAM,CAAC,UAAU,CAAC,kDAAkD,EAAE;YACpE,SAAS,EAAE,aAAa;YACxB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACvB,WAAW,EAAE,SAAS,CAAC,MAAM;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;gBAC3C,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;gBAE1E,MAAM,CAAC,UAAU,CAAC,gCAAgC,EAAE;oBAClD,SAAS,EAAE,aAAa;oBACxB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;oBACvB,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,MAAM;oBACvC,KAAK,EAAE,QAAQ,CAAC,KAAK;iBACtB,CAAC,CAAC;gBAEH,OAAO,QAAQ,CAAC;YAClB,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACnD,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAAC,SAAiB,EAAE,MAAc,EAAE,MAAmB;QACrF,WAAW;QACX,MAAM,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,mBAAmB,CAAC;QAEzD,qBAAqB;QACrB,MAAM,WAAW,GAAG;YAClB,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACvB,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP;4BACE,IAAI,EAAE,MAAM;4BACZ,IAAI,EAAE,MAAM;yBACb;wBACD;4BACE,IAAI,EAAE,WAAW;4BACjB,SAAS,EAAE;gCACT,GAAG,EAAE,SAAS;gCACd,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,MAAM;6BACtC;yBACF;qBACF;iBACF;aACF;YACD,MAAM,EAAE,KAAK,EAAG,WAAW;YAC3B,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YAClC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;SACtC,CAAC;QAEF,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE;YACtC,MAAM;YACN,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI;YACvB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS;YACjC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;SACtC,CAAC,CAAC;QAEH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;YACnC,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,eAAe,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE;gBAC/C,cAAc,EAAE,kBAAkB;gBAClC,QAAQ,EAAE,kBAAkB;aAC7B;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC;YACjC,MAAM;SACP,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,6BAA6B,CAAC,CAAC;YAEnF,qCAAqC;YACrC,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC5B,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;gBACvD,MAAM,cAAc,GAAG,UAAU,CAAC,CAAC,CAAC,eAAe,UAAU,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;gBAExE,MAAM,IAAI,aAAa,CACrB,8BAA8B,cAAc,sDAAsD,EAClG;oBACE,MAAM,EAAE,QAAQ,CAAC,MAAM;oBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;oBAC/B,YAAY,EAAE,SAAS;oBACvB,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,UAAU;oBACtB,QAAQ,EAAE,8CAA8C;iBACzD,CACF,CAAC;YACJ,CAAC;YAED,+BAA+B;YAC/B,MAAM,IAAI,aAAa,CACrB,mCAAmC,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,EAC3E;gBACE,MAAM,EAAE,QAAQ,CAAC,MAAM;gBACvB,UAAU,EAAE,QAAQ,CAAC,UAAU;gBAC/B,YAAY,EAAE,SAAS;gBACvB,QAAQ,EAAE,MAAM;aACjB,CACF,CAAC;QACJ,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAE3C,OAAO,IAAI,CAAC,aAAa,CAAC,YAAY,EAAE,aAAa,CAAC,CAAC;IACzD,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Model Configuration Manager
3
+ *
4
+ * @description 管理视觉模型的配置,从环境变量加载
5
+ */
6
+ export interface ModelConfig {
7
+ type: string;
8
+ name: string;
9
+ baseUrl: string;
10
+ apiKey: string;
11
+ timeout?: number;
12
+ maxRetries?: number;
13
+ thinking?: {
14
+ type: 'enabled' | 'disabled';
15
+ };
16
+ }
17
+ export interface ModelDefaults {
18
+ baseUrl: string;
19
+ modelName: string;
20
+ timeout: number;
21
+ maxRetries: number;
22
+ }
23
+ /**
24
+ * 从环境变量加载模型配置
25
+ */
26
+ export declare function loadModelConfig(): ModelConfig;
27
+ /**
28
+ * 验证模型配置
29
+ */
30
+ export declare function validateModelConfig(config: ModelConfig): boolean;
31
+ /**
32
+ * 脱敏显示 API Key
33
+ */
34
+ export declare function maskApiKey(apiKey: string): string;
35
+ /**
36
+ * 获取模型的显示信息(用于日志)
37
+ */
38
+ export declare function getModelDisplayInfo(config: ModelConfig): string;
39
+ //# sourceMappingURL=model-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-config.d.ts","sourceRoot":"","sources":["../../src/config/model-config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,SAAS,GAAG,UAAU,CAAA;KAAE,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,WAAW,CAsE7C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAiChE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAE/D"}
@@ -0,0 +1,115 @@
1
+ /**
2
+ * Model Configuration Manager
3
+ *
4
+ * @description 管理视觉模型的配置,从环境变量加载
5
+ */
6
+ import { ModelConfigError } from '../utils/errors.js';
7
+ import { logger } from '../utils/logger.js';
8
+ import { registry } from '../providers/provider-registry.js';
9
+ /**
10
+ * 从环境变量加载模型配置
11
+ */
12
+ export function loadModelConfig() {
13
+ try {
14
+ // 加载模型类型
15
+ const type = process.env.VISION_MODEL_TYPE;
16
+ if (!type) {
17
+ throw new ModelConfigError('Missing VISION_MODEL_TYPE environment variable');
18
+ }
19
+ if (!registry.has(type)) {
20
+ const supportedTypes = registry.getSupportedTypes().join(', ');
21
+ throw new ModelConfigError(`Unsupported model type: ${type}. Supported types: ${supportedTypes}`);
22
+ }
23
+ const provider = registry.get(type);
24
+ const defaults = provider.defaults;
25
+ // 加载必要配置
26
+ const name = process.env.VISION_MODEL_NAME || defaults.modelName;
27
+ const baseUrl = process.env.VISION_API_BASE_URL || defaults.baseUrl;
28
+ const apiKey = process.env.VISION_API_KEY;
29
+ if (!apiKey) {
30
+ throw new ModelConfigError('Missing VISION_API_KEY environment variable');
31
+ }
32
+ // 验证 API Key 格式
33
+ if (provider.validateApiKey) {
34
+ const validation = provider.validateApiKey(apiKey);
35
+ if (validation !== true) {
36
+ logger.warn(validation, { modelType: type });
37
+ }
38
+ }
39
+ // 加载可选配置
40
+ const timeout = process.env.VISION_API_TIMEOUT
41
+ ? parseInt(process.env.VISION_API_TIMEOUT, 10)
42
+ : defaults.timeout;
43
+ const maxRetries = process.env.VISION_MAX_RETRIES
44
+ ? parseInt(process.env.VISION_MAX_RETRIES, 10)
45
+ : defaults.maxRetries;
46
+ const config = {
47
+ type,
48
+ name,
49
+ baseUrl: baseUrl.replace(/\/$/, ''), // 移除末尾的 /
50
+ apiKey,
51
+ timeout,
52
+ maxRetries,
53
+ thinking: provider.enableThinking ? { type: 'enabled' } : undefined
54
+ };
55
+ logger.info('Model configuration loaded successfully', {
56
+ modelType: type,
57
+ modelName: name,
58
+ baseUrl: config.baseUrl,
59
+ provider: provider.displayName
60
+ });
61
+ return config;
62
+ }
63
+ catch (error) {
64
+ logger.error('Failed to load model configuration', error);
65
+ throw error;
66
+ }
67
+ }
68
+ /**
69
+ * 验证模型配置
70
+ */
71
+ export function validateModelConfig(config) {
72
+ try {
73
+ const errors = [];
74
+ if (!config.name || typeof config.name !== 'string') {
75
+ errors.push('Model name is required');
76
+ }
77
+ if (!config.baseUrl || typeof config.baseUrl !== 'string') {
78
+ errors.push('Base URL is required');
79
+ }
80
+ if (!config.apiKey || typeof config.apiKey !== 'string') {
81
+ errors.push('API Key is required');
82
+ }
83
+ if (typeof config.timeout !== 'number' || config.timeout <= 0) {
84
+ errors.push('Timeout must be a positive number');
85
+ }
86
+ if (typeof config.maxRetries !== 'number' || config.maxRetries < 0) {
87
+ errors.push('Max retries must be a non-negative number');
88
+ }
89
+ if (errors.length > 0) {
90
+ throw new ModelConfigError(errors.join('; '));
91
+ }
92
+ return true;
93
+ }
94
+ catch (error) {
95
+ logger.error('Model configuration validation failed', error);
96
+ throw error;
97
+ }
98
+ }
99
+ /**
100
+ * 脱敏显示 API Key
101
+ */
102
+ export function maskApiKey(apiKey) {
103
+ if (!apiKey || apiKey.length <= 8) {
104
+ return '***';
105
+ }
106
+ const visible = Math.min(4, Math.floor(apiKey.length / 4));
107
+ return `${apiKey.substring(0, visible)}${'*'.repeat(Math.max(1, apiKey.length - visible * 2))}${apiKey.substring(apiKey.length - visible)}`;
108
+ }
109
+ /**
110
+ * 获取模型的显示信息(用于日志)
111
+ */
112
+ export function getModelDisplayInfo(config) {
113
+ return `${config.type} - ${config.name} (API Key: ${maskApiKey(config.apiKey)})`;
114
+ }
115
+ //# sourceMappingURL=model-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"model-config.js","sourceRoot":"","sources":["../../src/config/model-config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Vision MCP Server
4
+ *
5
+ * @description MCP Server providing vision capabilities via GLM-4.6V and SiliconFlow
6
+ * This server implements the Model Context Protocol for LLM integration
7
+ *
8
+ * IMPORTANT: This server uses STDIO for MCP communication. Do not use console.log for debugging.
9
+ * Use console.error (stderr) for all logging as required by MCP protocol.
10
+ */
11
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
12
+ /**
13
+ * 创建并配置 MCP Server
14
+ */
15
+ declare function createMCPServer(): McpServer;
16
+ export { createMCPServer };
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAWpE;;GAEG;AACH,iBAAS,eAAe,IAAI,SAAS,CAoJpC;AAqDD,OAAO,EAAE,eAAe,EAAE,CAAC"}