@keyou007/agent-bot 0.1.14-alpha.0 → 0.1.14-alpha.2
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 +26 -0
- package/README.md +82 -55
- package/README.zh.md +82 -55
- package/config.example.yaml +5 -1
- package/dist/cli/AutostartManager.js +431 -0
- package/dist/cli/AutostartManager.js.map +1 -0
- package/dist/cli/FeishuAppConfiguration.js +17 -13
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/Initializer.js +35 -0
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/SelfUpdateRunner.js +552 -0
- package/dist/cli/SelfUpdateRunner.js.map +1 -0
- package/dist/cli/SelfUpdater.js +431 -0
- package/dist/cli/SelfUpdater.js.map +1 -0
- package/dist/cli/autostartOutput.js +63 -0
- package/dist/cli/autostartOutput.js.map +1 -0
- package/dist/cli/controlProtocol.js.map +1 -1
- package/dist/cli/help.js +92 -18
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/taskGroupOptions.js +14 -11
- package/dist/cli/taskGroupOptions.js.map +1 -1
- package/dist/cli/taskListOutput.js +3 -0
- package/dist/cli/taskListOutput.js.map +1 -1
- package/dist/cli/taskTarget.js +99 -0
- package/dist/cli/taskTarget.js.map +1 -0
- package/dist/cli.js +643 -58
- package/dist/cli.js.map +1 -1
- package/dist/codex/CodexRuntime.js +16 -5
- package/dist/codex/CodexRuntime.js.map +1 -1
- package/dist/commands/CommandRouter.js +20 -1
- package/dist/commands/CommandRouter.js.map +1 -1
- package/dist/config/loadConfig.js +2 -0
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/config/schema.js +2 -0
- package/dist/config/schema.js.map +1 -1
- package/dist/console/ConsoleTurnPresenter.js +2 -0
- package/dist/console/ConsoleTurnPresenter.js.map +1 -1
- package/dist/feishu/CardRenderer.js +584 -16
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/feishu/FeishuConnector.js +29 -8
- package/dist/feishu/FeishuConnector.js.map +1 -1
- package/dist/feishu/FeishuMarkdown.js +25 -1
- package/dist/feishu/FeishuMarkdown.js.map +1 -1
- package/dist/feishu/FeishuMessageClient.js +43 -0
- package/dist/feishu/FeishuMessageClient.js.map +1 -1
- package/dist/feishu/FeishuTurnPresenter.js +29 -1
- package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
- package/dist/feishu/ownerAccess.js +7 -0
- package/dist/feishu/ownerAccess.js.map +1 -0
- package/dist/index.js +148 -19
- package/dist/index.js.map +1 -1
- package/dist/presentation/OutboundRouter.js +19 -1
- package/dist/presentation/OutboundRouter.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +1444 -66
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/startup/StartupNotifier.js +65 -16
- package/dist/startup/StartupNotifier.js.map +1 -1
- package/dist/startup/startFeishu.js +2 -2
- package/dist/startup/startFeishu.js.map +1 -1
- package/dist/state/StateStore.js +268 -67
- package/dist/state/StateStore.js.map +1 -1
- package/dist/state/migrations.js +26 -0
- package/dist/state/migrations.js.map +1 -1
- package/dist/supervision/SafeRestartNotifier.js +17 -16
- package/dist/supervision/SafeRestartNotifier.js.map +1 -1
- package/dist/supervision/SafeRestartScheduler.js +12 -7
- package/dist/supervision/SafeRestartScheduler.js.map +1 -1
- package/dist/supervision/replacementSupervisor.js +45 -4
- package/dist/supervision/replacementSupervisor.js.map +1 -1
- package/dist/supervisor.js +30 -18
- package/dist/supervisor.js.map +1 -1
- package/docs/technical-reference.md +33 -10
- package/docs/technical-reference.zh.md +33 -10
- package/npm-shrinkwrap.json +2 -2
- package/package.json +2 -2
- package/skills/agent-bot/SKILL.md +107 -182
- package/src/cli/AutostartManager.ts +579 -0
- package/src/cli/FeishuAppConfiguration.ts +22 -7
- package/src/cli/Initializer.ts +57 -0
- package/src/cli/SelfUpdateRunner.ts +817 -0
- package/src/cli/SelfUpdater.ts +688 -0
- package/src/cli/autostartOutput.ts +75 -0
- package/src/cli/controlProtocol.ts +111 -1
- package/src/cli/help.ts +92 -18
- package/src/cli/taskGroupOptions.ts +27 -17
- package/src/cli/taskListOutput.ts +10 -0
- package/src/cli/taskTarget.ts +168 -0
- package/src/cli.ts +781 -65
- package/src/codex/CodexRuntime.ts +17 -5
- package/src/commands/CommandRouter.ts +19 -1
- package/src/commands/commandTypes.ts +3 -0
- package/src/config/loadConfig.ts +2 -0
- package/src/config/schema.ts +2 -0
- package/src/console/ConsoleTurnPresenter.ts +4 -1
- package/src/feishu/CardRenderer.ts +716 -16
- package/src/feishu/FeishuConnector.ts +44 -10
- package/src/feishu/FeishuMarkdown.ts +27 -1
- package/src/feishu/FeishuMessageClient.ts +58 -0
- package/src/feishu/FeishuTurnPresenter.ts +35 -2
- package/src/feishu/ownerAccess.ts +7 -0
- package/src/feishu/types.ts +7 -0
- package/src/index.ts +192 -22
- package/src/presentation/OutboundRouter.ts +28 -3
- package/src/proxy/ProxySessionController.ts +1707 -70
- package/src/runtime/types.ts +1 -0
- package/src/startup/StartupNotifier.ts +67 -17
- package/src/startup/startFeishu.ts +5 -3
- package/src/state/StateStore.ts +413 -65
- package/src/state/migrations.ts +26 -0
- package/src/supervision/SafeRestartNotifier.ts +17 -17
- package/src/supervision/SafeRestartScheduler.ts +13 -6
- package/src/supervision/replacementSupervisor.ts +50 -4
- package/src/supervisor.ts +35 -16
|
@@ -15,27 +15,68 @@ export class StartupNotifier {
|
|
|
15
15
|
this.options = options;
|
|
16
16
|
this.metadataHydrator = metadataHydrator;
|
|
17
17
|
}
|
|
18
|
-
async notify(startedAt, restartReason,
|
|
18
|
+
async notify(startedAt, restartReason, restartTargets = []) {
|
|
19
19
|
let targets;
|
|
20
20
|
try {
|
|
21
21
|
const activeGroupSince = new Date(startedAt.getTime() - 60_000);
|
|
22
22
|
const knownGroups = new Map(this.store.listChatContexts("group")
|
|
23
23
|
.filter((chat) => !isThreadContextKey(chat.contextKey))
|
|
24
24
|
.map((chat) => [chat.contextKey, chat]));
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
25
|
+
const targetsByContext = new Map();
|
|
26
|
+
for (const chat of this.store.listChatContexts("p2p")) {
|
|
27
|
+
targetsByContext.set(chat.contextKey, {
|
|
28
|
+
contextKey: chat.contextKey,
|
|
29
|
+
context: this.store.getUserContext(chat.contextKey),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
const recentGroups = this.store.listRecentlyActiveChatContexts(activeGroupSince)
|
|
33
|
+
.filter((chat) => chat.chatType === "group" && !isThreadContextKey(chat.contextKey));
|
|
34
|
+
for (const chat of recentGroups) {
|
|
35
|
+
targetsByContext.set(chat.contextKey, {
|
|
36
|
+
contextKey: chat.contextKey,
|
|
37
|
+
context: this.store.getUserContext(chat.contextKey),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
const explicitBaseContextKeys = new Set(restartTargets
|
|
41
|
+
.map((target) => target.contextKey.trim())
|
|
42
|
+
.filter((contextKey) => contextKey && !isThreadContextKey(contextKey)));
|
|
43
|
+
for (const target of restartTargets) {
|
|
44
|
+
const contextKey = target.contextKey.trim();
|
|
45
|
+
if (!contextKey)
|
|
46
|
+
continue;
|
|
47
|
+
if (isThreadContextKey(contextKey)) {
|
|
48
|
+
const baseContextKey = baseChatContextKey(contextKey);
|
|
49
|
+
if (!knownGroups.has(baseContextKey))
|
|
50
|
+
continue;
|
|
51
|
+
const replyMessageId = target.replyMessageId?.trim();
|
|
52
|
+
if (replyMessageId) {
|
|
53
|
+
if (!explicitBaseContextKeys.has(baseContextKey)) {
|
|
54
|
+
targetsByContext.delete(baseContextKey);
|
|
55
|
+
}
|
|
56
|
+
targetsByContext.set(contextKey, {
|
|
57
|
+
contextKey,
|
|
58
|
+
replyMessageId,
|
|
59
|
+
context: this.store.getUserContext(contextKey),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const group = knownGroups.get(baseContextKey);
|
|
64
|
+
targetsByContext.set(baseContextKey, {
|
|
65
|
+
contextKey: baseContextKey,
|
|
66
|
+
context: this.store.getUserContext(baseContextKey),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const group = knownGroups.get(contextKey);
|
|
72
|
+
if (group) {
|
|
73
|
+
targetsByContext.set(contextKey, {
|
|
74
|
+
contextKey,
|
|
75
|
+
context: this.store.getUserContext(contextKey),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
33
78
|
}
|
|
34
|
-
|
|
35
|
-
targets = chats.map((chat) => ({
|
|
36
|
-
contextKey: chat.contextKey,
|
|
37
|
-
context: this.store.getUserContext(chat.contextKey),
|
|
38
|
-
}));
|
|
79
|
+
targets = [...targetsByContext.values()];
|
|
39
80
|
}
|
|
40
81
|
catch (error) {
|
|
41
82
|
this.logger.warn({ error }, "Failed to load startup notification targets.");
|
|
@@ -47,7 +88,7 @@ export class StartupNotifier {
|
|
|
47
88
|
return;
|
|
48
89
|
targets = [{ contextKey: `open_id:${defaultUserOpenId}` }];
|
|
49
90
|
}
|
|
50
|
-
const deliveries = await Promise.all(targets.map(async ({ contextKey, context }) => {
|
|
91
|
+
const deliveries = await Promise.all(targets.map(async ({ contextKey, replyMessageId, context }) => {
|
|
51
92
|
let session = context?.currentSessionId ? this.store.getSession(context.currentSessionId) : undefined;
|
|
52
93
|
if (session && this.metadataHydrator) {
|
|
53
94
|
try {
|
|
@@ -84,7 +125,15 @@ export class StartupNotifier {
|
|
|
84
125
|
: undefined,
|
|
85
126
|
});
|
|
86
127
|
try {
|
|
87
|
-
|
|
128
|
+
if (replyMessageId) {
|
|
129
|
+
if (!this.outbound.replyInteractiveCard) {
|
|
130
|
+
throw new Error("The outbound transport cannot preserve the safe-restart topic.");
|
|
131
|
+
}
|
|
132
|
+
await this.outbound.replyInteractiveCard(contextKey, { messageId: replyMessageId, replyInThread: true }, card);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
await this.outbound.sendInteractiveCard(contextKey, card);
|
|
136
|
+
}
|
|
88
137
|
return true;
|
|
89
138
|
}
|
|
90
139
|
catch (error) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StartupNotifier.js","sourceRoot":"","sources":["../../src/startup/StartupNotifier.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAC;AAE9E,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"StartupNotifier.js","sourceRoot":"","sources":["../../src/startup/StartupNotifier.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export async function startFeishu(connector, notifier, startedAt, restartReason, prepare, onConnected,
|
|
1
|
+
export async function startFeishu(connector, notifier, startedAt, restartReason, prepare, onConnected, restartTargets = []) {
|
|
2
2
|
await prepare?.();
|
|
3
3
|
await connector.start();
|
|
4
|
-
await notifier.notify(startedAt, restartReason,
|
|
4
|
+
await notifier.notify(startedAt, restartReason, restartTargets);
|
|
5
5
|
onConnected?.();
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=startFeishu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"startFeishu.js","sourceRoot":"","sources":["../../src/startup/startFeishu.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"startFeishu.js","sourceRoot":"","sources":["../../src/startup/startFeishu.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,SAAmC,EACnC,QAAmC,EACnC,SAAe,EACf,aAAqB,EACrB,OAA6B,EAC7B,WAAwB,EACxB,cAAc,GAAgC,EAAE;IAEhD,MAAM,OAAO,EAAE,EAAE,CAAC;IAClB,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IACxB,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;IAChE,WAAW,EAAE,EAAE,CAAC;AAClB,CAAC"}
|
package/dist/state/StateStore.js
CHANGED
|
@@ -16,6 +16,7 @@ export class StateStore {
|
|
|
16
16
|
this.ensureSessionColumns();
|
|
17
17
|
this.ensureTurnSnapshotColumns();
|
|
18
18
|
this.ensureChatContextColumns();
|
|
19
|
+
this.ensureTurnAttemptColumns();
|
|
19
20
|
this.initializeContextSessionMappings();
|
|
20
21
|
this.db.exec("DROP INDEX IF EXISTS idx_sessions_remote_session_id_unique");
|
|
21
22
|
this.reconcileDuplicateRemoteSessions();
|
|
@@ -75,6 +76,27 @@ export class StateStore {
|
|
|
75
76
|
updated_at = excluded.updated_at
|
|
76
77
|
`).run(contextKey, chatType, now, now);
|
|
77
78
|
}
|
|
79
|
+
getChatContext(contextKey) {
|
|
80
|
+
const row = this.db.prepare("SELECT * FROM chat_contexts WHERE context_key = ?")
|
|
81
|
+
.get(contextKey);
|
|
82
|
+
return row ? mapChatContext(row) : undefined;
|
|
83
|
+
}
|
|
84
|
+
setChatRequiresMention(contextKey, requiresMention) {
|
|
85
|
+
const now = new Date().toISOString();
|
|
86
|
+
this.db.prepare(`
|
|
87
|
+
UPDATE chat_contexts
|
|
88
|
+
SET require_mention = ?, updated_at = ?
|
|
89
|
+
WHERE context_key = ? AND chat_type = 'group'
|
|
90
|
+
`).run(requiresMention ? 1 : 0, now, contextKey);
|
|
91
|
+
}
|
|
92
|
+
chatRequiresMention(contextKey) {
|
|
93
|
+
const row = this.db.prepare(`
|
|
94
|
+
SELECT require_mention
|
|
95
|
+
FROM chat_contexts
|
|
96
|
+
WHERE context_key = ? AND chat_type = 'group'
|
|
97
|
+
`).get(contextKey);
|
|
98
|
+
return row?.require_mention === 1;
|
|
99
|
+
}
|
|
78
100
|
listChatContexts(chatType) {
|
|
79
101
|
const rows = chatType
|
|
80
102
|
? this.db.prepare(`
|
|
@@ -83,13 +105,7 @@ export class StateStore {
|
|
|
83
105
|
ORDER BY updated_at DESC
|
|
84
106
|
`).all(chatType)
|
|
85
107
|
: this.db.prepare("SELECT * FROM chat_contexts ORDER BY updated_at DESC").all();
|
|
86
|
-
return rows.map(
|
|
87
|
-
contextKey: row.context_key,
|
|
88
|
-
chatType: row.chat_type,
|
|
89
|
-
lastActivityAt: row.last_activity_at ?? undefined,
|
|
90
|
-
createdAt: row.created_at,
|
|
91
|
-
updatedAt: row.updated_at,
|
|
92
|
-
}));
|
|
108
|
+
return rows.map(mapChatContext);
|
|
93
109
|
}
|
|
94
110
|
markChatActive(contextKey, activeAt = new Date()) {
|
|
95
111
|
const timestamp = activeAt.toISOString();
|
|
@@ -105,13 +121,7 @@ export class StateStore {
|
|
|
105
121
|
WHERE last_activity_at >= ?
|
|
106
122
|
ORDER BY last_activity_at DESC
|
|
107
123
|
`).all(since.toISOString());
|
|
108
|
-
return rows.map(
|
|
109
|
-
contextKey: row.context_key,
|
|
110
|
-
chatType: row.chat_type,
|
|
111
|
-
lastActivityAt: row.last_activity_at ?? undefined,
|
|
112
|
-
createdAt: row.created_at,
|
|
113
|
-
updatedAt: row.updated_at,
|
|
114
|
-
}));
|
|
124
|
+
return rows.map(mapChatContext);
|
|
115
125
|
}
|
|
116
126
|
enqueuePrompt(input) {
|
|
117
127
|
const createdAt = new Date().toISOString();
|
|
@@ -177,6 +187,131 @@ export class StateStore {
|
|
|
177
187
|
});
|
|
178
188
|
return cancel();
|
|
179
189
|
}
|
|
190
|
+
createTurnAttempt(input) {
|
|
191
|
+
const createdAt = input.createdAt ?? new Date().toISOString();
|
|
192
|
+
const updatedAt = input.updatedAt ?? createdAt;
|
|
193
|
+
const status = input.status ?? (input.turnId ? "running" : "accepted");
|
|
194
|
+
this.db.prepare(`
|
|
195
|
+
INSERT INTO turn_attempts (
|
|
196
|
+
attempt_id, local_session_id, context_key, prompt_text, local_image_paths_json,
|
|
197
|
+
message_id, reply_message_id, pending_turn_id, turn_id, recovered_from_turn_id,
|
|
198
|
+
recovery_count, retry_count, status, created_at, updated_at
|
|
199
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
200
|
+
`).run(input.attemptId, input.localSessionId, input.contextKey, input.promptText, JSON.stringify(input.localImagePaths ?? []), input.messageId ?? null, input.replyMessageId ?? null, input.pendingTurnId ?? null, input.turnId ?? null, input.recoveredFromTurnId ?? null, input.recoveryCount ?? 0, input.retryCount ?? 0, status, createdAt, updatedAt);
|
|
201
|
+
return this.getTurnAttempt(input.attemptId);
|
|
202
|
+
}
|
|
203
|
+
getTurnAttempt(attemptId) {
|
|
204
|
+
const row = this.db.prepare("SELECT * FROM turn_attempts WHERE attempt_id = ?")
|
|
205
|
+
.get(attemptId);
|
|
206
|
+
return row ? mapTurnAttempt(row) : undefined;
|
|
207
|
+
}
|
|
208
|
+
findIncompleteTurnAttemptForSession(localSessionId) {
|
|
209
|
+
const row = this.db.prepare(`
|
|
210
|
+
SELECT * FROM turn_attempts
|
|
211
|
+
WHERE local_session_id = ?
|
|
212
|
+
AND status IN ('accepted', 'running', 'recovering')
|
|
213
|
+
ORDER BY updated_at DESC, rowid DESC
|
|
214
|
+
LIMIT 1
|
|
215
|
+
`).get(localSessionId);
|
|
216
|
+
return row ? mapTurnAttempt(row) : undefined;
|
|
217
|
+
}
|
|
218
|
+
listIncompleteTurnAttempts() {
|
|
219
|
+
const rows = this.db.prepare(`
|
|
220
|
+
SELECT * FROM turn_attempts
|
|
221
|
+
WHERE status IN ('accepted', 'running', 'recovering')
|
|
222
|
+
ORDER BY created_at ASC, rowid ASC
|
|
223
|
+
`).all();
|
|
224
|
+
return rows.map(mapTurnAttempt);
|
|
225
|
+
}
|
|
226
|
+
updateTurnAttempt(attemptId, patch) {
|
|
227
|
+
const existing = this.getTurnAttempt(attemptId);
|
|
228
|
+
if (!existing)
|
|
229
|
+
return;
|
|
230
|
+
const value = (candidate, fallback) => candidate === undefined ? fallback ?? null : candidate;
|
|
231
|
+
this.db.prepare(`
|
|
232
|
+
UPDATE turn_attempts
|
|
233
|
+
SET message_id = ?, reply_message_id = ?, pending_turn_id = ?, turn_id = ?,
|
|
234
|
+
recovered_from_turn_id = ?, recovery_count = ?, retry_count = ?, status = ?, updated_at = ?
|
|
235
|
+
WHERE attempt_id = ?
|
|
236
|
+
`).run(value(patch.messageId, existing.messageId), value(patch.replyMessageId, existing.replyMessageId), value(patch.pendingTurnId, existing.pendingTurnId), value(patch.turnId, existing.turnId), value(patch.recoveredFromTurnId, existing.recoveredFromTurnId), patch.recoveryCount ?? existing.recoveryCount, patch.retryCount ?? existing.retryCount, patch.status ?? existing.status, new Date().toISOString(), attemptId);
|
|
237
|
+
}
|
|
238
|
+
bindTurnAttempt(localSessionId, turnId) {
|
|
239
|
+
const attempt = this.findIncompleteTurnAttemptForSession(localSessionId);
|
|
240
|
+
if (!attempt || (attempt.turnId && attempt.turnId !== turnId))
|
|
241
|
+
return undefined;
|
|
242
|
+
this.updateTurnAttempt(attempt.attemptId, { turnId, status: "running" });
|
|
243
|
+
return this.getTurnAttempt(attempt.attemptId);
|
|
244
|
+
}
|
|
245
|
+
markTurnAttemptTerminal(turnId, status) {
|
|
246
|
+
this.db.prepare(`
|
|
247
|
+
UPDATE turn_attempts
|
|
248
|
+
SET status = ?, updated_at = ?
|
|
249
|
+
WHERE turn_id = ?
|
|
250
|
+
`).run(status, new Date().toISOString(), turnId);
|
|
251
|
+
}
|
|
252
|
+
findIncompleteTurnAttemptByTurnId(turnId) {
|
|
253
|
+
const row = this.db.prepare(`
|
|
254
|
+
SELECT * FROM turn_attempts
|
|
255
|
+
WHERE turn_id = ? AND status IN ('accepted', 'running', 'recovering')
|
|
256
|
+
ORDER BY updated_at DESC, rowid DESC
|
|
257
|
+
LIMIT 1
|
|
258
|
+
`).get(turnId);
|
|
259
|
+
return row ? mapTurnAttempt(row) : undefined;
|
|
260
|
+
}
|
|
261
|
+
touchTurnAttempt(turnId, activityAt = new Date()) {
|
|
262
|
+
const timestamp = activityAt.toISOString();
|
|
263
|
+
const throttleCutoff = new Date(activityAt.getTime() - 15_000).toISOString();
|
|
264
|
+
this.db.prepare(`
|
|
265
|
+
UPDATE turn_attempts
|
|
266
|
+
SET updated_at = ?
|
|
267
|
+
WHERE turn_id = ?
|
|
268
|
+
AND status IN ('accepted', 'running', 'recovering')
|
|
269
|
+
AND updated_at < ?
|
|
270
|
+
`).run(timestamp, turnId, throttleCutoff);
|
|
271
|
+
}
|
|
272
|
+
prepareTurnAttemptRecovery(attemptId, recoveredFromTurnId) {
|
|
273
|
+
const existing = this.getTurnAttempt(attemptId);
|
|
274
|
+
if (!existing)
|
|
275
|
+
return undefined;
|
|
276
|
+
this.updateTurnAttempt(attemptId, {
|
|
277
|
+
pendingTurnId: null,
|
|
278
|
+
turnId: null,
|
|
279
|
+
recoveredFromTurnId: recoveredFromTurnId ?? existing.turnId ?? existing.recoveredFromTurnId ?? null,
|
|
280
|
+
recoveryCount: existing.recoveryCount + 1,
|
|
281
|
+
status: "recovering",
|
|
282
|
+
});
|
|
283
|
+
return this.getTurnAttempt(attemptId);
|
|
284
|
+
}
|
|
285
|
+
prepareTurnAttemptRetry(attemptId, failedTurnId) {
|
|
286
|
+
const existing = this.getTurnAttempt(attemptId);
|
|
287
|
+
if (!existing || existing.turnId !== failedTurnId || !isIncompleteTurnAttemptStatus(existing.status)) {
|
|
288
|
+
return undefined;
|
|
289
|
+
}
|
|
290
|
+
this.updateTurnAttempt(attemptId, {
|
|
291
|
+
pendingTurnId: null,
|
|
292
|
+
turnId: null,
|
|
293
|
+
recoveredFromTurnId: failedTurnId,
|
|
294
|
+
retryCount: existing.retryCount + 1,
|
|
295
|
+
status: "recovering",
|
|
296
|
+
});
|
|
297
|
+
return this.getTurnAttempt(attemptId);
|
|
298
|
+
}
|
|
299
|
+
rebindPendingTurnMessages(localSessionId, sourceTurnId, targetTurnId) {
|
|
300
|
+
const now = new Date().toISOString();
|
|
301
|
+
const rebind = this.db.transaction(() => {
|
|
302
|
+
this.db.prepare(`
|
|
303
|
+
UPDATE message_reactions
|
|
304
|
+
SET turn_id = ?, updated_at = ?
|
|
305
|
+
WHERE local_session_id = ? AND turn_id = ? AND status = 'pending'
|
|
306
|
+
`).run(targetTurnId, now, localSessionId, sourceTurnId);
|
|
307
|
+
this.db.prepare(`
|
|
308
|
+
UPDATE message_turn_bindings
|
|
309
|
+
SET turn_id = ?, updated_at = ?
|
|
310
|
+
WHERE local_session_id = ? AND turn_id = ?
|
|
311
|
+
`).run(targetTurnId, now, localSessionId, sourceTurnId);
|
|
312
|
+
});
|
|
313
|
+
rebind();
|
|
314
|
+
}
|
|
180
315
|
nextForkTitle(sourceTitle) {
|
|
181
316
|
const baseTitle = forkBaseTitle(sourceTitle);
|
|
182
317
|
const allocate = this.db.transaction(() => {
|
|
@@ -193,59 +328,6 @@ export class StateStore {
|
|
|
193
328
|
});
|
|
194
329
|
return formatForkTitle(baseTitle, allocate());
|
|
195
330
|
}
|
|
196
|
-
reconcileInterruptedAcpSessions(acpAgentNames) {
|
|
197
|
-
const agentClause = acpAgentNames.length
|
|
198
|
-
? ` OR (runtime_kind IS NULL AND agent_name IN (${acpAgentNames.map(() => "?").join(", ")}))`
|
|
199
|
-
: "";
|
|
200
|
-
const rows = this.db
|
|
201
|
-
.prepare(`SELECT * FROM sessions WHERE status = 'running' AND (runtime_kind = 'acp'${agentClause})`)
|
|
202
|
-
.all(...acpAgentNames);
|
|
203
|
-
if (rows.length === 0)
|
|
204
|
-
return [];
|
|
205
|
-
const now = new Date().toISOString();
|
|
206
|
-
const completedAt = Date.now();
|
|
207
|
-
const reconcile = this.db.transaction(() => {
|
|
208
|
-
for (const row of rows) {
|
|
209
|
-
this.db.prepare(`
|
|
210
|
-
UPDATE sessions
|
|
211
|
-
SET status = 'failed',
|
|
212
|
-
last_turn_status = CASE WHEN last_turn_id IS NULL THEN last_turn_status ELSE 'failed' END,
|
|
213
|
-
updated_at = ?
|
|
214
|
-
WHERE local_session_id = ?
|
|
215
|
-
`).run(now, row.local_session_id);
|
|
216
|
-
if (!row.last_turn_id)
|
|
217
|
-
continue;
|
|
218
|
-
const snapshotRow = this.db
|
|
219
|
-
.prepare("SELECT snapshot_json FROM turn_snapshots WHERE turn_id = ?")
|
|
220
|
-
.get(row.last_turn_id);
|
|
221
|
-
if (!snapshotRow)
|
|
222
|
-
continue;
|
|
223
|
-
try {
|
|
224
|
-
const snapshot = JSON.parse(snapshotRow.snapshot_json);
|
|
225
|
-
if (!["starting", "running", "tool_running", "waiting_for_approval"].includes(String(snapshot.status)))
|
|
226
|
-
continue;
|
|
227
|
-
const startedAt = typeof snapshot.startedAt === "number" ? snapshot.startedAt : undefined;
|
|
228
|
-
const failedSnapshot = {
|
|
229
|
-
...snapshot,
|
|
230
|
-
status: "failed",
|
|
231
|
-
completedAt,
|
|
232
|
-
...(startedAt === undefined ? {} : { durationMs: Math.max(0, completedAt - startedAt) }),
|
|
233
|
-
error: "Agent Bot 已重启,原 ACP 进程中的执行无法继续。",
|
|
234
|
-
};
|
|
235
|
-
delete failedSnapshot.activeTool;
|
|
236
|
-
delete failedSnapshot.approval;
|
|
237
|
-
this.db.prepare(`
|
|
238
|
-
UPDATE turn_snapshots SET snapshot_json = ?, updated_at = ? WHERE turn_id = ?
|
|
239
|
-
`).run(JSON.stringify(failedSnapshot), now, row.last_turn_id);
|
|
240
|
-
}
|
|
241
|
-
catch {
|
|
242
|
-
// Keep an unreadable historical snapshot intact while still correcting the session state.
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
});
|
|
246
|
-
reconcile();
|
|
247
|
-
return rows.map(mapSession);
|
|
248
|
-
}
|
|
249
331
|
setDefaultAgent(contextKey, agentName) {
|
|
250
332
|
const now = new Date().toISOString();
|
|
251
333
|
this.db
|
|
@@ -317,6 +399,24 @@ export class StateStore {
|
|
|
317
399
|
`)
|
|
318
400
|
.run(patch.acpSessionId ?? existing.acpSessionId ?? null, patch.status ?? existing.status, now, localSessionId);
|
|
319
401
|
}
|
|
402
|
+
archiveSession(localSessionId) {
|
|
403
|
+
const now = new Date().toISOString();
|
|
404
|
+
const archive = this.db.transaction(() => {
|
|
405
|
+
this.db.prepare(`
|
|
406
|
+
UPDATE sessions
|
|
407
|
+
SET status = 'closed', updated_at = ?
|
|
408
|
+
WHERE local_session_id = ?
|
|
409
|
+
`).run(now, localSessionId);
|
|
410
|
+
this.db.prepare(`
|
|
411
|
+
UPDATE user_contexts
|
|
412
|
+
SET current_session_id = CASE WHEN current_session_id = ? THEN NULL ELSE current_session_id END,
|
|
413
|
+
previous_session_id = CASE WHEN previous_session_id = ? THEN NULL ELSE previous_session_id END,
|
|
414
|
+
updated_at = ?
|
|
415
|
+
WHERE current_session_id = ? OR previous_session_id = ?
|
|
416
|
+
`).run(localSessionId, localSessionId, now, localSessionId, localSessionId);
|
|
417
|
+
});
|
|
418
|
+
archive();
|
|
419
|
+
}
|
|
320
420
|
updateRuntimeSession(localSessionId, patch) {
|
|
321
421
|
const existing = this.getSession(localSessionId);
|
|
322
422
|
if (!existing) {
|
|
@@ -369,6 +469,27 @@ export class StateStore {
|
|
|
369
469
|
.get(turnId);
|
|
370
470
|
return row ? JSON.parse(row.snapshot_json) : undefined;
|
|
371
471
|
}
|
|
472
|
+
findLatestTurnSnapshotForSession(localSessionId) {
|
|
473
|
+
const row = this.db.prepare(`
|
|
474
|
+
SELECT turn_id, local_session_id, context_key, snapshot_json, updated_at
|
|
475
|
+
FROM turn_snapshots
|
|
476
|
+
WHERE local_session_id = ?
|
|
477
|
+
ORDER BY
|
|
478
|
+
coalesce(json_extract(snapshot_json, '$.startedAt'), 0) DESC,
|
|
479
|
+
updated_at DESC,
|
|
480
|
+
rowid DESC
|
|
481
|
+
LIMIT 1
|
|
482
|
+
`).get(localSessionId);
|
|
483
|
+
return row
|
|
484
|
+
? {
|
|
485
|
+
turnId: row.turn_id,
|
|
486
|
+
localSessionId: row.local_session_id,
|
|
487
|
+
contextKey: row.context_key ?? undefined,
|
|
488
|
+
snapshot: JSON.parse(row.snapshot_json),
|
|
489
|
+
updatedAt: row.updated_at,
|
|
490
|
+
}
|
|
491
|
+
: undefined;
|
|
492
|
+
}
|
|
372
493
|
saveTurnRuntimeOrigin(turnId, localSessionId, agentName, remoteSessionId) {
|
|
373
494
|
this.db.prepare(`
|
|
374
495
|
INSERT OR IGNORE INTO turn_runtime_origins (
|
|
@@ -642,6 +763,41 @@ export class StateStore {
|
|
|
642
763
|
.all();
|
|
643
764
|
return rows.map(mapSession);
|
|
644
765
|
}
|
|
766
|
+
listUndeliveredCompletedTurns() {
|
|
767
|
+
const rows = this.db.prepare(`
|
|
768
|
+
SELECT snapshots.turn_id, snapshots.local_session_id, snapshots.context_key
|
|
769
|
+
FROM turn_snapshots AS snapshots
|
|
770
|
+
LEFT JOIN turn_deliveries AS deliveries ON deliveries.turn_id = snapshots.turn_id
|
|
771
|
+
WHERE json_extract(snapshots.snapshot_json, '$.status') = 'completed'
|
|
772
|
+
AND length(coalesce(json_extract(snapshots.snapshot_json, '$.finalResponse'), '')) > 0
|
|
773
|
+
AND deliveries.final_delivered_at IS NULL
|
|
774
|
+
ORDER BY snapshots.updated_at ASC
|
|
775
|
+
`).all();
|
|
776
|
+
return rows.map((row) => ({
|
|
777
|
+
turnId: row.turn_id,
|
|
778
|
+
localSessionId: row.local_session_id,
|
|
779
|
+
contextKey: row.context_key ?? undefined,
|
|
780
|
+
}));
|
|
781
|
+
}
|
|
782
|
+
findMessageIdForTurn(turnId) {
|
|
783
|
+
const binding = this.db.prepare(`
|
|
784
|
+
SELECT message_id
|
|
785
|
+
FROM message_turn_bindings
|
|
786
|
+
WHERE turn_id = ?
|
|
787
|
+
ORDER BY updated_at DESC, rowid DESC
|
|
788
|
+
LIMIT 1
|
|
789
|
+
`).get(turnId);
|
|
790
|
+
if (binding)
|
|
791
|
+
return binding.message_id;
|
|
792
|
+
const reaction = this.db.prepare(`
|
|
793
|
+
SELECT message_id
|
|
794
|
+
FROM message_reactions
|
|
795
|
+
WHERE turn_id = ?
|
|
796
|
+
ORDER BY updated_at DESC, rowid DESC
|
|
797
|
+
LIMIT 1
|
|
798
|
+
`).get(turnId);
|
|
799
|
+
return reaction?.message_id;
|
|
800
|
+
}
|
|
645
801
|
findLatestMessageIdForSession(localSessionId, contextKey) {
|
|
646
802
|
const row = this.db.prepare(`
|
|
647
803
|
SELECT message_id
|
|
@@ -991,6 +1147,15 @@ export class StateStore {
|
|
|
991
1147
|
if (!existing.has("last_activity_at")) {
|
|
992
1148
|
this.db.exec("ALTER TABLE chat_contexts ADD COLUMN last_activity_at TEXT");
|
|
993
1149
|
}
|
|
1150
|
+
if (!existing.has("require_mention")) {
|
|
1151
|
+
this.db.exec("ALTER TABLE chat_contexts ADD COLUMN require_mention INTEGER NOT NULL DEFAULT 0");
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
ensureTurnAttemptColumns() {
|
|
1155
|
+
const existing = new Set(this.db.pragma("table_info(turn_attempts)").map((column) => column.name));
|
|
1156
|
+
if (!existing.has("retry_count")) {
|
|
1157
|
+
this.db.exec("ALTER TABLE turn_attempts ADD COLUMN retry_count INTEGER NOT NULL DEFAULT 0");
|
|
1158
|
+
}
|
|
994
1159
|
}
|
|
995
1160
|
}
|
|
996
1161
|
const MAX_TASK_TITLE_LENGTH = 120;
|
|
@@ -1018,6 +1183,16 @@ function mapUserContext(row) {
|
|
|
1018
1183
|
updatedAt: row.updated_at,
|
|
1019
1184
|
};
|
|
1020
1185
|
}
|
|
1186
|
+
function mapChatContext(row) {
|
|
1187
|
+
return {
|
|
1188
|
+
contextKey: row.context_key,
|
|
1189
|
+
chatType: row.chat_type,
|
|
1190
|
+
requiresMention: row.require_mention === 1,
|
|
1191
|
+
lastActivityAt: row.last_activity_at ?? undefined,
|
|
1192
|
+
createdAt: row.created_at,
|
|
1193
|
+
updatedAt: row.updated_at,
|
|
1194
|
+
};
|
|
1195
|
+
}
|
|
1021
1196
|
function mapSession(row) {
|
|
1022
1197
|
return {
|
|
1023
1198
|
localSessionId: row.local_session_id,
|
|
@@ -1068,4 +1243,30 @@ function mapQueuedPrompt(row) {
|
|
|
1068
1243
|
createdAt: row.created_at,
|
|
1069
1244
|
};
|
|
1070
1245
|
}
|
|
1246
|
+
function mapTurnAttempt(row) {
|
|
1247
|
+
const parsedPaths = JSON.parse(row.local_image_paths_json);
|
|
1248
|
+
const localImagePaths = Array.isArray(parsedPaths)
|
|
1249
|
+
? parsedPaths.filter((value) => typeof value === "string")
|
|
1250
|
+
: [];
|
|
1251
|
+
return {
|
|
1252
|
+
attemptId: row.attempt_id,
|
|
1253
|
+
localSessionId: row.local_session_id,
|
|
1254
|
+
contextKey: row.context_key,
|
|
1255
|
+
promptText: row.prompt_text,
|
|
1256
|
+
localImagePaths: localImagePaths.length > 0 ? localImagePaths : undefined,
|
|
1257
|
+
messageId: row.message_id ?? undefined,
|
|
1258
|
+
replyMessageId: row.reply_message_id ?? undefined,
|
|
1259
|
+
pendingTurnId: row.pending_turn_id ?? undefined,
|
|
1260
|
+
turnId: row.turn_id ?? undefined,
|
|
1261
|
+
recoveredFromTurnId: row.recovered_from_turn_id ?? undefined,
|
|
1262
|
+
recoveryCount: row.recovery_count,
|
|
1263
|
+
retryCount: row.retry_count,
|
|
1264
|
+
status: row.status,
|
|
1265
|
+
createdAt: row.created_at,
|
|
1266
|
+
updatedAt: row.updated_at,
|
|
1267
|
+
};
|
|
1268
|
+
}
|
|
1269
|
+
function isIncompleteTurnAttemptStatus(status) {
|
|
1270
|
+
return status === "accepted" || status === "running" || status === "recovering";
|
|
1271
|
+
}
|
|
1071
1272
|
//# sourceMappingURL=StateStore.js.map
|