@turingflow/agent-kit 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/README.md +592 -2
  2. package/dist/agent.d.ts +27 -0
  3. package/dist/agent.js +31 -0
  4. package/dist/cli.d.ts +5 -0
  5. package/dist/cli.js +105 -0
  6. package/dist/handlers.d.ts +92 -0
  7. package/dist/handlers.js +211 -0
  8. package/dist/index.d.ts +13 -0
  9. package/dist/index.js +10 -0
  10. package/dist/sdk.d.ts +106 -0
  11. package/dist/sdk.js +309 -0
  12. package/dist/server/agent.d.ts +27 -0
  13. package/dist/server/agent.js +31 -0
  14. package/dist/server/artifact-hooks.d.ts +6 -0
  15. package/dist/server/artifact-hooks.js +37 -0
  16. package/dist/server/artifact-tool-tracker.d.ts +24 -0
  17. package/dist/server/artifact-tool-tracker.js +347 -0
  18. package/dist/server/artifacts.d.ts +227 -0
  19. package/dist/server/artifacts.js +1061 -0
  20. package/dist/server/auth/config.d.ts +34 -0
  21. package/dist/server/auth/config.js +82 -0
  22. package/dist/server/auth/db.d.ts +159 -0
  23. package/dist/server/auth/db.js +680 -0
  24. package/dist/server/auth/handlers.d.ts +27 -0
  25. package/dist/server/auth/handlers.js +297 -0
  26. package/dist/server/auth/index.d.ts +15 -0
  27. package/dist/server/auth/index.js +14 -0
  28. package/dist/server/auth/login-options.d.ts +14 -0
  29. package/dist/server/auth/login-options.js +50 -0
  30. package/dist/server/auth/providers/dingtalk.d.ts +16 -0
  31. package/dist/server/auth/providers/dingtalk.js +177 -0
  32. package/dist/server/auth/providers/feishu.d.ts +15 -0
  33. package/dist/server/auth/providers/feishu.js +100 -0
  34. package/dist/server/auth/providers/index.d.ts +13 -0
  35. package/dist/server/auth/providers/index.js +24 -0
  36. package/dist/server/auth/session.d.ts +48 -0
  37. package/dist/server/auth/session.js +108 -0
  38. package/dist/server/auth/types.d.ts +118 -0
  39. package/dist/server/auth/types.js +7 -0
  40. package/dist/server/browser-agent-mcp.d.ts +67 -0
  41. package/dist/server/browser-agent-mcp.js +608 -0
  42. package/dist/server/cli.d.ts +6 -0
  43. package/dist/server/cli.js +112 -0
  44. package/dist/server/debug-log.d.ts +25 -0
  45. package/dist/server/debug-log.js +86 -0
  46. package/dist/server/handlers.d.ts +141 -0
  47. package/dist/server/handlers.js +523 -0
  48. package/dist/server/index.d.ts +30 -0
  49. package/dist/server/index.js +28 -0
  50. package/dist/server/kit-api.d.ts +23 -0
  51. package/dist/server/kit-api.js +153 -0
  52. package/dist/server/model-sources.d.ts +32 -0
  53. package/dist/server/model-sources.js +58 -0
  54. package/dist/server/oa.d.ts +87 -0
  55. package/dist/server/oa.js +397 -0
  56. package/dist/server/providers/openrouter.d.ts +51 -0
  57. package/dist/server/providers/openrouter.js +283 -0
  58. package/dist/server/render-markdown.d.ts +2 -0
  59. package/dist/server/render-markdown.js +50 -0
  60. package/dist/server/sdk.d.ts +269 -0
  61. package/dist/server/sdk.js +2025 -0
  62. package/dist/server/session-access.d.ts +5 -0
  63. package/dist/server/session-access.js +68 -0
  64. package/dist/server/session-fork.d.ts +10 -0
  65. package/dist/server/session-fork.js +142 -0
  66. package/dist/server/session-store.d.ts +56 -0
  67. package/dist/server/session-store.js +148 -0
  68. package/dist/server/sessions.d.ts +24 -0
  69. package/dist/server/sessions.js +541 -0
  70. package/dist/server/share.d.ts +15 -0
  71. package/dist/server/share.js +433 -0
  72. package/dist/server/tool-activity.d.ts +2 -0
  73. package/dist/server/tool-activity.js +26 -0
  74. package/dist/server/transcription/xiaomi-mimo.d.ts +8 -0
  75. package/dist/server/transcription/xiaomi-mimo.js +86 -0
  76. package/dist/server/upload.d.ts +13 -0
  77. package/dist/server/upload.js +81 -0
  78. package/dist/server/user-files.d.ts +28 -0
  79. package/dist/server/user-files.js +311 -0
  80. package/dist/server/voice.d.ts +25 -0
  81. package/dist/server/voice.js +61 -0
  82. package/dist/server/web-fetch.d.ts +71 -0
  83. package/dist/server/web-fetch.js +330 -0
  84. package/dist/styles.css +3354 -0
  85. package/dist/transcription/xiaomi-mimo.d.ts +8 -0
  86. package/dist/transcription/xiaomi-mimo.js +86 -0
  87. package/dist/ui/index.d.ts +358 -0
  88. package/dist/ui/index.js +7730 -0
  89. package/dist/upload.d.ts +13 -0
  90. package/dist/upload.js +81 -0
  91. package/dist/voice.d.ts +25 -0
  92. package/dist/voice.js +61 -0
  93. package/package.json +74 -4
