Kimi Code CLI Web Sessions API 全解析:从 REST 接口到源码实现
2026/9/15 17:13:15 网站建设 项目流程

Kimi Code CLI Web Sessions API 全解析:从 REST 接口到源码实现

【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli

Kimi Code CLI(本仓库即其核心代码)内置了一个基于 FastAPI 的 Web 界面,而SessionsApi正是该 Web 界面用于管理会话(Session)的完整 REST API 集合。本文以web/src/lib/api/docs/SessionsApi.md为骨架,结合后端路由实现 src/kimi_cli/web/api/sessions.py、数据模型 src/kimi_cli/web/models.py 与前端 TypeScript 客户端 web/src/lib/api/apis/SessionsApi.ts,逐接口讲解会话的创建、查询、更新、删除、文件读写、git 变更统计与 AI 标题生成,帮助你在自己的应用或脚本中直接对接这套会话管理能力。

一、API 总览:10 个端点覆盖会话全生命周期

SessionsApi 的所有请求都相对http://localhost发起,统一挂载在/api/sessions/前缀之下。后端由 src/kimi_cli/web/api/sessions.py 中的APIRouter(prefix="/api/sessions", tags=["sessions"])提供路由,完整端点如下:

MethodHTTP requestDescription
createSessionApiSessionsPostPOST/api/sessions/Create a new session
deleteSessionApiSessionsSessionIdDeleteDELETE/api/sessions/{session_id}Delete a session
generateSessionTitleApiSessionsSessionIdGenerateTitlePostPOST/api/sessions/{session_id}/generate-titleGenerate session title using AI
getSessionApiSessionsSessionIdGetGET/api/sessions/{session_id}Get session
getSessionFileApiSessionsSessionIdFilesPathGetGET/api/sessions/{session_id}/files/{path}Get file or list directory from session work_dir
getSessionGitDiffApiSessionsSessionIdGitDiffGetGET/api/sessions/{session_id}/git-diffGet git diff stats
getSessionUploadFileApiSessionsSessionIdUploadsPathGetGET/api/sessions/{session_id}/uploads/{path}Get uploaded file from session uploads
listSessionsApiSessionsGetGET/api/sessions/List all sessions
updateSessionApiSessionsSessionIdPatchPATCH/api/sessions/{session_id}Update session
uploadSessionFileApiSessionsSessionIdFilesPostPOST/api/sessions/{session_id}/filesUpload file to session

从功能上可以划分为四组:

  1. 会话生命周期:创建(POST/)、查询单个(GET/{session_id})、列表(GET/)、更新(PATCH/{session_id})、删除(DELETE/{session_id});
  2. 工作目录文件访问:读取/列目录(GET/{session_id}/files/{path})、上传文件(POST/{session_id}/files)、读取上传文件(GET/{session_id}/uploads/{path});
  3. git 仓库状态:获取工作目录 diff 统计(GET/{session_id}/git-diff);
  4. AI 辅助:基于首轮对话生成会话标题(POST/{session_id}/generate-title)。

所有接口的Accept均为application/json;其中创建、生成标题、更新接口的Content-Typeapplication/json,上传文件接口为multipart/form-data。除 200(Successful Response)外,所有接口都可能返回422 Validation Error,对应 FastAPI/Pydantic 的请求体校验失败。

二、环境与前置:如何启动 Web 服务

