@hileeon/mcc 0.1.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 (138) hide show
  1. package/.claude/CLAUDE.md +204 -0
  2. package/.claude/agents/.gitkeep +0 -0
  3. package/.claude/settings.json +9 -0
  4. package/.claude/skills/.gitkeep +0 -0
  5. package/README.md +127 -0
  6. package/dist/accounts/instance-manager.d.ts +11 -0
  7. package/dist/accounts/instance-manager.d.ts.map +1 -0
  8. package/dist/accounts/instance-manager.js +89 -0
  9. package/dist/accounts/instance-manager.js.map +1 -0
  10. package/dist/accounts/shared-manager.d.ts +25 -0
  11. package/dist/accounts/shared-manager.d.ts.map +1 -0
  12. package/dist/accounts/shared-manager.js +186 -0
  13. package/dist/accounts/shared-manager.js.map +1 -0
  14. package/dist/accounts/store.d.ts +30 -0
  15. package/dist/accounts/store.d.ts.map +1 -0
  16. package/dist/accounts/store.js +128 -0
  17. package/dist/accounts/store.js.map +1 -0
  18. package/dist/core/model-router.d.ts +30 -0
  19. package/dist/core/model-router.d.ts.map +1 -0
  20. package/dist/core/model-router.js +64 -0
  21. package/dist/core/model-router.js.map +1 -0
  22. package/dist/dashboard-server.d.ts +5 -0
  23. package/dist/dashboard-server.d.ts.map +1 -0
  24. package/dist/dashboard-server.js +387 -0
  25. package/dist/dashboard-server.js.map +1 -0
  26. package/dist/mcc.d.ts +8 -0
  27. package/dist/mcc.d.ts.map +1 -0
  28. package/dist/mcc.js +474 -0
  29. package/dist/mcc.js.map +1 -0
  30. package/dist/mcp/external-registry.d.ts +24 -0
  31. package/dist/mcp/external-registry.d.ts.map +1 -0
  32. package/dist/mcp/external-registry.js +99 -0
  33. package/dist/mcp/external-registry.js.map +1 -0
  34. package/dist/mcp/installer.d.ts +31 -0
  35. package/dist/mcp/installer.d.ts.map +1 -0
  36. package/dist/mcp/installer.js +273 -0
  37. package/dist/mcp/installer.js.map +1 -0
  38. package/dist/mcp/mcp-config.d.ts +86 -0
  39. package/dist/mcp/mcp-config.d.ts.map +1 -0
  40. package/dist/mcp/mcp-config.js +178 -0
  41. package/dist/mcp/mcp-config.js.map +1 -0
  42. package/dist/mcp/registry.d.ts +23 -0
  43. package/dist/mcp/registry.d.ts.map +1 -0
  44. package/dist/mcp/registry.js +100 -0
  45. package/dist/mcp/registry.js.map +1 -0
  46. package/dist/proxy/proxy-daemon.d.ts +27 -0
  47. package/dist/proxy/proxy-daemon.d.ts.map +1 -0
  48. package/dist/proxy/proxy-daemon.js +192 -0
  49. package/dist/proxy/proxy-daemon.js.map +1 -0
  50. package/dist/proxy/proxy-entry.d.ts +11 -0
  51. package/dist/proxy/proxy-entry.d.ts.map +1 -0
  52. package/dist/proxy/proxy-entry.js +74 -0
  53. package/dist/proxy/proxy-entry.js.map +1 -0
  54. package/dist/proxy/proxy-paths.d.ts +27 -0
  55. package/dist/proxy/proxy-paths.d.ts.map +1 -0
  56. package/dist/proxy/proxy-paths.js +125 -0
  57. package/dist/proxy/proxy-paths.js.map +1 -0
  58. package/dist/proxy/proxy-server.d.ts +20 -0
  59. package/dist/proxy/proxy-server.d.ts.map +1 -0
  60. package/dist/proxy/proxy-server.js +280 -0
  61. package/dist/proxy/proxy-server.js.map +1 -0
  62. package/dist/proxy/upstream-url.d.ts +7 -0
  63. package/dist/proxy/upstream-url.d.ts.map +1 -0
  64. package/dist/proxy/upstream-url.js +38 -0
  65. package/dist/proxy/upstream-url.js.map +1 -0
  66. package/dist/shared/logger.d.ts +23 -0
  67. package/dist/shared/logger.d.ts.map +1 -0
  68. package/dist/shared/logger.js +184 -0
  69. package/dist/shared/logger.js.map +1 -0
  70. package/dist/shared/provider-preset-catalog.d.ts +41 -0
  71. package/dist/shared/provider-preset-catalog.d.ts.map +1 -0
  72. package/dist/shared/provider-preset-catalog.js +299 -0
  73. package/dist/shared/provider-preset-catalog.js.map +1 -0
  74. package/docs/decisions.md +33 -0
  75. package/docs/lessons.md +8 -0
  76. package/docs/product.md +37 -0
  77. package/lib/mcp/mcc-image-analysis-server.cjs +454 -0
  78. package/lib/mcp/mcc-websearch-server.cjs +339 -0
  79. package/lib/mcp-hooks/image-analysis-runtime.cjs +510 -0
  80. package/lib/mcp-hooks/image-analyzer-transformer.cjs +526 -0
  81. package/lib/mcp-hooks/websearch-transformer.cjs +1421 -0
  82. package/lib/proxy/config/config-loader-facade.js +24 -0
  83. package/lib/proxy/glmt/delta-accumulator.js +363 -0
  84. package/lib/proxy/glmt/glmt-transformer.js +204 -0
  85. package/lib/proxy/glmt/index.js +41 -0
  86. package/lib/proxy/glmt/locale-enforcer.js +69 -0
  87. package/lib/proxy/glmt/pipeline/content-transformer.js +162 -0
  88. package/lib/proxy/glmt/pipeline/index.js +20 -0
  89. package/lib/proxy/glmt/pipeline/request-transformer.js +116 -0
  90. package/lib/proxy/glmt/pipeline/response-builder.js +205 -0
  91. package/lib/proxy/glmt/pipeline/stream-parser.js +234 -0
  92. package/lib/proxy/glmt/pipeline/tool-call-handler.js +78 -0
  93. package/lib/proxy/glmt/pipeline/types.js +6 -0
  94. package/lib/proxy/glmt/reasoning-enforcer.js +151 -0
  95. package/lib/proxy/glmt/sse-parser.js +102 -0
  96. package/lib/proxy/services/logging.js +13 -0
  97. package/lib/proxy/transformers/request-transformer.js +452 -0
  98. package/lib/proxy/transformers/sse-stream-transformer.js +199 -0
  99. package/lib/shared/logger.cjs +138 -0
  100. package/package.json +35 -0
  101. package/src/accounts/instance-manager.ts +58 -0
  102. package/src/accounts/shared-manager.ts +154 -0
  103. package/src/accounts/store.ts +111 -0
  104. package/src/core/model-router.ts +82 -0
  105. package/src/dashboard-server.ts +407 -0
  106. package/src/mcc.ts +474 -0
  107. package/src/mcp/external-registry.ts +73 -0
  108. package/src/mcp/installer.ts +258 -0
  109. package/src/mcp/mcp-config.ts +168 -0
  110. package/src/mcp/registry.ts +89 -0
  111. package/src/proxy/proxy-daemon.ts +184 -0
  112. package/src/proxy/proxy-entry.ts +63 -0
  113. package/src/proxy/proxy-paths.ts +97 -0
  114. package/src/proxy/proxy-server.ts +278 -0
  115. package/src/proxy/upstream-url.ts +38 -0
  116. package/src/shared/logger.ts +140 -0
  117. package/src/shared/provider-preset-catalog.ts +340 -0
  118. package/tsconfig.json +33 -0
  119. package/ui/.prettierrc +9 -0
  120. package/ui/index.html +12 -0
  121. package/ui/package.json +33 -0
  122. package/ui/postcss.config.js +6 -0
  123. package/ui/src/App.tsx +753 -0
  124. package/ui/src/components/ui/button.tsx +48 -0
  125. package/ui/src/components/ui/card.tsx +50 -0
  126. package/ui/src/components/ui/input.tsx +21 -0
  127. package/ui/src/components/ui/label.tsx +20 -0
  128. package/ui/src/components/ui/select.tsx +80 -0
  129. package/ui/src/components/ui/switch.tsx +26 -0
  130. package/ui/src/components/ui/tabs.tsx +52 -0
  131. package/ui/src/index.css +33 -0
  132. package/ui/src/lib/api.ts +185 -0
  133. package/ui/src/lib/utils.ts +6 -0
  134. package/ui/src/main.tsx +10 -0
  135. package/ui/src/vite-env.d.ts +1 -0
  136. package/ui/tailwind.config.js +49 -0
  137. package/ui/tsconfig.json +25 -0
  138. package/ui/vite.config.ts +20 -0
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ /**
4
+ * LocaleEnforcer - Force English output from GLM models
5
+ *
6
+ * Purpose: GLM models default to Chinese when prompts are ambiguous or contain Chinese context.
7
+ * This module always injects "MUST respond in English" instruction into system prompt or first user message.
8
+ *
9
+ * Usage:
10
+ * const enforcer = new LocaleEnforcer();
11
+ * const modifiedMessages = enforcer.injectInstruction(messages);
12
+ *
13
+ * Strategy:
14
+ * 1. If system prompt exists: Prepend instruction
15
+ * 2. If no system prompt: Prepend to first user message
16
+ * 3. Preserve message structure (string vs array content)
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.LocaleEnforcer = void 0;
20
+ class LocaleEnforcer {
21
+ constructor(options = {}) {
22
+ this.instruction =
23
+ options.instruction ||
24
+ 'CRITICAL: You MUST respond in English only, regardless of the input language or context. This is a strict requirement.';
25
+ }
26
+ /**
27
+ * Inject English instruction into messages
28
+ * @param messages - Messages array to modify
29
+ * @returns Modified messages array
30
+ */
31
+ injectInstruction(messages) {
32
+ // Clone messages to avoid mutation
33
+ const modifiedMessages = JSON.parse(JSON.stringify(messages));
34
+ // Strategy 1: Inject into system prompt (preferred)
35
+ const systemIndex = modifiedMessages.findIndex((m) => m.role === 'system');
36
+ if (systemIndex >= 0) {
37
+ const systemMsg = modifiedMessages[systemIndex];
38
+ if (typeof systemMsg.content === 'string') {
39
+ systemMsg.content = `${this.instruction}\n\n${systemMsg.content}`;
40
+ }
41
+ else if (Array.isArray(systemMsg.content)) {
42
+ systemMsg.content.unshift({
43
+ type: 'text',
44
+ text: this.instruction,
45
+ });
46
+ }
47
+ return modifiedMessages;
48
+ }
49
+ // Strategy 2: Prepend to first user message
50
+ const userIndex = modifiedMessages.findIndex((m) => m.role === 'user');
51
+ if (userIndex >= 0) {
52
+ const userMsg = modifiedMessages[userIndex];
53
+ if (typeof userMsg.content === 'string') {
54
+ userMsg.content = `${this.instruction}\n\n${userMsg.content}`;
55
+ }
56
+ else if (Array.isArray(userMsg.content)) {
57
+ userMsg.content.unshift({
58
+ type: 'text',
59
+ text: this.instruction,
60
+ });
61
+ }
62
+ return modifiedMessages;
63
+ }
64
+ // No system or user messages found (edge case)
65
+ return modifiedMessages;
66
+ }
67
+ }
68
+ exports.LocaleEnforcer = LocaleEnforcer;
69
+ //# sourceMappingURL=locale-enforcer.js.map
@@ -0,0 +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;
162
+ //# sourceMappingURL=content-transformer.js.map
@@ -0,0 +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; } });
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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;
116
+ //# sourceMappingURL=request-transformer.js.map
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+ /**
3
+ * ResponseBuilder - Create SSE events for Anthropic streaming format
4
+ *
5
+ * Responsibilities:
6
+ * - Create message_start, message_delta, message_stop events
7
+ * - Create content_block_start, content_block_delta, content_block_stop events
8
+ * - Generate thinking signatures
9
+ * - Map stop reasons between formats
10
+ */
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.ResponseBuilder = void 0;
36
+ const crypto = __importStar(require("crypto"));
37
+ class ResponseBuilder {
38
+ constructor(verbose = false) {
39
+ this.verbose = verbose;
40
+ }
41
+ /**
42
+ * Create message_start event
43
+ */
44
+ createMessageStartEvent(accumulator) {
45
+ return {
46
+ event: 'message_start',
47
+ data: {
48
+ type: 'message_start',
49
+ message: {
50
+ id: accumulator.getMessageId(),
51
+ type: 'message',
52
+ role: accumulator.getRole(),
53
+ content: [],
54
+ model: accumulator.getModel() || 'glm-5',
55
+ stop_reason: null,
56
+ usage: {
57
+ input_tokens: accumulator.getInputTokens(),
58
+ output_tokens: 0,
59
+ },
60
+ },
61
+ },
62
+ };
63
+ }
64
+ /**
65
+ * Create content_block_start event
66
+ */
67
+ createContentBlockStartEvent(block) {
68
+ return {
69
+ event: 'content_block_start',
70
+ data: {
71
+ type: 'content_block_start',
72
+ index: block.index,
73
+ content_block: {
74
+ type: block.type,
75
+ [block.type]: '',
76
+ },
77
+ },
78
+ };
79
+ }
80
+ /**
81
+ * Create thinking_delta event
82
+ */
83
+ createThinkingDeltaEvent(block, delta) {
84
+ return {
85
+ event: 'content_block_delta',
86
+ data: {
87
+ type: 'content_block_delta',
88
+ index: block.index,
89
+ delta: {
90
+ type: 'thinking_delta',
91
+ thinking: delta,
92
+ },
93
+ },
94
+ };
95
+ }
96
+ /**
97
+ * Create text_delta event
98
+ */
99
+ createTextDeltaEvent(block, delta) {
100
+ return {
101
+ event: 'content_block_delta',
102
+ data: {
103
+ type: 'content_block_delta',
104
+ index: block.index,
105
+ delta: {
106
+ type: 'text_delta',
107
+ text: delta,
108
+ },
109
+ },
110
+ };
111
+ }
112
+ /**
113
+ * Create thinking signature delta event
114
+ */
115
+ createSignatureDeltaEvent(block) {
116
+ // FIX: Guard against empty content (signature timing race)
117
+ if (!block.content || block.content.length === 0) {
118
+ if (this.verbose) {
119
+ console.error(`[ResponseBuilder] WARNING: Skipping signature for empty thinking block ${block.index}`);
120
+ console.error(`This indicates a race condition - signature requested before content accumulated`);
121
+ }
122
+ return null;
123
+ }
124
+ const signature = this.generateThinkingSignature(block.content);
125
+ if (this.verbose) {
126
+ console.error(`[ResponseBuilder] Generating signature for block ${block.index}: ${block.content.length} chars`);
127
+ }
128
+ return {
129
+ event: 'content_block_delta',
130
+ data: {
131
+ type: 'content_block_delta',
132
+ index: block.index,
133
+ delta: {
134
+ type: 'thinking_signature_delta',
135
+ signature: signature,
136
+ },
137
+ },
138
+ };
139
+ }
140
+ /**
141
+ * Create content_block_stop event
142
+ */
143
+ createContentBlockStopEvent(block) {
144
+ return {
145
+ event: 'content_block_stop',
146
+ data: {
147
+ type: 'content_block_stop',
148
+ index: block.index,
149
+ },
150
+ };
151
+ }
152
+ /**
153
+ * Generate finalization events (message_delta + message_stop)
154
+ */
155
+ createFinalizationEvents(accumulator, stopReason) {
156
+ return [
157
+ {
158
+ event: 'message_delta',
159
+ data: {
160
+ type: 'message_delta',
161
+ delta: {
162
+ stop_reason: stopReason,
163
+ },
164
+ usage: {
165
+ input_tokens: accumulator.getInputTokens(),
166
+ output_tokens: accumulator.getOutputTokens(),
167
+ },
168
+ },
169
+ },
170
+ {
171
+ event: 'message_stop',
172
+ data: {
173
+ type: 'message_stop',
174
+ },
175
+ },
176
+ ];
177
+ }
178
+ /**
179
+ * Generate thinking signature for Claude Code UI
180
+ */
181
+ generateThinkingSignature(thinking) {
182
+ // Generate signature hash
183
+ const hash = crypto.createHash('sha256').update(thinking).digest('hex').substring(0, 16);
184
+ return {
185
+ type: 'thinking_signature',
186
+ hash: hash,
187
+ length: thinking.length,
188
+ timestamp: Date.now(),
189
+ };
190
+ }
191
+ /**
192
+ * Map OpenAI stop reason to Anthropic stop reason
193
+ */
194
+ mapStopReason(openaiReason) {
195
+ const mapping = {
196
+ stop: 'end_turn',
197
+ length: 'max_tokens',
198
+ tool_calls: 'tool_use',
199
+ content_filter: 'stop_sequence',
200
+ };
201
+ return mapping[openaiReason] || 'end_turn';
202
+ }
203
+ }
204
+ exports.ResponseBuilder = ResponseBuilder;
205
+ //# sourceMappingURL=response-builder.js.map