feat(context): 添加上下文压缩 API 和 UI 组件

Server API:
- 扩展 Agent Adapter 接口添加压缩相关方法
- 新增 context.ts 路由 (GET /sessions/:id/context, POST /sessions/:id/compress)
- 扩展 config.ts 添加摘要模型配置接口 (GET/PUT /config/summary)

UI 组件:
- 新增 ContextUsage 组件显示上下文使用情况
- 扩展 ConfigPanel 添加摘要模型配置区域
- 添加 API 客户端方法和类型定义

Web 集成:
- 在 Chat 页面头部集成 ContextUsage 紧凑模式显示
This commit is contained in:
2025-12-14 20:33:51 +08:00
parent f54f24b079
commit 70a9a154a4
13 changed files with 934 additions and 10 deletions
+106
View File
@@ -0,0 +1,106 @@
/**
* Context API Routes
*
* 上下文压缩相关的 REST API
*/
import { Hono } from 'hono';
import { getSessionManager } from '../session/manager.js';
import {
getContextUsage,
compressContext,
type ContextUsageInfo,
type CompressionResult,
} from '../agent/adapter.js';
export const contextRouter = new Hono();
/**
* GET /sessions/:id/context - 获取会话上下文使用情况
*/
contextRouter.get('/sessions/:id/context', (c) => {
const sessionId = c.req.param('id');
const sessionManager = getSessionManager();
// 验证会话存在
if (!sessionManager.exists(sessionId)) {
return c.json(
{
success: false,
error: 'Session not found',
},
404
);
}
const usage = getContextUsage(sessionId);
if (!usage) {
// Agent 未初始化,返回默认值
return c.json({
success: true,
data: {
input: 0,
contextLimit: 200000,
available: 180000,
usagePercent: 0,
formatted: '0/180K (0%)',
shouldCompress: false,
} as ContextUsageInfo,
});
}
return c.json({
success: true,
data: usage,
});
});
/**
* POST /sessions/:id/compress - 触发手动压缩
*/
contextRouter.post('/sessions/:id/compress', async (c) => {
const sessionId = c.req.param('id');
const sessionManager = getSessionManager();
// 验证会话存在
if (!sessionManager.exists(sessionId)) {
return c.json(
{
success: false,
error: 'Session not found',
},
404
);
}
try {
const body = await c.req.json().catch(() => ({}));
const force = body.force === true;
const result = await compressContext(sessionId, force);
if (!result) {
return c.json(
{
success: false,
error: 'Agent not initialized for this session',
},
400
);
}
return c.json({
success: true,
data: result,
});
} catch (error) {
return c.json(
{
success: false,
error: error instanceof Error ? error.message : 'Compression failed',
},
500
);
}
});