@hileeon/mcc 0.1.8 → 0.2.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 (102) hide show
  1. package/README.md +229 -127
  2. package/dist/accounts/store.d.ts +12 -0
  3. package/dist/accounts/store.d.ts.map +1 -1
  4. package/dist/accounts/store.js.map +1 -1
  5. package/dist/commands/launch.d.ts +9 -0
  6. package/dist/commands/launch.d.ts.map +1 -0
  7. package/dist/commands/launch.js +162 -0
  8. package/dist/commands/launch.js.map +1 -0
  9. package/dist/commands/mcp.d.ts +9 -0
  10. package/dist/commands/mcp.d.ts.map +1 -0
  11. package/dist/commands/mcp.js +112 -0
  12. package/dist/commands/mcp.js.map +1 -0
  13. package/dist/commands/profile-test.d.ts +17 -0
  14. package/dist/commands/profile-test.d.ts.map +1 -0
  15. package/dist/commands/profile-test.js +188 -0
  16. package/dist/commands/profile-test.js.map +1 -0
  17. package/dist/commands/profile.d.ts +8 -0
  18. package/dist/commands/profile.d.ts.map +1 -0
  19. package/dist/commands/profile.js +125 -0
  20. package/dist/commands/profile.js.map +1 -0
  21. package/dist/core/model-router.d.ts.map +1 -1
  22. package/dist/core/model-router.js +36 -3
  23. package/dist/core/model-router.js.map +1 -1
  24. package/dist/{dashboard-server.d.ts → dashboard/server.d.ts} +1 -1
  25. package/dist/dashboard/server.d.ts.map +1 -0
  26. package/dist/{dashboard-server.js → dashboard/server.js} +254 -48
  27. package/dist/dashboard/server.js.map +1 -0
  28. package/dist/mcc.d.ts +4 -2
  29. package/dist/mcc.d.ts.map +1 -1
  30. package/dist/mcc.js +127 -408
  31. package/dist/mcc.js.map +1 -1
  32. package/dist/mcp/installer.d.ts.map +1 -1
  33. package/dist/mcp/installer.js +5 -2
  34. package/dist/mcp/installer.js.map +1 -1
  35. package/dist/mcp/mcp-config.d.ts +33 -3
  36. package/dist/mcp/mcp-config.d.ts.map +1 -1
  37. package/dist/mcp/mcp-config.js +81 -29
  38. package/dist/mcp/mcp-config.js.map +1 -1
  39. package/dist/proxy/proxy-daemon.d.ts +1 -1
  40. package/dist/proxy/proxy-daemon.d.ts.map +1 -1
  41. package/dist/proxy/proxy-daemon.js +27 -7
  42. package/dist/proxy/proxy-daemon.js.map +1 -1
  43. package/dist/proxy/proxy-entry.js +11 -4
  44. package/dist/proxy/proxy-entry.js.map +1 -1
  45. package/dist/proxy/proxy-paths.d.ts +1 -0
  46. package/dist/proxy/proxy-paths.d.ts.map +1 -1
  47. package/dist/proxy/proxy-paths.js.map +1 -1
  48. package/dist/proxy/proxy-server.d.ts +1 -0
  49. package/dist/proxy/proxy-server.d.ts.map +1 -1
  50. package/dist/proxy/proxy-server.js +114 -6
  51. package/dist/proxy/proxy-server.js.map +1 -1
  52. package/dist/shared/config.d.ts +15 -0
  53. package/dist/shared/config.d.ts.map +1 -0
  54. package/dist/shared/config.js +79 -0
  55. package/dist/shared/config.js.map +1 -0
  56. package/dist/shared/logger.d.ts +23 -18
  57. package/dist/shared/logger.d.ts.map +1 -1
  58. package/dist/shared/logger.js +17 -178
  59. package/dist/shared/logger.js.map +1 -1
  60. package/dist/shared/provider-preset-catalog.d.ts +8 -2
  61. package/dist/shared/provider-preset-catalog.d.ts.map +1 -1
  62. package/dist/shared/provider-preset-catalog.js +61 -31
  63. package/dist/shared/provider-preset-catalog.js.map +1 -1
  64. package/dist/shared/test-image.d.ts +15 -0
  65. package/dist/shared/test-image.d.ts.map +1 -0
  66. package/dist/shared/test-image.js +89 -0
  67. package/dist/shared/test-image.js.map +1 -0
  68. package/dist/ui/assets/index-7kowlJw9.js +40 -0
  69. package/dist/ui/assets/index-DnC-lskL.css +1 -0
  70. package/dist/ui/index.html +21 -13
  71. package/dist/update.d.ts +31 -0
  72. package/dist/update.d.ts.map +1 -0
  73. package/dist/update.js +196 -0
  74. package/dist/update.js.map +1 -0
  75. package/lib/mcp/mcc-image-analysis-server.cjs +454 -454
  76. package/lib/mcp/mcc-websearch-server.cjs +339 -339
  77. package/lib/mcp-hooks/image-analysis-runtime.cjs +563 -510
  78. package/lib/mcp-hooks/image-analyzer-transformer.cjs +526 -526
  79. package/lib/mcp-hooks/websearch-transformer.cjs +1597 -1421
  80. package/lib/proxy/config/config-loader-facade.js +24 -24
  81. package/lib/proxy/glmt/delta-accumulator.js +362 -362
  82. package/lib/proxy/glmt/glmt-transformer.js +203 -203
  83. package/lib/proxy/glmt/index.js +40 -40
  84. package/lib/proxy/glmt/locale-enforcer.js +68 -68
  85. package/lib/proxy/glmt/pipeline/content-transformer.js +161 -161
  86. package/lib/proxy/glmt/pipeline/index.js +19 -19
  87. package/lib/proxy/glmt/pipeline/request-transformer.js +115 -115
  88. package/lib/proxy/glmt/pipeline/response-builder.js +204 -204
  89. package/lib/proxy/glmt/pipeline/stream-parser.js +233 -233
  90. package/lib/proxy/glmt/pipeline/tool-call-handler.js +77 -77
  91. package/lib/proxy/glmt/pipeline/types.js +5 -5
  92. package/lib/proxy/glmt/reasoning-enforcer.js +150 -150
  93. package/lib/proxy/glmt/sse-parser.js +101 -101
  94. package/lib/proxy/services/logging.js +13 -13
  95. package/lib/proxy/transformers/request-transformer.js +471 -471
  96. package/lib/proxy/transformers/sse-stream-transformer.js +198 -198
  97. package/lib/shared/logger.cjs +160 -138
  98. package/package.json +58 -41
  99. package/dist/dashboard-server.d.ts.map +0 -1
  100. package/dist/dashboard-server.js.map +0 -1
  101. package/dist/ui/assets/index-B16lhKZ6.js +0 -40
  102. package/dist/ui/assets/index-jEfiB6-h.css +0 -1
