@keyou007/agent-bot 0.1.14-alpha.2 → 0.1.14
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/README.md +7 -4
- package/README.zh.md +7 -4
- package/dist/cli/FeishuAppConfiguration.js +4 -0
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/controlProtocol.js.map +1 -1
- package/dist/cli/help.js +2 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli.js +18 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/CommandRouter.js +9 -0
- package/dist/commands/CommandRouter.js.map +1 -1
- package/dist/feishu/CardRenderer.js +94 -15
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/feishu/FeishuMessageClient.js +16 -0
- package/dist/feishu/FeishuMessageClient.js.map +1 -1
- package/dist/feishu/FeishuTurnPresenter.js +42 -6
- package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/presentation/OutboundRouter.js +7 -0
- package/dist/presentation/OutboundRouter.js.map +1 -1
- package/dist/presentation/TurnStateReducer.js +21 -7
- package/dist/presentation/TurnStateReducer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +102 -2
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/state/StateStore.js +35 -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 -0
- package/src/cli/FeishuAppConfiguration.ts +4 -0
- package/src/cli/controlProtocol.ts +8 -0
- package/src/cli/help.ts +2 -0
- package/src/cli.ts +28 -0
- package/src/commands/CommandRouter.ts +8 -0
- package/src/commands/commandTypes.ts +1 -0
- package/src/feishu/CardRenderer.ts +114 -12
- package/src/feishu/FeishuMessageClient.ts +33 -0
- package/src/feishu/FeishuTurnPresenter.ts +43 -6
- package/src/feishu/types.ts +1 -0
- package/src/index.ts +2 -0
- package/src/presentation/OutboundRouter.ts +7 -0
- package/src/presentation/TurnStateReducer.ts +21 -7
- package/src/proxy/ProxySessionController.ts +131 -3
- package/src/state/StateStore.ts +37 -0
|
@@ -76,6 +76,7 @@ const HELP_COMMAND_SECTIONS = [
|
|
|
76
76
|
usage: "[序号或任务 ID]",
|
|
77
77
|
description: "归档当前或指定任务",
|
|
78
78
|
},
|
|
79
|
+
{ command: "/dismiss", description: "归档当前任务并解散当前群" },
|
|
79
80
|
{
|
|
80
81
|
command: "/switch",
|
|
81
82
|
usage: "[序号或任务 ID]",
|
|
@@ -273,7 +274,7 @@ export class ProxySessionController {
|
|
|
273
274
|
if (isQueueIndependentCommand(command)) {
|
|
274
275
|
await this.outbound.withReplyTarget(message.contextKey, replyTarget, async () => {
|
|
275
276
|
try {
|
|
276
|
-
if (command.type !== "forkgroup")
|
|
277
|
+
if (command.type !== "forkgroup" && command.type !== "dismiss")
|
|
277
278
|
await this.ensureThreadFork(message);
|
|
278
279
|
await this.execute(message.contextKey, command, message.messageId, replyTarget, localImagePaths, message.userId, message);
|
|
279
280
|
if (!isPromptCommand(command))
|
|
@@ -426,6 +427,14 @@ export class ProxySessionController {
|
|
|
426
427
|
});
|
|
427
428
|
await this.refreshSessionsCardFromAction(scopedAction);
|
|
428
429
|
}
|
|
430
|
+
else if (kind === "group_dismiss_keep") {
|
|
431
|
+
this.assertDismissGroupRequester(scopedAction);
|
|
432
|
+
await this.outbound.updateInteractiveCard(contextKey, requiredCardMessageId(scopedAction.messageId), this.cardRenderer.renderDismissGroupKept());
|
|
433
|
+
}
|
|
434
|
+
else if (kind === "group_dismiss_confirm") {
|
|
435
|
+
this.assertDismissGroupRequester(scopedAction);
|
|
436
|
+
await this.dismissGroupAndArchiveTask(contextKey, String(scopedAction.value.sessionId ?? ""), "command");
|
|
437
|
+
}
|
|
429
438
|
else if (kind === "session_stop") {
|
|
430
439
|
const sessionId = String(scopedAction.value.sessionId ?? "");
|
|
431
440
|
await this.stopSessionReference(contextKey, sessionId);
|
|
@@ -577,6 +586,12 @@ export class ProxySessionController {
|
|
|
577
586
|
source: "cli",
|
|
578
587
|
});
|
|
579
588
|
}
|
|
589
|
+
async controlDismissTask(localSessionId) {
|
|
590
|
+
const record = this.store.getSession(localSessionId);
|
|
591
|
+
if (!record)
|
|
592
|
+
throw new Error(`Task not found: ${localSessionId}`);
|
|
593
|
+
return this.dismissGroupAndArchiveTask(this.controlSessionContextKey(record), localSessionId, "cli");
|
|
594
|
+
}
|
|
580
595
|
async controlGetTaskStatus(localSessionId) {
|
|
581
596
|
const record = this.store.getSession(localSessionId);
|
|
582
597
|
if (!record)
|
|
@@ -1114,6 +1129,9 @@ export class ProxySessionController {
|
|
|
1114
1129
|
});
|
|
1115
1130
|
return;
|
|
1116
1131
|
}
|
|
1132
|
+
case "dismiss":
|
|
1133
|
+
await this.openDismissGroupCard(contextKey, userId);
|
|
1134
|
+
return;
|
|
1117
1135
|
case "status":
|
|
1118
1136
|
await this.status(contextKey, command.sessionId);
|
|
1119
1137
|
return;
|
|
@@ -3875,6 +3893,88 @@ export class ProxySessionController {
|
|
|
3875
3893
|
title,
|
|
3876
3894
|
};
|
|
3877
3895
|
}
|
|
3896
|
+
async openDismissGroupCard(contextKey, userId) {
|
|
3897
|
+
const groupContextKey = this.dismissibleGroupContextKey(contextKey);
|
|
3898
|
+
if (!userId)
|
|
3899
|
+
throw new Error("无法识别当前用户,不能发起解散群操作。");
|
|
3900
|
+
const session = this.requireCurrentSession(groupContextKey);
|
|
3901
|
+
await this.outbound.sendInteractiveCard(groupContextKey, this.cardRenderer.renderDismissGroupConfirmation({
|
|
3902
|
+
contextKey: groupContextKey,
|
|
3903
|
+
sessionId: session.localSessionId,
|
|
3904
|
+
taskTitle: session.title ?? session.remoteSessionId ?? session.localSessionId,
|
|
3905
|
+
requestedBy: userId,
|
|
3906
|
+
}));
|
|
3907
|
+
}
|
|
3908
|
+
assertDismissGroupRequester(action) {
|
|
3909
|
+
const requestedBy = String(action.value.requestedBy ?? "");
|
|
3910
|
+
if (!requestedBy || !action.userId || action.userId !== requestedBy) {
|
|
3911
|
+
throw new Error("只有发起解散操作的用户可以点击这张卡片。");
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
async dismissGroupAndArchiveTask(contextKey, localSessionId, source) {
|
|
3915
|
+
const groupContextKey = this.dismissibleGroupContextKey(contextKey);
|
|
3916
|
+
const session = this.store.getSessionForContext(localSessionId, groupContextKey);
|
|
3917
|
+
if (!session)
|
|
3918
|
+
throw new Error("解散群卡片已失效,请重新发送 /dismiss。");
|
|
3919
|
+
const currentSessionId = this.store.getUserContext(groupContextKey)?.currentSessionId;
|
|
3920
|
+
if (session.status !== "closed" && currentSessionId !== localSessionId) {
|
|
3921
|
+
throw new Error("当前任务已经切换,解散群卡片已失效,请重新发送 /dismiss。");
|
|
3922
|
+
}
|
|
3923
|
+
this.assertNoOtherActiveGroupTasks(groupContextKey, localSessionId);
|
|
3924
|
+
const archived = session.status === "closed"
|
|
3925
|
+
? {
|
|
3926
|
+
localSessionId: session.localSessionId,
|
|
3927
|
+
remoteSessionId: session.remoteSessionId ?? session.acpSessionId ?? "",
|
|
3928
|
+
title: session.title ?? session.remoteSessionId ?? session.localSessionId,
|
|
3929
|
+
}
|
|
3930
|
+
: await this.archiveSessionReference(groupContextKey, localSessionId, {
|
|
3931
|
+
announce: false,
|
|
3932
|
+
source: "dismiss",
|
|
3933
|
+
});
|
|
3934
|
+
const chatId = groupContextKey.slice("chat_id:".length);
|
|
3935
|
+
try {
|
|
3936
|
+
await this.outbound.deleteGroup(groupContextKey, chatId);
|
|
3937
|
+
}
|
|
3938
|
+
catch (error) {
|
|
3939
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
3940
|
+
throw new Error(`当前任务已归档,但解散群失败:${message}`);
|
|
3941
|
+
}
|
|
3942
|
+
const detachedSessionIds = this.store.removeChatContext(groupContextKey);
|
|
3943
|
+
for (const detachedSessionId of detachedSessionIds) {
|
|
3944
|
+
const linked = this.store.getSession(detachedSessionId);
|
|
3945
|
+
const routedContextKey = this.outbound.getSessionContextKey(detachedSessionId) ?? linked?.contextKey;
|
|
3946
|
+
if (routedContextKey && baseChatContextKey(routedContextKey) === groupContextKey) {
|
|
3947
|
+
this.outbound.unregisterSession(detachedSessionId);
|
|
3948
|
+
}
|
|
3949
|
+
}
|
|
3950
|
+
this.store.audit(groupContextKey, "group_dismissed", {
|
|
3951
|
+
chatId,
|
|
3952
|
+
localSessionId,
|
|
3953
|
+
remoteSessionId: archived.remoteSessionId,
|
|
3954
|
+
source,
|
|
3955
|
+
});
|
|
3956
|
+
return { ...archived, chatId };
|
|
3957
|
+
}
|
|
3958
|
+
assertNoOtherActiveGroupTasks(contextKey, dismissedSessionId) {
|
|
3959
|
+
const active = this.store.listSessionsForChat(contextKey).find((session) => (session.localSessionId !== dismissedSessionId
|
|
3960
|
+
&& session.status !== "closed"
|
|
3961
|
+
&& (session.status === "running"
|
|
3962
|
+
|| Boolean(this.runtimes.forAgent(session.agentName).getSession(session.localSessionId)?.activeTurnId)
|
|
3963
|
+
|| this.store.countQueuedPrompts(session.localSessionId) > 0)));
|
|
3964
|
+
if (active) {
|
|
3965
|
+
throw new Error(`群内任务仍在执行或有排队消息,暂时不能解散:${active.title ?? active.localSessionId}`);
|
|
3966
|
+
}
|
|
3967
|
+
}
|
|
3968
|
+
dismissibleGroupContextKey(contextKey) {
|
|
3969
|
+
if (isThreadContextKey(contextKey)) {
|
|
3970
|
+
throw new Error("/dismiss 不能在话题中使用,请回到群聊正文后重试。");
|
|
3971
|
+
}
|
|
3972
|
+
const groupContextKey = baseChatContextKey(contextKey);
|
|
3973
|
+
if (!groupContextKey.startsWith("chat_id:") || this.store.getChatContext(groupContextKey)?.chatType !== "group") {
|
|
3974
|
+
throw new Error("/dismiss 仅适用于普通群聊。");
|
|
3975
|
+
}
|
|
3976
|
+
return groupContextKey;
|
|
3977
|
+
}
|
|
3878
3978
|
resolveSessionReference(contextKey, reference) {
|
|
3879
3979
|
if (reference === undefined) {
|
|
3880
3980
|
const previous = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent).previousSessionId;
|
|
@@ -4700,7 +4800,7 @@ function isBotOwnedActiveTurn(record, remote) {
|
|
|
4700
4800
|
&& record.lastTurnId === remote.lastTurnId;
|
|
4701
4801
|
}
|
|
4702
4802
|
function isQueueIndependentCommand(command) {
|
|
4703
|
-
if (["archive", "stop", "status", "restart", "mute", "help", "sessions", "dir", "goal", "nosteer"].includes(command.type))
|
|
4803
|
+
if (["archive", "dismiss", "stop", "status", "restart", "mute", "help", "sessions", "dir", "goal", "nosteer"].includes(command.type))
|
|
4704
4804
|
return true;
|
|
4705
4805
|
if (command.type === "agent")
|
|
4706
4806
|
return command.agent === undefined;
|