aws-runtime-bridge 1.9.40 → 1.9.41
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.
- package/dist/adapter/AcodeSdkAdapter.d.ts +31 -4
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +382 -57
- package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/ClaudeSdkAdapter.js +1 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts +19 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +62 -0
- package/dist/adapter/types.d.ts +21 -6
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +10 -1
- package/dist/index.js +11 -0
- package/dist/routes/ai-sources.js +4 -1
- package/dist/routes/dashboard.d.ts.map +1 -1
- package/dist/routes/dashboard.js +1 -1
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +6 -3
- package/dist/routes/sessions.js +89 -4
- package/dist/routes/sub-agents.js +15 -1
- package/dist/routes/terminal.d.ts +3 -0
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +122 -5
- package/dist/services/acode-package.d.ts +8 -1
- package/dist/services/acode-package.d.ts.map +1 -1
- package/dist/services/acode-package.js +33 -4
- package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
- package/dist/services/aws-client-agent-mcp.js +11 -4
- package/dist/services/fileSnapshotStore.js +1 -1
- package/dist/services/legacy-path-migration.d.ts +3 -0
- package/dist/services/legacy-path-migration.d.ts.map +1 -0
- package/dist/services/legacy-path-migration.js +66 -0
- package/dist/services/lifecycle-state.d.ts.map +1 -1
- package/dist/services/lifecycle-state.js +1 -1
- package/dist/services/runtime-binding.d.ts +5 -0
- package/dist/services/runtime-binding.d.ts.map +1 -1
- package/dist/services/runtime-binding.js +33 -1
- package/dist/services/session-output.d.ts +7 -1
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +16 -2
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.js +504 -3
- package/package/acode/dist/compaction.d.ts +43 -7
- package/package/acode/dist/compaction.d.ts.map +1 -1
- package/package/acode/dist/compaction.js +286 -31
- package/package/acode/dist/runtime.d.ts +120 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +921 -71
- package/package/acode/dist/sub-agent-manager.d.ts +96 -1
- package/package/acode/dist/sub-agent-manager.d.ts.map +1 -1
- package/package/acode/dist/sub-agent-manager.js +293 -3
- package/package/acode/dist/sub-agent-store.d.ts +8 -1
- package/package/acode/dist/sub-agent-store.d.ts.map +1 -1
- package/package/acode/dist/sub-agent-store.js +55 -0
- package/package/acode/dist/sub-agent-types.d.ts +4 -0
- package/package/acode/dist/sub-agent-types.d.ts.map +1 -1
- package/package/acode/dist/types.d.ts +19 -0
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +9 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +69 -10
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.js +4 -0
- package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.js +3 -1
- package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/context-manager.d.ts +4 -1
- package/package/aws-client-agent-mcp/dist/context-manager.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/context-manager.js +6 -2
- package/package/aws-client-agent-mcp/dist/context-manager.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/context-manager.test.js +5 -0
- package/package/aws-client-agent-mcp/dist/context-manager.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +5 -0
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +15 -1
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +92 -34
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +606 -208
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +151 -51
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +7 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +18 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts +32 -9
- package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-store.js +58 -19
- package/package/aws-client-agent-mcp/dist/memory-store.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/memory-tools.js +3 -3
- package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +13 -0
- package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/message-buffer.js +23 -0
- package/package/aws-client-agent-mcp/dist/message-buffer.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +13 -0
- package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/server-memory-store.js +18 -0
- package/package/aws-client-agent-mcp/dist/server-memory-store.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +34 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +146 -18
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package.json +1 -1
|
@@ -2,6 +2,31 @@ import { ACodeRuntime } from "./runtime.js";
|
|
|
2
2
|
import type { ACodeRuntimeConfig } from "./types.js";
|
|
3
3
|
import { SubAgentStore } from "./sub-agent-store.js";
|
|
4
4
|
import type { SubAgentContextSnapshot, SubAgentEvent, SubAgentStatus, SubAgentType } from "./sub-agent-types.js";
|
|
5
|
+
/**
|
|
6
|
+
* 子 agent 终态通知(供 poll_message race 使用)。
|
|
7
|
+
* 当子 agent 到达 completed/failed/cancelled 时入队,由 takeCompletedSubAgents 消费。
|
|
8
|
+
*/
|
|
9
|
+
export interface SubAgentCompletionNotification {
|
|
10
|
+
subId: string;
|
|
11
|
+
subagentType: SubAgentType;
|
|
12
|
+
description: string;
|
|
13
|
+
status: SubAgentStatus;
|
|
14
|
+
output: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
durationMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Sub-agent 完成一轮后由外部执行的重新检查回调。
|
|
20
|
+
* - 返回 { done: true } 表示目标已达成,sub-agent 可正常结束
|
|
21
|
+
* - 返回 { done: false, continueMessage } 表示未完成,将 continueMessage 作为下一轮 submit 注入同一 sub-agent
|
|
22
|
+
*
|
|
23
|
+
* 回调内可查询服务端真实状态(如 read_memory / get_memory_stats),
|
|
24
|
+
* 而非依赖 LLM 自报结果,提供系统级硬保证。
|
|
25
|
+
*/
|
|
26
|
+
export type SubAgentRecheckFn = (output: string, turn: number) => Promise<{
|
|
27
|
+
done: boolean;
|
|
28
|
+
continueMessage?: string;
|
|
29
|
+
}>;
|
|
5
30
|
/** spawn 选项 */
|
|
6
31
|
export interface SubAgentSpawnOptions {
|
|
7
32
|
parentAgentId: string;
|
|
@@ -12,6 +37,8 @@ export interface SubAgentSpawnOptions {
|
|
|
12
37
|
workingDirectory: string;
|
|
13
38
|
/** 父 agent 的 ACodeRuntimeConfig,子 agent 继承 model/prompt 等 */
|
|
14
39
|
parentConfig: ACodeRuntimeConfig;
|
|
40
|
+
/** 静默完成:为 true 时子 agent 到达终态后不进入 completionQueue,不通过 poll_message 通知主 agent */
|
|
41
|
+
silent?: boolean;
|
|
15
42
|
}
|
|
16
43
|
/** 内存中的 sub-agent entry(含运行时实例) */
|
|
17
44
|
export interface SubAgentEntry {
|
|
@@ -30,17 +57,23 @@ export interface SubAgentEntry {
|
|
|
30
57
|
runtime: ACodeRuntime;
|
|
31
58
|
abortController: AbortController;
|
|
32
59
|
contextSnapshot: SubAgentContextSnapshot;
|
|
60
|
+
/** 该 sub-agent 创建时可用的工具列表(exposedName) */
|
|
61
|
+
availableTools: string[];
|
|
33
62
|
/** 运行完成后的 Promise resolve/reject(供 awaitCompletion 等待) */
|
|
34
63
|
completionResolve?: (result: {
|
|
35
64
|
output: string;
|
|
36
65
|
error?: string;
|
|
37
66
|
}) => void;
|
|
38
|
-
completionReject?: (err:
|
|
67
|
+
completionReject?: (err: any) => void;
|
|
39
68
|
/** 运行完成 Promise(start 时创建,终态时 settle) */
|
|
40
69
|
completionPromise?: Promise<{
|
|
41
70
|
output: string;
|
|
42
71
|
error?: string;
|
|
43
72
|
}>;
|
|
73
|
+
/** 静默完成:为 true 时不进入 completionQueue,不通过 poll_message 通知主 agent */
|
|
74
|
+
silent?: boolean;
|
|
75
|
+
/** 已通过 awaitCompletion 消费:为 true 时不进入 completionQueue,避免 poll_message 重复返回 */
|
|
76
|
+
awaited?: boolean;
|
|
44
77
|
}
|
|
45
78
|
/** SubAgentManager 构造配置 */
|
|
46
79
|
export interface SubAgentManagerOptions {
|
|
@@ -82,6 +115,16 @@ export declare class SubAgentManager {
|
|
|
82
115
|
private readonly subscribers;
|
|
83
116
|
/** 已完成 entry 的清理定时器 */
|
|
84
117
|
private cleanupTimer;
|
|
118
|
+
/**
|
|
119
|
+
* 终态通知队列:子 agent 到达终态时入队,takeCompletedSubAgents 消费。
|
|
120
|
+
* 供 poll_message 在 ACode 运行时层检测子 agent 完成事件。
|
|
121
|
+
*/
|
|
122
|
+
private readonly completionQueue;
|
|
123
|
+
/**
|
|
124
|
+
* waitForAnyCompletion 的 resolve 回调,终态事件到达时调用。
|
|
125
|
+
* null 表示当前没有等待者。
|
|
126
|
+
*/
|
|
127
|
+
private completionWaiterResolve;
|
|
85
128
|
constructor(opts: SubAgentManagerOptions);
|
|
86
129
|
/** 创建 sub-agent(不立即运行;调 start 才执行) */
|
|
87
130
|
spawn(opts: SubAgentSpawnOptions): Promise<string>;
|
|
@@ -94,6 +137,17 @@ export declare class SubAgentManager {
|
|
|
94
137
|
* 同一 sub-agent 只能 start 一次;重复 start 抛错。
|
|
95
138
|
*/
|
|
96
139
|
start(subId: string): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* 带 recheck 循环的异步启动(不阻塞,立即返回)。
|
|
142
|
+
*
|
|
143
|
+
* 与 start 的区别:每轮 submit 完成后调用 recheck 回调查询服务端真实状态。
|
|
144
|
+
* 若 recheck 返回 { done: false, continueMessage },将 continueMessage 作为
|
|
145
|
+
* 下一轮 submit 注入同一 sub-agent(保持上下文连续性),最多重试 maxRetries 次。
|
|
146
|
+
*
|
|
147
|
+
* 适用场景:memory 过期整理 / 文件变更更新 / 容量整理等需要系统级硬保证
|
|
148
|
+
* "确实完成"的场景,不依赖 LLM 自报结果。
|
|
149
|
+
*/
|
|
150
|
+
startWithRecheck(subId: string, recheck: SubAgentRecheckFn, maxRetries?: number): Promise<void>;
|
|
97
151
|
/**
|
|
98
152
|
* 阻塞等待指定 sub-agent 数组全部完成(completed/failed/cancelled)。
|
|
99
153
|
*
|
|
@@ -124,6 +178,19 @@ export declare class SubAgentManager {
|
|
|
124
178
|
* - **不删除 entry**(保留在内存供 list/get_status 查询,30min 后由定时器清理)
|
|
125
179
|
*/
|
|
126
180
|
private runEntryToCompletion;
|
|
181
|
+
/**
|
|
182
|
+
* 带 recheck 循环的 entry 执行(多轮 submit)。
|
|
183
|
+
*
|
|
184
|
+
* 与 runEntryToCompletion 的区别:
|
|
185
|
+
* 1. 第一轮 submit(entry.prompt) 完成后,调用 recheck 回调查询服务端真实状态
|
|
186
|
+
* 2. 若 recheck 返回 { done: false, continueMessage },将 continueMessage 注入下一轮 submit
|
|
187
|
+
* 3. 最多重试 maxRetries 次;超过后视为完成(不再继续)
|
|
188
|
+
* 4. onEvent 监听器跨所有轮次累积 assistant_delta,最终 output 包含全部轮次的文本
|
|
189
|
+
*
|
|
190
|
+
* turnFailed 标志在每轮 submit 前重置,确保上一轮的失败状态不影响下一轮判断。
|
|
191
|
+
* recheck 自身抛错时视为 done(不阻塞 sub-agent 结束),仅记录日志。
|
|
192
|
+
*/
|
|
193
|
+
private runEntryToCompletionWithRecheck;
|
|
127
194
|
/**
|
|
128
195
|
* @deprecated 兼容旧接口:spawn + 阻塞等待完成。
|
|
129
196
|
* 新代码应使用 spawn + start + awaitCompletion。
|
|
@@ -145,10 +212,38 @@ export declare class SubAgentManager {
|
|
|
145
212
|
* "进行中" 列表。前端 "进行中" tab 与 SSE snapshot 都应使用此方法。
|
|
146
213
|
*/
|
|
147
214
|
listActiveByParent(parentAgentId: string): SubAgentEntry[];
|
|
215
|
+
/**
|
|
216
|
+
* 取走并清空终态通知队列。
|
|
217
|
+
*
|
|
218
|
+
* 主流程:返回 completionQueue 中的所有通知并清空队列。
|
|
219
|
+
* 供 ACode 运行时在 poll_message 调用前后检查子 agent 是否已完成。
|
|
220
|
+
* 每次 poll_message 调用前先调此方法,若有已完成子 agent 则直接返回,无需等待 MCP。
|
|
221
|
+
*/
|
|
222
|
+
takeCompletedSubAgents(): SubAgentCompletionNotification[];
|
|
223
|
+
/**
|
|
224
|
+
* 等待任意子 agent 到达终态(completed/failed/cancelled)。
|
|
225
|
+
*
|
|
226
|
+
* 主流程:如果 completionQueue 中已有通知,立即 resolve;
|
|
227
|
+
* 否则注册一个 resolve 回调,在下次子 agent 终态事件到达时触发。
|
|
228
|
+
* 供 ACode 运行时在 poll_message 期间 race 子 agent 完成事件。
|
|
229
|
+
*
|
|
230
|
+
* 返回 { promise, cancel }:
|
|
231
|
+
* - promise: 子 agent 终态时 resolve
|
|
232
|
+
* - cancel: 取消等待(poll_message 先返回时调用,清理 resolve 回调)
|
|
233
|
+
*/
|
|
234
|
+
waitForAnyCompletion(): {
|
|
235
|
+
promise: Promise<SubAgentCompletionNotification>;
|
|
236
|
+
cancel: () => void;
|
|
237
|
+
};
|
|
148
238
|
/** 订阅 sub-agent 事件(subId 或 "*" 全局) */
|
|
149
239
|
subscribe(subId: string, cb: EventSubscriber): () => void;
|
|
150
240
|
/** 清理所有运行中的 sub-agent(bridge 关闭时调用) */
|
|
151
241
|
dispose(): Promise<void>;
|
|
242
|
+
/**
|
|
243
|
+
* 将子 agent 终态事件入队并通知等待者。
|
|
244
|
+
* 主流程:构建通知对象 -> 入队 completionQueue -> 若有 waitForAnyCompletion 等待者则立即 resolve。
|
|
245
|
+
*/
|
|
246
|
+
private enqueueCompletion;
|
|
152
247
|
private countByStatus;
|
|
153
248
|
private addToParentMap;
|
|
154
249
|
private removeFromParentMap;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sub-agent-manager.d.ts","sourceRoot":"","sources":["../src/sub-agent-manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EACV,uBAAuB,EACvB,aAAa,EAEb,cAAc,EACd,YAAY,EACb,MAAM,sBAAsB,CAAC;AAK9B,eAAe;AACf,MAAM,WAAW,oBAAoB;IACnC,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,YAAY,EAAE,YAAY,CAAC;IAC3B,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,MAAM,CAAC;IACzB,6DAA6D;IAC7D,YAAY,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"sub-agent-manager.d.ts","sourceRoot":"","sources":["../src/sub-agent-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,6 +34,16 @@ export class SubAgentManager {
|
|
|
34
34
|
this.subscribers = new Map(); // subId 或 "*" -> subs
|
|
35
35
|
/** 已完成 entry 的清理定时器 */
|
|
36
36
|
this.cleanupTimer = null;
|
|
37
|
+
/**
|
|
38
|
+
* 终态通知队列:子 agent 到达终态时入队,takeCompletedSubAgents 消费。
|
|
39
|
+
* 供 poll_message 在 ACode 运行时层检测子 agent 完成事件。
|
|
40
|
+
*/
|
|
41
|
+
this.completionQueue = [];
|
|
42
|
+
/**
|
|
43
|
+
* waitForAnyCompletion 的 resolve 回调,终态事件到达时调用。
|
|
44
|
+
* null 表示当前没有等待者。
|
|
45
|
+
*/
|
|
46
|
+
this.completionWaiterResolve = null;
|
|
37
47
|
this.store = opts.store;
|
|
38
48
|
this.maxConcurrent = opts.maxConcurrent ?? 5;
|
|
39
49
|
// 启动定期清理已完成 entry 的定时器(每 5 分钟扫一次)
|
|
@@ -53,6 +63,7 @@ export class SubAgentManager {
|
|
|
53
63
|
const startedAt = Date.now();
|
|
54
64
|
const abortController = new AbortController();
|
|
55
65
|
// 构造子 agent 的 config(继承父 agent 的 model/prompt,但独立 sessionId)
|
|
66
|
+
// 若父 agent 配置了 subAgentModel/subAgentEffort,则覆盖子 agent 的 model/effort
|
|
56
67
|
const childConfig = {
|
|
57
68
|
...opts.parentConfig,
|
|
58
69
|
sessionId: subId,
|
|
@@ -60,6 +71,18 @@ export class SubAgentManager {
|
|
|
60
71
|
agentId: `${opts.parentAgentId}__sub__${subId}`,
|
|
61
72
|
// sub-agent 不继承 initialPrompt(用 submit 触发)
|
|
62
73
|
initialPrompt: undefined,
|
|
74
|
+
// sub-agent 不允许再 spawn 自己的子 agent(禁止递归嵌套)
|
|
75
|
+
subAgentManager: undefined,
|
|
76
|
+
// Sub Agent 模型/强度覆盖:有值则覆盖继承的 model/effort
|
|
77
|
+
...(opts.parentConfig.subAgentModel
|
|
78
|
+
? { model: opts.parentConfig.subAgentModel }
|
|
79
|
+
: {}),
|
|
80
|
+
...(opts.parentConfig.subAgentEffort
|
|
81
|
+
? { effort: opts.parentConfig.subAgentEffort }
|
|
82
|
+
: {}),
|
|
83
|
+
// 子 agent 不再继承 subAgent 专用覆盖字段(防止孙 agent 二次覆盖)
|
|
84
|
+
subAgentModel: undefined,
|
|
85
|
+
subAgentEffort: undefined,
|
|
63
86
|
};
|
|
64
87
|
const runtime = new ACodeRuntime(childConfig);
|
|
65
88
|
const entry = {
|
|
@@ -73,11 +96,13 @@ export class SubAgentManager {
|
|
|
73
96
|
startedAt,
|
|
74
97
|
runtime,
|
|
75
98
|
abortController,
|
|
99
|
+
silent: opts.silent,
|
|
76
100
|
contextSnapshot: {
|
|
77
101
|
tokenUsage: { input: 0, output: 0 },
|
|
78
102
|
messageCount: 0,
|
|
79
103
|
updatedAt: new Date().toISOString(),
|
|
80
104
|
},
|
|
105
|
+
availableTools: [],
|
|
81
106
|
};
|
|
82
107
|
this.subAgents.set(subId, entry);
|
|
83
108
|
this.addToParentMap(opts.parentAgentId, subId);
|
|
@@ -118,6 +143,34 @@ export class SubAgentManager {
|
|
|
118
143
|
// 这里捕获防止 unhandled rejection
|
|
119
144
|
});
|
|
120
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* 带 recheck 循环的异步启动(不阻塞,立即返回)。
|
|
148
|
+
*
|
|
149
|
+
* 与 start 的区别:每轮 submit 完成后调用 recheck 回调查询服务端真实状态。
|
|
150
|
+
* 若 recheck 返回 { done: false, continueMessage },将 continueMessage 作为
|
|
151
|
+
* 下一轮 submit 注入同一 sub-agent(保持上下文连续性),最多重试 maxRetries 次。
|
|
152
|
+
*
|
|
153
|
+
* 适用场景:memory 过期整理 / 文件变更更新 / 容量整理等需要系统级硬保证
|
|
154
|
+
* "确实完成"的场景,不依赖 LLM 自报结果。
|
|
155
|
+
*/
|
|
156
|
+
async startWithRecheck(subId, recheck, maxRetries = 3) {
|
|
157
|
+
const entry = this.subAgents.get(subId);
|
|
158
|
+
if (!entry) {
|
|
159
|
+
throw new Error(`sub-agent not found: ${subId}`);
|
|
160
|
+
}
|
|
161
|
+
if (entry.status !== "pending") {
|
|
162
|
+
throw new Error(`sub-agent ${subId} cannot start from status: ${entry.status}`);
|
|
163
|
+
}
|
|
164
|
+
// 创建 completionPromise(在 finally 中 settle)
|
|
165
|
+
entry.completionPromise = new Promise((resolve, reject) => {
|
|
166
|
+
entry.completionResolve = resolve;
|
|
167
|
+
entry.completionReject = reject;
|
|
168
|
+
});
|
|
169
|
+
// 异步启动,不阻塞调用方
|
|
170
|
+
void this.runEntryToCompletionWithRecheck(entry, recheck, maxRetries).catch(() => {
|
|
171
|
+
// 内部已处理异常并更新状态;这里捕获防止 unhandled rejection
|
|
172
|
+
});
|
|
173
|
+
}
|
|
121
174
|
/**
|
|
122
175
|
* 阻塞等待指定 sub-agent 数组全部完成(completed/failed/cancelled)。
|
|
123
176
|
*
|
|
@@ -155,6 +208,9 @@ export class SubAgentManager {
|
|
|
155
208
|
}
|
|
156
209
|
return;
|
|
157
210
|
}
|
|
211
|
+
// 标记为 awaited:防止 enqueueCompletion 将终态通知推入 completionQueue
|
|
212
|
+
// (避免后续 poll_message 重复返回已被 await 消费的结果)
|
|
213
|
+
entry.awaited = true;
|
|
158
214
|
// 如果还在 pending,自动 start
|
|
159
215
|
if (entry.status === "pending") {
|
|
160
216
|
await this.start(subId);
|
|
@@ -179,6 +235,14 @@ export class SubAgentManager {
|
|
|
179
235
|
});
|
|
180
236
|
}
|
|
181
237
|
});
|
|
238
|
+
// 等待全部完成后,清理 completionQueue 中可能已存在的这些 subId 的通知
|
|
239
|
+
// (处理子 agent 在 awaited 标记设置前已完成入队的情况)
|
|
240
|
+
const subIdSet = new Set(subIds);
|
|
241
|
+
for (let i = this.completionQueue.length - 1; i >= 0; i--) {
|
|
242
|
+
if (subIdSet.has(this.completionQueue[i].subId)) {
|
|
243
|
+
this.completionQueue.splice(i, 1);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
182
246
|
if (timeoutMs > 0) {
|
|
183
247
|
await Promise.race([
|
|
184
248
|
Promise.allSettled(waitPromises),
|
|
@@ -237,6 +301,8 @@ export class SubAgentManager {
|
|
|
237
301
|
this.emitEvent(entry.subId, "running", {});
|
|
238
302
|
try {
|
|
239
303
|
await entry.runtime.start();
|
|
304
|
+
// 记录启动后的可用工具列表
|
|
305
|
+
entry.availableTools = entry.runtime.getAvailableTools();
|
|
240
306
|
await entry.runtime.submit(entry.prompt);
|
|
241
307
|
// 实际 API 中 submit 解析后所有事件已同步触发完毕(EventEmitter.emit 是同步的)
|
|
242
308
|
// 若 turn_complete 标记 failed,抛错走 catch
|
|
@@ -257,6 +323,7 @@ export class SubAgentManager {
|
|
|
257
323
|
});
|
|
258
324
|
this.emitEvent(entry.subId, "completed", { result: output });
|
|
259
325
|
entry.completionResolve?.({ output });
|
|
326
|
+
this.enqueueCompletion(entry, output, undefined);
|
|
260
327
|
}
|
|
261
328
|
catch (err) {
|
|
262
329
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -273,6 +340,139 @@ export class SubAgentManager {
|
|
|
273
340
|
});
|
|
274
341
|
this.emitEvent(entry.subId, "failed", { error: errorMessage });
|
|
275
342
|
entry.completionResolve?.({ output: "", error: errorMessage });
|
|
343
|
+
this.enqueueCompletion(entry, "", errorMessage);
|
|
344
|
+
}
|
|
345
|
+
finally {
|
|
346
|
+
// 移除临时监听器
|
|
347
|
+
try {
|
|
348
|
+
entry.runtime.removeListener?.("event", onEvent);
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
/* 忽略移除失败 */
|
|
352
|
+
}
|
|
353
|
+
// 完成后清理 runtime 实例(释放内存),但保留 entry 供查询
|
|
354
|
+
try {
|
|
355
|
+
await entry.runtime.stop();
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
/* 忽略 stop 失败 */
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* 带 recheck 循环的 entry 执行(多轮 submit)。
|
|
364
|
+
*
|
|
365
|
+
* 与 runEntryToCompletion 的区别:
|
|
366
|
+
* 1. 第一轮 submit(entry.prompt) 完成后,调用 recheck 回调查询服务端真实状态
|
|
367
|
+
* 2. 若 recheck 返回 { done: false, continueMessage },将 continueMessage 注入下一轮 submit
|
|
368
|
+
* 3. 最多重试 maxRetries 次;超过后视为完成(不再继续)
|
|
369
|
+
* 4. onEvent 监听器跨所有轮次累积 assistant_delta,最终 output 包含全部轮次的文本
|
|
370
|
+
*
|
|
371
|
+
* turnFailed 标志在每轮 submit 前重置,确保上一轮的失败状态不影响下一轮判断。
|
|
372
|
+
* recheck 自身抛错时视为 done(不阻塞 sub-agent 结束),仅记录日志。
|
|
373
|
+
*/
|
|
374
|
+
async runEntryToCompletionWithRecheck(entry, recheck, maxRetries) {
|
|
375
|
+
const chunks = [];
|
|
376
|
+
let turnFailed = false;
|
|
377
|
+
let turnErrorMessage;
|
|
378
|
+
const onEvent = (event) => {
|
|
379
|
+
if (!event)
|
|
380
|
+
return;
|
|
381
|
+
switch (event.type) {
|
|
382
|
+
case "assistant_delta":
|
|
383
|
+
if (typeof event.data?.text === "string") {
|
|
384
|
+
chunks.push(event.data.text);
|
|
385
|
+
}
|
|
386
|
+
break;
|
|
387
|
+
case "turn_complete":
|
|
388
|
+
if (event.data?.failed) {
|
|
389
|
+
turnFailed = true;
|
|
390
|
+
}
|
|
391
|
+
break;
|
|
392
|
+
case "error":
|
|
393
|
+
if (typeof event.data?.message === "string") {
|
|
394
|
+
turnErrorMessage = event.data.message;
|
|
395
|
+
}
|
|
396
|
+
break;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
entry.runtime.on("event", onEvent);
|
|
400
|
+
// 状态 -> running
|
|
401
|
+
entry.status = "running";
|
|
402
|
+
await this.store.updateStatus(entry.parentAgentId, entry.subId, { status: "running" });
|
|
403
|
+
this.emitEvent(entry.subId, "running", {});
|
|
404
|
+
try {
|
|
405
|
+
await entry.runtime.start();
|
|
406
|
+
entry.availableTools = entry.runtime.getAvailableTools();
|
|
407
|
+
// 第一轮:使用初始 prompt
|
|
408
|
+
await entry.runtime.submit(entry.prompt);
|
|
409
|
+
if (turnFailed) {
|
|
410
|
+
throw new Error(turnErrorMessage ?? "sub-agent turn failed");
|
|
411
|
+
}
|
|
412
|
+
let turn = 1;
|
|
413
|
+
// recheck 循环:最多 maxRetries 次
|
|
414
|
+
while (turn <= maxRetries) {
|
|
415
|
+
let recheckResult;
|
|
416
|
+
try {
|
|
417
|
+
recheckResult = await recheck(chunks.join(""), turn);
|
|
418
|
+
}
|
|
419
|
+
catch (recheckErr) {
|
|
420
|
+
// recheck 自身出错:不阻塞 sub-agent 结束,视为完成
|
|
421
|
+
console.error(`[SubAgentManager] recheck threw error for subId=${entry.subId} turn=${turn}, treating as done:`, recheckErr instanceof Error ? recheckErr.message : String(recheckErr));
|
|
422
|
+
break;
|
|
423
|
+
}
|
|
424
|
+
if (recheckResult.done) {
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
// 未完成:注入 continueMessage 进行下一轮
|
|
428
|
+
const continueMessage = recheckResult.continueMessage ?? "经检查,未完成处理,请继续。";
|
|
429
|
+
// 重置 turn 失败标记,确保本轮失败状态不影响下一轮判断
|
|
430
|
+
turnFailed = false;
|
|
431
|
+
turnErrorMessage = undefined;
|
|
432
|
+
console.error(`[SubAgentManager] recheck not done for subId=${entry.subId} turn=${turn}/${maxRetries}, ` +
|
|
433
|
+
`injecting continue message (${continueMessage.length} chars)`);
|
|
434
|
+
await entry.runtime.submit(continueMessage);
|
|
435
|
+
if (turnFailed) {
|
|
436
|
+
throw new Error(turnErrorMessage ?? `sub-agent turn ${turn + 1} failed during recheck continuation`);
|
|
437
|
+
}
|
|
438
|
+
turn++;
|
|
439
|
+
}
|
|
440
|
+
if (turn > maxRetries) {
|
|
441
|
+
console.error(`[SubAgentManager] recheck reached maxRetries=${maxRetries} for subId=${entry.subId}, ` +
|
|
442
|
+
`completing with potentially unfinished work`);
|
|
443
|
+
}
|
|
444
|
+
const output = chunks.join("");
|
|
445
|
+
entry.status = "completed";
|
|
446
|
+
entry.result = output;
|
|
447
|
+
entry.endedAt = Date.now();
|
|
448
|
+
entry.durationMs = entry.endedAt - entry.startedAt;
|
|
449
|
+
await this.store.updateStatus(entry.parentAgentId, entry.subId, {
|
|
450
|
+
status: "completed",
|
|
451
|
+
result: output,
|
|
452
|
+
endedAt: entry.endedAt,
|
|
453
|
+
durationMs: entry.durationMs,
|
|
454
|
+
contextSnapshot: undefined,
|
|
455
|
+
});
|
|
456
|
+
this.emitEvent(entry.subId, "completed", { result: output });
|
|
457
|
+
entry.completionResolve?.({ output });
|
|
458
|
+
this.enqueueCompletion(entry, output, undefined);
|
|
459
|
+
}
|
|
460
|
+
catch (err) {
|
|
461
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
462
|
+
entry.status = "failed";
|
|
463
|
+
entry.errorMessage = errorMessage;
|
|
464
|
+
entry.endedAt = Date.now();
|
|
465
|
+
entry.durationMs = entry.endedAt - entry.startedAt;
|
|
466
|
+
await this.store.updateStatus(entry.parentAgentId, entry.subId, {
|
|
467
|
+
status: "failed",
|
|
468
|
+
errorMessage,
|
|
469
|
+
endedAt: entry.endedAt,
|
|
470
|
+
durationMs: entry.durationMs,
|
|
471
|
+
contextSnapshot: undefined,
|
|
472
|
+
});
|
|
473
|
+
this.emitEvent(entry.subId, "failed", { error: errorMessage });
|
|
474
|
+
entry.completionResolve?.({ output: "", error: errorMessage });
|
|
475
|
+
this.enqueueCompletion(entry, "", errorMessage);
|
|
276
476
|
}
|
|
277
477
|
finally {
|
|
278
478
|
// 移除临时监听器
|
|
@@ -337,6 +537,7 @@ export class SubAgentManager {
|
|
|
337
537
|
this.emitEvent(subId, "cancelled", {});
|
|
338
538
|
// settle completionPromise(cancelled 视为 error)
|
|
339
539
|
entry.completionResolve?.({ output: "", error: "aborted" });
|
|
540
|
+
this.enqueueCompletion(entry, "", "aborted");
|
|
340
541
|
}
|
|
341
542
|
/** 获取内存中的 entry */
|
|
342
543
|
getSubAgent(subId) {
|
|
@@ -360,6 +561,52 @@ export class SubAgentManager {
|
|
|
360
561
|
listActiveByParent(parentAgentId) {
|
|
361
562
|
return this.listByParent(parentAgentId).filter((e) => e.status === "pending" || e.status === "running");
|
|
362
563
|
}
|
|
564
|
+
/**
|
|
565
|
+
* 取走并清空终态通知队列。
|
|
566
|
+
*
|
|
567
|
+
* 主流程:返回 completionQueue 中的所有通知并清空队列。
|
|
568
|
+
* 供 ACode 运行时在 poll_message 调用前后检查子 agent 是否已完成。
|
|
569
|
+
* 每次 poll_message 调用前先调此方法,若有已完成子 agent 则直接返回,无需等待 MCP。
|
|
570
|
+
*/
|
|
571
|
+
takeCompletedSubAgents() {
|
|
572
|
+
if (this.completionQueue.length === 0)
|
|
573
|
+
return [];
|
|
574
|
+
const drained = this.completionQueue.splice(0);
|
|
575
|
+
return drained;
|
|
576
|
+
}
|
|
577
|
+
/**
|
|
578
|
+
* 等待任意子 agent 到达终态(completed/failed/cancelled)。
|
|
579
|
+
*
|
|
580
|
+
* 主流程:如果 completionQueue 中已有通知,立即 resolve;
|
|
581
|
+
* 否则注册一个 resolve 回调,在下次子 agent 终态事件到达时触发。
|
|
582
|
+
* 供 ACode 运行时在 poll_message 期间 race 子 agent 完成事件。
|
|
583
|
+
*
|
|
584
|
+
* 返回 { promise, cancel }:
|
|
585
|
+
* - promise: 子 agent 终态时 resolve
|
|
586
|
+
* - cancel: 取消等待(poll_message 先返回时调用,清理 resolve 回调)
|
|
587
|
+
*/
|
|
588
|
+
waitForAnyCompletion() {
|
|
589
|
+
// 如果队列中已有通知,立即返回
|
|
590
|
+
if (this.completionQueue.length > 0) {
|
|
591
|
+
const notif = this.completionQueue.shift();
|
|
592
|
+
return {
|
|
593
|
+
promise: Promise.resolve(notif),
|
|
594
|
+
cancel: () => { },
|
|
595
|
+
};
|
|
596
|
+
}
|
|
597
|
+
let cancelled = false;
|
|
598
|
+
const promise = new Promise((resolve) => {
|
|
599
|
+
this.completionWaiterResolve = (notif) => {
|
|
600
|
+
if (!cancelled)
|
|
601
|
+
resolve(notif);
|
|
602
|
+
};
|
|
603
|
+
});
|
|
604
|
+
const cancel = () => {
|
|
605
|
+
cancelled = true;
|
|
606
|
+
this.completionWaiterResolve = null;
|
|
607
|
+
};
|
|
608
|
+
return { promise, cancel };
|
|
609
|
+
}
|
|
363
610
|
/** 订阅 sub-agent 事件(subId 或 "*" 全局) */
|
|
364
611
|
subscribe(subId, cb) {
|
|
365
612
|
let set = this.subscribers.get(subId);
|
|
@@ -387,6 +634,34 @@ export class SubAgentManager {
|
|
|
387
634
|
this.subscribers.clear();
|
|
388
635
|
}
|
|
389
636
|
// ---------- 内部方法 ----------
|
|
637
|
+
/**
|
|
638
|
+
* 将子 agent 终态事件入队并通知等待者。
|
|
639
|
+
* 主流程:构建通知对象 -> 入队 completionQueue -> 若有 waitForAnyCompletion 等待者则立即 resolve。
|
|
640
|
+
*/
|
|
641
|
+
enqueueCompletion(entry, output, error) {
|
|
642
|
+
// 静默完成或已被 awaitCompletion 消费的子 agent 不进入 completionQueue
|
|
643
|
+
if (entry.silent || entry.awaited) {
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
const notif = {
|
|
647
|
+
subId: entry.subId,
|
|
648
|
+
subagentType: entry.subagentType,
|
|
649
|
+
description: entry.description,
|
|
650
|
+
status: entry.status,
|
|
651
|
+
output,
|
|
652
|
+
error,
|
|
653
|
+
durationMs: entry.durationMs,
|
|
654
|
+
};
|
|
655
|
+
this.completionQueue.push(notif);
|
|
656
|
+
// 如果有 poll_message 正在等待子 agent 完成事件,立即通知
|
|
657
|
+
if (this.completionWaiterResolve) {
|
|
658
|
+
const resolve = this.completionWaiterResolve;
|
|
659
|
+
this.completionWaiterResolve = null;
|
|
660
|
+
// 从队列中取出刚入队的通知(即此条)
|
|
661
|
+
const queued = this.completionQueue.pop();
|
|
662
|
+
resolve(queued ?? notif);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
390
665
|
countByStatus(parentAgentId, ...statuses) {
|
|
391
666
|
return this.listByParent(parentAgentId).filter((e) => statuses.includes(e.status)).length;
|
|
392
667
|
}
|
|
@@ -459,7 +734,8 @@ export class SubAgentManager {
|
|
|
459
734
|
}
|
|
460
735
|
break;
|
|
461
736
|
case "assistant_delta":
|
|
462
|
-
|
|
737
|
+
// 累积文本,截断到最近 500 字符
|
|
738
|
+
snapshot.lastAssistantText = ((snapshot.lastAssistantText ?? "") + (event.data?.text ?? "")).slice(-500);
|
|
463
739
|
snapshot.messageCount += 1;
|
|
464
740
|
this.emitEvent(subId, "delta", { text: event.data?.text });
|
|
465
741
|
break;
|
|
@@ -467,10 +743,10 @@ export class SubAgentManager {
|
|
|
467
743
|
// runtime 发射的 mcp_status 使用 action 字段(而非 phase)
|
|
468
744
|
if (event.data?.action === "call_tool") {
|
|
469
745
|
snapshot.currentTool = event.data?.tool;
|
|
470
|
-
this.emitEvent(subId, "tool_start", { tool: snapshot.currentTool });
|
|
746
|
+
this.emitEvent(subId, "tool_start", { tool: snapshot.currentTool, snapshot: { ...snapshot } });
|
|
471
747
|
}
|
|
472
748
|
else if (event.data?.action === "tool_result") {
|
|
473
|
-
this.emitEvent(subId, "tool_end", { tool: snapshot.currentTool });
|
|
749
|
+
this.emitEvent(subId, "tool_end", { tool: snapshot.currentTool, snapshot: { ...snapshot } });
|
|
474
750
|
snapshot.currentTool = undefined;
|
|
475
751
|
}
|
|
476
752
|
break;
|
|
@@ -510,6 +786,19 @@ export class SubAgentManager {
|
|
|
510
786
|
}
|
|
511
787
|
}
|
|
512
788
|
}
|
|
789
|
+
// tool_start / tool_end 异步落盘(fire-and-forget,不阻塞事件发射)
|
|
790
|
+
if (type === "tool_start" || type === "tool_end") {
|
|
791
|
+
const entry = this.subAgents.get(subId);
|
|
792
|
+
if (entry) {
|
|
793
|
+
console.error(`[SubAgentManager] appendEvent: subId=${subId} type=${type} tool=${data.tool ?? "?"} parentAgentId=${entry.parentAgentId}`);
|
|
794
|
+
void this.store.appendEvent(entry.parentAgentId, subId, event).catch((err) => {
|
|
795
|
+
console.error(`[SubAgentManager] appendEvent FAILED: subId=${subId} error=${err instanceof Error ? err.message : String(err)}`);
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
console.error(`[SubAgentManager] appendEvent SKIPPED (entry not found): subId=${subId} type=${type}`);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
513
802
|
}
|
|
514
803
|
toRecord(entry) {
|
|
515
804
|
return {
|
|
@@ -526,6 +815,7 @@ export class SubAgentManager {
|
|
|
526
815
|
endedAt: entry.endedAt,
|
|
527
816
|
durationMs: entry.durationMs,
|
|
528
817
|
contextSnapshot: entry.status === "running" ? entry.contextSnapshot : undefined,
|
|
818
|
+
availableTools: entry.availableTools,
|
|
529
819
|
};
|
|
530
820
|
}
|
|
531
821
|
/** 获取当前上下文快照(供 HTTP 路由调用) */
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SubAgentDocument, SubAgentRecord } from "./sub-agent-types.js";
|
|
1
|
+
import type { SubAgentDocument, SubAgentEvent, SubAgentRecord } from "./sub-agent-types.js";
|
|
2
2
|
/**
|
|
3
3
|
* Sub Agent JSON 文件存储,按 agentId 隔离。
|
|
4
4
|
* 文件路径:{homedir}/.acode/sub-agents/{agentId}.json
|
|
@@ -29,5 +29,12 @@ export declare class SubAgentStore {
|
|
|
29
29
|
updateStatus(agentId: string, subId: string, patch: Partial<SubAgentRecord>): Promise<void>;
|
|
30
30
|
/** 列出该 agent 的全部 sub-agent(已按 startedAt 倒序) */
|
|
31
31
|
list(agentId: string): Promise<SubAgentRecord[]>;
|
|
32
|
+
/** 追加一条事件到指定 sub-agent 的 events 数组(用于 tool_start/tool_end 持久化) */
|
|
33
|
+
appendEvent(agentId: string, subId: string, event: SubAgentEvent): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* 扫描所有 agent 文件,把 status="running"/"pending" 的记录修正为 "failed"。
|
|
36
|
+
* 在 bridge 启动时调用,清理上次进程异常退出留下的僵尸记录。
|
|
37
|
+
*/
|
|
38
|
+
reconcileZombies(): Promise<number>;
|
|
32
39
|
}
|
|
33
40
|
//# sourceMappingURL=sub-agent-store.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sub-agent-store.d.ts","sourceRoot":"","sources":["../src/sub-agent-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"sub-agent-store.d.ts","sourceRoot":"","sources":["../src/sub-agent-store.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE5F;;;;;;;;;;;GAWG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAC7B,OAAO,CAAC,UAAU,CAAoC;;IAMtD,+BAA+B;IAC/B,OAAO,CAAC,QAAQ;IAKhB,wCAAwC;IAClC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAoBtD,wBAAwB;IAClB,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC;IAKzE,oCAAoC;IAC9B,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,cAAc,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAiBxE,wBAAwB;IAClB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE,eAAe;IACT,YAAY,CAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,OAAO,CAAC,cAAc,CAAC,GAC7B,OAAO,CAAC,IAAI,CAAC;IAQhB,+CAA+C;IACzC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAItD,kEAAkE;IAC5D,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC;IAYtF;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,MAAM,CAAC;CAmC1C"}
|