@@ -1,162 +1,162 @@
1
- "use strict";
2
- /**
3
- * ContentTransformer - Handle message sanitization and content transformations
4
- *
5
- * Responsibilities:
6
- * - Sanitize messages for OpenAI API compatibility
7
- * - Extract thinking control tags from messages
8
- * - Detect think keywords in user prompts
9
- * - Transform tools between Anthropic and OpenAI formats
10
- */
11
- Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.ContentTransformer = void 0;
13
- class ContentTransformer {
14
- constructor(defaultThinking = true) {
15
- this.defaultThinking = defaultThinking;
16
- }
17
- /**
18
- * Sanitize messages for OpenAI API compatibility
19
- */
20
- sanitizeMessages(messages) {
21
- const result = [];
22
- for (const msg of messages) {
23
- // If content is a string, add as-is
24
- if (typeof msg.content === 'string') {
25
- result.push(msg);
26
- continue;
27
- }
28
- // If content is an array, process blocks
29
- if (Array.isArray(msg.content)) {
30
- // Separate tool_result blocks from other content
31
- const toolResults = msg.content.filter((block) => block.type === 'tool_result');
32
- const textBlocks = msg.content.filter((block) => block.type === 'text');
33
- // CRITICAL: Tool messages must come BEFORE user text in OpenAI API
34
- for (const toolResult of toolResults) {
35
- result.push({
36
- role: 'tool',
37
- content: typeof toolResult.content === 'string'
38
- ? toolResult.content
39
- : JSON.stringify(toolResult.content),
40
- });
41
- }
42
- // Add text content as user/assistant message AFTER tool messages
43
- if (textBlocks.length > 0) {
44
- const textContent = textBlocks.length === 1
45
- ? textBlocks[0].text || ''
46
- : textBlocks.map((b) => b.text || '').join('\n');
47
- result.push({
48
- role: msg.role,
49
- content: textContent,
50
- });
51
- }
52
- // If no content at all, add empty message
53
- if (textBlocks.length === 0 && toolResults.length === 0) {
54
- result.push({
55
- role: msg.role,
56
- content: '',
57
- });
58
- }
59
- continue;
60
- }
61
- // Fallback: return message as-is
62
- result.push(msg);
63
- }
64
- return result;
65
- }
66
- /**
67
- * Transform Anthropic tools to OpenAI tools format
68
- */
69
- transformTools(anthropicTools) {
70
- return anthropicTools.map((tool) => ({
71
- type: 'function',
72
- function: {
73
- name: tool.name,
74
- description: tool.description,
75
- parameters: tool.input_schema || {},
76
- },
77
- }));
78
- }
79
- /**
80
- * Check if messages contain thinking control tags
81
- */
82
- hasThinkingTags(messages) {
83
- for (const msg of messages) {
84
- if (msg.role !== 'user')
85
- continue;
86
- const content = msg.content;
87
- if (typeof content !== 'string')
88
- continue;
89
- // Check for control tags
90
- if (/<Thinking:(On|Off)>/i.test(content) || /<Effort:(Low|Medium|High)>/i.test(content)) {
91
- return true;
92
- }
93
- }
94
- return false;
95
- }
96
- /**
97
- * Extract thinking control tags from user messages
98
- */
99
- extractThinkingControl(messages) {
100
- const config = {
101
- thinking: this.defaultThinking,
102
- effort: 'medium',
103
- };
104
- // Scan user messages for control tags
105
- for (const msg of messages) {
106
- if (msg.role !== 'user')
107
- continue;
108
- const content = msg.content;
109
- if (typeof content !== 'string')
110
- continue;
111
- // Check for <Thinking:On|Off>
112
- const thinkingMatch = content.match(/<Thinking:(On|Off)>/i);
113
- if (thinkingMatch) {
114
- config.thinking = thinkingMatch[1].toLowerCase() === 'on';
115
- }
116
- // Check for <Effort:Low|Medium|High>
117
- const effortMatch = content.match(/<Effort:(Low|Medium|High)>/i);
118
- if (effortMatch) {
119
- config.effort = effortMatch[1].toLowerCase();
120
- }
121
- }
122
- return config;
123
- }
124
- /**
125
- * Detect Anthropic-style "think" keywords in user prompts
126
- */
127
- detectThinkKeywords(messages) {
128
- if (!messages || messages.length === 0)
129
- return null;
130
- // Extract text from user messages
131
- const text = messages
132
- .filter((m) => m.role === 'user')
133
- .map((m) => {
134
- if (typeof m.content === 'string')
135
- return m.content;
136
- if (Array.isArray(m.content)) {
137
- return m.content
138
- .filter((block) => block.type === 'text')
139
- .map((block) => block.text || '')
140
- .join(' ');
141
- }
142
- return '';
143
- })
144
- .join(' ');
145
- // Priority: ultrathink > think harder > think hard > think
146
- if (/\bultrathink\b/i.test(text)) {
147
- return { thinking: true, effort: 'max', keyword: 'ultrathink' };
148
- }
149
- if (/\bthink\s+harder\b/i.test(text)) {
150
- return { thinking: true, effort: 'high', keyword: 'think harder' };
151
- }
152
- if (/\bthink\s+hard\b/i.test(text)) {
153
- return { thinking: true, effort: 'medium', keyword: 'think hard' };
154
- }
155
- if (/\bthink\b/i.test(text)) {
156
- return { thinking: true, effort: 'low', keyword: 'think' };
157
- }
158
- return null; // No keywords detected
159
- }
160
- }
161
- exports.ContentTransformer = ContentTransformer;
1
+ "use strict";
2
+ /**
3
+ * ContentTransformer - Handle message sanitization and content transformations
4
+ *
5
+ * Responsibilities:
6
+ * - Sanitize messages for OpenAI API compatibility
7
+ * - Extract thinking control tags from messages
8
+ * - Detect think keywords in user prompts
9
+ * - Transform tools between Anthropic and OpenAI formats
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.ContentTransformer = void 0;
13
+ class ContentTransformer {
14
+ constructor(defaultThinking = true) {
15
+ this.defaultThinking = defaultThinking;
16
+ }
17
+ /**
18
+ * Sanitize messages for OpenAI API compatibility
19
+ */
20
+ sanitizeMessages(messages) {
21
+ const result = [];
22
+ for (const msg of messages) {
23
+ // If content is a string, add as-is
24
+ if (typeof msg.content === 'string') {
25
+ result.push(msg);
26
+ continue;
27
+ }
28
+ // If content is an array, process blocks
29
+ if (Array.isArray(msg.content)) {
30
+ // Separate tool_result blocks from other content
31
+ const toolResults = msg.content.filter((block) => block.type === 'tool_result');
32
+ const textBlocks = msg.content.filter((block) => block.type === 'text');
33
+ // CRITICAL: Tool messages must come BEFORE user text in OpenAI API
34
+ for (const toolResult of toolResults) {
35
+ result.push({
36
+ role: 'tool',
37
+ content: typeof toolResult.content === 'string'
38
+ ? toolResult.content
39
+ : JSON.stringify(toolResult.content),
40
+ });
41
+ }
42
+ // Add text content as user/assistant message AFTER tool messages
43
+ if (textBlocks.length > 0) {
44
+ const textContent = textBlocks.length === 1
45
+ ? textBlocks[0].text || ''
46
+ : textBlocks.map((b) => b.text || '').join('\n');
47
+ result.push({
48
+ role: msg.role,
49
+ content: textContent,
50
+ });
51
+ }
52
+ // If no content at all, add empty message
53
+ if (textBlocks.length === 0 && toolResults.length === 0) {
54
+ result.push({
55
+ role: msg.role,
56
+ content: '',
57
+ });
58
+ }
59
+ continue;
60
+ }
61
+ // Fallback: return message as-is
62
+ result.push(msg);
63
+ }
64
+ return result;
65
+ }
66
+ /**
67
+ * Transform Anthropic tools to OpenAI tools format
68
+ */
69
+ transformTools(anthropicTools) {
70
+ return anthropicTools.map((tool) => ({
71
+ type: 'function',
72
+ function: {
73
+ name: tool.name,
74
+ description: tool.description,
75
+ parameters: tool.input_schema || {},
76
+ },
77
+ }));
78
+ }
79
+ /**
80
+ * Check if messages contain thinking control tags
81
+ */
82
+ hasThinkingTags(messages) {
83
+ for (const msg of messages) {
84
+ if (msg.role !== 'user')
85
+ continue;
86
+ const content = msg.content;
87
+ if (typeof content !== 'string')
88
+ continue;
89
+ // Check for control tags
90
+ if (/<Thinking:(On|Off)>/i.test(content) || /<Effort:(Low|Medium|High)>/i.test(content)) {
91
+ return true;
92
+ }
93
+ }
94
+ return false;
95
+ }
96
+ /**
97
+ * Extract thinking control tags from user messages
98
+ */
99
+ extractThinkingControl(messages) {
100
+ const config = {
101
+ thinking: this.defaultThinking,
102
+ effort: 'medium',
103
+ };
104
+ // Scan user messages for control tags
105
+ for (const msg of messages) {
106
+ if (msg.role !== 'user')
107
+ continue;
108
+ const content = msg.content;
109
+ if (typeof content !== 'string')
110
+ continue;
111
+ // Check for <Thinking:On|Off>
112
+ const thinkingMatch = content.match(/<Thinking:(On|Off)>/i);
113
+ if (thinkingMatch) {
114
+ config.thinking = thinkingMatch[1].toLowerCase() === 'on';
115
+ }
116
+ // Check for <Effort:Low|Medium|High>
117
+ const effortMatch = content.match(/<Effort:(Low|Medium|High)>/i);
118
+ if (effortMatch) {
119
+ config.effort = effortMatch[1].toLowerCase();
120
+ }
121
+ }
122
+ return config;
123
+ }
124
+ /**
125
+ * Detect Anthropic-style "think" keywords in user prompts
126
+ */
127
+ detectThinkKeywords(messages) {
128
+ if (!messages || messages.length === 0)
129
+ return null;
130
+ // Extract text from user messages
131
+ const text = messages
132
+ .filter((m) => m.role === 'user')
133
+ .map((m) => {
134
+ if (typeof m.content === 'string')
135
+ return m.content;
136
+ if (Array.isArray(m.content)) {
137
+ return m.content
138
+ .filter((block) => block.type === 'text')
139
+ .map((block) => block.text || '')
140
+ .join(' ');
141
+ }
142
+ return '';
143
+ })
144
+ .join(' ');
145
+ // Priority: ultrathink > think harder > think hard > think
146
+ if (/\bultrathink\b/i.test(text)) {
147
+ return { thinking: true, effort: 'max', keyword: 'ultrathink' };
148
+ }
149
+ if (/\bthink\s+harder\b/i.test(text)) {
150
+ return { thinking: true, effort: 'high', keyword: 'think harder' };
151
+ }
152
+ if (/\bthink\s+hard\b/i.test(text)) {
153
+ return { thinking: true, effort: 'medium', keyword: 'think hard' };
154
+ }
155
+ if (/\bthink\b/i.test(text)) {
156
+ return { thinking: true, effort: 'low', keyword: 'think' };
157
+ }
158
+ return null; // No keywords detected
159
+ }
160
+ }
161
+ exports.ContentTransformer = ContentTransformer;
162
162
  //# sourceMappingURL=content-transformer.js.map
