@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,238 @@
1
+ /**
2
+ * Image Input Normalization Utility
3
+ *
4
+ * @description 统一处理图片输入:支持 URL、base64(data URL) 和本地路径
5
+ */
6
+ import { readFile } from 'fs/promises';
7
+ import { InvalidInputError, ImageLoadError, VisionMCPError } from './errors.js';
8
+ import { logger } from './logger.js';
9
+ /**
10
+ * 支持的图片 MIME 类型
11
+ * 仅支持 GLM 和 SiliconFlow 明确支持的格式(保守列表)
12
+ * D-002: Only support image input types supported by GLM/SiliconFlow
13
+ */
14
+ const SUPPORTED_MIME_TYPES = [
15
+ 'image/jpeg',
16
+ 'image/jpg',
17
+ 'image/png',
18
+ 'image/webp'
19
+ ];
20
+ /**
21
+ * 文件扩展名到 MIME 类型的映射
22
+ * 仅支持 GLM 和 SiliconFlow 明确支持的格式
23
+ */
24
+ const EXT_TO_MIME_TYPE = {
25
+ '.jpg': 'image/jpeg',
26
+ '.jpeg': 'image/jpeg',
27
+ '.png': 'image/png',
28
+ '.webp': 'image/webp'
29
+ };
30
+ /**
31
+ * 检测输入类型
32
+ */
33
+ export function detectInputType(input) {
34
+ // 检测 base64 data URL
35
+ if (input.startsWith('data:image/') && input.includes(';base64,')) {
36
+ return 'base64';
37
+ }
38
+ // 检测 URL(http 或 https)
39
+ if (input.startsWith('http://') || input.startsWith('https://')) {
40
+ return 'url';
41
+ }
42
+ // 其他情况视为本地路径
43
+ return 'local';
44
+ }
45
+ /**
46
+ * 从文件扩展名获取 MIME 类型
47
+ */
48
+ export function getMimeTypeFromFileName(filename) {
49
+ const ext = filename.toLowerCase().substring(filename.lastIndexOf('.'));
50
+ const mimeType = EXT_TO_MIME_TYPE[ext];
51
+ if (!mimeType) {
52
+ throw new InvalidInputError(`Unsupported file extension: ${ext}`, { filename, supportedExtensions: Object.keys(EXT_TO_MIME_TYPE) });
53
+ }
54
+ return mimeType;
55
+ }
56
+ /**
57
+ * 从 data URL 提取 MIME 类型
58
+ */
59
+ export function getMimeTypeFromDataUrl(dataUrl) {
60
+ const match = dataUrl.match(/^data:(image\/[^;]+);base64,/i);
61
+ if (!match) {
62
+ throw new InvalidInputError('Invalid data URL format. Expected: data:image/*;base64,...', { dataUrl });
63
+ }
64
+ const mimeType = match[1].toLowerCase();
65
+ if (!SUPPORTED_MIME_TYPES.includes(mimeType)) {
66
+ throw new InvalidInputError(`Unsupported image MIME type: ${mimeType}`, { supportedTypes: SUPPORTED_MIME_TYPES });
67
+ }
68
+ return mimeType;
69
+ }
70
+ /**
71
+ * 检测 URL 是否指向图片文件
72
+ */
73
+ export function isImageUrl(url) {
74
+ try {
75
+ const urlObj = new URL(url);
76
+ const pathname = urlObj.pathname.toLowerCase();
77
+ return Object.keys(EXT_TO_MIME_TYPE).some(ext => pathname.endsWith(ext));
78
+ }
79
+ catch {
80
+ // 无效的 URL
81
+ return false;
82
+ }
83
+ }
84
+ /**
85
+ * 规范化图片输入为统一的 data URL 格式
86
+ */
87
+ export async function normalizeImageInput(input) {
88
+ const type = detectInputType(input);
89
+ // 默认启用严格 URL 验证(符合 D-002),可通过 VISION_STRICT_URL_VALIDATION=false 禁用
90
+ const strictValidation = process.env.VISION_STRICT_URL_VALIDATION !== 'false';
91
+ logger.debug('Normalizing image input', {
92
+ type,
93
+ inputLength: input.length,
94
+ strictValidation
95
+ });
96
+ try {
97
+ switch (type) {
98
+ case 'base64':
99
+ return await normalizeBase64Input(input);
100
+ case 'url':
101
+ return await normalizeUrlInput(input, strictValidation);
102
+ case 'local':
103
+ return await normalizeLocalInput(input);
104
+ default:
105
+ throw new InvalidInputError(`Unsupported input type: ${type}`, { input, detectedType: type });
106
+ }
107
+ }
108
+ catch (error) {
109
+ if (error instanceof VisionMCPError) {
110
+ throw error;
111
+ }
112
+ throw new ImageLoadError(`Failed to normalize image input`, { input, type }, error);
113
+ }
114
+ }
115
+ /**
116
+ * 规范化 base64 data URL 输入
117
+ */
118
+ async function normalizeBase64Input(input) {
119
+ try {
120
+ // 验证格式
121
+ if (!input.includes(',') || input.split(',').length !== 2) {
122
+ throw new InvalidInputError('Invalid data URL format. Expected: data:image/*;base64,DATA');
123
+ }
124
+ const mimeType = getMimeTypeFromDataUrl(input);
125
+ const dataPart = input.split(',')[1];
126
+ // 验证 base64 数据
127
+ if (!dataPart || dataPart.length === 0) {
128
+ throw new InvalidInputError('No base64 data found in data URL');
129
+ }
130
+ logger.debug('Base64 input validated', { mimeType, dataLength: dataPart.length });
131
+ return {
132
+ type: 'base64',
133
+ originalInput: input,
134
+ dataUrl: input,
135
+ mimeType
136
+ };
137
+ }
138
+ catch (error) {
139
+ throw new ImageLoadError('Invalid base64 data URL', { input }, error);
140
+ }
141
+ }
142
+ /**
143
+ * 规范化 URL 输入
144
+ *
145
+ * @description 当前直接返回 URL,实际场景中可以下载并转换为 base64
146
+ */
147
+ async function normalizeUrlInput(input, strictValidation) {
148
+ try {
149
+ // 验证 URL 格式
150
+ const url = new URL(input);
151
+ if (!url.protocol.startsWith('http')) {
152
+ throw new InvalidInputError('Only HTTP/HTTPS URLs are supported', { protocol: url.protocol });
153
+ }
154
+ // 检测是否为图片 URL
155
+ if (!isImageUrl(input)) {
156
+ if (strictValidation) {
157
+ throw new InvalidInputError(`URL does not have a supported image extension (allowed: ${Object.keys(EXT_TO_MIME_TYPE).join(', ')})`, { url: input });
158
+ }
159
+ else {
160
+ logger.warn('URL does not appear to point to an image file', { url: input });
161
+ logger.warn('Set VISION_STRICT_URL_VALIDATION=true to enforce strict validation', { url: input });
162
+ }
163
+ }
164
+ logger.debug('URL input validated', { url: input, strictValidation });
165
+ // 注意:SiliconFlow 和 GLM 都直接支持 URL
166
+ // 这里我们保持为 URL 格式,适配器会处理
167
+ return {
168
+ type: 'url',
169
+ originalInput: input,
170
+ dataUrl: input, // 保持为 URL
171
+ mimeType: 'image/*' // 实际类型由模型确定
172
+ };
173
+ }
174
+ catch (error) {
175
+ if (error instanceof TypeError) {
176
+ throw new InvalidInputError('Invalid URL format', { input }, error);
177
+ }
178
+ throw new ImageLoadError('Failed to process URL input', { input }, error);
179
+ }
180
+ }
181
+ /**
182
+ * 规范化本地文件路径输入
183
+ *
184
+ * @description 读取本地文件并转换为 base64 data URL
185
+ */
186
+ async function normalizeLocalInput(input) {
187
+ try {
188
+ logger.debug('Reading local file', { path: input });
189
+ // 读取文件
190
+ const fileBuffer = await readFile(input);
191
+ if (fileBuffer.length === 0) {
192
+ throw new ImageLoadError('File is empty', { path: input });
193
+ }
194
+ // 检测 MIME 类型
195
+ const mimeType = getMimeTypeFromFileName(input);
196
+ // 转换为 base64
197
+ const base64Data = fileBuffer.toString('base64');
198
+ const dataUrl = `data:${mimeType};base64,${base64Data}`;
199
+ logger.debug('Local file converted to base64', {
200
+ path: input,
201
+ mimeType,
202
+ size: fileBuffer.length,
203
+ dataUrlLength: dataUrl.length
204
+ });
205
+ return {
206
+ type: 'local',
207
+ originalInput: input,
208
+ dataUrl,
209
+ mimeType
210
+ };
211
+ }
212
+ catch (error) {
213
+ if (error.code === 'ENOENT') {
214
+ throw new ImageLoadError('File not found', { path: input }, error);
215
+ }
216
+ if (error.code === 'EACCES') {
217
+ throw new ImageLoadError('Permission denied reading file', { path: input }, error);
218
+ }
219
+ throw new ImageLoadError('Failed to read local file', { path: input }, error);
220
+ }
221
+ }
222
+ /**
223
+ * 获取图片大小信息(用于日志)
224
+ */
225
+ export function getImageSizeInfo(dataUrl) {
226
+ try {
227
+ const base64Data = dataUrl.includes(',')
228
+ ? dataUrl.split(',')[1]
229
+ : dataUrl;
230
+ // 计算大小(base64 编码的原始数据)
231
+ const decodedSize = Math.floor(base64Data.length * 0.75);
232
+ return { size: decodedSize };
233
+ }
234
+ catch {
235
+ return { size: 0 };
236
+ }
237
+ }
238
+ //# sourceMappingURL=image-input.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-input.js","sourceRoot":"","sources":["../../src/utils/image-input.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Logger Utility
3
+ *
4
+ * @description 统一的日志工具,确保只使用 stdout 输出
5
+ * 符合 MCP 协议要求:stdout 用于 JSON-RPC 通信,日志使用 stderr
6
+ */
7
+ export declare enum LogLevel {
8
+ DEBUG = 0,
9
+ INFO = 1,
10
+ WARN = 2,
11
+ ERROR = 3
12
+ }
13
+ export interface LogEntry {
14
+ timestamp: string;
15
+ level: keyof typeof LogLevel;
16
+ message: string;
17
+ requestId?: string;
18
+ modelType?: string;
19
+ latency?: number;
20
+ [key: string]: any;
21
+ }
22
+ export declare class Logger {
23
+ private static instance;
24
+ private logLevel;
25
+ private constructor();
26
+ static getInstance(): Logger;
27
+ /**
28
+ * 写入日志到 stderr
29
+ * @param entry 日志条目
30
+ */
31
+ private write;
32
+ /**
33
+ * 记录 DEBUG 级别日志
34
+ */
35
+ debug(message: string, meta?: Record<string, any>): void;
36
+ /**
37
+ * 记录 INFO 级别日志
38
+ */
39
+ info(message: string, meta?: Record<string, any>): void;
40
+ /**
41
+ * 记录 WARN 级别日志
42
+ */
43
+ warn(message: string, meta?: Record<string, any>): void;
44
+ /**
45
+ * 记录 ERROR 级别日志
46
+ */
47
+ error(message: string, error?: Error | unknown, meta?: Record<string, any>): void;
48
+ /**
49
+ * 为请求添加上下文信息的日志记录
50
+ */
51
+ logRequest(message: string, context: {
52
+ requestId?: string;
53
+ modelType?: string;
54
+ latency?: number;
55
+ [key: string]: any;
56
+ }): void;
57
+ }
58
+ export declare const logger: Logger;
59
+ /**
60
+ * 装饰器:记录函数执行时间和错误
61
+ */
62
+ export declare function withLogging(target: any, propertyKey: string, descriptor: PropertyDescriptor): PropertyDescriptor;
63
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,oBAAY,QAAQ;IAClB,KAAK,IAAI;IACT,IAAI,IAAI;IACR,IAAI,IAAI;IACR,KAAK,IAAI;CACV;AAED,MAAM,WAAW,QAAQ;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,OAAO,QAAQ,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,qBAAa,MAAM;IACjB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAW;IAE3B,OAAO;WAkBO,WAAW,IAAI,MAAM;IAOnC;;;OAGG;IACH,OAAO,CAAC,KAAK;IAKb;;OAEG;IACI,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAW/D;;OAEG;IACI,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAW9D;;OAEG;IACI,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAW9D;;OAEG;IACI,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,OAAO,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAyBxF;;OAEG;IACI,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE;QAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACpB,GAAG,IAAI;CAUT;AAGD,eAAO,MAAM,MAAM,QAAuB,CAAC;AAE3C;;GAEG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,kBAAkB,sBAgC3F"}
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Logger Utility
3
+ *
4
+ * @description 统一的日志工具,确保只使用 stdout 输出
5
+ * 符合 MCP 协议要求:stdout 用于 JSON-RPC 通信,日志使用 stderr
6
+ */
7
+ export var LogLevel;
8
+ (function (LogLevel) {
9
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
10
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
11
+ LogLevel[LogLevel["WARN"] = 2] = "WARN";
12
+ LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
13
+ })(LogLevel || (LogLevel = {}));
14
+ export class Logger {
15
+ static instance;
16
+ logLevel;
17
+ constructor() {
18
+ // 从环境变量读取日志级别,默认为 INFO
19
+ const envLevel = process.env.LOG_LEVEL?.toUpperCase();
20
+ switch (envLevel) {
21
+ case 'DEBUG':
22
+ this.logLevel = LogLevel.DEBUG;
23
+ break;
24
+ case 'WARN':
25
+ this.logLevel = LogLevel.WARN;
26
+ break;
27
+ case 'ERROR':
28
+ this.logLevel = LogLevel.ERROR;
29
+ break;
30
+ default:
31
+ this.logLevel = LogLevel.INFO;
32
+ }
33
+ }
34
+ static getInstance() {
35
+ if (!Logger.instance) {
36
+ Logger.instance = new Logger();
37
+ }
38
+ return Logger.instance;
39
+ }
40
+ /**
41
+ * 写入日志到 stderr
42
+ * @param entry 日志条目
43
+ */
44
+ write(entry) {
45
+ // MCP 协议要求:stdout 用于 JSON-RPC,日志必须使用 stderr
46
+ console.error(JSON.stringify(entry));
47
+ }
48
+ /**
49
+ * 记录 DEBUG 级别日志
50
+ */
51
+ debug(message, meta) {
52
+ if (this.logLevel <= LogLevel.DEBUG) {
53
+ this.write({
54
+ timestamp: new Date().toISOString(),
55
+ level: 'DEBUG',
56
+ message,
57
+ ...meta
58
+ });
59
+ }
60
+ }
61
+ /**
62
+ * 记录 INFO 级别日志
63
+ */
64
+ info(message, meta) {
65
+ if (this.logLevel <= LogLevel.INFO) {
66
+ this.write({
67
+ timestamp: new Date().toISOString(),
68
+ level: 'INFO',
69
+ message,
70
+ ...meta
71
+ });
72
+ }
73
+ }
74
+ /**
75
+ * 记录 WARN 级别日志
76
+ */
77
+ warn(message, meta) {
78
+ if (this.logLevel <= LogLevel.WARN) {
79
+ this.write({
80
+ timestamp: new Date().toISOString(),
81
+ level: 'WARN',
82
+ message,
83
+ ...meta
84
+ });
85
+ }
86
+ }
87
+ /**
88
+ * 记录 ERROR 级别日志
89
+ */
90
+ error(message, error, meta) {
91
+ if (this.logLevel <= LogLevel.ERROR) {
92
+ const logEntry = {
93
+ timestamp: new Date().toISOString(),
94
+ level: 'ERROR',
95
+ message,
96
+ ...meta
97
+ };
98
+ if (error) {
99
+ if (error instanceof Error) {
100
+ logEntry.error = {
101
+ name: error.name,
102
+ message: error.message,
103
+ stack: error.stack
104
+ };
105
+ }
106
+ else {
107
+ logEntry.error = String(error);
108
+ }
109
+ }
110
+ this.write(logEntry);
111
+ }
112
+ }
113
+ /**
114
+ * 为请求添加上下文信息的日志记录
115
+ */
116
+ logRequest(message, context) {
117
+ const { requestId, modelType, latency, ...rest } = context;
118
+ this.info(message, {
119
+ ...(requestId && { requestId }),
120
+ ...(modelType && { modelType }),
121
+ ...(latency !== undefined && { latency }),
122
+ ...rest
123
+ });
124
+ }
125
+ }
126
+ // 导出单例实例
127
+ export const logger = Logger.getInstance();
128
+ /**
129
+ * 装饰器:记录函数执行时间和错误
130
+ */
131
+ export function withLogging(target, propertyKey, descriptor) {
132
+ const originalMethod = descriptor.value;
133
+ descriptor.value = async function (...args) {
134
+ const startTime = Date.now();
135
+ const requestId = Math.random().toString(36).substring(7);
136
+ logger.debug(`[${propertyKey}] Starting execution`, { requestId });
137
+ try {
138
+ const result = await originalMethod.apply(this, args);
139
+ const latency = Date.now() - startTime;
140
+ logger.logRequest(`[${propertyKey}] Completed successfully`, {
141
+ requestId,
142
+ latency
143
+ });
144
+ return result;
145
+ }
146
+ catch (error) {
147
+ const latency = Date.now() - startTime;
148
+ logger.error(`[${propertyKey}] Execution failed`, error, {
149
+ requestId,
150
+ latency
151
+ });
152
+ throw error;
153
+ }
154
+ };
155
+ return descriptor;
156
+ }
157
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Thinking Extractor Functions
3
+ *
4
+ * @description Independent module for thinking content extraction functions.
5
+ * Separated to avoid circular dependencies with provider-registry.ts.
6
+ */
7
+ /**
8
+ * Re-export the type for backward compatibility
9
+ * This type is defined here to avoid importing thinking-filter.ts
10
+ */
11
+ export interface ModelResponseEnvelope {
12
+ content: string;
13
+ reasoning?: string;
14
+ thinking?: string;
15
+ rawResponse?: unknown;
16
+ }
17
+ /**
18
+ * Type for extracting thinking content from raw model responses
19
+ */
20
+ export type ThinkingExtractor = (rawResponse: unknown) => ModelResponseEnvelope;
21
+ /**
22
+ * Extracts thinking content from GLM-4.6V model responses
23
+ */
24
+ export declare function extractGLMThinking(rawResponse: unknown): ModelResponseEnvelope;
25
+ /**
26
+ * Extracts thinking content from OpenAI-compatible responses (SiliconFlow)
27
+ */
28
+ export declare function extractOpenAIThinking(rawResponse: unknown): ModelResponseEnvelope;
29
+ /**
30
+ * Extracts thinking content from Claude Messages API responses
31
+ * Claude response format: { content: [{type: "text", text: "..."}], usage: {...} }
32
+ */
33
+ export declare function extractClaudeThinking(rawResponse: unknown): ModelResponseEnvelope;
34
+ //# sourceMappingURL=thinking-extractors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-extractors.d.ts","sourceRoot":"","sources":["../../src/utils/thinking-extractors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,WAAW,EAAE,OAAO,KAAK,qBAAqB,CAAC;AAEhF;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,OAAO,GAAG,qBAAqB,CAkB9E;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,qBAAqB,CAkBjF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,GAAG,qBAAqB,CA4BjF"}
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Thinking Extractor Functions
3
+ *
4
+ * @description Independent module for thinking content extraction functions.
5
+ * Separated to avoid circular dependencies with provider-registry.ts.
6
+ */
7
+ import { logger } from './logger.js';
8
+ /**
9
+ * Extracts thinking content from GLM-4.6V model responses
10
+ */
11
+ export function extractGLMThinking(rawResponse) {
12
+ try {
13
+ // @ts-ignore - Access response structure
14
+ const choice = rawResponse?.choices?.[0];
15
+ const message = choice?.message || {};
16
+ return {
17
+ content: message.content || '',
18
+ reasoning: message.reasoning || message.thinking || '',
19
+ rawResponse
20
+ };
21
+ }
22
+ catch (error) {
23
+ logger.warn('Failed to extract GLM thinking content', { error });
24
+ return {
25
+ content: '',
26
+ rawResponse
27
+ };
28
+ }
29
+ }
30
+ /**
31
+ * Extracts thinking content from OpenAI-compatible responses (SiliconFlow)
32
+ */
33
+ export function extractOpenAIThinking(rawResponse) {
34
+ try {
35
+ // @ts-ignore - Access response structure
36
+ const choice = rawResponse?.choices?.[0];
37
+ const message = choice?.message || {};
38
+ return {
39
+ content: message.content || '',
40
+ reasoning: message.reasoning || '',
41
+ rawResponse
42
+ };
43
+ }
44
+ catch (error) {
45
+ logger.warn('Failed to extract OpenAI thinking content', { error });
46
+ return {
47
+ content: '',
48
+ rawResponse
49
+ };
50
+ }
51
+ }
52
+ /**
53
+ * Extracts thinking content from Claude Messages API responses
54
+ * Claude response format: { content: [{type: "text", text: "..."}], usage: {...} }
55
+ */
56
+ export function extractClaudeThinking(rawResponse) {
57
+ try {
58
+ // @ts-ignore - Access response structure
59
+ const contentBlocks = rawResponse?.content || [];
60
+ // 提取所有文本内容
61
+ const textParts = contentBlocks
62
+ .filter((block) => block?.type === 'text')
63
+ .map((block) => block?.text || '')
64
+ .filter(Boolean);
65
+ const content = textParts.join('\n\n');
66
+ // Claude 的 extended thinking 可能返回在 thinking 字段中
67
+ // 但大多数情况下不会单独返回,而是混在 content 中
68
+ // stripThinking 会处理这种情况
69
+ return {
70
+ content,
71
+ reasoning: rawResponse?.thinking || '',
72
+ rawResponse
73
+ };
74
+ }
75
+ catch (error) {
76
+ logger.warn('Failed to extract Claude thinking content', { error });
77
+ return {
78
+ content: '',
79
+ rawResponse
80
+ };
81
+ }
82
+ }
83
+ //# sourceMappingURL=thinking-extractors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-extractors.js","sourceRoot":"","sources":["../../src/utils/thinking-extractors.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAkBrC;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,WAAoB;IACrD,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,MAAM,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;QAEtC,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,EAAE;YACtD,WAAW;SACZ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,wCAAwC,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACjE,OAAO;YACL,OAAO,EAAE,EAAE;YACX,WAAW;SACZ,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAoB;IACxD,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,MAAM,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,IAAI,EAAE,CAAC;QAEtC,OAAO;YACL,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;YAC9B,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,EAAE;YAClC,WAAW;SACZ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,OAAO;YACL,OAAO,EAAE,EAAE;YACX,WAAW;SACZ,CAAC;IACJ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,WAAoB;IACxD,IAAI,CAAC;QACH,yCAAyC;QACzC,MAAM,aAAa,GAAG,WAAW,EAAE,OAAO,IAAI,EAAE,CAAC;QAEjD,WAAW;QACX,MAAM,SAAS,GAAG,aAAa;aAC5B,MAAM,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,KAAK,MAAM,CAAC;aAC9C,GAAG,CAAC,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,IAAI,EAAE,CAAC;aACtC,MAAM,CAAC,OAAO,CAAC,CAAC;QAEnB,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAEvC,gDAAgD;QAChD,+BAA+B;QAC/B,wBAAwB;QACxB,OAAO;YACL,OAAO;YACP,SAAS,EAAG,WAAmB,EAAE,QAAQ,IAAI,EAAE;YAC/C,WAAW;SACZ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,CAAC,IAAI,CAAC,2CAA2C,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACpE,OAAO;YACL,OAAO,EAAE,EAAE;YACX,WAAW;SACZ,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Thinking/Reasoning Content Filter
3
+ *
4
+ * @description Filters thinking/reasoning content from model responses to prevent
5
+ * exposing internal reasoning to MCP clients. Supports multiple models and response formats.
6
+ *
7
+ * Architecture Decision: Keep thinking enabled at model level but strip reasoning
8
+ * content before returning to MCP client.
9
+ */
10
+ import { ModelResponseEnvelope, ThinkingExtractor } from './thinking-extractors.js';
11
+ export type { ModelResponseEnvelope, ThinkingExtractor };
12
+ /**
13
+ * Registry of thinking extractors by model type
14
+ * Uses imported extractor functions to avoid circular dependencies
15
+ */
16
+ export declare const THINKING_EXTRACTORS: Record<string, ThinkingExtractor>;
17
+ /**
18
+ * Strips thinking content from model response envelope
19
+ * @param envelope - Response envelope that may contain thinking content
20
+ * @returns Cleaned content string with all thinking content removed
21
+ */
22
+ export declare function stripThinking(envelope: ModelResponseEnvelope): string;
23
+ /**
24
+ * Filters thinking content from raw model response
25
+ * This is the main entry point for filtering thinking content
26
+ *
27
+ * @param rawResponse - The raw response from the model API
28
+ * @param modelType - The type of model (e.g., 'glm-4.6v', 'siliconflow')
29
+ * @returns Cleaned content string with thinking content removed
30
+ */
31
+ export declare function filterThinkingContent(rawResponse: unknown, modelType: string): string;
32
+ //# sourceMappingURL=thinking-filter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"thinking-filter.d.ts","sourceRoot":"","sources":["../../src/utils/thinking-filter.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EAIlB,MAAM,0BAA0B,CAAC;AAGlC,YAAY,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,CAAC;AAsBzD;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAOjE,CAAC;AAuCF;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,qBAAqB,GAAG,MAAM,CAiCrE;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAgCrF"}