分析 API
代码分析任务管理相关的 API 端点。
端点概览
| 方法 | 端点 | 描述 | 认证 |
|---|---|---|---|
| POST | /analysis | 创建分析任务 | ✅ |
| GET | /analysis | 分析列表 | ✅ |
| GET | /projects/{id}/analysis | 项目分析列表 | ✅ |
| GET | /analysis/{id} | 分析详情 | ✅ |
| POST | /analysis/{id}/rerun | 重新运行分析 | ✅ |
| DELETE | /analysis/{id} | 取消分析 | ✅ |
| GET | /analysis/{id}/findings | 分析发现列表 | ✅ |
| GET | /analysis/{id}/requests | LLM 请求列表 | ✅ |
| GET | /analysis/{id}/tool-calls | 工具调用列表 | ✅ |
创建分析
POST /api/v1/analysis
创建新的代码分析任务。
请求
http
POST /api/v1/analysis
Authorization: Bearer <token>
Content-Type: application/json
{
"repository_id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "security_review",
"trigger_type": "manual",
"repository_ref": "main",
"requested_by": "User Name",
"title": "Security review for main branch"
}参数说明:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
repository_id | string | ✅ | 仓库 ID |
task_type | string | ✅ | 任务类型 |
trigger_type | string | ✅ | 触发类型 |
repository_ref | string | ❌ | Git 引用(分支/标签) |
requested_by | string | ✅ | 请求人名称 |
pull_request_number | integer | ❌ | PR 编号 |
commit_sha | string | ❌ | Commit SHA |
base_sha | string | ❌ | 基准 SHA(PR) |
head_sha | string | ❌ | HEAD SHA(PR) |
title | string | ❌ | 任务标题 |
任务类型 (task_type):
security_review- 安全审查code_review- 代码审查full_analysis- 全面分析
触发类型 (trigger_type):
manual- 手动触发push- 代码推送pull_request- PR 触发rerun- 重新运行webhook- Webhook 触发
响应
成功 (201 Created):
json
{
"analysis_id": "660e8400-e29b-41d4-a716-446655440000",
"repository_id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "security_review",
"trigger_type": "manual",
"status": "submitted",
"repository_provider": "github",
"repository_url": "https://github.com/owner/repo",
"repository_ref": "main",
"requested_by": "User Name",
"requested_by_user_id": "450e8400-e29b-41d4-a716-446655440000",
"title": "Security review for main branch",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:00:00Z"
}错误响应:
400 Bad Request: 参数验证失败404 Not Found: 仓库不存在
示例
typescript
const createAnalysis = async (
repositoryId: string,
taskType: 'security_review' | 'code_review' | 'full_analysis'
) => {
const response = await fetch('/api/v1/analysis', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
repository_id: repositoryId,
task_type: taskType,
trigger_type: 'manual',
repository_ref: 'main',
requested_by: 'Current User',
}),
});
return response.json();
};分析列表
GET /api/v1/analysis
获取当前用户的所有分析任务。
请求
http
GET /api/v1/analysis?status=running&limit=20&offset=0
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | integer | 20 | 每页数量 |
offset | integer | 0 | 偏移量 |
status | string | - | 状态过滤 |
状态值:
submitted- 已提交pending- 待处理running- 运行中completed- 已完成failed- 失败cancelled- 已取消
响应
成功 (200 OK):
json
{
"analyses": [
{
"analysis_id": "660e8400-e29b-41d4-a716-446655440000",
"repository_id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "security_review",
"trigger_type": "manual",
"status": "running",
"repository_provider": "github",
"repository_url": "https://github.com/owner/repo",
"repository_ref": "main",
"requested_by": "User Name",
"title": "Security review",
"started_at": "2024-01-01T12:01:00Z",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:01:00Z"
}
],
"total": 1
}GET /api/v1/projects/{id}/analysis
获取特定项目的分析任务。
请求
http
GET /api/v1/projects/550e8400-e29b-41d4-a716-446655440000/analysis?limit=20
Authorization: Bearer <token>响应格式与全局分析列表相同。
分析详情
GET /api/v1/analysis/{id}
获取分析任务的详细信息。
请求
http
GET /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <token>响应
成功 (200 OK):
json
{
"analysis_id": "660e8400-e29b-41d4-a716-446655440000",
"repository_id": "550e8400-e29b-41d4-a716-446655440000",
"task_type": "security_review",
"trigger_type": "manual",
"status": "completed",
"repository_provider": "github",
"repository_url": "https://github.com/owner/repo",
"repository_ref": "main",
"requested_by": "User Name",
"requested_by_user_id": "450e8400-e29b-41d4-a716-446655440000",
"title": "Security review",
"started_at": "2024-01-01T12:01:00Z",
"completed_at": "2024-01-01T12:15:00Z",
"created_at": "2024-01-01T12:00:00Z",
"updated_at": "2024-01-01T12:15:00Z"
}错误响应:
404 Not Found: 分析不存在或无权访问
重新运行分析
POST /api/v1/analysis/{id}/rerun
重新运行已完成或失败的分析。
请求
http
POST /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000/rerun
Authorization: Bearer <token>响应
成功 (201 Created):
返回新创建的分析任务,字段与创建分析相同。
错误响应:
404 Not Found: 原分析不存在400 Bad Request: 分析状态不允许重新运行
示例
typescript
const rerunAnalysis = async (analysisId: string) => {
const response = await fetch(`/api/v1/analysis/${analysisId}/rerun`, {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` },
});
return response.json();
};取消分析
DELETE /api/v1/analysis/{id}
取消正在运行的分析任务。
请求
http
DELETE /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000
Authorization: Bearer <token>响应
成功 (204 No Content):
无响应体。
错误响应:
404 Not Found: 分析不存在400 Bad Request: 分析已完成,无法取消
分析发现
GET /api/v1/analysis/{id}/findings
获取分析任务发现的问题列表。
请求
http
GET /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000/findings?limit=50
Authorization: Bearer <token>查询参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
limit | integer | 50 | 每页数量 |
offset | integer | 0 | 偏移量 |
响应
成功 (200 OK):
json
{
"findings": [
{
"session_id": "770e8400-e29b-41d4-a716-446655440000",
"severity": "high",
"title": "SQL Injection vulnerability",
"file_path": "src/database.rs",
"line_start": 42,
"line_end": 45,
"body": "Detailed description of the issue...",
"suggested_fix": "Use parameterized queries instead...",
"reported_at": "2024-01-01T12:10:00Z"
}
],
"total": 1
}严重程度 (severity):
critical- 严重high- 高medium- 中low- 低info- 信息
LLM 请求记录
GET /api/v1/analysis/{id}/requests
获取分析过程中的 LLM API 请求记录。
请求
http
GET /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000/requests?limit=100
Authorization: Bearer <token>响应
成功 (200 OK):
json
{
"requests": [
{
"request_id": "880e8400-e29b-41d4-a716-446655440000",
"session_id": "770e8400-e29b-41d4-a716-446655440000",
"analysis_id": "660e8400-e29b-41d4-a716-446655440000",
"model": "claude-opus-4",
"input_tokens": 1500,
"output_tokens": 800,
"total_tokens": 2300,
"cached_input_tokens": 500,
"created_at": "2024-01-01T12:05:00Z"
}
],
"total": 1
}用途:
- Token 使用统计
- 成本计算
- 性能分析
工具调用记录
GET /api/v1/analysis/{id}/tool-calls
获取 Agent 执行的工具调用记录。
请求
http
GET /api/v1/analysis/660e8400-e29b-41d4-a716-446655440000/tool-calls?limit=100
Authorization: Bearer <token>响应
成功 (200 OK):
json
{
"tool_calls": [
{
"tool_call_id": "990e8400-e29b-41d4-a716-446655440000",
"request_id": "880e8400-e29b-41d4-a716-446655440000",
"session_id": "770e8400-e29b-41d4-a716-446655440000",
"analysis_id": "660e8400-e29b-41d4-a716-446655440000",
"tool_name": "read_file",
"tool_input": { "path": "src/main.rs" },
"tool_output": { "content": "..." },
"status": "completed",
"created_at": "2024-01-01T12:05:00Z",
"completed_at": "2024-01-01T12:05:01Z"
}
],
"total": 1
}工具状态:
pending- 待执行running- 执行中completed- 已完成failed- 失败
状态流转
submitted → pending → running → completed
↘ failed
↘ cancelled状态说明:
- submitted: 任务已提交,等待入队
- pending: 已入队,等待 Agent 执行
- running: Agent 正在执行
- completed: 执行完成
- failed: 执行失败
- cancelled: 用户取消
实时更新
使用 SSE 获取分析状态实时更新:
typescript
const connectSSE = (analysisId: string) => {
const token = localStorage.getItem('token');
const url = `/api/v1/sse/analysis/${analysisId}?token=${token}`;
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
console.log('Analysis update:', data);
// 根据事件类型处理
if (data.type === 'status_changed') {
updateStatus(data.status);
}
};
return eventSource;
};详见 SSE API。
最佳实践
1. 轮询状态
typescript
const waitForCompletion = async (analysisId: string) => {
const interval = 5000; // 5秒
while (true) {
const analysis = await getAnalysis(analysisId);
if (['completed', 'failed', 'cancelled'].includes(analysis.status)) {
return analysis;
}
await new Promise(resolve => setTimeout(resolve, interval));
}
};2. 错误重试
typescript
const createAnalysisWithRetry = async (data, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await createAnalysis(data);
} catch (error) {
if (i === maxRetries - 1) throw error;
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
}
}
};3. Token 统计
typescript
const calculateCost = (requests: Request[]) => {
const totalInputTokens = requests.reduce((sum, r) => sum + r.input_tokens, 0);
const totalOutputTokens = requests.reduce((sum, r) => sum + r.output_tokens, 0);
const cachedTokens = requests.reduce((sum, r) => sum + (r.cached_input_tokens || 0), 0);
return {
inputTokens: totalInputTokens,
outputTokens: totalOutputTokens,
cachedTokens,
effectiveInputTokens: totalInputTokens - cachedTokens,
};
};