@@ -1,20 +1,20 @@
1
- "use strict";
2
- /**
3
- * Pipeline Module Exports
4
- *
5
- * Barrel file for the GLMT transformation pipeline
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- exports.RequestTransformer = exports.StreamParser = exports.ResponseBuilder = exports.ToolCallHandler = exports.ContentTransformer = void 0;
9
- // Pipeline components
10
- var content_transformer_1 = require("./content-transformer");
11
- Object.defineProperty(exports, "ContentTransformer", { enumerable: true, get: function () { return content_transformer_1.ContentTransformer; } });
12
- var tool_call_handler_1 = require("./tool-call-handler");
13
- Object.defineProperty(exports, "ToolCallHandler", { enumerable: true, get: function () { return tool_call_handler_1.ToolCallHandler; } });
14
- var response_builder_1 = require("./response-builder");
15
- Object.defineProperty(exports, "ResponseBuilder", { enumerable: true, get: function () { return response_builder_1.ResponseBuilder; } });
16
- var stream_parser_1 = require("./stream-parser");
17
- Object.defineProperty(exports, "StreamParser", { enumerable: true, get: function () { return stream_parser_1.StreamParser; } });
18
- var request_transformer_1 = require("./request-transformer");
19
- Object.defineProperty(exports, "RequestTransformer", { enumerable: true, get: function () { return request_transformer_1.RequestTransformer; } });
1
+ "use strict";
2
+ /**
3
+ * Pipeline Module Exports
4
+ *
5
+ * Barrel file for the GLMT transformation pipeline
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.RequestTransformer = exports.StreamParser = exports.ResponseBuilder = exports.ToolCallHandler = exports.ContentTransformer = void 0;
9
+ // Pipeline components
10
+ var content_transformer_1 = require("./content-transformer");
11
+ Object.defineProperty(exports, "ContentTransformer", { enumerable: true, get: function () { return content_transformer_1.ContentTransformer; } });
12
+ var tool_call_handler_1 = require("./tool-call-handler");
13
+ Object.defineProperty(exports, "ToolCallHandler", { enumerable: true, get: function () { return tool_call_handler_1.ToolCallHandler; } });
14
+ var response_builder_1 = require("./response-builder");
15
+ Object.defineProperty(exports, "ResponseBuilder", { enumerable: true, get: function () { return response_builder_1.ResponseBuilder; } });
16
+ var stream_parser_1 = require("./stream-parser");
17
+ Object.defineProperty(exports, "StreamParser", { enumerable: true, get: function () { return stream_parser_1.StreamParser; } });
18
+ var request_transformer_1 = require("./request-transformer");
19
+ Object.defineProperty(exports, "RequestTransformer", { enumerable: true, get: function () { return request_transformer_1.RequestTransformer; } });
20
20
  //# sourceMappingURL=index.js.map
@@ -1,116 +1,116 @@
1
- "use strict";
2
- /**
3
- * RequestTransformer - Handle Anthropic → OpenAI request transformation
4
- *
5
- * Responsibilities:
6
- * - Transform Anthropic request format to OpenAI format
7
- * - Inject locale and reasoning instructions
8
- * - Map models and configure parameters
9
- */
10
- Object.defineProperty(exports, "__esModule", { value: true });
11
- exports.RequestTransformer = void 0;
12
- const locale_enforcer_1 = require("../locale-enforcer");
13
- const reasoning_enforcer_1 = require("../reasoning-enforcer");
14
- const content_transformer_1 = require("./content-transformer");
15
- class RequestTransformer {
16
- constructor(config = {}) {
17
- const defaultThinking = config.defaultThinking ?? true;
18
- this.log = config.log || (() => { });
19
- this.localeEnforcer = new locale_enforcer_1.LocaleEnforcer();
20
- this.reasoningEnforcer = new reasoning_enforcer_1.ReasoningEnforcer({
21
- enabled: config.explicitReasoning ?? true,
22
- });
23
- this.contentTransformer = new content_transformer_1.ContentTransformer(defaultThinking);
24
- this.modelMaxTokens = {
25
- 'GLM-4.6': 128000,
26
- 'GLM-4.5': 96000,
27
- 'GLM-4.5-air': 16000,
28
- };
29
- }
30
- /**
31
- * Transform Anthropic request to OpenAI format
32
- */
33
- transform(anthropicRequest) {
34
- try {
35
- const messages = anthropicRequest.messages || [];
36
- // 1. Extract thinking control from messages
37
- const thinkingConfig = this.contentTransformer.extractThinkingControl(messages);
38
- const hasControlTags = this.contentTransformer.hasThinkingTags(messages);
39
- // 2. Detect "think" keywords in user prompts
40
- const keywordConfig = this.contentTransformer.detectThinkKeywords(messages);
41
- if (keywordConfig && !anthropicRequest.thinking && !hasControlTags) {
42
- thinkingConfig.thinking = keywordConfig.thinking;
43
- thinkingConfig.effort = keywordConfig.effort;
44
- this.log(`Detected think keyword: ${keywordConfig.keyword}, effort=${keywordConfig.effort}`);
45
- }
46
- // 3. Check anthropicRequest.thinking parameter (takes precedence)
47
- if (anthropicRequest.thinking) {
48
- if (anthropicRequest.thinking.type === 'enabled') {
49
- thinkingConfig.thinking = true;
50
- this.log('Claude CLI explicitly enabled thinking');
51
- }
52
- else if (anthropicRequest.thinking.type === 'disabled') {
53
- thinkingConfig.thinking = false;
54
- this.log('Claude CLI explicitly disabled thinking');
55
- }
56
- }
57
- this.log(`Final thinking control: ${JSON.stringify(thinkingConfig)}`);
58
- // 4. Map model
59
- const glmModel = this.mapModel(anthropicRequest.model);
60
- // 5. Inject locale instruction
61
- const messagesWithLocale = this.localeEnforcer.injectInstruction(messages);
62
- // 6. Inject reasoning instruction
63
- const messagesWithReasoning = this.reasoningEnforcer.injectInstruction(messagesWithLocale, thinkingConfig);
64
- // 7. Build OpenAI request
65
- const openaiRequest = {
66
- model: glmModel,
67
- messages: this.contentTransformer.sanitizeMessages(messagesWithReasoning),
68
- max_tokens: this.getMaxTokens(glmModel),
69
- stream: anthropicRequest.stream ?? false,
70
- };
71
- // 8. Transform tools if present
72
- if (anthropicRequest.tools && anthropicRequest.tools.length > 0) {
73
- openaiRequest.tools = this.contentTransformer.transformTools(anthropicRequest.tools);
74
- openaiRequest.tool_choice = 'auto';
75
- this.log(`Transformed ${anthropicRequest.tools.length} tools for OpenAI format`);
76
- }
77
- // 9. Preserve optional parameters
78
- if (anthropicRequest.temperature !== undefined) {
79
- openaiRequest.temperature = anthropicRequest.temperature;
80
- }
81
- if (anthropicRequest.top_p !== undefined) {
82
- openaiRequest.top_p = anthropicRequest.top_p;
83
- }
84
- if (anthropicRequest.stream !== undefined) {
85
- openaiRequest.stream = anthropicRequest.stream;
86
- }
87
- // 10. Inject reasoning parameters
88
- this.injectReasoningParams(openaiRequest, thinkingConfig);
89
- return { openaiRequest, thinkingConfig };
90
- }
91
- catch (error) {
92
- const err = error;
93
- console.error('[RequestTransformer] Transformation error:', err);
94
- return {
95
- openaiRequest: anthropicRequest,
96
- thinkingConfig: { thinking: false, effort: 'medium' },
97
- error: err.message,
98
- };
99
- }
100
- }
101
- injectReasoningParams(openaiRequest, thinkingConfig) {
102
- openaiRequest.do_sample = true;
103
- if (thinkingConfig.thinking) {
104
- openaiRequest.reasoning = true;
105
- openaiRequest.reasoning_effort = thinkingConfig.effort;
106
- }
107
- }
108
- mapModel(_anthropicModel) {
109
- return 'GLM-4.6';
110
- }
111
- getMaxTokens(model) {
112
- return this.modelMaxTokens[model] || 128000;
113
- }
114
- }
115
- exports.RequestTransformer = RequestTransformer;
1
+ "use strict";
2
+ /**
3
+ * RequestTransformer - Handle Anthropic → OpenAI request transformation
4
+ *
5
+ * Responsibilities:
6
+ * - Transform Anthropic request format to OpenAI format
7
+ * - Inject locale and reasoning instructions
8
+ * - Map models and configure parameters
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.RequestTransformer = void 0;
12
+ const locale_enforcer_1 = require("../locale-enforcer");
13
+ const reasoning_enforcer_1 = require("../reasoning-enforcer");
14
+ const content_transformer_1 = require("./content-transformer");
15
+ class RequestTransformer {
16
+ constructor(config = {}) {
17
+ const defaultThinking = config.defaultThinking ?? true;
18
+ this.log = config.log || (() => { });
19
+ this.localeEnforcer = new locale_enforcer_1.LocaleEnforcer();
20
+ this.reasoningEnforcer = new reasoning_enforcer_1.ReasoningEnforcer({
21
+ enabled: config.explicitReasoning ?? true,
22
+ });
23
+ this.contentTransformer = new content_transformer_1.ContentTransformer(defaultThinking);
24
+ this.modelMaxTokens = {
25
+ 'GLM-4.6': 128000,
26
+ 'GLM-4.5': 96000,
27
+ 'GLM-4.5-air': 16000,
28
+ };
29
+ }
30
+ /**
31
+ * Transform Anthropic request to OpenAI format
32
+ */
33
+ transform(anthropicRequest) {
34
+ try {
35
+ const messages = anthropicRequest.messages || [];
36
+ // 1. Extract thinking control from messages
37
+ const thinkingConfig = this.contentTransformer.extractThinkingControl(messages);
38
+ const hasControlTags = this.contentTransformer.hasThinkingTags(messages);
39
+ // 2. Detect "think" keywords in user prompts
40
+ const keywordConfig = this.contentTransformer.detectThinkKeywords(messages);
41
+ if (keywordConfig && !anthropicRequest.thinking && !hasControlTags) {
42
+ thinkingConfig.thinking = keywordConfig.thinking;
43
+ thinkingConfig.effort = keywordConfig.effort;
44
+ this.log(`Detected think keyword: ${keywordConfig.keyword}, effort=${keywordConfig.effort}`);
45
+ }
46
+ // 3. Check anthropicRequest.thinking parameter (takes precedence)
47
+ if (anthropicRequest.thinking) {
48
+ if (anthropicRequest.thinking.type === 'enabled') {
49
+ thinkingConfig.thinking = true;
50
+ this.log('Claude CLI explicitly enabled thinking');
51
+ }
52
+ else if (anthropicRequest.thinking.type === 'disabled') {
53
+ thinkingConfig.thinking = false;
54
+ this.log('Claude CLI explicitly disabled thinking');
55
+ }
56
+ }
57
+ this.log(`Final thinking control: ${JSON.stringify(thinkingConfig)}`);
58
+ // 4. Map model
59
+ const glmModel = this.mapModel(anthropicRequest.model);
60
+ // 5. Inject locale instruction
61
+ const messagesWithLocale = this.localeEnforcer.injectInstruction(messages);
62
+ // 6. Inject reasoning instruction
63
+ const messagesWithReasoning = this.reasoningEnforcer.injectInstruction(messagesWithLocale, thinkingConfig);
64
+ // 7. Build OpenAI request
65
+ const openaiRequest = {
66
+ model: glmModel,
67
+ messages: this.contentTransformer.sanitizeMessages(messagesWithReasoning),
68
+ max_tokens: this.getMaxTokens(glmModel),
69
+ stream: anthropicRequest.stream ?? false,
70
+ };
71
+ // 8. Transform tools if present
72
+ if (anthropicRequest.tools && anthropicRequest.tools.length > 0) {
73
+ openaiRequest.tools = this.contentTransformer.transformTools(anthropicRequest.tools);
74
+ openaiRequest.tool_choice = 'auto';
75
+ this.log(`Transformed ${anthropicRequest.tools.length} tools for OpenAI format`);
76
+ }
77
+ // 9. Preserve optional parameters
78
+ if (anthropicRequest.temperature !== undefined) {
79
+ openaiRequest.temperature = anthropicRequest.temperature;
80
+ }
81
+ if (anthropicRequest.top_p !== undefined) {
82
+ openaiRequest.top_p = anthropicRequest.top_p;
83
+ }
84
+ if (anthropicRequest.stream !== undefined) {
85
+ openaiRequest.stream = anthropicRequest.stream;
86
+ }
87
+ // 10. Inject reasoning parameters
88
+ this.injectReasoningParams(openaiRequest, thinkingConfig);
89
+ return { openaiRequest, thinkingConfig };
90
+ }
91
+ catch (error) {
92
+ const err = error;
93
+ console.error('[RequestTransformer] Transformation error:', err);
94
+ return {
95
+ openaiRequest: anthropicRequest,
96
+ thinkingConfig: { thinking: false, effort: 'medium' },
97
+ error: err.message,
98
+ };
99
+ }
100
+ }
101
+ injectReasoningParams(openaiRequest, thinkingConfig) {
102
+ openaiRequest.do_sample = true;
103
+ if (thinkingConfig.thinking) {
104
+ openaiRequest.reasoning = true;
105
+ openaiRequest.reasoning_effort = thinkingConfig.effort;
106
+ }
107
+ }
108
+ mapModel(_anthropicModel) {
109
+ return 'GLM-4.6';
110
+ }
111
+ getMaxTokens(model) {
112
+ return this.modelMaxTokens[model] || 128000;
113
+ }
114
+ }
115
+ exports.RequestTransformer = RequestTransformer;
116
116
  //# sourceMappingURL=request-transformer.js.map