Skip to content

Commit 7e2b16e

Browse files
committed
✨ 支持 Agent 会话后台运行模式
UI 断开后会话继续执行,重新连接后通过 sync 快照恢复进度。 - 新增 RunningConversation 注册表与 broadcastEvent/updateStreamingState 机制 - handleConversationChat 支持 background 参数,断开只移除 listener 不 abort - 新增 attachToConversation 处理器,重连时发送 sync 快照 - UI hooks 新增 attachToConversation、useRunningConversations - ChatArea 自动 attach 运行中会话,ChatInput 增加后台模式开关 - 会话列表显示运行中指示器 - Script API (cat_agent) 支持 background 参数和 attach() 方法 - 26 个单元测试覆盖核心逻辑
1 parent f9f0c14 commit 7e2b16e

10 files changed

Lines changed: 1228 additions & 48 deletions

File tree

src/app/service/agent/types.ts

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,15 @@ export type ChatStreamEvent =
9393
| { type: "content_block_complete"; block: ImageBlock | FileBlock | AudioBlock; data?: string }
9494
| { type: "ask_user"; id: string; question: string; options?: string[]; multiple?: boolean }
9595
| { type: "sub_agent_event"; agentId: string; description: string; event: ChatStreamEvent }
96+
| {
97+
type: "task_update";
98+
tasks: Array<{
99+
id: string;
100+
subject: string;
101+
status: "pending" | "in_progress" | "completed";
102+
description?: string;
103+
}>;
104+
}
96105
| { type: "new_message" }
97106
| {
98107
type: "done";
@@ -105,7 +114,19 @@ export type ChatStreamEvent =
105114
durationMs?: number;
106115
}
107116
| { type: "error"; message: string; errorCode?: string }
108-
| { type: "compact_done"; summary: string; originalCount: number };
117+
| { type: "compact_done"; summary: string; originalCount: number }
118+
| {
119+
type: "sync";
120+
streamingMessage?: { content: string; thinking?: string; toolCalls: ToolCall[] };
121+
pendingAskUser?: { id: string; question: string; options?: string[]; multiple?: boolean };
122+
tasks: Array<{
123+
id: string;
124+
subject: string;
125+
status: "pending" | "in_progress" | "completed";
126+
description?: string;
127+
}>;
128+
status: "running" | "done" | "error";
129+
};
109130

110131
// UI -> Service Worker 的聊天请求
111132
export type ChatRequest = {
@@ -164,6 +185,7 @@ export type ConversationCreateOptions = {
164185
commands?: Record<string, CommandHandler>; // 自定义命令处理器,以 / 开头
165186
ephemeral?: boolean; // 临时会话:不持久化、不加载内置资源、工具由脚本提供
166187
cache?: boolean; // 是否启用 prompt caching,默认 true
188+
background?: boolean; // 后台运行:UI 断开后继续执行,默认 false
167189
};
168190

169191
// conv.chat() 的参数
@@ -176,7 +198,12 @@ export type ChatReply = {
176198
content: MessageContent;
177199
thinking?: string;
178200
toolCalls?: ToolCall[];
179-
usage?: { inputTokens: number; outputTokens: number; cacheCreationInputTokens?: number; cacheReadInputTokens?: number };
201+
usage?: {
202+
inputTokens: number;
203+
outputTokens: number;
204+
cacheCreationInputTokens?: number;
205+
cacheReadInputTokens?: number;
206+
};
180207
command?: boolean; // 标识该回复来自命令处理
181208
};
182209

@@ -186,7 +213,12 @@ export type StreamChunk = {
186213
content?: string;
187214
block?: ContentBlock;
188215
toolCall?: ToolCall;
189-
usage?: { inputTokens: number; outputTokens: number; cacheCreationInputTokens?: number; cacheReadInputTokens?: number };
216+
usage?: {
217+
inputTokens: number;
218+
outputTokens: number;
219+
cacheCreationInputTokens?: number;
220+
cacheReadInputTokens?: number;
221+
};
190222
error?: string;
191223
/** 错误分类码:"rate_limit" | "auth" | "tool_timeout" | "max_iterations" | "api_error" */
192224
errorCode?: string;
@@ -252,8 +284,8 @@ export type SkillApiRequest =
252284
// CAT.agent.opfs API 请求
253285
export type OPFSApiRequest =
254286
| { action: "write"; path: string; content: string | Blob; scriptUuid: string }
255-
| { action: "read"; path: string; format?: "text" | "bloburl"; scriptUuid: string }
256-
| { action: "readAttachment"; id: string; format?: "bloburl" | "dataurl"; scriptUuid: string }
287+
| { action: "read"; path: string; format?: "text" | "bloburl" | "blob"; scriptUuid: string }
288+
| { action: "readAttachment"; id: string; scriptUuid: string }
257289
| { action: "list"; path?: string; scriptUuid: string }
258290
| { action: "delete"; path: string; scriptUuid: string };
259291

src/app/service/content/gm_api/cat_agent.ts

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ export class ConversationInstance {
3535
toolCalls?: ToolCall[];
3636
}> = [];
3737

38+
private background: boolean;
39+
3840
constructor(
3941
private conv: Conversation,
4042
private gmSendMessage: (api: string, params: any[]) => Promise<any>,
@@ -45,9 +47,11 @@ export class ConversationInstance {
4547
commands?: Record<string, CommandHandler>,
4648
ephemeral?: boolean,
4749
system?: string,
48-
cache?: boolean
50+
cache?: boolean,
51+
background?: boolean
4952
) {
5053
this.ephemeral = ephemeral || false;
54+
this.background = background || false;
5155
this.cache = cache;
5256
this.systemPrompt = system;
5357
if (initialTools) {
@@ -109,6 +113,9 @@ export class ConversationInstance {
109113
if (this.cache !== undefined) {
110114
connectParams.cache = this.cache;
111115
}
116+
if (this.background) {
117+
connectParams.background = true;
118+
}
112119
if (this.ephemeral) {
113120
connectParams.ephemeral = true;
114121
connectParams.messages = this.messageHistory;
@@ -179,6 +186,9 @@ export class ConversationInstance {
179186
if (this.cache !== undefined) {
180187
connectParams.cache = this.cache;
181188
}
189+
if (this.background) {
190+
connectParams.background = true;
191+
}
182192
if (this.ephemeral) {
183193
connectParams.ephemeral = true;
184194
connectParams.messages = this.messageHistory;
@@ -286,6 +296,14 @@ export class ConversationInstance {
286296
]);
287297
}
288298

299+
// 附加到后台运行中的会话,返回流式事件
300+
async attach(): Promise<AsyncIterable<StreamChunk>> {
301+
const conn = await this.gmConnect("CAT_agentAttachToConversation", [
302+
{ conversationId: this.conv.id, scriptUuid: this.scriptUuid },
303+
]);
304+
return this.processStream(conn, new Map());
305+
}
306+
289307
// 处理非流式 chat 的响应
290308
private processChat(
291309
conn: MessageConnect,
@@ -543,7 +561,8 @@ function buildInstance(
543561
options?.commands,
544562
options?.ephemeral,
545563
options?.system,
546-
options?.cache
564+
options?.cache,
565+
options?.background
547566
);
548567
}
549568

0 commit comments

Comments
 (0)