package/README.md CHANGED
@@ -1,3 +1,593 @@
1
- # Temporary Holding Version
1
+ # agent-kit(Agent 前后端一体 SDK)
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 基于 CodeBuddy 订阅(`@tencent-ai/agent-sdk`)+ hy3 模型、面向 Next.js(App Router)的一体化 Agent 聊天套件。**目标:第三方应用开箱即用**——宿主工程只需「配环境变量 → 挂 12 个薄路由文件 → 一行装配前端」,全部公共能力(对话 / 产物 / 上传 / 语音 / OAuth 登录 / 会话持久化 / workbuddy 风格三栏 UI)都在 kit 内。
4
+
5
+ > 本文档写给**应用开发者的 AI**(如 Codex)。所有步骤都是可直接复制执行的样板,请按顺序完成并用末尾「验证清单」自检。
6
+
7
+ ---
8
+
9
+ ## 1. 能力清单
10
+
11
+ | 能力 | 说明 |
12
+ |---|---|
13
+ | 订阅式对话 | SSE 流式输出,多轮上下文自动续接(前端按页面生成稳定 sessionId) |
14
+ | 多模态 | 最后一条 user 消息带 `imageUrls[]` 即传图给模型 |
15
+ | 工具调用 | 默认 `[Read, Bash, Write]` 白名单,可配置 |
16
+ | 产物收集/预览 | 会话内 html / markdown / image / pdf 产物,右侧面板 + 内嵌预览 + 下载 |
17
+ | 上传 | 图片/文件上传(落盘 public/uploads + attachments 双份,删会话自动清理) |
18
+ | 语音输入 | 录音 → `/api/voice/token` + `/api/voice/transcribe`(小米 MiMo ASR,可换) |
19
+ | 组织登录 | 钉钉 / 飞书 OAuth + 客户端 JSAPI 免登 + dev 免登 + 游客模式 |
20
+ | 会话持久化 | PostgreSQL:users / agent_sessions / agent_messages,**自动幂等迁移** |
21
+ | 聊天 UI | workbuddy 风格三栏(会话列表 / 聊天 / 文件面板),全部参数化 |
22
+ | 一站式装配 | `<AgentApp basePath="/agent" />`:登录态 → 聊天 or 登录页自动分流 |
23
+
24
+ ## 2. 集成架构(宿主只做薄胶水)
25
+
26
+ ```
27
+ 你的 Next.js 应用
28
+ ├── 环境变量(复制 kit 的 .env.example)
29
+ ├── app/layout.js # 引 agent-kit/styles.css(1 行)
30
+ ├── app/page.js # <AgentApp basePath="/agent" />(约 5 行)
31
+ ├── app/login/page.js # <LoginPage basePath="/agent" />(server 组件,约 10 行)
32
+ └── app/api/**/route.js # 12 个薄路由文件(每个 3~10 行,全部转发 agent-kit 工厂)
33
+ ```
34
+
35
+ kit 侧提供(无需改动):
36
+ - 服务端工厂:`createAgentApiRoute`(chat/upload/voice/artifact)、`createLoginHandlers`、`createSessionHandlers`、`runSdkQuery`/`createAgentStream`
37
+ - 前端组件:`AgentApp` / `AgentChat` / `LoginPage` / `DingTalkAutoLogin` / `useAgentAuth`
38
+ - 样式:`agent-kit/styles.css`(单文件,含全部聊天/登录样式)
39
+
40
+ ---
41
+
42
+ ## Step 0 — 前置条件
43
+
44
+ - Node.js ≥ 18,目标工程为 **Next.js App Router**(`next.config.mjs` 需支持 `basePath`)
45
+ - 一次性完成 CodeBuddy 登录(浏览器登录,凭据存 `~/.codebuddy`,SDK 持久化、之后自动复用,无需 API Key)。
46
+ **login/logout 是宿主应用侧职责**,agent-kit 不内置认证命令;参考实现见 `apps/web`:
47
+ ```bash
48
+ # 在 apps/web 目录下
49
+ npm run login # 自动打开浏览器完成 CodeBuddy 登录(scripts/codebuddy-auth.mjs)
50
+ npm run logout # 登出(切外部 API 通道前执行,清订阅凭据)
51
+ ```
52
+ 宿主应用只需按同样方式实现(直接调用 `@tencent-ai/agent-sdk` 的
53
+ `unstable_v2_authenticate` / `unstable_v2_logout`),无需持有 kit 源码。
54
+ - 国内网络默认 `CODEBUDDY_INTERNET_ENVIRONMENT=internal`(**SDK 已内置默认值,可不配**;国际版留空即可)
55
+ - (推荐,否则无会话持久化)PostgreSQL 8+,账号可建库
56
+
57
+ ## Step 0.5 — LLM 通道选择(订阅 vs 外部 OpenAI 兼容 API)
58
+
59
+ `AGENT_PROVIDER` 决定对话走哪条通道,`codebuddy` 为默认(CodeBuddy 订阅,需先 `login`):
60
+
61
+ | 值 | 通道 | 说明 |
62
+ |---|---|---|
63
+ | `codebuddy`(默认) | CodeBuddy 订阅 | 用 `AGENT_MODEL` 指定模型,需先在宿主应用完成登录(如 web `npm run login`) |
64
+ | `openrouter` | OpenAI 兼容外部 API | 走 `OPENAI_*` 三件套,**不消耗订阅**;登录状态不影响该通道 |
65
+
66
+ 外部 API 通道(任意满足 OpenAI `chat/completions` 格式的厂商:OpenRouter / DeepSeek / 通义等)最小配置:
67
+
68
+ ```env
69
+ AGENT_PROVIDER=openrouter
70
+ OPENAI_API_KEY=sk-xxxx # 厂商控制台创建(OpenRouter / DeepSeek 等)
71
+ OPENAI_BASE_URL=https://openrouter.ai/api/v1 # 或 https://api.deepseek.com
72
+ OPENAI_MODEL=google/gemma-4-31b-it:free # 或 deepseek-flash 等
73
+ ```
74
+
75
+ 切换外部通道前建议先在宿主应用 `npm run logout`(清掉订阅凭据,避免干扰)。注意:该通道当前为纯对话(v1),**不含 CodeBuddy 的 WebSearch 等 agent 工具**;工具循环在应用层自建(见后续版本)。
76
+
77
+ ## Step 1 — 安装
78
+
79
+ 同一 monorepo 内(`"agent-kit": "workspace:*"` 或相对路径依赖均可):
80
+
81
+ ```bash
82
+ npm install # 根目录安装,或
83
+ npm install agent-kit --workspace=your-app # 给指定应用装
84
+ ```
85
+
86
+ peerDependencies:`react >= 18`、`react-dom >= 18`(宿主已有则无需重复安装)。
87
+
88
+ ## Step 2 — 环境变量
89
+
90
+ 把本组件自带的契约样例 `packages/agent-kit/.env.example` 复制为宿主(应用)的 `.env` 并填写。**最小可用配置**:
91
+
92
+ ```env
93
+ # —— Agent 框架通道(缺省即 codebuddy,一般无需改)——
94
+ AGENT_PROVIDER=codebuddy # codebuddy(默认)| openrouter | codex;决定 agent loop/工具/WebSearch 由谁提供
95
+
96
+ # —— LLM / Agent ——
97
+ # 以下两项 SDK 已内置默认值(internal + hy3),**不配也能直接跑**;仅在有特殊需求时显式覆盖。
98
+ # CODEBUDDY_INTERNET_ENVIRONMENT=internal # 国内版默认值(国际版留空);可省略
99
+ # AGENT_MODEL=hy3 # 主模型默认值,腾讯混元 Hy3,订阅内免费;可省略
100
+ CODEBUDDY_INTERNET_ENVIRONMENT=internal
101
+ AGENT_MODEL=hy3 # 订阅内免费
102
+ # CODEBUDDY_FALLBACK_MODEL=deepseek-v4.1-flash # 主模型 429 时 CLI 自动切换的兜底(走积分计费,不可与主模型相同)
103
+ # AGENT_MODEL_LIST=hy3,deepseek-v4.1-flash,default,hunyuan-chat,hy4-preview,hy4-preview-x,hy3-x,deepseek-v4-pro,deepseek-v4-flash,deepseek-v3-2-volc,glm-5.3,glm-5.3-flash,glm-5.3-flashx,glm-5.2,glm-5.1,glm-5.0,glm-5.0-turbo,glm-5v-turbo,glm-4.7,glm-4.6,glm-4.6v,kimi-k3-2,kimi-k2.8-preview,kimi-k2.7,kimi-k2.6,kimi-k2.5,kimi-k2-thinking,minimax-m2.5,minimax-m2.7,minimax-m3-pay # 模型选择下拉:逗号分隔;配置后输入区语音按钮左侧显示下拉,
104
+ # 用户选择随每次发送生效(session 流 setModel 运行中切换);
105
+ # 留空 = 不允许用户选择模型(不显示下拉)。
106
+ # 服务端 SDK 与各宿主前端共用此变量名,无需任何前缀。
107
+
108
+ # —— 日志(可选,排查问题时建议开 debug)——
109
+ # AGENT_KIT_LOG_LEVEL=info
110
+
111
+ # —— 认证方式 ——
112
+ # 支持多值(, 或 | 分隔)。guest(游客模式)与 dev(开发免登)已移除,必须真实登录:
113
+ # feishu → 单方式:登录页直接 302 到飞书 OAuth,不出现选择器
114
+ # dingtalk|feishu → 多方式:登录页渲染黑白灰登录方式选择器
115
+ # none → 关闭登录
116
+ AUTH_PROVIDER=feishu
117
+ AUTH_COOKIE_PATH=/agent # 必须与 Next basePath 完全一致
118
+ AUTH_SESSION_SECRET=replace_with_a_long_random_secret
119
+ AUTH_SECURE_COOKIE=false # 本地 http 必须 false;生产 https 必须 true
120
+
121
+ # —— 数据库(PostgreSQL;必填,数据强制落库,无开关)——
122
+ POSTGRES_HOST=127.0.0.1
123
+ POSTGRES_PORT=5432
124
+ POSTGRES_USER=postgres
125
+ POSTGRES_DB=agent
126
+ POSTGRES_PASSWORD=your_password
127
+
128
+ # —— 语音(可选;不填则语音按钮自动禁用)——
129
+ AGENT_KIT_ASR_PROVIDER=xiaomi
130
+ AGENT_KIT_ASR_HOST=https://agent.aotsea.com
131
+ AGENT_KIT_ASR_API_KEY=
132
+
133
+ # —— 钉钉 OAuth(AUTH_PROVIDER=dingtalk 时必填)——
134
+ DD_CLIENT_ID=xxx
135
+ DD_CLIENT_SECRET=xxx
136
+ DD_CORP_ID=xxx
137
+ # 企业内部应用微应用 AgentId:分享到钉钉会话(H5 JSAPI dd.config 前端鉴权)必填,缺失报「无效的agentid」
138
+ DD_AGENT_ID=xxx
139
+
140
+ # —— 飞书 OAuth(AUTH_PROVIDER=feishu 时必填)——
141
+ # 仅支持企业内部应用(ISV 应用商店应用未实现)
142
+ # FS_APP_ID=xxx
143
+ # FS_APP_SECRET=xxx
144
+ # 可选:国际版改 https://app.feishu.com(国内默认 open.feishu.cn)
145
+ # FS_BASE_URL=https://open.feishu.cn
146
+ # 可选:OAuth 回调地址,默认自动拼接为 <origin><AUTH_COOKIE_PATH>/api/auth/callback
147
+ # web(:3100,basePath /agent):http://localhost:3100/agent/api/auth/callback
148
+ # local(:17800,cookiePath /):http://127.0.0.1:17800/api/auth/callback
149
+ # FS_REDIRECT_URI=
150
+ ```
151
+
152
+ > 提示:`APP_PUBLIC_URL` 不填时自动从请求推断(本地开发无需配置);生产部署建议显式设置外网地址。
153
+
154
+ ## Step 3 — 数据库(自动迁移,零手动步骤)
155
+
156
+ 只要配好 `POSTGRES_*`,**首次调用任何会话/登录接口时**,kit 会在进程内后台执行一次幂等建表(`IF NOT EXISTS`,可安全重复):
157
+
158
+ - `users`(OAuth 用户)
159
+ - `agent_sessions`(会话:id / title / user / model)
160
+ - `agent_messages`(消息:role / content / steps / artifacts / attachment)
161
+
162
+ 无需手动建表。想手动执行也可以 `node -e "import('agent-kit').then(m => m.migrate())"`。
163
+
164
+ ## Step 4 — 服务端路由挂载
165
+
166
+ 在宿主 `app/api/` 下创建下列 **12 个文件**(内容可直接复制;`runtime`/`dynamic` 必须保留)。路由路径会随你的 basePath 自动生效(如 basePath=`/agent` → `/agent/api/chat`)。
167
+
168
+ ### 4.1 主端点(chat / upload / voice / artifact 全包)
169
+
170
+ `app/api/[...agent]/route.js`:
171
+
172
+ ```js
173
+ import { createAgentApiRoute } from "agent-kit";
174
+
175
+ export const runtime = "nodejs";
176
+ export const dynamic = "force-dynamic";
177
+
178
+ // 单文件承载全部 agent-kit 端点:/api/chat、/api/upload、/api/voice/token、
179
+ // /api/voice/transcribe、/api/artifact(含 GET 产物渲染 / POST 产物回写)。
180
+ export const { POST, GET } = createAgentApiRoute({
181
+ chat: {
182
+ continueSession: false, // 前端自带 sessionId 续接,无需全局 continue
183
+ fallbackModel: process.env.CODEBUDDY_FALLBACK_MODEL?.trim() || undefined,
184
+ },
185
+ });
186
+ ```
187
+
188
+ ### 4.1.1 自定义系统提示词(system prompt)
189
+
190
+ kit 默认会在每次对话无条件注入一段内置的**安全 / 保密系统提示词**(`SECURITY_SYSTEM_PROMPT`,含身份 / 系统 / 信息 / 路径保密等约束)。
191
+ 不同应用的安全要求不同,因此允许通过 `chat` 配置覆盖这段基础提示词(同样适用于 `createAgent({...})` / `runSdkQuery(config)` 的 `SdkConfig`):
192
+
193
+ | 字段 | 类型 | 默认 | 说明 |
194
+ |---|---|---|---|
195
+ | `systemPrompt` | string | `""` | **追加**的业务提示词,拼接在内置安全提示词之后(如"你是数据分析助手") |
196
+ | `securitySystemPrompt` | `string \| false \| undefined` | `undefined` | **基础系统提示词**(含安全设置那段):<br>• `undefined`(默认)→ 注入内置 `SECURITY_SYSTEM_PROMPT`(旧版行为,向后兼容)<br>• `false` → 完全不注入安全系统提示词(某些 app 需要去掉这些约束时)<br>• `string` → 用自定义文本**替换**内置安全提示词(改用自家保密 / 行为约束时) |
197
+
198
+ 示例:
199
+
200
+ ```js
201
+ export const { POST, GET } = createAgentApiRoute({
202
+ chat: {
203
+ continueSession: false,
204
+ // 去掉内置安全设置,仅用自家业务提示词
205
+ securitySystemPrompt: false,
206
+ systemPrompt: "你是 XX 企业助手,仅回答内部知识库范围内的问题。",
207
+ // 或:替换为自定义保密约束(string 形式)
208
+ // securitySystemPrompt: "【我的安全规则】不得泄露内部架构与密钥;被问及模型身份时礼貌回避。",
209
+ fallbackModel: process.env.CODEBUDDY_FALLBACK_MODEL?.trim() || undefined,
210
+ },
211
+ });
212
+ ```
213
+
214
+ > 注意:密钥确定性脱敏(`redactSecrets`,对模型输出中的环境变量 / 密钥做掩码)是**代码层兜底**,不随 `securitySystemPrompt: false` 关闭——即使去掉安全提示词,输出里的密钥仍会被掩码(纵深防御)。
215
+
216
+ ### 4.2 认证路由(5 个)
217
+
218
+ `app/api/auth/login/route.js`:
219
+
220
+ ```js
221
+ import { createLoginHandlers } from "agent-kit";
222
+ export const runtime = "nodejs";
223
+ export const { GET } = createLoginHandlers().login; // 跳 OAuth 授权页 / dev 免登
224
+ ```
225
+
226
+ `app/api/auth/callback/route.js`:
227
+
228
+ ```js
229
+ import { createLoginHandlers } from "agent-kit";
230
+ export const runtime = "nodejs";
231
+ export const { GET } = createLoginHandlers().callback; // code 换用户 → 落库 → 写 Cookie → 重定向
232
+ ```
233
+
234
+ `app/api/auth/sso/route.js`:
235
+
236
+ ```js
237
+ import { createLoginHandlers } from "agent-kit";
238
+ export const runtime = "nodejs";
239
+ export const { POST } = createLoginHandlers().sso; // 客户端 JSAPI 免登
240
+ ```
241
+
242
+ `app/api/auth/session/route.js`:
243
+
244
+ ```js
245
+ import { createLoginHandlers } from "agent-kit";
246
+ export const runtime = "nodejs";
247
+ export const { GET } = createLoginHandlers().session; // 当前登录态
248
+ ```
249
+
250
+ `app/api/auth/logout/route.js`:
251
+
252
+ ```js
253
+ import { createLoginHandlers } from "agent-kit";
254
+ export const runtime = "nodejs";
255
+ export const { POST } = createLoginHandlers().logout; // 清除会话 Cookie
256
+ ```
257
+
258
+ ### 4.3 会话管理路由(6 个)
259
+
260
+ `app/api/sessions/route.js`:
261
+
262
+ ```js
263
+ import { createSessionHandlers } from "agent-kit";
264
+ export const runtime = "nodejs";
265
+ const { list, create } = createSessionHandlers();
266
+ export const GET = list; // 会话列表
267
+ export const POST = create; // 注册新会话
268
+ ```
269
+
270
+ `app/api/sessions/[id]/route.js`:
271
+
272
+ ```js
273
+ import { createSessionHandlers } from "agent-kit";
274
+ export const runtime = "nodejs";
275
+ const { rename, remove } = createSessionHandlers();
276
+ export const PATCH = rename; // 重命名
277
+ export const DELETE = remove; // 删除(含清理磁盘产物/附件)
278
+ ```
279
+
280
+ `app/api/sessions/[id]/messages/route.js`:
281
+
282
+ ```js
283
+ import { createSessionHandlers } from "agent-kit";
284
+ export const runtime = "nodejs";
285
+ const { messages, appendMessage } = createSessionHandlers();
286
+ export const GET = messages; // 历史消息
287
+ export const POST = appendMessage;
288
+ ```
289
+
290
+ `app/api/sessions/[id]/auto-title/route.js`:
291
+
292
+ ```js
293
+ import { createSessionHandlers } from "agent-kit";
294
+ export const runtime = "nodejs";
295
+ const { autoTitle } = createSessionHandlers();
296
+ export const POST = autoTitle;
297
+ ```
298
+
299
+ `app/api/sessions/[id]/close-sdk/route.js`:
300
+
301
+ ```js
302
+ import { createSessionHandlers } from "agent-kit";
303
+ export const runtime = "nodejs";
304
+ const { closeSdk } = createSessionHandlers();
305
+ export const POST = closeSdk;
306
+ ```
307
+
308
+ `app/api/sessions/[id]/truncate/route.js`:
309
+
310
+ ```js
311
+ import { createSessionHandlers } from "agent-kit";
312
+ export const runtime = "nodejs";
313
+ const { truncate } = createSessionHandlers();
314
+ export const POST = truncate;
315
+ ```
316
+
317
+ ## Step 5 — 前端装配
318
+
319
+ ### 5.1 `next.config.mjs`(basePath 与 AUTH_COOKIE_PATH 一致)
320
+
321
+ ```js
322
+ const nextConfig = {
323
+ basePath: "/agent",
324
+ // ...其余配置
325
+ };
326
+ export default nextConfig;
327
+ ```
328
+
329
+ ### 5.2 `app/layout.js`
330
+
331
+ ```jsx
332
+ // 聊天 UI 全部样式来自 agent-kit 单一来源;应用级覆盖写在自己的 globals.css
333
+ import "agent-kit/styles.css";
334
+ import "./globals.css";
335
+
336
+ export const metadata = { title: "AI 助手", description: "agent-kit 聊天" };
337
+
338
+ export default function RootLayout({ children }) {
339
+ return (
340
+ <html lang="zh-CN">
341
+ <body>{children}</body>
342
+ </html>
343
+ );
344
+ }
345
+ ```
346
+
347
+ ### 5.3 `app/page.js`(一站式装配,宿主最少代码)
348
+
349
+ ```jsx
350
+ "use client";
351
+ // 登录态 / 游客模式 / 聊天 UI / 登录页分流全部由 agent-kit 处理
352
+ import { AgentApp } from "agent-kit/ui";
353
+
354
+ export default function HomePage() {
355
+ return (
356
+ <div style={{ position: "relative", minHeight: "100vh" }}>
357
+ <AgentApp
358
+ basePath="/agent"
359
+ title="AI 助手" // 聊天顶栏标题
360
+ sidebarLogo="/agent/logo.png" // 左栏顶部 Logo(可选)
361
+ // 可继续透传 ChatWindowProps:scenes / logoSrc / uploadEnabled / voiceEnabled ...
362
+ />
363
+ </div>
364
+ );
365
+ }
366
+ ```
367
+
368
+ ### 5.4 `app/login/page.js`(登录页,AUTH_PROVIDER 驱动)
369
+
370
+ ```jsx
371
+ import { redirect } from "next/navigation";
372
+ import { getLoginOptions } from "agent-kit";
373
+ import { LoginPage } from "agent-kit/ui";
374
+
375
+ // AUTH_PROVIDER 决定登录页行为:
376
+ // - 单个真实登录方式(不含 guest)→ 服务端直接 302 到该方式 OAuth,无选择器
377
+ // - 仅 guest → 302 到 ?guest=1
378
+ // - 多个(如 feishu|guest)→ 渲染黑白灰登录方式选择器
379
+ export default function LoginPageRoute({ searchParams }) {
380
+ const params = searchParams || {};
381
+ const options = getLoginOptions();
382
+ const root = options.cookiePath; // = Next basePath,如 /agent
383
+
384
+ const rawNext = typeof params.next === "string" ? params.next : "";
385
+ const safeNext = rawNext.startsWith(root) ? rawNext : `${root}/`;
386
+ const total = options.providers.length + (options.hasGuest ? 1 : 0);
387
+
388
+ if (total === 1) {
389
+ if (options.hasGuest) redirect(`${root}/?guest=1`);
390
+ redirect(
391
+ `${root}/api/auth/login?provider=${encodeURIComponent(options.providers[0].id)}&next=${encodeURIComponent(safeNext)}`,
392
+ );
393
+ }
394
+
395
+ return (
396
+ <LoginPage
397
+ basePath={root}
398
+ title="AI 助手"
399
+ error={typeof params.error === "string" ? params.error : undefined}
400
+ next={safeNext}
401
+ providers={options.providers}
402
+ hasGuest={options.hasGuest}
403
+ />
404
+ );
405
+ }
406
+ ```
407
+
408
+ 钉钉 App 内免登:把 `<DingTalkAutoLogin basePath="/agent" clientId={process.env.DD_CLIENT_ID} corpId={process.env.DD_CORP_ID} />` 作为 `LoginPage` 的 children 传入(`LoginPage` 由服务端页面渲染,直接在服务端读取 env 传入即可,无需 NEXT_PUBLIC_ 前缀)。
409
+
410
+ ### 5.5 `LoginPage` 的 `providers` / `hasGuest`
411
+
412
+ `getLoginOptions()`(服务端)返回:
413
+
414
+ | 字段 | 说明 |
415
+ |---|---|
416
+ | `providers` | 可用的真实登录方式(`[{id, name}]`,id ∈ dingtalk/feishu/dev;OAuth 已按 env 过滤是否配置完整) |
417
+ | `hasGuest` | `AUTH_PROVIDER` 是否含 `guest` |
418
+ | `cookiePath` | 会话 Cookie 路径(= basePath),登录跳转均基于它 |
419
+
420
+ `LoginPage` 只负责渲染选择器(多方式场景);单方式由上面的 `redirect` 处理,不会走到组件。
421
+
422
+ ## Step 6 — 验证清单(AI 自检)
423
+
424
+ 按顺序执行,全部通过即集成成功:
425
+
426
+ 1. **安装/编译**:`npm run typecheck -w agent-kit` 无 TS 错误;宿主 `npm run dev` 启动无编译报错
427
+ 2. **页面可达**:`curl -I http://localhost:3100/agent` → 200;`/agent/login` → 200
428
+ 3. **游客模式**:访问 `/agent?guest=1` → 出现三栏聊天 UI(左栏会话列表、中栏输入框、右栏按钮)
429
+ 4. **发送消息**:发一条消息 → 用户消息立即置顶、模型 SSE 流式回复逐字出现;回复结束出现负责人卡片
430
+ 5. **产物链路**:让模型生成一份 html → 回复内出现产物卡片;右侧「输出产物」面板出现该文件;点击打开内嵌预览;下载按钮可下载
431
+ 6. **会话持久化**(需数据库):刷新页面 → 历史消息恢复;左侧会话列表出现新会话并带自动标题;发送第二条消息 → 标题更新
432
+ 7. **登录态**(AUTH_PROVIDER=dev):访问 `/agent` → 直接进入已登录聊天;点击用户区域 → 退出登录 → 跳 `/agent/login`
433
+ 8. **删除清理**:删除会话 → 对应产物/附件文件从磁盘移除(public/uploads、attachments)
434
+ 9. **安全隔离**:未登录直接请求 `GET /agent/api/artifact?session=<任意>&list=1` → 403;游客续接他人会话(无令牌/错令牌)→ 403;正常登录/游客对话与产物预览不受影响
435
+
436
+ ## Step 7 — 安全隔离模型(集成 AI 必读)
437
+
438
+ kit 内置**按用户隔离**的会话访问控制:任何用户只能访问**自己**会话的数据(消息 / 产物 / 常驻 CLI 会话),
439
+ 且**智能体(模型工具链)不能被绕过**。分四层实现:
440
+
441
+ ### 7.1 端点鉴权矩阵
442
+
443
+ | 端点 | 登录用户 | 游客(guest=1) | 无登录 |
444
+ |---|---|---|---|
445
+ | `POST /api/chat`(首轮 resume=false) | 会话 Cookie → DB `agent_sessions.user_id` 归属校验 | 须带 `sessionToken`(`guest-` 前缀会话,首轮自动绑定) | 403 |
446
+ | `POST /api/chat`(续接 resume=true) | 同上(DB 无此会话 → 403) | 令牌必须匹配首轮绑定值 | 403 |
447
+ | `POST /api/chat/answer` | 同上 | 同令牌 | 403 |
448
+ | `POST /api/chat/steer` | 同上 | 同令牌 | 403 |
449
+ | `GET /api/artifact?session=...&file=...` | 会话 Cookie → DB 归属 | URL 须带 `ticket`(HMAC 签名,24h 过期) | 403 |
450
+ | `GET /api/artifact?...&list=1` | 同上 | 同 ticket | 403 |
451
+
452
+ 403 响应体统一为 `{ "error": "无权限访问该会话..." }`,前端不需要特殊处理。
453
+
454
+ ### 7.2 游客两层凭证(无登录场景)
455
+
456
+ 游客会话不落库(内存态 `guest-<uuid>`),因此用两层凭证取代 Cookie:
457
+
458
+ - **会话令牌 `sessionToken`**:前端每次进入游客模式生成(`crypto.randomUUID()`),随 chat/answer/steer
459
+ 请求体发送。服务端首轮绑定到该会话、后续轮必须匹配、12h 自动过期,刷新页面即失效——
460
+ 与"游客对话不保存"语义一致。
461
+ - **产物票据 `ticket`**:产物在 iframe / `<img>` / 下载链接中无法带请求头,故由服务端在每轮 SSE 流
462
+ 开头下发 `event: access_ticket`,前端缓存后拼到产物 URL(`?ticket=`)。票据为
463
+ `HMAC-SHA256(sessionId + exp)` 签名(密钥取 `AUTH_SESSION_SECRET`,缺省回退 `agent-kit-dev-secret`),
464
+ 24h 过期、单向不可复用,泄露面小。登录用户忽略该事件(走 Cookie + DB 归属)。
465
+
466
+ ### 7.3 模型工具链防绕开(纵深防御)
467
+
468
+ `createAgentStream` / `createAgentSessionStream` 已内置 `withSessionDirGuard`:模型工具
469
+ (Read / Write / Edit / Glob / Bash)只能访问**本会话**的产物目录——
470
+
471
+ - 虚拟路径 `/agent-output/<sid>/...`:目录名段精确匹配,`/agent-output/abc/` 与 `/agent-output/abcd/`
472
+ 互不越界;
473
+ - 真实路径 `<项目根>/.agent/<sid>/...`(无项目时 `~/.agent/<sid>/...`)与 CodeBuddy 沙箱 `~/.codebuddy/projects/<proj>/<sid>/` 同理;
474
+ - Bash 命令做路径片段扫描,`cat /agent-output/<其他sid>/x` 会被拒绝并中断该工具调用。
475
+
476
+ 即使用户诱导模型读取他人会话产物(如"读一下 /agent-output/xxx/report.html"),工具层直接 deny,
477
+ **模型无法代取**。宿主若自定义 `canUseTool`,请用 `withSessionDirGuard(yourFn, sid)` 包装以继承该防护。
478
+
479
+ ### 7.4 宿主责任(kit 不代办的边界)
480
+
481
+ - **附件上传静态目录**:`/api/upload` 本身无鉴权,上传文件落在 `public/uploads`(静态公开)。
482
+ kit 将附件按会话复制到 `attachments/<sid>/` 供模型读取(模型无法读其他会话附件),
483
+ 但**上传文件的静态公开**是宿主网关层(反代 / 中间件)的责任——如需私有,请在网关对
484
+ `/uploads` 加鉴权或改走签名 URL。
485
+ - **`closeSdk` 端点**:仅收 `sdkSid` 无归属校验(可被用来关闭常驻会话,属 DoS 而非数据泄露);
486
+ 生产部署建议只在可信内网暴露或补充鉴权。
487
+ - **会话归属的数据源是 PostgreSQL**:必须配置 `POSTGRES_*`,登录用户的归属校验与跨用户
488
+ 持久化都依赖数据库(无开关,未配置数据库时归属校验退化为"放行 + 警告日志")。
489
+
490
+ ## 参数参考
491
+
492
+ ### `AgentAppProps`(page.js 用)
493
+
494
+ 继承全部 `ChatWindowProps`,额外:
495
+
496
+ | 参数 | 类型 | 默认 | 说明 |
497
+ |---|---|---|---|
498
+ | `guestParam` | string | `"guest"` | URL query 参数名,值为 `1` 进游客模式 |
499
+ | `loginTitle` | string | `title` | 登录页标题 |
500
+ | `loginTagline` | string | `"组织身份认证后使用"` | 登录页副标题 |
501
+ | `loginLogoUrl` | string | — | 登录页 Logo |
502
+ | `loadingFallback` | ReactNode | `"加载中…"` | 登录态探测期间的占位 |
503
+
504
+ ### `ChatWindowProps`(高级用法:直接用 `AgentChat`)
505
+
506
+ | 参数 | 类型 | 默认 | 说明 |
507
+ |---|---|---|---|
508
+ | `basePath` | string | `"/"` | API 根路径(chat/upload/artifact/sessions 都基于它) |
509
+ | `title` | string | `"AI 助手"` | 顶栏标题 |
510
+ | `initialUser` | `{name, avatar?, unionId?}` | — | 登录用户(退出按钮数据源) |
511
+ | `guest` | boolean | `false` | 游客模式:不持久化、无会话列表 |
512
+ | `onLogout` | () => void | — | 退出回调(不传时 AgentApp 默认跳登录页) |
513
+ | `logoSrc` | string | — | 顶栏 Logo URL |
514
+ | `sidebarLogo` | string | — | 左栏顶部 Logo URL(不传显示"会话") |
515
+ | `scenes` | Scene[] | 内置 | 场景 tab(传 `null` 隐藏) |
516
+ | `uploadEnabled` | boolean | `true` | 是否启用附件上传 |
517
+ | `voiceEnabled` | boolean | `true` | 是否启用语音输入 |
518
+ | `chatEndpoint` / `uploadEndpoint` | string | 由 basePath 推导 | 端点覆盖 |
519
+ | `renderSessionFooter` | `(context: { sessionId, messages }) => ReactNode` | — | 在有助手消息的会话底部渲染一次宿主内容,可按会话决定是否显示 |
520
+
521
+ 例如,宿主可以在热线会话底部放置人工联系卡片:
522
+
523
+ ```jsx
524
+ <AgentApp
525
+ basePath="/agent"
526
+ renderSessionFooter={({ sessionId }) => (
527
+ <div className="hotline-contact-card" data-session-id={sessionId}>
528
+ <strong>需要人工帮助?</strong>
529
+ <a href="tel:12345">联系热线 12345</a>
530
+ </div>
531
+ )}
532
+ />
533
+ ```
534
+
535
+ ### 公共导出清单
536
+
537
+ ```
538
+ agent-kit → createAgentApiRoute / createLoginHandlers / createSessionHandlers /
539
+ createAgentStream / runSdkQuery / Agent / createUploadHandler /
540
+ createArtifactHandler / WebFetch / migrate / isAuthEnabled ...
541
+ agent-kit/ui → AgentApp / AgentChat(ChatWindow) / LoginPage / DingTalkAutoLogin /
542
+ useAgentAuth / Markdown / FeedbackButtons / 全部 TS 类型
543
+ agent-kit/styles.css → 全部样式(聊天 + 登录),单文件引入
544
+ ```
545
+
546
+ ## 目录结构
547
+
548
+ ```
549
+ packages/agent-kit/
550
+ ├── README.md
551
+ ├── package.json # exports: "."(server) / "./ui" / "./styles.css"
552
+ ├── tsconfig.json # 服务端
553
+ ├── tsconfig.ui.json # UI(DOM lib + react-jsx)
554
+ └── src/
555
+ ├── server/
556
+ │ ├── index.ts # 主入口(工厂 + SDK 导出)
557
+ │ ├── sdk.ts # runSdkQuery / createAgentStream / createAgentSessionStream
558
+ │ ├── agent.ts # Agent 工厂(多工具轮 / steer / resume)
559
+ │ ├── handlers.ts # createAgentApiRoute(chat/upload/voice/artifact)
560
+ │ ├── artifacts.ts # 产物类型推断 / 渲染 / 列表 / 下载
561
+ │ ├── upload.ts # 上传落盘(public/uploads + attachments)
562
+ │ ├── voice.ts # 语音令牌
563
+ │ ├── transcription/ # ASR 提供方(xiaomi-mimo)
564
+ │ ├── sessions.ts # createSessionHandlers(列表/改名/删除/消息/标题)
565
+ │ ├── session-store.ts
566
+ │ ├── web-fetch.ts # WebFetch MCP 工具
567
+ │ ├── cli.ts # 订阅对话演示/冒烟(demo / 交互);登录命令见宿主应用
568
+ │ └── auth/
569
+ │ ├── schema.sql # 幂等建表(自动迁移)
570
+ │ ├── db.ts # 连接池 / migrate / 会话与消息 CRUD
571
+ │ ├── handlers.ts # createLoginHandlers(login/callback/sso/session/logout)
572
+ │ ├── session.ts # Cookie / 会话令牌
573
+ │ ├── config.ts # env 解析(AUTH_PROVIDER 等)
574
+ │ └── providers/ # dingtalk / feishu 抽象
575
+ └── ui/
576
+ ├── index.ts # /ui 入口
577
+ ├── AgentApp.tsx # 一站式装配(认证分流)
578
+ ├── useAgentAuth.ts # 登录态 hook
579
+ ├── LoginPage.tsx # 登录页(server-safe)
580
+ ├── DingTalkAutoLogin.tsx
581
+ ├── ChatWindow.tsx # 主聊天组件(全部 UI 逻辑)
582
+ ├── Markdown.tsx / FeedbackButtons.tsx
583
+ └── styles.css
584
+ ```
585
+
586
+ ## FAQ
587
+
588
+ - **登录页报"认证应用配置不完整"**:检查 `AUTH_PROVIDER` 与对应提供方 env(DD_* / FS_*)是否齐全。
589
+ - **模型 429**:配置 `CODEBUDDY_FALLBACK_MODEL`(不可与主模型相同),CLI 自动切换。
590
+ - **历史消息为空**:确认 `POSTGRES_*` 可达(自动迁移只在首次连接时跑一次,若此前连失败需重启进程)。
591
+ - **语音按钮不可用**:`AGENT_KIT_ASR_HOST/API_KEY` 未配置(预期行为)。
592
+ - **产物/附件磁盘**:产物目录为隐藏的 `.agent`(选了项目在项目根 `.agent/`,无项目在 `~/.agent/`);附件在 `public/uploads/`、`attachments/`;删除会话时按消息记录清理。
593
+ - **改完代码**:kit 是 TS 源码直引(main 指向 src),宿主 dev server 热更新即可,无需 build。
@@ -0,0 +1,27 @@
1
+ /**
2
+ * agent-kit · Agent 工厂与高级会话封装
3
+ *
4
+ * createAgent(config) 返回一个带状态(多轮历史由 SDK 会话延续)的 Agent 实例,
5
+ * 供服务端应用直接使用:
6
+ *
7
+ * const agent = createAgent({ systemPrompt: "你是数据分析助手" });
8
+ * const reply = await agent.chat("分析 ./data 下的数据");
9
+ */
10
+ import { type SdkConfig } from "./sdk.js";
11
+ export interface AgentConfig extends SdkConfig {
12
+ /** 会话级追加提示词(同 SdkConfig.systemPrompt) */
13
+ systemPrompt?: string;
14
+ }
15
+ export declare class Agent {
16
+ private config;
17
+ constructor(config?: AgentConfig);
18
+ /**
19
+ * 发起一轮订阅对话并返回模型最终文本。
20
+ * 多轮上下文由 SDK 会话(continue:true)自动延续。
21
+ */
22
+ chat(message: string): Promise<string>;
23
+ /** 当前配置(只读) */
24
+ getConfig(): AgentConfig;
25
+ }
26
+ /** 创建 Agent 实例 */
27
+ export declare function createAgent(config?: AgentConfig): Agent;
package/dist/agent.js ADDED
@@ -0,0 +1,31 @@
1
+ /**
2
+ * agent-kit · Agent 工厂与高级会话封装
3
+ *
4
+ * createAgent(config) 返回一个带状态(多轮历史由 SDK 会话延续)的 Agent 实例,
5
+ * 供服务端应用直接使用:
6
+ *
7
+ * const agent = createAgent({ systemPrompt: "你是数据分析助手" });
8
+ * const reply = await agent.chat("分析 ./data 下的数据");
9
+ */
10
+ import { runSdkQuery } from "./sdk.js";
11
+ export class Agent {
12
+ config;
13
+ constructor(config = {}) {
14
+ this.config = config;
15
+ }
16
+ /**
17
+ * 发起一轮订阅对话并返回模型最终文本。
18
+ * 多轮上下文由 SDK 会话(continue:true)自动延续。
19
+ */
20
+ async chat(message) {
21
+ return runSdkQuery(message, this.config);
22
+ }
23
+ /** 当前配置(只读) */
24
+ getConfig() {
25
+ return { ...this.config };
26
+ }
27
+ }
28
+ /** 创建 Agent 实例 */
29
+ export function createAgent(config = {}) {
30
+ return new Agent(config);
31
+ }
package/dist/cli.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * agent-kit · CLI 演示入口(订阅对话冒烟)
3
+ * 认证只走订阅方式:npm run login 完成 CodeBuddy 登录后,SDK 自动复用凭据。
4
+ */
5
+ export {};