Spaces:
Running
Running
const os = require('os'); | |
const zlib = require('zlib'); | |
const crypto = require('crypto'); | |
const { v4: uuidv4 } = require('uuid'); | |
const $root = require('../proto/message.js'); | |
function generateCursorBody(messages, modelName) { | |
const instruction = messages | |
.filter(msg => msg.role === 'system') | |
.map(msg => msg.content) | |
.join('\n') | |
const formattedMessages = messages | |
.filter(msg => msg.role !== 'system') | |
.map(msg => ({ | |
content: msg.content, | |
role: msg.role === 'user' ? 1 : 2, | |
messageId: uuidv4(), | |
...(msg.role === 'user' ? { chatModeEnum: 1 } : {}) | |
//...(msg.role !== 'user' ? { summaryId: uuidv4() } : {}) | |
})); | |
const messageIds = formattedMessages.map(msg => { | |
const { role, messageId, summaryId } = msg; | |
return summaryId ? { role, messageId, summaryId } : { role, messageId }; | |
}); | |
const body = { | |
request:{ | |
messages: formattedMessages, | |
unknown2: 1, | |
instruction: { | |
instruction: instruction | |
}, | |
unknown4: 1, | |
model: { | |
name: modelName, | |
empty: '', | |
}, | |
webTool: "", | |
unknown13: 1, | |
cursorSetting: { | |
name: "cursor\\aisettings", | |
unknown3: "", | |
unknown6: { | |
unknwon1: "", | |
unknown2: "" | |
}, | |
unknown8: 1, | |
unknown9: 1 | |
}, | |
unknown19: 1, | |
//unknown22: 1, | |
conversationId: uuidv4(), | |
metadata: { | |
os: "win32", | |
arch: "x64", | |
version: "10.0.22631", | |
path: "C:\\Program Files\\PowerShell\\7\\pwsh.exe", | |
timestamp: new Date().toISOString(), | |
}, | |
unknown27: 0, | |
//unknown29: "", | |
messageIds: messageIds, | |
largeContext: 0, | |
unknown38: 0, | |
chatModeEnum: 1, | |
unknown47: "", | |
unknown48: 0, | |
unknown49: 0, | |
unknown51: 0, | |
unknown53: 1, | |
chatMode: "Ask" | |
} | |
}; | |
const errMsg = $root.StreamUnifiedChatWithToolsRequest.verify(body); | |
if (errMsg) throw Error(errMsg); | |
const instance = $root.StreamUnifiedChatWithToolsRequest.create(body); | |
let buffer = $root.StreamUnifiedChatWithToolsRequest.encode(instance).finish(); | |
let magicNumber = 0x00 | |
if (formattedMessages.length >= 3){ | |
buffer = zlib.gzipSync(buffer) | |
magicNumber = 0x01 | |
} | |
const finalBody = Buffer.concat([ | |
Buffer.from([magicNumber]), | |
Buffer.from(buffer.length.toString(16).padStart(8, '0'), 'hex'), | |
buffer | |
]) | |
return finalBody | |
} | |
function chunkToUtf8String(chunk) { | |
const results = [] | |
const errorResults = { hasError: false, errorMessage: '' } | |
const buffer = Buffer.from(chunk, 'hex'); | |
//console.log("Chunk buffer:", buffer.toString('hex')) | |
try { | |
for(let i = 0; i < buffer.length; i++){ | |
const magicNumber = parseInt(buffer.subarray(i, i + 1).toString('hex'), 16) | |
const dataLength = parseInt(buffer.subarray(i + 1, i + 5).toString('hex'), 16) | |
const data = buffer.subarray(i + 5, i + 5 + dataLength) | |
//console.log("Parsed buffer:", magicNumber, dataLength, data.toString('hex')) | |
if (magicNumber == 0 || magicNumber == 1) { | |
const gunzipData = magicNumber == 0 ? data : zlib.gunzipSync(data) | |
const response = $root.StreamUnifiedChatWithToolsResponse.decode(gunzipData); | |
const thinking = response?.message?.thinking?.content | |
if (thinking !== undefined){ | |
results.push(thinking); | |
//console.log(thinking); | |
} | |
const content = response?.message?.content | |
if (content !== undefined){ | |
results.push(content) | |
//console.log(content) | |
} | |
} | |
else if (magicNumber == 2 || magicNumber == 3) { | |
// Json message | |
const gunzipData = magicNumber == 2 ? data : zlib.gunzipSync(data) | |
const utf8 = gunzipData.toString('utf-8') | |
const message = JSON.parse(utf8) | |
if (message != null && (typeof message !== 'object' || | |
(Array.isArray(message) ? message.length > 0 : Object.keys(message).length > 0))){ | |
//results.push(utf8) | |
console.error(utf8) | |
// 检查是否为错误消息 | |
if (message && message.error) { | |
errorResults.hasError = true; | |
errorResults.errorMessage = utf8; | |
} | |
} | |
} | |
else { | |
//console.log('Unknown magic number when parsing chunk response: ' + magicNumber) | |
} | |
i += 5 + dataLength - 1 | |
} | |
} catch (err) { | |
console.log('Error parsing chunk response:', err) | |
} | |
// 如果存在错误,返回错误对象 | |
if (errorResults.hasError) { | |
return { error: errorResults.errorMessage }; | |
} | |
return results.join('') | |
} | |
function generateHashed64Hex(input, salt = '') { | |
const hash = crypto.createHash('sha256'); | |
hash.update(input + salt); | |
return hash.digest('hex'); | |
} | |
function obfuscateBytes(byteArray) { | |
let t = 165; | |
for (let r = 0; r < byteArray.length; r++) { | |
byteArray[r] = (byteArray[r] ^ t) + (r % 256); | |
t = byteArray[r]; | |
} | |
return byteArray; | |
} | |
function generateCursorChecksum(token) { | |
const machineId = generateHashed64Hex(token, 'machineId'); | |
const macMachineId = generateHashed64Hex(token, 'macMachineId'); | |
const timestamp = Math.floor(Date.now() / 1e6); | |
const byteArray = new Uint8Array([ | |
(timestamp >> 40) & 255, | |
(timestamp >> 32) & 255, | |
(timestamp >> 24) & 255, | |
(timestamp >> 16) & 255, | |
(timestamp >> 8) & 255, | |
255 & timestamp, | |
]); | |
const obfuscatedBytes = obfuscateBytes(byteArray); | |
const encodedChecksum = Buffer.from(obfuscatedBytes).toString('base64'); | |
return `${encodedChecksum}${machineId}/${macMachineId}`; | |
} | |
module.exports = { | |
generateCursorBody, | |
chunkToUtf8String, | |
generateHashed64Hex, | |
generateCursorChecksum | |
}; | |