@dahawa/hawa-cli-analysis 1.0.7 → 1.0.8
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.
- package/.tools.json +6 -6
- package/.vscode/launch.json +26 -26
- package/_uclaude.js +0 -0
- package/anthropic-transformer.js +986 -986
- package/api-anthropic.js +279 -279
- package/api-openai.js +538 -538
- package/clogger-openai.js +190 -190
- package/clogger.js +318 -318
- package/codex/mcp-client.js +556 -556
- package/codex/mcpclient.js +117 -117
- package/codex/mcpserver.js +374 -374
- package/codex/mcpserverproxy.js +143 -143
- package/codex/test.js +30 -30
- package/mcp/claude-mcpproxy-launcher.js +4 -4
- package/package.json +2 -1
- package/simple-transform-example.js +212 -212
- package/tests/test-lazy-load.js +35 -35
- package/tests/test_mcp_proxy.js +50 -50
- package/tests/test_supabase_mcp.js +41 -41
- package/uclaude.js +3 -3
- package/ucodex-proxy.js +172 -172
- package/ucodex.js +127 -127
package/clogger-openai.js
CHANGED
|
@@ -1,190 +1,190 @@
|
|
|
1
|
-
import {mergeAnthropic} from './api-anthropic.js';
|
|
2
|
-
import LoggerManage from "./logger-manager.js"
|
|
3
|
-
import { URL } from 'url';
|
|
4
|
-
import anthropicTransformer from "./anthropic-transformer.js"
|
|
5
|
-
import {parseOpenAIChatCompletion} from "./api-openai.js";
|
|
6
|
-
let logger = LoggerManage.getLogger("claudecode");
|
|
7
|
-
|
|
8
|
-
logger.system.debug("-------------Clogger Start--------------------------");
|
|
9
|
-
|
|
10
|
-
function deepClone(obj) {
|
|
11
|
-
const result = JSON.parse(JSON.stringify(obj));
|
|
12
|
-
return result;
|
|
13
|
-
}
|
|
14
|
-
function formateLine(str){
|
|
15
|
-
let r = str.replace(/\\n/g, '\n');
|
|
16
|
-
return r;
|
|
17
|
-
}
|
|
18
|
-
function toSimpleLog(full, wire_api = "chat"){
|
|
19
|
-
let log = {
|
|
20
|
-
request:{},
|
|
21
|
-
response:{},
|
|
22
|
-
openai:{
|
|
23
|
-
request:{},
|
|
24
|
-
response:{}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
//anthropic 转换
|
|
28
|
-
log.request.model = full.request.body.model;
|
|
29
|
-
log.request.messages = full.request.body.messages;
|
|
30
|
-
log.request.system = full.request.body.system;
|
|
31
|
-
log.response.content = full.response.body.content;
|
|
32
|
-
|
|
33
|
-
// openai 转换
|
|
34
|
-
log.openai.request.model = full.openai.request.body.model;
|
|
35
|
-
log.openai.request.messages = full.openai.request.body.messages;
|
|
36
|
-
log.openai.response.choices = full.openai.response.body.choices;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return log;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function logAPI(fullLog){
|
|
43
|
-
logger.full.debug(fullLog);
|
|
44
|
-
logger.simple.debug(toSimpleLog(fullLog));
|
|
45
|
-
//要及时输出
|
|
46
|
-
logger.simple.flush();
|
|
47
|
-
logger.full.flush();
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
function headersToObject(headers) {
|
|
52
|
-
const obj = {};
|
|
53
|
-
try {
|
|
54
|
-
for (const [k, v] of headers.entries()) obj[k] = v;
|
|
55
|
-
} catch {}
|
|
56
|
-
return obj;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
*
|
|
61
|
-
*
|
|
62
|
-
* 拦截 claude code 请求,这里应该拦截模型情况。当前拦截了所有的请求,模型请求可以通过 endpoint 判断出来
|
|
63
|
-
* 当前的逻辑需要优化
|
|
64
|
-
*
|
|
65
|
-
*/
|
|
66
|
-
function instrumentFetch() {
|
|
67
|
-
if (!global.fetch || global.fetch.__ProxyInstrumented) return;
|
|
68
|
-
|
|
69
|
-
logger.system.debug("-------------Clogger instrumentFetch--------------------------");
|
|
70
|
-
|
|
71
|
-
const originalFetch = global.fetch;
|
|
72
|
-
global.fetch = async (input, init = {}) => {
|
|
73
|
-
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
74
|
-
const endpoints = [
|
|
75
|
-
'/v1/messages'
|
|
76
|
-
];
|
|
77
|
-
let urlPath = (new URL(url)).pathname;
|
|
78
|
-
|
|
79
|
-
if(!(endpoints.some(t => urlPath.includes(t) && init.method == "POST"))){
|
|
80
|
-
//console.log("不是模型请求直接返回" +init.method +":" + url +" -> " + urlPath);
|
|
81
|
-
return originalFetch(input,init);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
//console.log("请求地址: " + url);
|
|
85
|
-
//转换前的请求
|
|
86
|
-
let initBody = JSON.parse(init.body);
|
|
87
|
-
//请求的 JSON
|
|
88
|
-
let requestBody = await anthropicTransformer.transformRequestOut(initBody);
|
|
89
|
-
//转换后的请求
|
|
90
|
-
let openaiRequestBodyString = JSON.stringify(requestBody);
|
|
91
|
-
|
|
92
|
-
//console.log(JSON.parse(openaiRequestBody));
|
|
93
|
-
|
|
94
|
-
//打印请求信息 init.body
|
|
95
|
-
const response = await originalFetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
96
|
-
method: "POST",
|
|
97
|
-
headers: {
|
|
98
|
-
"Content-Type": "application/json",
|
|
99
|
-
Authorization: `Bearer ${process.env.ANTHROPIC_AUTH_TOKEN}`
|
|
100
|
-
},
|
|
101
|
-
body: openaiRequestBodyString,
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
let responseToClient = response.clone();
|
|
105
|
-
|
|
106
|
-
// 判断OpenRouter响应是否为异常
|
|
107
|
-
if (!response.ok) {
|
|
108
|
-
// 读取OpenRouter错误响应
|
|
109
|
-
const openrouterErrorText = await response.text();
|
|
110
|
-
logger.system.error(`OpenRouter API error response: ${response.status} ${response.statusText}`, {
|
|
111
|
-
url: url,
|
|
112
|
-
status: response.status,
|
|
113
|
-
errorResponse: openrouterErrorText
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// 将OpenRouter错误响应转换为Claude Code错误响应格式
|
|
117
|
-
let claudeErrorResponse;
|
|
118
|
-
try {
|
|
119
|
-
const openrouterError = JSON.parse(openrouterErrorText);
|
|
120
|
-
claudeErrorResponse = {
|
|
121
|
-
type: "error",
|
|
122
|
-
error: {
|
|
123
|
-
type: "api_error",
|
|
124
|
-
message: openrouterError.error?.message || `OpenRouter API error: ${response.statusText}`,
|
|
125
|
-
code: `OPENROUTER_${response.status}_ERROR`
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
} catch (parseError) {
|
|
129
|
-
// 如果无法解析OpenRouter的错误JSON,使用通用错误格式
|
|
130
|
-
claudeErrorResponse = {
|
|
131
|
-
type: "error",
|
|
132
|
-
error: {
|
|
133
|
-
type: "api_error",
|
|
134
|
-
message: `OpenRouter API error: ${response.statusText}`,
|
|
135
|
-
code: `OPENROUTER_${response.status}_ERROR`
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// 返回转换后的错误响应
|
|
141
|
-
return new Response(JSON.stringify(claudeErrorResponse), {
|
|
142
|
-
status: response.status,
|
|
143
|
-
statusText: response.statusText,
|
|
144
|
-
headers: {
|
|
145
|
-
"Content-Type": "application/json"
|
|
146
|
-
}
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
//完整的请求日志,保护请求和响应
|
|
151
|
-
let fullLog = {request:{
|
|
152
|
-
url:url,
|
|
153
|
-
method: init.method,
|
|
154
|
-
headers: headersToObject(init.headers),
|
|
155
|
-
body: initBody
|
|
156
|
-
},response:{
|
|
157
|
-
status: response.status,
|
|
158
|
-
statusText: response.statusText,
|
|
159
|
-
headers: headersToObject(response.headers)
|
|
160
|
-
},openai:{
|
|
161
|
-
request: {
|
|
162
|
-
body: requestBody
|
|
163
|
-
},
|
|
164
|
-
response: {}
|
|
165
|
-
}};
|
|
166
|
-
|
|
167
|
-
let res = await anthropicTransformer.transformResponseIn(responseToClient);
|
|
168
|
-
let toClientRes = await res.clone();
|
|
169
|
-
|
|
170
|
-
(async () => {
|
|
171
|
-
|
|
172
|
-
fullLog.openai.response.body = await parseOpenAIChatCompletion(await response.text());
|
|
173
|
-
fullLog.response.body = mergeAnthropic(await res.text());
|
|
174
|
-
|
|
175
|
-
//其他类型是错误的
|
|
176
|
-
logAPI(fullLog);
|
|
177
|
-
|
|
178
|
-
})().catch(err => console.error('日志解析错误:', err));
|
|
179
|
-
|
|
180
|
-
return toClientRes;
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
};
|
|
184
|
-
global.fetch.__ProxyInstrumented = true;
|
|
185
|
-
}
|
|
186
|
-
try{
|
|
187
|
-
instrumentFetch();
|
|
188
|
-
}catch(e){
|
|
189
|
-
logger.system.error(e);
|
|
190
|
-
}
|
|
1
|
+
import {mergeAnthropic} from './api-anthropic.js';
|
|
2
|
+
import LoggerManage from "./logger-manager.js"
|
|
3
|
+
import { URL } from 'url';
|
|
4
|
+
import anthropicTransformer from "./anthropic-transformer.js"
|
|
5
|
+
import {parseOpenAIChatCompletion} from "./api-openai.js";
|
|
6
|
+
let logger = LoggerManage.getLogger("claudecode");
|
|
7
|
+
|
|
8
|
+
logger.system.debug("-------------Clogger Start--------------------------");
|
|
9
|
+
|
|
10
|
+
function deepClone(obj) {
|
|
11
|
+
const result = JSON.parse(JSON.stringify(obj));
|
|
12
|
+
return result;
|
|
13
|
+
}
|
|
14
|
+
function formateLine(str){
|
|
15
|
+
let r = str.replace(/\\n/g, '\n');
|
|
16
|
+
return r;
|
|
17
|
+
}
|
|
18
|
+
function toSimpleLog(full, wire_api = "chat"){
|
|
19
|
+
let log = {
|
|
20
|
+
request:{},
|
|
21
|
+
response:{},
|
|
22
|
+
openai:{
|
|
23
|
+
request:{},
|
|
24
|
+
response:{}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
//anthropic 转换
|
|
28
|
+
log.request.model = full.request.body.model;
|
|
29
|
+
log.request.messages = full.request.body.messages;
|
|
30
|
+
log.request.system = full.request.body.system;
|
|
31
|
+
log.response.content = full.response.body.content;
|
|
32
|
+
|
|
33
|
+
// openai 转换
|
|
34
|
+
log.openai.request.model = full.openai.request.body.model;
|
|
35
|
+
log.openai.request.messages = full.openai.request.body.messages;
|
|
36
|
+
log.openai.response.choices = full.openai.response.body.choices;
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
return log;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function logAPI(fullLog){
|
|
43
|
+
logger.full.debug(fullLog);
|
|
44
|
+
logger.simple.debug(toSimpleLog(fullLog));
|
|
45
|
+
//要及时输出
|
|
46
|
+
logger.simple.flush();
|
|
47
|
+
logger.full.flush();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
function headersToObject(headers) {
|
|
52
|
+
const obj = {};
|
|
53
|
+
try {
|
|
54
|
+
for (const [k, v] of headers.entries()) obj[k] = v;
|
|
55
|
+
} catch {}
|
|
56
|
+
return obj;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
*
|
|
61
|
+
*
|
|
62
|
+
* 拦截 claude code 请求,这里应该拦截模型情况。当前拦截了所有的请求,模型请求可以通过 endpoint 判断出来
|
|
63
|
+
* 当前的逻辑需要优化
|
|
64
|
+
*
|
|
65
|
+
*/
|
|
66
|
+
function instrumentFetch() {
|
|
67
|
+
if (!global.fetch || global.fetch.__ProxyInstrumented) return;
|
|
68
|
+
|
|
69
|
+
logger.system.debug("-------------Clogger instrumentFetch--------------------------");
|
|
70
|
+
|
|
71
|
+
const originalFetch = global.fetch;
|
|
72
|
+
global.fetch = async (input, init = {}) => {
|
|
73
|
+
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
74
|
+
const endpoints = [
|
|
75
|
+
'/v1/messages'
|
|
76
|
+
];
|
|
77
|
+
let urlPath = (new URL(url)).pathname;
|
|
78
|
+
|
|
79
|
+
if(!(endpoints.some(t => urlPath.includes(t) && init.method == "POST"))){
|
|
80
|
+
//console.log("不是模型请求直接返回" +init.method +":" + url +" -> " + urlPath);
|
|
81
|
+
return originalFetch(input,init);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
//console.log("请求地址: " + url);
|
|
85
|
+
//转换前的请求
|
|
86
|
+
let initBody = JSON.parse(init.body);
|
|
87
|
+
//请求的 JSON
|
|
88
|
+
let requestBody = await anthropicTransformer.transformRequestOut(initBody);
|
|
89
|
+
//转换后的请求
|
|
90
|
+
let openaiRequestBodyString = JSON.stringify(requestBody);
|
|
91
|
+
|
|
92
|
+
//console.log(JSON.parse(openaiRequestBody));
|
|
93
|
+
|
|
94
|
+
//打印请求信息 init.body
|
|
95
|
+
const response = await originalFetch("https://openrouter.ai/api/v1/chat/completions", {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: {
|
|
98
|
+
"Content-Type": "application/json",
|
|
99
|
+
Authorization: `Bearer ${process.env.ANTHROPIC_AUTH_TOKEN}`
|
|
100
|
+
},
|
|
101
|
+
body: openaiRequestBodyString,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
let responseToClient = response.clone();
|
|
105
|
+
|
|
106
|
+
// 判断OpenRouter响应是否为异常
|
|
107
|
+
if (!response.ok) {
|
|
108
|
+
// 读取OpenRouter错误响应
|
|
109
|
+
const openrouterErrorText = await response.text();
|
|
110
|
+
logger.system.error(`OpenRouter API error response: ${response.status} ${response.statusText}`, {
|
|
111
|
+
url: url,
|
|
112
|
+
status: response.status,
|
|
113
|
+
errorResponse: openrouterErrorText
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
// 将OpenRouter错误响应转换为Claude Code错误响应格式
|
|
117
|
+
let claudeErrorResponse;
|
|
118
|
+
try {
|
|
119
|
+
const openrouterError = JSON.parse(openrouterErrorText);
|
|
120
|
+
claudeErrorResponse = {
|
|
121
|
+
type: "error",
|
|
122
|
+
error: {
|
|
123
|
+
type: "api_error",
|
|
124
|
+
message: openrouterError.error?.message || `OpenRouter API error: ${response.statusText}`,
|
|
125
|
+
code: `OPENROUTER_${response.status}_ERROR`
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
} catch (parseError) {
|
|
129
|
+
// 如果无法解析OpenRouter的错误JSON,使用通用错误格式
|
|
130
|
+
claudeErrorResponse = {
|
|
131
|
+
type: "error",
|
|
132
|
+
error: {
|
|
133
|
+
type: "api_error",
|
|
134
|
+
message: `OpenRouter API error: ${response.statusText}`,
|
|
135
|
+
code: `OPENROUTER_${response.status}_ERROR`
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// 返回转换后的错误响应
|
|
141
|
+
return new Response(JSON.stringify(claudeErrorResponse), {
|
|
142
|
+
status: response.status,
|
|
143
|
+
statusText: response.statusText,
|
|
144
|
+
headers: {
|
|
145
|
+
"Content-Type": "application/json"
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
//完整的请求日志,保护请求和响应
|
|
151
|
+
let fullLog = {request:{
|
|
152
|
+
url:url,
|
|
153
|
+
method: init.method,
|
|
154
|
+
headers: headersToObject(init.headers),
|
|
155
|
+
body: initBody
|
|
156
|
+
},response:{
|
|
157
|
+
status: response.status,
|
|
158
|
+
statusText: response.statusText,
|
|
159
|
+
headers: headersToObject(response.headers)
|
|
160
|
+
},openai:{
|
|
161
|
+
request: {
|
|
162
|
+
body: requestBody
|
|
163
|
+
},
|
|
164
|
+
response: {}
|
|
165
|
+
}};
|
|
166
|
+
|
|
167
|
+
let res = await anthropicTransformer.transformResponseIn(responseToClient);
|
|
168
|
+
let toClientRes = await res.clone();
|
|
169
|
+
|
|
170
|
+
(async () => {
|
|
171
|
+
|
|
172
|
+
fullLog.openai.response.body = await parseOpenAIChatCompletion(await response.text());
|
|
173
|
+
fullLog.response.body = mergeAnthropic(await res.text());
|
|
174
|
+
|
|
175
|
+
//其他类型是错误的
|
|
176
|
+
logAPI(fullLog);
|
|
177
|
+
|
|
178
|
+
})().catch(err => console.error('日志解析错误:', err));
|
|
179
|
+
|
|
180
|
+
return toClientRes;
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
};
|
|
184
|
+
global.fetch.__ProxyInstrumented = true;
|
|
185
|
+
}
|
|
186
|
+
try{
|
|
187
|
+
instrumentFetch();
|
|
188
|
+
}catch(e){
|
|
189
|
+
logger.system.error(e);
|
|
190
|
+
}
|