@dahawa/hawa-cli-analysis 1.0.4
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 +7 -0
- package/.vscode/launch.json +27 -0
- package/LICENSE +21 -0
- package/README.md +196 -0
- package/_uclaude.js +165 -0
- package/anthropic-transformer.js +986 -0
- package/api-anthropic.js +279 -0
- package/api-openai.js +539 -0
- package/claude/claude-openai-proxy.js +305 -0
- package/claude/claude-proxy.js +341 -0
- package/clogger-openai.js +190 -0
- package/clogger.js +318 -0
- package/codex/mcp-client.js +556 -0
- package/codex/mcpclient.js +118 -0
- package/codex/mcpserver.js +374 -0
- package/codex/mcpserverproxy.js +144 -0
- package/codex/test.js +30 -0
- package/config.js +105 -0
- package/index.js +0 -0
- package/logger-manager.js +85 -0
- package/logger.js +112 -0
- package/mcp/claude-mcpproxy-launcher.js +5 -0
- package/mcp_oauth_tokens.js +40 -0
- package/package.json +36 -0
- package/port-manager.js +80 -0
- package/simple-transform-example.js +213 -0
- package/tests/test-lazy-load.js +36 -0
- package/tests/test.js +30 -0
- package/tests/test_mcp_proxy.js +51 -0
- package/tests/test_supabase_mcp.js +42 -0
- package/uclaude.js +221 -0
- package/ucodex-proxy.js +173 -0
- package/ucodex.js +129 -0
- package/untils.js +261 -0
|
@@ -0,0 +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
|
+
}
|
package/clogger.js
ADDED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import {mergeAnthropic} from './api-anthropic.js';
|
|
2
|
+
import LoggerManage from "./logger-manager.js"
|
|
3
|
+
import { URL } from 'url';
|
|
4
|
+
import { readFileSync } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
|
|
7
|
+
let logger = LoggerManage.getLogger("claudecode");
|
|
8
|
+
|
|
9
|
+
logger.system.debug("-------------Clogger Start--------------------------");
|
|
10
|
+
|
|
11
|
+
// 配置文件相关功能
|
|
12
|
+
let toolsConfig = {
|
|
13
|
+
blacklist: [],
|
|
14
|
+
descriptions: {}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
function loadToolsConfig() {
|
|
18
|
+
try {
|
|
19
|
+
const configPath = join(process.cwd(), '.tools.json');
|
|
20
|
+
const configContent = readFileSync(configPath, 'utf8');
|
|
21
|
+
const config = JSON.parse(configContent);
|
|
22
|
+
|
|
23
|
+
if (config.tools) {
|
|
24
|
+
toolsConfig.blacklist = config.tools.blacklist || [];
|
|
25
|
+
toolsConfig.descriptions = config.tools.descriptions || {};
|
|
26
|
+
logger.system.debug(`成功加载配置文件,黑名单: ${toolsConfig.blacklist.length} 个工具,描述重写: ${Object.keys(toolsConfig.descriptions).length} 个工具`);
|
|
27
|
+
}
|
|
28
|
+
} catch (error) {
|
|
29
|
+
if (error.code === 'ENOENT') {
|
|
30
|
+
logger.system.debug('未找到 .tools.json 配置文件,使用默认配置');
|
|
31
|
+
} else {
|
|
32
|
+
logger.system.error(`加载配置文件失败: ${error.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 在启动时加载配置
|
|
38
|
+
loadToolsConfig();
|
|
39
|
+
|
|
40
|
+
function deepClone(obj) {
|
|
41
|
+
const result = JSON.parse(JSON.stringify(obj));
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// 处理请求body中的tools,应用黑名单过滤和描述改写
|
|
46
|
+
function processRequestTools(body) {
|
|
47
|
+
if (!body || !body.tools || !Array.isArray(body.tools)) {
|
|
48
|
+
return body;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const originalCount = body.tools.length;
|
|
52
|
+
|
|
53
|
+
// 过滤黑名单中的工具
|
|
54
|
+
body.tools = body.tools.filter(tool => {
|
|
55
|
+
const toolName = tool.name || tool.function?.name;
|
|
56
|
+
if (!toolName) return true;
|
|
57
|
+
|
|
58
|
+
const isBlacklisted = toolsConfig.blacklist.includes(toolName);
|
|
59
|
+
if (isBlacklisted) {
|
|
60
|
+
logger.system.debug(`过滤黑名单工具: ${toolName}`);
|
|
61
|
+
}
|
|
62
|
+
return !isBlacklisted;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
// 改写工具描述
|
|
66
|
+
body.tools = body.tools.map(tool => {
|
|
67
|
+
const toolName = tool.name || tool.function?.name;
|
|
68
|
+
if (toolName && toolsConfig.descriptions[toolName]) {
|
|
69
|
+
logger.system.debug(`改写工具描述: ${toolName} -> ${toolsConfig.descriptions[toolName]}`);
|
|
70
|
+
|
|
71
|
+
// 根据工具结构更新描述
|
|
72
|
+
if (tool.description !== undefined) {
|
|
73
|
+
tool.description = toolsConfig.descriptions[toolName];
|
|
74
|
+
} else if (tool.function && tool.function.description !== undefined) {
|
|
75
|
+
tool.function.description = toolsConfig.descriptions[toolName];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return tool;
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const filteredCount = body.tools.length;
|
|
82
|
+
if (originalCount !== filteredCount) {
|
|
83
|
+
logger.system.debug(`工具过滤完成: ${originalCount} -> ${filteredCount}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return body;
|
|
87
|
+
}
|
|
88
|
+
function formateLine(str){
|
|
89
|
+
let r = str.replace(/\\n/g, '\n');
|
|
90
|
+
return r;
|
|
91
|
+
}
|
|
92
|
+
function toSimpleLog(fullLog){
|
|
93
|
+
//删除 tool 列表
|
|
94
|
+
let slog = deepClone(fullLog);
|
|
95
|
+
let result = {
|
|
96
|
+
request:slog.request.body.messages,
|
|
97
|
+
response:slog.response.body.content
|
|
98
|
+
};
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function logAPI(fullLog){
|
|
103
|
+
//console.log('Writing to log files...');
|
|
104
|
+
try {
|
|
105
|
+
logger.full.debug(fullLog);
|
|
106
|
+
logger.simple.debug(toSimpleLog(fullLog));
|
|
107
|
+
|
|
108
|
+
// 立即同步到文件
|
|
109
|
+
if (logger.full.flush) {
|
|
110
|
+
logger.full.flush();
|
|
111
|
+
}
|
|
112
|
+
if (logger.simple.flush) {
|
|
113
|
+
logger.simple.flush();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// console.log('Log files written successfully');
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error('Error writing to log files:', error);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
//兼容 SDK 直接使用
|
|
124
|
+
function headersToObject(headers) {
|
|
125
|
+
if (!headers) return {};
|
|
126
|
+
if (typeof headers.entries === 'function') {
|
|
127
|
+
return Object.fromEntries(headers.entries());
|
|
128
|
+
}
|
|
129
|
+
return { ...headers }; // assume it’s a plain object
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
*
|
|
135
|
+
*
|
|
136
|
+
* 拦截 claude code 请求,这里应该拦截模型情况。当前拦截了所有的请求,模型请求可以通过 endpoint 判断出来
|
|
137
|
+
* 当前的逻辑需要优化
|
|
138
|
+
*
|
|
139
|
+
*/
|
|
140
|
+
|
|
141
|
+
function instrumentFetch() {
|
|
142
|
+
if (!global.fetch || global.fetch.__ProxyInstrumented) return;
|
|
143
|
+
|
|
144
|
+
logger.system.debug("-------------Clogger instrumentFetch--------------------------");
|
|
145
|
+
|
|
146
|
+
const originalFetch = global.fetch;
|
|
147
|
+
global.fetch = async (input, init = {}) => {
|
|
148
|
+
const url = typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url;
|
|
149
|
+
const endpoints = [
|
|
150
|
+
'/v1/messages',
|
|
151
|
+
'/anthropic/v1/messages'
|
|
152
|
+
];
|
|
153
|
+
|
|
154
|
+
let urlPath = (new URL(url)).pathname;
|
|
155
|
+
|
|
156
|
+
if(!(endpoints.some(t => urlPath.includes(t) && (init.method == "POST" || init.method == "post" ) ))){
|
|
157
|
+
logger.system.debug("不是模型请求直接返回" +init.method +":" + url +" -> " + urlPath);
|
|
158
|
+
return originalFetch(input,init);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
//打印请求信息 init.body
|
|
162
|
+
let processedBody = init.body;
|
|
163
|
+
|
|
164
|
+
// 如果是模型请求,处理请求body中的tools
|
|
165
|
+
if (init.body) {
|
|
166
|
+
try {
|
|
167
|
+
const bodyObj = JSON.parse(init.body);
|
|
168
|
+
const processedBodyObj = processRequestTools(bodyObj);
|
|
169
|
+
processedBody = JSON.stringify(processedBodyObj);
|
|
170
|
+
|
|
171
|
+
if (processedBody !== init.body) {
|
|
172
|
+
logger.system.debug('请求body中的tools已被处理');
|
|
173
|
+
}
|
|
174
|
+
} catch (error) {
|
|
175
|
+
logger.system.error(`处理请求body失败: ${error.message}`);
|
|
176
|
+
// 如果处理失败,使用原始body
|
|
177
|
+
processedBody = init.body;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
//console.log(Object.prototype.toString.call(init.headers));
|
|
182
|
+
//console.log(init.headers);
|
|
183
|
+
|
|
184
|
+
//如果对 tools 修改了这里的长度肯定要变化的
|
|
185
|
+
let requestHeaders = headersToObject(init.headers);
|
|
186
|
+
delete requestHeaders["content-length"]; //可能还有大小写问题
|
|
187
|
+
//console.log(requestHeaders);
|
|
188
|
+
|
|
189
|
+
let response;
|
|
190
|
+
try{
|
|
191
|
+
response = await originalFetch(url, {
|
|
192
|
+
method: init.method,
|
|
193
|
+
headers: requestHeaders,
|
|
194
|
+
body: processedBody,
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
}catch(e){
|
|
198
|
+
logger.system.error(`处理请求失败: ${requestHeaders}`);
|
|
199
|
+
console.log(e);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
// 检查响应状态,处理错误情况
|
|
205
|
+
if (!response.ok) {
|
|
206
|
+
logger.system.error(`API error request:${url} ${JSON.stringify(requestHeaders)} ${processedBody}` );
|
|
207
|
+
// 读取原始错误响应
|
|
208
|
+
const errorText = await response.text();
|
|
209
|
+
logger.system.error(`API error response: ${response.status} ${response.statusText}`, {
|
|
210
|
+
url: url,
|
|
211
|
+
status: response.status,
|
|
212
|
+
errorResponse: errorText
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
// 尝试解析错误响应并转换为通用错误格式
|
|
216
|
+
let errorResponse;
|
|
217
|
+
try {
|
|
218
|
+
const originalError = JSON.parse(errorText);
|
|
219
|
+
|
|
220
|
+
// 构建通用错误响应格式
|
|
221
|
+
errorResponse = {
|
|
222
|
+
type: "error",
|
|
223
|
+
error: {
|
|
224
|
+
type: "api_error",
|
|
225
|
+
message: originalError.error?.message || originalError.message || `API error: ${response.statusText}`,
|
|
226
|
+
code: originalError.error?.code || originalError.code || `API_${response.status}_ERROR`
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// 如果有详细错误信息,保留原始结构
|
|
231
|
+
if (originalError.error?.details) {
|
|
232
|
+
errorResponse.error.details = originalError.error.details;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
} catch (parseError) {
|
|
236
|
+
// 如果无法解析错误JSON,使用通用错误格式
|
|
237
|
+
logger.system.error(`Failed to parse error response: ${parseError.message}`);
|
|
238
|
+
errorResponse = {
|
|
239
|
+
type: "error",
|
|
240
|
+
error: {
|
|
241
|
+
type: "api_error",
|
|
242
|
+
message: `API error: ${response.statusText}`,
|
|
243
|
+
code: `API_${response.status}_ERROR`
|
|
244
|
+
}
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// 返回标准化的错误响应
|
|
249
|
+
return new Response(JSON.stringify(errorResponse), {
|
|
250
|
+
status: response.status,
|
|
251
|
+
statusText: response.statusText,
|
|
252
|
+
headers: {
|
|
253
|
+
"Content-Type": "application/json"
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
//logger.full.debug("13132131313");
|
|
259
|
+
//response = proxyResponse(response);
|
|
260
|
+
let responseToClient = response.clone()
|
|
261
|
+
// stream 不能通过 content type 判断,
|
|
262
|
+
let isStream = true;
|
|
263
|
+
if(Object.hasOwn(init.body, "stream") && !init.body.stream){
|
|
264
|
+
isStream = false;
|
|
265
|
+
logger.full.debug("模型不是流请求");
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
//完整的请求日志,保护请求和响应
|
|
270
|
+
let fullLog = {request:{
|
|
271
|
+
url:url,
|
|
272
|
+
method: init.method,
|
|
273
|
+
headers: headersToObject(init.headers),
|
|
274
|
+
body: JSON.parse(processedBody)
|
|
275
|
+
},response:{
|
|
276
|
+
status: response.status,
|
|
277
|
+
statusText: response.statusText,
|
|
278
|
+
headers: headersToObject(response.headers)
|
|
279
|
+
}};
|
|
280
|
+
|
|
281
|
+
//logger.full.debug("1111111111111>>>>>>" );
|
|
282
|
+
|
|
283
|
+
try{
|
|
284
|
+
//日志解析要异步执行保证效率
|
|
285
|
+
(async ()=>{
|
|
286
|
+
if(isStream){
|
|
287
|
+
let alllog = await response.text();
|
|
288
|
+
//logger.full.debug("alllog "+alllog)
|
|
289
|
+
fullLog.response.body = mergeAnthropic(alllog);
|
|
290
|
+
}else{
|
|
291
|
+
fullLog.response.body = await response.json();
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// logger.full.debug("adassdadadadad>>>>>>" + JSON.stringify(fullLog));
|
|
295
|
+
|
|
296
|
+
logAPI(fullLog);
|
|
297
|
+
|
|
298
|
+
})().catch(err => logger.system.error('日志解析错误:' + "\nStack trace: " + err.stack));
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
return new Response(responseToClient.body, {
|
|
303
|
+
status: response.status,
|
|
304
|
+
statusText: response.statusText,
|
|
305
|
+
headers: response.headers
|
|
306
|
+
});
|
|
307
|
+
}catch(e){
|
|
308
|
+
logger.system.error(e);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
global.fetch.__ProxyInstrumented = true;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
try{
|
|
315
|
+
instrumentFetch();
|
|
316
|
+
}catch(e){
|
|
317
|
+
logger.system.error(e);
|
|
318
|
+
}
|