@keyou007/agent-bot 0.1.19 → 0.1.20-alpha.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.
- package/CHANGELOG.md +10 -0
- package/README.md +6 -2
- package/README.zh.md +1 -1
- package/dist/cli/controlProtocol.js.map +1 -1
- package/dist/cli/help.js +2 -2
- package/dist/cli.js +5 -4
- package/dist/cli.js.map +1 -1
- package/dist/config/AgentExecutionDefaultsStore.js +1 -1
- package/dist/config/AgentExecutionDefaultsStore.js.map +1 -1
- package/dist/feishu/CardRenderer.js +10 -6
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/local-files/LocalFileViewerServer.js +11 -3
- package/dist/local-files/LocalFileViewerServer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +29 -72
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/state/StateStore.js +41 -0
- package/dist/state/StateStore.js.map +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/agent-bot/SKILL.md +2 -1
- package/src/cli/controlProtocol.ts +0 -1
- package/src/cli/help.ts +2 -2
- package/src/cli.ts +6 -7
- package/src/config/AgentExecutionDefaultsStore.ts +1 -1
- package/src/feishu/CardRenderer.ts +11 -7
- package/src/local-files/LocalFileViewerServer.ts +12 -3
- package/src/proxy/ProxySessionController.ts +31 -77
- package/src/state/StateStore.ts +40 -0
|
@@ -143,10 +143,9 @@ interface AppServerReleaseSchedule {
|
|
|
143
143
|
runtime: AgentRuntime;
|
|
144
144
|
status: AppServerReleaseCardView["status"];
|
|
145
145
|
blockingTaskCount: number;
|
|
146
|
+
blockingTaskTitles: string[];
|
|
146
147
|
targets: Map<string, AppServerReleaseCardTarget>;
|
|
147
148
|
forced: boolean;
|
|
148
|
-
releaseAt?: number;
|
|
149
|
-
releaseCountdownSeconds?: number;
|
|
150
149
|
releaseStarted?: boolean;
|
|
151
150
|
error?: string;
|
|
152
151
|
timer?: NodeJS.Timeout;
|
|
@@ -184,7 +183,6 @@ const RECOVERY_HEARTBEAT_INTERVAL_MS = 60 * 1_000;
|
|
|
184
183
|
const SHELL_COMMAND_JOB_POLL_INTERVAL_MS = 1_000;
|
|
185
184
|
const SHELL_COMMAND_JOB_RELAUNCH_DELAY_MS = 5_000;
|
|
186
185
|
const APP_SERVER_RELEASE_POLL_INTERVAL_MS = 500;
|
|
187
|
-
const APP_SERVER_RELEASE_IDLE_DELAY_MS = 5_000;
|
|
188
186
|
const FORWARD_ATTACHMENT_WINDOW_MS = 800;
|
|
189
187
|
const DEFAULT_MERGED_FORWARD_INSTRUCTION = "请参考以下内容回复用户";
|
|
190
188
|
const DEFAULT_REFERENCED_MESSAGE_INSTRUCTION = "请参考引用消息回复用户";
|
|
@@ -454,7 +452,6 @@ export interface ControlTaskReleaseResult {
|
|
|
454
452
|
agentName: string;
|
|
455
453
|
status: "waiting" | "released";
|
|
456
454
|
blockingTaskCount: number;
|
|
457
|
-
releaseInSeconds?: number;
|
|
458
455
|
}
|
|
459
456
|
|
|
460
457
|
export interface ProxyLifecycle {
|
|
@@ -1287,7 +1284,6 @@ export class ProxySessionController {
|
|
|
1287
1284
|
agentName: result.agentName,
|
|
1288
1285
|
status: result.status,
|
|
1289
1286
|
blockingTaskCount: result.blockingTaskCount,
|
|
1290
|
-
...(result.releaseInSeconds !== undefined ? { releaseInSeconds: result.releaseInSeconds } : {}),
|
|
1291
1287
|
};
|
|
1292
1288
|
}
|
|
1293
1289
|
|
|
@@ -2888,8 +2884,7 @@ export class ProxySessionController {
|
|
|
2888
2884
|
const anchor = this.store.findTurnAnchorByMessageId(messageId);
|
|
2889
2885
|
if (!anchor) return false;
|
|
2890
2886
|
if (record.lastTurnId === anchor.turnId) return true;
|
|
2891
|
-
return this.store.
|
|
2892
|
-
.some((turn) => turn.turnId === anchor.turnId);
|
|
2887
|
+
return this.store.hasTaskHistoryTurn(record.localSessionId, anchor.turnId);
|
|
2893
2888
|
}
|
|
2894
2889
|
|
|
2895
2890
|
private async forkThreadSession(message: IncomingMessage): Promise<void> {
|
|
@@ -6974,7 +6969,6 @@ export class ProxySessionController {
|
|
|
6974
6969
|
agentName: string;
|
|
6975
6970
|
status: "waiting" | "released" | "failed";
|
|
6976
6971
|
blockingTaskCount: number;
|
|
6977
|
-
releaseInSeconds?: number;
|
|
6978
6972
|
error?: string;
|
|
6979
6973
|
}> {
|
|
6980
6974
|
const record = requestedRecord ?? this.requireCurrentSession(contextKey);
|
|
@@ -6986,20 +6980,17 @@ export class ProxySessionController {
|
|
|
6986
6980
|
let schedule = this.appServerReleaseSchedules.get(record.agentName);
|
|
6987
6981
|
const created = !schedule;
|
|
6988
6982
|
if (!schedule) {
|
|
6989
|
-
const
|
|
6983
|
+
const blockers = this.appServerReleaseBlockers(record.agentName, runtime);
|
|
6984
|
+
const blockingTaskCount = blockers.length;
|
|
6990
6985
|
schedule = {
|
|
6991
6986
|
id: this.nextAppServerReleaseScheduleId++,
|
|
6992
6987
|
agentName: record.agentName,
|
|
6993
6988
|
runtime,
|
|
6994
6989
|
status: "waiting",
|
|
6995
6990
|
blockingTaskCount,
|
|
6991
|
+
blockingTaskTitles: this.appServerReleaseTaskTitles(blockers),
|
|
6996
6992
|
targets: new Map(),
|
|
6997
6993
|
forced: false,
|
|
6998
|
-
...(blockingTaskCount === 0
|
|
6999
|
-
? {
|
|
7000
|
-
releaseCountdownSeconds: Math.ceil(APP_SERVER_RELEASE_IDLE_DELAY_MS / 1_000),
|
|
7001
|
-
}
|
|
7002
|
-
: {}),
|
|
7003
6994
|
};
|
|
7004
6995
|
this.appServerReleaseSchedules.set(record.agentName, schedule);
|
|
7005
6996
|
}
|
|
@@ -7012,14 +7003,6 @@ export class ProxySessionController {
|
|
|
7012
7003
|
if (messageId) {
|
|
7013
7004
|
schedule.targets.set(`${contextKey}\u0000${messageId}`, { contextKey, messageId });
|
|
7014
7005
|
}
|
|
7015
|
-
if (
|
|
7016
|
-
schedule.status === "waiting"
|
|
7017
|
-
&& schedule.blockingTaskCount === 0
|
|
7018
|
-
&& schedule.releaseCountdownSeconds !== undefined
|
|
7019
|
-
&& schedule.releaseAt === undefined
|
|
7020
|
-
) {
|
|
7021
|
-
schedule.releaseAt = Date.now() + APP_SERVER_RELEASE_IDLE_DELAY_MS;
|
|
7022
|
-
}
|
|
7023
7006
|
} catch (error) {
|
|
7024
7007
|
if (created && schedule.targets.size === 0) {
|
|
7025
7008
|
this.clearAppServerReleaseSchedule(schedule);
|
|
@@ -7032,9 +7015,6 @@ export class ProxySessionController {
|
|
|
7032
7015
|
agentName: schedule.agentName,
|
|
7033
7016
|
status: schedule.status === "failed" ? "failed" : schedule.status === "released" ? "released" : "waiting",
|
|
7034
7017
|
blockingTaskCount: schedule.blockingTaskCount,
|
|
7035
|
-
...(schedule.releaseCountdownSeconds !== undefined
|
|
7036
|
-
? { releaseInSeconds: schedule.releaseCountdownSeconds }
|
|
7037
|
-
: {}),
|
|
7038
7018
|
...(schedule.error ? { error: schedule.error } : {}),
|
|
7039
7019
|
};
|
|
7040
7020
|
}
|
|
@@ -7046,7 +7026,7 @@ export class ProxySessionController {
|
|
|
7046
7026
|
if (!Number.isSafeInteger(scheduleId) || !schedule || schedule.id !== scheduleId || schedule.status !== "waiting") {
|
|
7047
7027
|
throw new Error("释放卡片已失效,请重新发送 /release。");
|
|
7048
7028
|
}
|
|
7049
|
-
await this.performAppServerRelease(schedule
|
|
7029
|
+
await this.performAppServerRelease(schedule);
|
|
7050
7030
|
}
|
|
7051
7031
|
|
|
7052
7032
|
private async cancelAppServerRelease(action: CardAction): Promise<void> {
|
|
@@ -7081,6 +7061,10 @@ export class ProxySessionController {
|
|
|
7081
7061
|
});
|
|
7082
7062
|
}
|
|
7083
7063
|
|
|
7064
|
+
private appServerReleaseTaskTitles(blockers: SessionRecord[]): string[] {
|
|
7065
|
+
return blockers.map((session) => session.title?.trim() || "未命名任务");
|
|
7066
|
+
}
|
|
7067
|
+
|
|
7084
7068
|
private armAppServerReleaseCheck(schedule: AppServerReleaseSchedule): void {
|
|
7085
7069
|
if (schedule.status !== "waiting" || schedule.timer || schedule.inFlight) return;
|
|
7086
7070
|
schedule.timer = setTimeout(() => {
|
|
@@ -7095,36 +7079,22 @@ export class ProxySessionController {
|
|
|
7095
7079
|
|
|
7096
7080
|
private async refreshAppServerReleaseSchedule(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7097
7081
|
if (this.appServerReleaseSchedules.get(schedule.agentName) !== schedule || schedule.status !== "waiting") return;
|
|
7098
|
-
const
|
|
7099
|
-
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
schedule.
|
|
7103
|
-
|
|
7104
|
-
|
|
7105
|
-
|
|
7106
|
-
|
|
7107
|
-
this.armAppServerReleaseCheck(schedule);
|
|
7108
|
-
return;
|
|
7109
|
-
}
|
|
7110
|
-
schedule.blockingTaskCount = 0;
|
|
7111
|
-
if (schedule.releaseAt !== undefined) {
|
|
7112
|
-
const releaseCountdownSeconds = Math.max(0, Math.ceil((schedule.releaseAt - Date.now()) / 1_000));
|
|
7113
|
-
if (releaseCountdownSeconds > 0) {
|
|
7114
|
-
if (schedule.releaseCountdownSeconds !== releaseCountdownSeconds) {
|
|
7115
|
-
schedule.releaseCountdownSeconds = releaseCountdownSeconds;
|
|
7116
|
-
await this.publishAppServerReleaseSchedule(schedule);
|
|
7117
|
-
}
|
|
7118
|
-
this.armAppServerReleaseCheck(schedule);
|
|
7119
|
-
return;
|
|
7120
|
-
}
|
|
7082
|
+
const blockers = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime);
|
|
7083
|
+
const blockingTaskCount = blockers.length;
|
|
7084
|
+
const blockingTaskTitles = this.appServerReleaseTaskTitles(blockers);
|
|
7085
|
+
const titlesChanged = schedule.blockingTaskTitles.length !== blockingTaskTitles.length
|
|
7086
|
+
|| schedule.blockingTaskTitles.some((title, index) => title !== blockingTaskTitles[index]);
|
|
7087
|
+
if (schedule.blockingTaskCount !== blockingTaskCount || titlesChanged) {
|
|
7088
|
+
schedule.blockingTaskCount = blockingTaskCount;
|
|
7089
|
+
schedule.blockingTaskTitles = blockingTaskTitles;
|
|
7090
|
+
await this.publishAppServerReleaseSchedule(schedule);
|
|
7121
7091
|
}
|
|
7122
|
-
|
|
7092
|
+
this.armAppServerReleaseCheck(schedule);
|
|
7123
7093
|
}
|
|
7124
7094
|
|
|
7125
|
-
private async performAppServerRelease(schedule: AppServerReleaseSchedule
|
|
7095
|
+
private async performAppServerRelease(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7126
7096
|
if (schedule.inFlight) return schedule.inFlight;
|
|
7127
|
-
const operation = this.performAppServerReleaseNow(schedule
|
|
7097
|
+
const operation = this.performAppServerReleaseNow(schedule);
|
|
7128
7098
|
schedule.inFlight = operation;
|
|
7129
7099
|
try {
|
|
7130
7100
|
await operation;
|
|
@@ -7134,31 +7104,17 @@ export class ProxySessionController {
|
|
|
7134
7104
|
}
|
|
7135
7105
|
}
|
|
7136
7106
|
|
|
7137
|
-
private async performAppServerReleaseNow(schedule: AppServerReleaseSchedule
|
|
7107
|
+
private async performAppServerReleaseNow(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7138
7108
|
if (schedule.timer) {
|
|
7139
7109
|
clearTimeout(schedule.timer);
|
|
7140
7110
|
schedule.timer = undefined;
|
|
7141
7111
|
}
|
|
7142
|
-
const interruptedWork =
|
|
7143
|
-
|
|
7144
|
-
else {
|
|
7145
|
-
const blockingTaskCount = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime).length;
|
|
7146
|
-
if (blockingTaskCount > 0) {
|
|
7147
|
-
schedule.status = "waiting";
|
|
7148
|
-
schedule.blockingTaskCount = blockingTaskCount;
|
|
7149
|
-
schedule.releaseAt = undefined;
|
|
7150
|
-
schedule.releaseCountdownSeconds = undefined;
|
|
7151
|
-
schedule.releaseStarted = false;
|
|
7152
|
-
await this.publishAppServerReleaseSchedule(schedule);
|
|
7153
|
-
this.armAppServerReleaseCheck(schedule);
|
|
7154
|
-
return;
|
|
7155
|
-
}
|
|
7156
|
-
}
|
|
7112
|
+
const interruptedWork = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime).length > 0;
|
|
7113
|
+
await this.cancelQueuedPromptsForAppServerRelease(schedule.agentName);
|
|
7157
7114
|
|
|
7158
7115
|
schedule.status = "releasing";
|
|
7159
7116
|
schedule.blockingTaskCount = 0;
|
|
7160
|
-
schedule.
|
|
7161
|
-
schedule.releaseCountdownSeconds = undefined;
|
|
7117
|
+
schedule.blockingTaskTitles = [];
|
|
7162
7118
|
schedule.releaseStarted = false;
|
|
7163
7119
|
schedule.forced = interruptedWork;
|
|
7164
7120
|
await this.publishAppServerReleaseSchedule(schedule);
|
|
@@ -7168,18 +7124,18 @@ export class ProxySessionController {
|
|
|
7168
7124
|
) return;
|
|
7169
7125
|
schedule.releaseStarted = true;
|
|
7170
7126
|
try {
|
|
7171
|
-
const result = await schedule.runtime.release?.({ force });
|
|
7127
|
+
const result = await schedule.runtime.release?.({ force: true });
|
|
7172
7128
|
if (!result) throw new Error("当前 Agent 不支持释放 App Server。");
|
|
7173
7129
|
if (result.status === "busy") {
|
|
7130
|
+
const blockers = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime);
|
|
7174
7131
|
schedule.status = "waiting";
|
|
7175
7132
|
schedule.blockingTaskCount = Math.max(
|
|
7176
7133
|
result.activeSessionIds?.length ?? 0,
|
|
7177
|
-
|
|
7134
|
+
blockers.length,
|
|
7178
7135
|
1,
|
|
7179
7136
|
);
|
|
7137
|
+
schedule.blockingTaskTitles = this.appServerReleaseTaskTitles(blockers);
|
|
7180
7138
|
schedule.forced = false;
|
|
7181
|
-
schedule.releaseAt = undefined;
|
|
7182
|
-
schedule.releaseCountdownSeconds = undefined;
|
|
7183
7139
|
schedule.releaseStarted = false;
|
|
7184
7140
|
await this.publishAppServerReleaseSchedule(schedule);
|
|
7185
7141
|
this.armAppServerReleaseCheck(schedule);
|
|
@@ -7239,9 +7195,7 @@ export class ProxySessionController {
|
|
|
7239
7195
|
scheduleId: schedule.id,
|
|
7240
7196
|
agentName: schedule.agentName,
|
|
7241
7197
|
...(schedule.blockingTaskCount > 0 ? { blockingTaskCount: schedule.blockingTaskCount } : {}),
|
|
7242
|
-
...(schedule.
|
|
7243
|
-
? { releaseInSeconds: schedule.releaseCountdownSeconds }
|
|
7244
|
-
: {}),
|
|
7198
|
+
...(schedule.blockingTaskTitles.length > 0 ? { blockingTaskTitles: schedule.blockingTaskTitles } : {}),
|
|
7245
7199
|
...(schedule.forced ? { forced: true } : {}),
|
|
7246
7200
|
...(schedule.error ? { error: schedule.error } : {}),
|
|
7247
7201
|
};
|
package/src/state/StateStore.ts
CHANGED
|
@@ -1255,6 +1255,46 @@ export class StateStore {
|
|
|
1255
1255
|
}));
|
|
1256
1256
|
}
|
|
1257
1257
|
|
|
1258
|
+
hasTaskHistoryTurn(localSessionId: string, turnId: string): boolean {
|
|
1259
|
+
const readParent = this.db.prepare(`
|
|
1260
|
+
SELECT ts.local_session_id, tpl.parent_turn_id
|
|
1261
|
+
FROM turn_snapshots ts
|
|
1262
|
+
LEFT JOIN turn_parent_links tpl ON tpl.turn_id = ts.turn_id
|
|
1263
|
+
WHERE ts.turn_id = ?
|
|
1264
|
+
AND json_extract(ts.snapshot_json, '$.status') = 'completed'
|
|
1265
|
+
`);
|
|
1266
|
+
type ParentRow = { local_session_id: string; parent_turn_id: string | null };
|
|
1267
|
+
const target = readParent.get(turnId) as ParentRow | undefined;
|
|
1268
|
+
if (!target) return false;
|
|
1269
|
+
if (target.local_session_id === localSessionId) return true;
|
|
1270
|
+
|
|
1271
|
+
const backfilledSessions = new Set<string>();
|
|
1272
|
+
let ancestorTurnId = this.findForkSourceTurnId(localSessionId);
|
|
1273
|
+
if (!ancestorTurnId) {
|
|
1274
|
+
// Reset-only legacy tasks may have partially saved cross-session links.
|
|
1275
|
+
this.backfillTurnParents(localSessionId);
|
|
1276
|
+
backfilledSessions.add(localSessionId);
|
|
1277
|
+
ancestorTurnId = this.findCrossSessionParentTurnId(localSessionId);
|
|
1278
|
+
}
|
|
1279
|
+
const visited = new Set<string>();
|
|
1280
|
+
while (ancestorTurnId && !visited.has(ancestorTurnId)) {
|
|
1281
|
+
if (ancestorTurnId === turnId) return true;
|
|
1282
|
+
visited.add(ancestorTurnId);
|
|
1283
|
+
const ancestor = readParent.get(ancestorTurnId) as ParentRow | undefined;
|
|
1284
|
+
if (!ancestor) return false;
|
|
1285
|
+
let parentTurnId = ancestor.parent_turn_id;
|
|
1286
|
+
// Older snapshots may lack parent links. Repair each owner at most once,
|
|
1287
|
+
// without loading full snapshots or rebuilding already linked ancestry.
|
|
1288
|
+
if (!parentTurnId && !backfilledSessions.has(ancestor.local_session_id)) {
|
|
1289
|
+
this.backfillTurnParents(ancestor.local_session_id);
|
|
1290
|
+
backfilledSessions.add(ancestor.local_session_id);
|
|
1291
|
+
parentTurnId = (readParent.get(ancestorTurnId) as ParentRow | undefined)?.parent_turn_id ?? null;
|
|
1292
|
+
}
|
|
1293
|
+
ancestorTurnId = parentTurnId ?? undefined;
|
|
1294
|
+
}
|
|
1295
|
+
return false;
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1258
1298
|
listTaskTurnGraph(localSessionId: string): CompletedTurnSnapshotRecord[] {
|
|
1259
1299
|
this.backfillTurnParents(localSessionId);
|
|
1260
1300
|
const records = new Map(
|