/** * API 客户端 * 封装与后端的 HTTP 通信 */ import * as vscode from 'vscode'; import * as https from 'https'; import * as http from 'http'; import { URL } from 'url'; import { getApiUrl, getConfig } from '../config/settings'; import type { ToolCallResult, AnswerRequest, ToolResultResponse, AnswerResponse, ToolConfirmResponse, UserInfoResponse, InvitationVerifyRequest, InvitationVerifyResponse, InvitationStatusResponse } from '../types/api'; /** * HTTP 请求选项 */ interface RequestOptions { method: 'GET' | 'POST' | 'PUT' | 'DELETE'; headers?: Record; body?: unknown; timeout?: number; } /** * 获取当前登录的 Token */ async function getAuthToken(): Promise { try { const session = await vscode.authentication.getSession('iccoder', [], { silent: true }); return session?.accessToken; } catch { return undefined; } } /** * 发送 HTTP 请求 */ async function request(path: string, options: RequestOptions): Promise { const url = new URL(getApiUrl(path)); const { timeout } = getConfig(); // 自动获取 Token const token = await getAuthToken(); const isHttps = url.protocol === 'https:'; const httpModule = isHttps ? https : http; const requestOptions: http.RequestOptions = { hostname: url.hostname, port: url.port || (isHttps ? 443 : 80), path: url.pathname + url.search, method: options.method, headers: { 'Content-Type': 'application/json', ...(token ? { 'Authorization': `Bearer ${token}` } : {}), ...options.headers }, timeout: options.timeout || timeout }; return new Promise((resolve, reject) => { const req = httpModule.request(requestOptions, (res) => { let data = ''; res.on('data', (chunk) => { data += chunk; }); res.on('end', () => { try { const json = JSON.parse(data); if (res.statusCode && res.statusCode >= 200 && res.statusCode < 300) { resolve(json as T); } else { reject(new Error(json.error || json.message || `HTTP ${res.statusCode}`)); } } catch (e) { reject(new Error(`解析响应失败: ${data}`)); } }); }); req.on('error', (error) => { reject(error); }); req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); }); if (options.body) { req.write(JSON.stringify(options.body)); } req.end(); }); } /** * 提交工具执行结果 * POST /api/tool/result */ export async function submitToolResult(result: ToolCallResult): Promise { console.log(`[API] 提交工具结果: callId=${result.id}`); return request('/api/tool/result', { method: 'POST', body: result }); } /** * 提交用户回答 * POST /api/task/answer */ export async function submitAnswer(answer: AnswerRequest): Promise { console.log(`[API] 提交用户回答: askId=${answer.askId}`); return request('/api/task/answer', { method: 'POST', body: answer }); } /** * 提交工具确认响应(Ask 模式) * POST /api/tool/confirm */ export async function submitToolConfirm(response: ToolConfirmResponse): Promise { console.log(`[API] 提交工具确认: confirmId=${response.confirmId}, approved=${response.approved}`); return request('/api/tool/confirm', { method: 'POST', body: response }); } /** * 健康检查 * GET /api/dialog/health */ export async function healthCheck(): Promise<{ status: string }> { return request<{ status: string }>('/api/dialog/health', { method: 'GET', timeout: 5000 }); } /** * 停止对话请求 */ export interface StopDialogRequest { taskId: string; } /** * 停止对话响应 */ export interface StopDialogResponse { success: boolean; taskId: string; message?: string; error?: string; } /** * 停止对话 * POST /api/dialog/stop */ export async function stopDialog(taskId: string): Promise { console.log(`[API] 停止对话: taskId=${taskId}`); return request('/api/dialog/stop', { method: 'POST', body: { taskId } }); } /** 压缩对话响应 */ export interface CompactDialogResponse { success: boolean; taskId: string; message?: string; error?: string; } /** * 手动压缩对话历史 * POST /api/dialog/compact */ export async function compactDialog(taskId: string): Promise { console.log(`[API] 压缩对话: taskId=${taskId}`); return request('/api/dialog/compact', { method: 'POST', body: { taskId } }); } /** * 创建成功的工具结果 */ export function createSuccessResult(id: number, text: string): ToolCallResult { return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text }], isError: false } }; } /** * 创建业务错误的工具结果(如编译失败) */ export function createBusinessErrorResult(id: number, errorMessage: string): ToolCallResult { return { jsonrpc: '2.0', id, result: { content: [{ type: 'text', text: errorMessage }], isError: true } }; } /** * 创建系统错误的工具结果 */ export function createSystemErrorResult(id: number, code: number, message: string): ToolCallResult { return { jsonrpc: '2.0', id, error: { code, message } }; } /** * 获取用户信息 * GET /system/user/getInfo */ export async function getUserInfo(): Promise { console.log('[API] 获取用户信息'); return request('/system/user/getInfo', { method: 'GET' }); } /** 余额查询响应 */ export interface CreditBalanceResponse { success: boolean; balance?: number; error?: string; } /** * 查询用户资源点余额 * GET /api/dialog/balance?userId=xxx */ export async function getCreditBalance(userId: string): Promise { console.log('[API] 查询余额: userId=', userId); return request(`/api/dialog/balance?userId=${userId}`, { method: 'GET', timeout: 5000 }); } /** * 验证邀请码 * POST /api/invitation/verify */ export async function verifyInvitationCode(code: string): Promise { console.log('[API] 验证邀请码'); const body: InvitationVerifyRequest = { code }; return request('/api/invitation/verify', { method: 'POST', body }); } /** * 查询邀请码验证状态 * GET /api/invitation/status */ export async function checkInvitationStatus(): Promise { console.log('[API] 查询邀请码验证状态'); return request('/api/invitation/status', { method: 'GET' }); }