SessionsApi 运行在 kimi-cli 自带的 Web 服务进程内,服务入口为 src/kimi_cli/web/app.py,路由注册在 src/kimi_cli/web/api/sessions.py。启动后通过kimi web类命令拉起 FastAPI 应用,默认监听本地端口(Base URL 即http://localhost)。

从 src/kimi_cli/web/store/sessions.py 的设计说明可以看出,该存储层采用cache-aside 模式

  • 读时缓存:首次读取填充缓存,后续读直接命中;
  • 写时失效:所有 API 变更操作都会调用invalidate_sessions_cache()清空缓存;
  • TTL 兜底:缓存默认CACHE_TTL = 5.0秒过期,作为外部变更的安全网。

该设计适用于单 worker 进程部署(例如不带-w参数的 uvicorn),所有变更都经由同一套 API 完成,偶发的陈旧数据(最多 5 秒)是可接受的。

三、会话生命周期:创建、查询、列表、更新与删除

3.1 创建会话:POST /api/sessions/

import { Configuration, SessionsApi, } from ''; import type { CreateSessionApiSessionsPostRequest } from ''; async function example() { const api = new SessionsApi(); const body = { // CreateSessionRequest (optional) createSessionRequest: { workDir: "/path/to/project", createDir: false, }, } satisfies CreateSessionApiSessionsPostRequest; try { const data = await api.createSessionApiSessionsPost(body); console.log(data); } catch (error) { console.error(error); } }

请求体 CreateSessionRequest(可选,对应后端src/kimi_cli/web/api/sessions.pyCreateSessionRequest模型,见 sessions.py#L358-L362):

字段类型说明默认值
workDirstring会话工作目录,支持~展开用户主目录(Path.home()
createDirboolean目录不存在时是否自动创建false

后端行为细节(sessions.py#L299-L355):

  • work_dir不存在且create_dir=False,返回404Directory does not exist;若create_dir=True则自动mkdir(parents=True),权限不足返回 403,其他OSError返回 400;
  • work_dir不是目录时返回 400Path is not a directory
  • 会话底层由KimiCLISession.create(work_dir=...)创建,session_dir落在该工作目录的会话目录中;
  • 返回的 Session 包含session_idtitlelastUpdatedisRunningstatusworkDirsessionDirarchived等字段(定义见 models.py#L64-L74)。

3.2 查询单个会话:GET /api/sessions/{session_id}

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", } satisfies GetSessionApiSessionsSessionIdGetRequest; const data = await api.getSessionApiSessionsSessionIdGet(body);

后端(sessions.py#L285-L296)按 UUID 加载会话,并用 runner 中的进程状态实时回填is_runningstatus(SessionStatus 的state取值见 models.py#L11,为"stopped" | "idle" | "busy" | "restarting" | "error")。会话不存在时返回null

3.3 列表查询:GET /api/sessions/

const body = { limit: 100, // number, optional, default 100, max 500 offset: 0, // number, optional, default 0 q: "kimi", // string, optional, 按 title 或 work_dir 过滤 archived: true, // boolean, optional } satisfies ListSessionsApiSessionsGetRequest; const data = await api.listSessionsApiSessionsGet(body);

参数语义(后端见 sessions.py#L249-L282):

参数类型说明默认值/约束
limitnumber返回的最大会话数默认 100,最大 500,<=0时回退到 100
offsetnumber跳过的会话数默认 0,负数钳制为 0
qstring按标题或工作目录搜索可选
archivedboolean归档过滤:None(不传)只返回未归档;true只返回归档可选

列表接口还有两个值得注意的后端行为:

  • 每次调用都会在后台触发run_auto_archive()(内部节流,最多每 5 分钟执行一次),将超过AUTO_ARCHIVE_DAYS = 15天的会话自动归档(见 store/sessions.py#L39);
  • 返回前会遍历每个会话,用 runner 的运行态填充is_runningstatus,因此列表天然携带实时状态。

3.4 更新会话:PATCH /api/sessions/{session_id}

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", updateSessionRequest: { title: "重构认证模块", archived: true, }, } satisfies UpdateSessionApiSessionsSessionIdPatchRequest; const data = await api.updateSessionApiSessionsSessionIdPatch(body);

请求体 UpdateSessionRequest(后端模型见 models.py#L77-L81):

字段类型约束说明
titlestring可选,min_length=1, max_length=200重命名会话标题
archivedboolean可选归档/取消归档

后端实现(sessions.py#L586-L626)通过load_session_state/save_session_state持久化:设置title时同时标记title_generated=True(避免后续 AI 标题覆盖手动命名);归档时记录archived_at并清除auto_archive_exempt,取消归档则重置并标记为免除自动归档。更新成功返回刷新后的Session

注意:updateSessionRequest在文档参数表中标记为必填,而sessionId为路径参数。另外该接口会先校验会话是否 busy(见 3.5 的get_editable_session)。

3.5 删除会话:DELETE /api/sessions/{session_id}

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", } satisfies DeleteSessionApiSessionsSessionIdDeleteRequest; const data = await api.deleteSessionApiSessionsSessionIdDelete(body); // any

删除是物理删除(后端见 sessions.py#L565-L583):先停止关联的 runner 进程,若该会话是该工作目录的last_session_id则清空元数据引用,最后shutil.rmtree删除整个session_dir,并失效会话缓存。删除与更新共用get_editable_session(sessions.py#L110-L128)——当会话正在运行(busy)时会返回 400Session is busy,避免在任务执行中修改或删除会话。

四、文件与上传:工作目录访问的完整闭环

4.1 读取文件或列出目录:GET /api/sessions/{session_id}/files/{path}

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", path: "src/main.py", // 相对 work_dir 的路径 } satisfies GetSessionFileApiSessionsSessionIdFilesPathGetRequest; const data = await api.getSessionFileApiSessionsSessionIdFilesPathGet(body);

行为(后端见 sessions.py#L463-L547):

  • path指向文件:返回文件内容,Content-Typemimetypes.guess_type推断,并通过Content-Disposition: attachment下载;
  • path指向目录:返回 JSON 数组,每项为{"name", "type": "directory"|"file", "size"},按「目录优先、名称升序」排序(size仅文件有);
  • 路径解析经过resolve()必须仍在 work_dir 内,否则返回 400Invalid path: path traversal not allowed(防目录穿越)。

4.2 上传文件:POST /api/sessions/{session_id}/files

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", file: BINARY_DATA_HERE, // Blob, multipart/form-data } satisfies UploadSessionFileApiSessionsSessionIdFilesPostRequest; const data = await api.uploadSessionFileApiSessionsSessionIdFilesPost(body);

返回 UploadSessionFileResponse(pathfilenamesize)。后端关键实现(sessions.py#L379-L413):

  • 文件保存到会话目录下的uploads/子目录;
  • 单文件上限 100MBMAX_UPLOAD_SIZE = 100 * 1024 * 1024),超限返回413File too large (max 100MB)
  • 文件名经过sanitize_filename清洗(仅保留字母数字与._-字符),并拼接 UUID 前缀(如report_3f2a9b.pdf)避免冲突与恶意文件名;
  • 上传前同样经过 busy 校验。

4.3 读取上传文件:GET /api/sessions/{session_id}/uploads/{path}

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", path: "report_3f2a9b.pdf", } satisfies GetSessionUploadFileApiSessionsSessionIdUploadsPathGetRequest; const data = await api.getSessionUploadFileApiSessionsSessionIdUploadsPathGet(body);

后端(sessions.py#L416-L460)将path解析后限制在uploads/目录内(同样防目录穿越),以inline方式内联返回文件,便于前端直接预览图片、PDF 等。

4.4 公开访问安全策略(重要实现细节)

getSessionFilerestrict_sensitive_apis开启时会叠加多层防护(sessions.py#L159-L191):

  1. 路径深度限制:相对路径深度超过DEFAULT_MAX_PUBLIC_PATH_DEPTH = 6返回 403;
  2. 敏感路径拦截:路径中出现.ssh.aws.kubeid_rsacredentials等关键词,或.pem.key.p12等敏感扩展名时返回 403;
  3. 符号链接检查:路径任一组件是 symlink 则拒绝(防止绕过目录限制);
  4. 敏感家目录检测:解析后若落入~/.ssh~/.gnupg~/.aws~/.kube等位置返回 403。

列目录时也会过滤掉上述敏感条目,避免泄露凭证类文件。

五、Git 变更统计:GET /api/sessions/{session_id}/git-diff

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", } satisfies GetSessionGitDiffApiSessionsSessionIdGitDiffGetRequest; const data = await api.getSessionGitDiffApiSessionsSessionIdGitDiffGet(body);

返回 GitDiffStats(isGitRepohasChangestotalAdditionstotalDeletionsfiles: GitFileDiff[]error),其中 GitFileDiff 包含pathadditionsdeletionsstatusadded|modified|deleted|renamed,见 models.py#L42-L50)。

后端实现(sessions.py#L1131-L1245)本质上是把git命令行封装成 API:

  • 工作目录没有.git时返回is_git_repo=False
  • 通过git rev-parse --verify HEAD判断仓库是否有提交;
  • 有 HEAD 时执行git diff --numstat HEAD(同时覆盖已暂存与未暂存变更),解析+/-行数并推断文件状态(只有增量为added、只有删除为deleted、否则modified);
  • 再执行git ls-files --others --exclude-standard收集未跟踪的新文件,以status="added"追加(行数记为 0);
  • 每个 git 子进程都设置了5 秒超时,超时返回error="Git command timed out";无 HEAD 时只汇报未跟踪文件。

该接口非常适合在 Web 界面里渲染「AI 改动概览」:无需本地安装额外依赖,前端拿到聚合后的增减行数与文件级明细即可直接展示。

六、AI 会话标题生成:POST /api/sessions/{session_id}/generate-title

const body = { sessionId: "38400000-8cf0-11bd-b23e-10b96e4ef00d", // GenerateTitleRequest (optional) - 不传时后端自动从 wire.jsonl 读取首轮对话 generateTitleRequest: { userMessage: "帮我重构认证模块", assistantResponse: "好的,我将从以下几个方面开始重构……", }, } satisfies GenerateSessionTitleApiSessionsSessionIdGenerateTitlePostRequest; const data = await api.generateSessionTitleApiSessionsSessionIdGenerateTitlePost(body);

请求体 GenerateTitleRequest(userMessageassistantResponse均可选)与响应 GenerateTitleResponse(title)的后端模型见 models.py#L84-L98。核心逻辑在 sessions.py#L749-L901:

  1. 去重保护:若会话状态中title_generated已为真,直接返回现有标题,避免重复消耗 token;
  2. 内容兜底:请求体缺参时,通过extract_first_turn_from_wire(sessions.py#L629-L681)解析会话目录下的wire.jsonl,提取首轮TurnBegin的用户输入与ContentPart文本作为候选;拿不到用户消息时返回"Untitled"
  3. 文本截断兜底:将用户消息压缩为单行并用shorten(text, width=50)截断到 50 字符作为 fallback 标题;
  4. AI 生成:使用配置的默认模型(config.default_model),走kosong.generate+create_llm,系统提示要求输出不超过 50 字符、无引号无解释的纯标题;prompt 截取首轮对话各 300 字符;对 Kimi 提供商还会用SESSION_TITLE_MAX_COMPLETION_TOKENS = 512限制生成 token 数(并与配置的max_completion_tokens取较小值);
  5. 失败重试:AI 调用失败不抛错,title_generate_attempts递增;连续失败 3 次后直接采用截断的 fallback 标题并标记title_generated=True
  6. 并发安全:LLM 调用期间若其他请求已定稿标题,则以最新状态为准(read-modify-write 重新加载 state),避免覆盖手动重命名。

AI 成功生成时返回 AI 标题(超 50 字符会被截断);失败但未达 3 次时返回 fallback 标题(不标记 generated,允许下次重试)。

七、数据模型一览

以下模型文档均位于 web/src/lib/api/docs,与后端 Pydantic 定义(models.py)一一对应:

模型关键字段说明
SessionsessionId, title, lastUpdated, isRunning, status, workDir, sessionDir, archivedWeb UI 会话元数据
SessionStatussessionId, state, seq, workerId, reason, detail, updatedAt运行时状态,state ∈ {stopped, idle, busy, restarting, error}
CreateSessionRequestworkDir, createDir创建会话请求体
UpdateSessionRequesttitle, archived更新会话请求体
GenerateTitleRequestuserMessage, assistantResponseAI 标题生成请求体(可空)
GenerateTitleResponsetitleAI 标题生成响应
GitDiffStatsisGitRepo, hasChanges, totalAdditions, totalDeletions, files, error工作目录 git diff 统计
GitFileDiffpath, additions, deletions, status单文件 diff 统计
UploadSessionFileResponsepath, filename, size上传响应

八、前端集成方式:SessionsApi TypeScript 客户端

web/src/lib/api/apis/SessionsApi.ts是 OpenAPI Generator 自动生成的 TypeScript 客户端(561 行),每个端点对应一个强类型方法(如createSessionApiSessionsPostlistSessionsApiSessionsGet),并预定义了形如CreateSessionApiSessionsPostRequest的请求接口(SessionsApi.ts#L46-L80)。前端可直接:

import { SessionsApi } from '../apis'; import { Configuration } from '../runtime'; const api = new SessionsApi(new Configuration({ basePath: 'http://localhost' })); const sessions = await api.listSessionsApiSessionsGet({ limit: 50, q: 'kimi' });

结合本文第四、五节的接口,一个典型的「会话浏览器」页面可以这样组织数据流:

  1. listSessionsApiSessionsGet渲染会话列表(标题、更新时间、运行状态、归档过滤);
  2. 选中会话后getSessionApiSessionsSessionIdGet拉取详情;
  3. getSessionGitDiffApiSessionsSessionIdGitDiffGet展示该会话工作目录的代码改动统计;
  4. getSessionFileApiSessionsSessionIdFilesPathGet浏览/预览工作目录文件;
  5. generateSessionTitleApiSessionsSessionIdGenerateTitlePost为新会话自动生成标题;
  6. updateSessionApiSessionsSessionIdPatch/deleteSessionApiSessionsSessionIdDelete完成重命名、归档与清理。

九、错误码速查与注意事项

所有接口统一的响应码:

状态码说明
200Successful Response(含Sessionany、数组等)
400参数/状态非法:路径穿越、会话 busy、目录不是文件夹等
403敏感文件/符号链接/目录深度超限(公开模式)
404会话不存在、文件不存在、目录不存在
413上传文件超过 100MB
422Pydantic 校验失败(参数类型/范围错误,如limit>500会被后端钳制而非报错)

使用时的关键约束:

  • 路径参数session_id为 UUID 格式(文档示例为38400000-8cf0-11bd-b23e-10b96e4ef00d),非法 UUID 会触发 422;
  • busy 会话只读:更新、删除、上传、生成标题前都会检查会话是否正在运行,忙碌时返回 400;
  • 目录穿越防护files/{path}uploads/{path}均经过resolve()归一化校验,越界即 400;
  • 多进程部署注意:会话存储的 cache-aside 设计面向单 worker 进程,多进程部署时缓存一致性需自行评估(见 store/sessions.py 头部注释)。

十、小结

SessionsApi 是 kimi-cli Web 界面的会话中枢:它以 10 个 REST 端点完整覆盖「创建—运行—读取—更新—删除」的会话生命周期,并额外提供工作目录文件浏览、上传下载、git diff 统计与 AI 标题生成等增强能力。配合后端的 FastAPI 路由(sessions.py)、Pydantic 模型(models.py)与 TypeScript 客户端(SessionsApi.ts),无论是构建自定义前端、编写自动化脚本,还是深度定制会话管理,都能找到直接可用的接口与清晰的实现参考。

【免费下载链接】kimi-cliKimi Code CLI is your next CLI agent.项目地址: https://gitcode.com/GitHub_Trending/ki/kimi-cli

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询