@keyou007/agent-bot 0.1.17-alpha.2 → 0.1.18-alpha.0
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 +9 -0
- package/dist/feishu/CardRenderer.js +6 -16
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/local-files/LocalFileViewerServer.js +519 -59
- package/dist/local-files/LocalFileViewerServer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +62 -9
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/startup/StartupNotifier.js +7 -4
- package/dist/startup/StartupNotifier.js.map +1 -1
- package/docs/technical-reference.md +2 -0
- package/docs/technical-reference.zh.md +2 -0
- package/npm-shrinkwrap.json +108 -2
- package/package.json +3 -1
- package/src/feishu/CardRenderer.ts +6 -22
- package/src/local-files/LocalFileViewerServer.ts +536 -61
- package/src/proxy/ProxySessionController.ts +68 -7
- package/src/startup/StartupNotifier.ts +9 -4
|
@@ -125,6 +125,7 @@ const SESSION_PROMPT_PREVIEW_LENGTH = 50;
|
|
|
125
125
|
const DIRECTORY_PAGE_SIZE = 15;
|
|
126
126
|
const RESET_HISTORY_PAGE_SIZE = 10;
|
|
127
127
|
const MAX_LLM_TURN_RETRIES = 3;
|
|
128
|
+
const QUEUED_PROMPT_RETRY_DELAY_MS = 5_000;
|
|
128
129
|
const RECOVERY_ACTIVITY_WINDOW_MS = 10 * 60 * 1_000;
|
|
129
130
|
const RECOVERY_HEARTBEAT_INTERVAL_MS = 60 * 1_000;
|
|
130
131
|
const SHELL_COMMAND_JOB_POLL_INTERVAL_MS = 1_000;
|
|
@@ -132,7 +133,7 @@ const SHELL_COMMAND_JOB_RELAUNCH_DELAY_MS = 5_000;
|
|
|
132
133
|
const FORWARD_ATTACHMENT_WINDOW_MS = 800;
|
|
133
134
|
const DEFAULT_MERGED_FORWARD_INSTRUCTION = "请参考以下内容回复用户";
|
|
134
135
|
const DEFAULT_REFERENCED_MESSAGE_INSTRUCTION = "请参考引用消息回复用户";
|
|
135
|
-
const TURN_STOP_REQUESTED_MESSAGE = "
|
|
136
|
+
const TURN_STOP_REQUESTED_MESSAGE = "已发送停止信号,任务会自动停止。";
|
|
136
137
|
const REMOTE_SESSION_REFERENCE_PREFIX = "agent-runtime:";
|
|
137
138
|
const WINDOWS_DRIVES_DIRECTORY = "agentbot://windows-drives";
|
|
138
139
|
const IMAGE_FILE_EXTENSIONS = new Set([
|
|
@@ -428,6 +429,7 @@ export class ProxySessionController {
|
|
|
428
429
|
private readonly threadInitializations = new Map<string, Promise<void>>();
|
|
429
430
|
private readonly llmRetryingSessions = new Set<string>();
|
|
430
431
|
private readonly retriedFailureTurnIds = new Set<string>();
|
|
432
|
+
private readonly queuedPromptRetryTimers = new Map<string, NodeJS.Timeout>();
|
|
431
433
|
private readonly recoveryRetryTimers = new Map<string, NodeJS.Timeout>();
|
|
432
434
|
private readonly pendingMergedForwards = new Map<string, PendingForwardAttachment>();
|
|
433
435
|
private readonly pendingResourceForwards = new Map<string, PendingForwardAttachment>();
|
|
@@ -1097,6 +1099,8 @@ export class ProxySessionController {
|
|
|
1097
1099
|
for (const pending of this.pendingResourceForwards.values()) pending.resolveAttachment(undefined);
|
|
1098
1100
|
this.pendingResourceForwards.clear();
|
|
1099
1101
|
this.relatedReactionMessageIds.clear();
|
|
1102
|
+
for (const timer of this.queuedPromptRetryTimers.values()) clearTimeout(timer);
|
|
1103
|
+
this.queuedPromptRetryTimers.clear();
|
|
1100
1104
|
for (const timer of this.recoveryRetryTimers.values()) clearTimeout(timer);
|
|
1101
1105
|
this.recoveryRetryTimers.clear();
|
|
1102
1106
|
for (const [jobId] of this.shellCommandJobMonitors) this.stopShellCommandJobMonitor(jobId);
|
|
@@ -1753,7 +1757,7 @@ export class ProxySessionController {
|
|
|
1753
1757
|
}
|
|
1754
1758
|
switch (command.type) {
|
|
1755
1759
|
case "shell":
|
|
1756
|
-
await this.runShellCommand(contextKey, command.command, messageId);
|
|
1760
|
+
await this.runShellCommand(contextKey, command.command, messageId, incomingMessage);
|
|
1757
1761
|
return;
|
|
1758
1762
|
case "dir":
|
|
1759
1763
|
await this.openDirectoryBrowser(contextKey, command.directory);
|
|
@@ -3993,6 +3997,11 @@ export class ProxySessionController {
|
|
|
3993
3997
|
}
|
|
3994
3998
|
|
|
3995
3999
|
private scheduleNextQueuedPrompt(sessionId: string): Promise<void> {
|
|
4000
|
+
const retryTimer = this.queuedPromptRetryTimers.get(sessionId);
|
|
4001
|
+
if (retryTimer) {
|
|
4002
|
+
clearTimeout(retryTimer);
|
|
4003
|
+
this.queuedPromptRetryTimers.delete(sessionId);
|
|
4004
|
+
}
|
|
3996
4005
|
const previous = this.queuedPromptStarts.get(sessionId) ?? Promise.resolve();
|
|
3997
4006
|
const next = previous.catch(() => undefined).then(() => this.startNextQueuedPromptIfIdle(sessionId));
|
|
3998
4007
|
this.queuedPromptStarts.set(sessionId, next);
|
|
@@ -4001,6 +4010,23 @@ export class ProxySessionController {
|
|
|
4001
4010
|
});
|
|
4002
4011
|
}
|
|
4003
4012
|
|
|
4013
|
+
private scheduleQueuedPromptRetry(sessionId: string): void {
|
|
4014
|
+
if (this.queuedPromptRetryTimers.has(sessionId)) return;
|
|
4015
|
+
if (this.store.countQueuedPrompts(sessionId) === 0) return;
|
|
4016
|
+
const timer = setTimeout(() => {
|
|
4017
|
+
this.queuedPromptRetryTimers.delete(sessionId);
|
|
4018
|
+
void this.scheduleNextQueuedPrompt(sessionId).catch((error: unknown) => {
|
|
4019
|
+
this.logger.warn(
|
|
4020
|
+
{ error, errorMessage: runtimeErrorMessage(error), sessionId },
|
|
4021
|
+
"Failed to retry queued prompt start.",
|
|
4022
|
+
);
|
|
4023
|
+
this.scheduleQueuedPromptRetry(sessionId);
|
|
4024
|
+
});
|
|
4025
|
+
}, QUEUED_PROMPT_RETRY_DELAY_MS);
|
|
4026
|
+
timer.unref?.();
|
|
4027
|
+
this.queuedPromptRetryTimers.set(sessionId, timer);
|
|
4028
|
+
}
|
|
4029
|
+
|
|
4004
4030
|
private async startNextQueuedPromptIfIdle(sessionId: string): Promise<void> {
|
|
4005
4031
|
if (this.store.countQueuedPrompts(sessionId) === 0) return;
|
|
4006
4032
|
const baseRecord = this.store.getSession(sessionId);
|
|
@@ -4028,10 +4054,22 @@ export class ProxySessionController {
|
|
|
4028
4054
|
);
|
|
4029
4055
|
if (prompt.messageId) await this.bindMessageReactionToTurn(prompt.messageId, sessionId, turnId);
|
|
4030
4056
|
} catch (error) {
|
|
4031
|
-
this.logger.warn(
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4057
|
+
this.logger.warn(
|
|
4058
|
+
{
|
|
4059
|
+
error,
|
|
4060
|
+
errorMessage: runtimeErrorMessage(error),
|
|
4061
|
+
phase: prompt ? "start" : "preflight",
|
|
4062
|
+
sessionId,
|
|
4063
|
+
},
|
|
4064
|
+
"Failed to start queued prompt.",
|
|
4065
|
+
);
|
|
4066
|
+
if (!prompt) {
|
|
4067
|
+
this.scheduleQueuedPromptRetry(sessionId);
|
|
4068
|
+
return;
|
|
4069
|
+
}
|
|
4070
|
+
if (prompt.messageId) await this.finalizeStandaloneMessageReaction(prompt.messageId, "failed");
|
|
4071
|
+
await this.sendError(prompt.contextKey, error);
|
|
4072
|
+
if (this.store.countQueuedPrompts(sessionId) > 0) {
|
|
4035
4073
|
queueMicrotask(() => void this.scheduleNextQueuedPrompt(sessionId));
|
|
4036
4074
|
}
|
|
4037
4075
|
}
|
|
@@ -4925,8 +4963,9 @@ export class ProxySessionController {
|
|
|
4925
4963
|
contextKey: string,
|
|
4926
4964
|
command: string,
|
|
4927
4965
|
sourceMessageId?: string,
|
|
4966
|
+
incomingMessage?: IncomingMessage,
|
|
4928
4967
|
): Promise<void> {
|
|
4929
|
-
const cwd = this.
|
|
4968
|
+
const cwd = this.shellCommandCwd(contextKey, incomingMessage);
|
|
4930
4969
|
const created = await this.shellCommandJobs.createJob({ contextKey, sourceMessageId, command, cwd });
|
|
4931
4970
|
let cardMessageId: string | undefined;
|
|
4932
4971
|
const initialState: ShellCommandCardView = {
|
|
@@ -4972,6 +5011,28 @@ export class ProxySessionController {
|
|
|
4972
5011
|
}
|
|
4973
5012
|
}
|
|
4974
5013
|
|
|
5014
|
+
private shellCommandCwd(contextKey: string, incomingMessage?: IncomingMessage): string {
|
|
5015
|
+
const current = this.currentSession(contextKey);
|
|
5016
|
+
if (current) return current.cwd;
|
|
5017
|
+
|
|
5018
|
+
if (incomingMessage?.threadContext) {
|
|
5019
|
+
const anchor = threadForkAnchorMessageIds(incomingMessage)
|
|
5020
|
+
.map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
|
|
5021
|
+
.find((candidate) => candidate !== undefined);
|
|
5022
|
+
const source = anchor?.contextKey
|
|
5023
|
+
? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
|
|
5024
|
+
: anchor
|
|
5025
|
+
? this.store.getSession(anchor.localSessionId)
|
|
5026
|
+
: undefined;
|
|
5027
|
+
const sourceContextKey = anchor?.contextKey ?? source?.contextKey;
|
|
5028
|
+
if (source && sourceContextKey && baseChatContextKey(sourceContextKey) === baseChatContextKey(contextKey)) {
|
|
5029
|
+
return source.cwd;
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
|
|
5033
|
+
return this.config.defaults.cwd;
|
|
5034
|
+
}
|
|
5035
|
+
|
|
4975
5036
|
private monitorShellCommandJob(
|
|
4976
5037
|
job: ShellCommandJobSnapshot,
|
|
4977
5038
|
seededState?: ShellCommandCardView,
|
|
@@ -48,8 +48,13 @@ export class StartupNotifier {
|
|
|
48
48
|
.filter((chat) => !isThreadContextKey(chat.contextKey))
|
|
49
49
|
.map((chat) => [chat.contextKey, chat]),
|
|
50
50
|
);
|
|
51
|
+
const knownPrivateChats = new Map(
|
|
52
|
+
this.store.listChatContexts("p2p")
|
|
53
|
+
.filter((chat) => !isThreadContextKey(chat.contextKey))
|
|
54
|
+
.map((chat) => [chat.contextKey, chat]),
|
|
55
|
+
);
|
|
51
56
|
const targetsByContext = new Map<string, StartupNotificationTarget>();
|
|
52
|
-
for (const chat of
|
|
57
|
+
for (const chat of knownPrivateChats.values()) {
|
|
53
58
|
targetsByContext.set(chat.contextKey, {
|
|
54
59
|
contextKey: chat.contextKey,
|
|
55
60
|
context: this.store.getUserContext(chat.contextKey),
|
|
@@ -71,10 +76,11 @@ export class StartupNotifier {
|
|
|
71
76
|
if (!contextKey) continue;
|
|
72
77
|
if (isThreadContextKey(contextKey)) {
|
|
73
78
|
const baseContextKey = baseChatContextKey(contextKey);
|
|
74
|
-
|
|
79
|
+
const parentChat = knownGroups.get(baseContextKey) ?? knownPrivateChats.get(baseContextKey);
|
|
80
|
+
if (!parentChat) continue;
|
|
75
81
|
const replyMessageId = target.replyMessageId?.trim();
|
|
76
82
|
if (replyMessageId) {
|
|
77
|
-
if (!explicitBaseContextKeys.has(baseContextKey)) {
|
|
83
|
+
if (parentChat.chatType === "group" && !explicitBaseContextKeys.has(baseContextKey)) {
|
|
78
84
|
targetsByContext.delete(baseContextKey);
|
|
79
85
|
}
|
|
80
86
|
targetsByContext.set(contextKey, {
|
|
@@ -83,7 +89,6 @@ export class StartupNotifier {
|
|
|
83
89
|
context: this.store.getUserContext(contextKey),
|
|
84
90
|
});
|
|
85
91
|
} else {
|
|
86
|
-
const group = knownGroups.get(baseContextKey)!;
|
|
87
92
|
targetsByContext.set(baseContextKey, {
|
|
88
93
|
contextKey: baseContextKey,
|
|
89
94
|
context: this.store.getUserContext(baseContextKey),
|