@keyou007/agent-bot 0.1.19 → 0.1.20-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 +4 -0
- package/README.md +1 -1
- 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/feishu/CardRenderer.js +10 -6
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +28 -70
- package/dist/proxy/ProxySessionController.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/feishu/CardRenderer.ts +11 -7
- package/src/proxy/ProxySessionController.ts +30 -75
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keyou007/agent-bot",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.20-alpha.0",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@keyou007/agent-bot",
|
|
9
|
-
"version": "0.1.
|
|
9
|
+
"version": "0.1.20-alpha.0",
|
|
10
10
|
"license": "GPL-3.0-only",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@agentclientprotocol/sdk": "1.2.1",
|
package/package.json
CHANGED
|
@@ -74,9 +74,10 @@ agentbot task title "<title>"
|
|
|
74
74
|
- `prompt` posts the Prompt to the task's Feishu conversation before submitting it.
|
|
75
75
|
- `queue` creates a later turn instead of steering the active turn. `nosteer` is an alias.
|
|
76
76
|
- `stop` requests an Agent interrupt; it does not kill the Agent process.
|
|
77
|
+
- `release` sends a Lark confirmation card for releasing the Agent's shared App Server. It never releases automatically; the user must click **Release** or **Release Now** on the card.
|
|
77
78
|
- `dismiss --yes` irreversibly dissolves the task's current Feishu group and archives its current task. Use it only after the user explicitly confirms.
|
|
78
79
|
|
|
79
|
-
From Feishu, `/release`
|
|
80
|
+
From Feishu, `/release` sends a confirmation card for handing App Server tasks back to Codex Desktop without archiving them. It lists the current Agent's running and queued work and never releases automatically. **Release** confirms an idle release, **Release Now** interrupts active work and clears queued Prompts, and **Cancel** cancels the pending release. Because each App Server Agent is shared, releasing affects every task loaded by that Agent process.
|
|
80
81
|
|
|
81
82
|
Create or branch work in the same conversation:
|
|
82
83
|
|
package/src/cli/help.ts
CHANGED
|
@@ -45,7 +45,7 @@ export function renderCliHelp(version: string, language: CliLanguage = cliLangua
|
|
|
45
45
|
task shell [任务] <命令> 在任务目录执行本地命令
|
|
46
46
|
task stop [任务] 停止任务
|
|
47
47
|
task archive [任务] 归档任务
|
|
48
|
-
task release [任务]
|
|
48
|
+
task release [任务] 发送共享 App Server 释放确认卡片
|
|
49
49
|
task dismiss [任务] --yes 归档任务并解散其当前群聊
|
|
50
50
|
task title [任务] <标题> 重命名任务
|
|
51
51
|
task restart [任务] [--force] 从任务会话请求安全或立即重启
|
|
@@ -138,7 +138,7 @@ Task commands:
|
|
|
138
138
|
task shell [task] <command> Run a local command in the task directory
|
|
139
139
|
task stop [task] Stop a task
|
|
140
140
|
task archive [task] Archive a task
|
|
141
|
-
task release [task]
|
|
141
|
+
task release [task] Send a confirmation card to release the shared App Server
|
|
142
142
|
task dismiss [task] --yes Archive a task and dissolve its current group
|
|
143
143
|
task title [task] <title> Rename a task
|
|
144
144
|
task restart [task] [--force] Request a safe or immediate restart from a task
|
package/src/cli.ts
CHANGED
|
@@ -1337,15 +1337,14 @@ async function taskCommand(input: string[]): Promise<void> {
|
|
|
1337
1337
|
`App Server tasks released for ${released.agentName}.\n`,
|
|
1338
1338
|
`已释放 ${released.agentName} 的 App Server 任务。\n`,
|
|
1339
1339
|
));
|
|
1340
|
-
} else if (released.releaseInSeconds !== undefined) {
|
|
1341
|
-
process.stdout.write(cliText(
|
|
1342
|
-
`App Server release scheduled for ${released.agentName} in ${released.releaseInSeconds} seconds.\n`,
|
|
1343
|
-
`已安排在 ${released.releaseInSeconds} 秒后释放 ${released.agentName} 的 App Server。\n`,
|
|
1344
|
-
));
|
|
1345
1340
|
} else {
|
|
1346
1341
|
process.stdout.write(cliText(
|
|
1347
|
-
|
|
1348
|
-
|
|
1342
|
+
released.blockingTaskCount > 0
|
|
1343
|
+
? `App Server release card sent for ${released.agentName} (${released.blockingTaskCount} blocking). Confirm in Lark to release.\n`
|
|
1344
|
+
: `App Server release card sent for ${released.agentName}. Confirm in Lark to release.\n`,
|
|
1345
|
+
released.blockingTaskCount > 0
|
|
1346
|
+
? `已发送 ${released.agentName} 的 App Server 释放卡片(${released.blockingTaskCount} 个任务阻塞)。请在飞书中确认释放。\n`
|
|
1347
|
+
: `已发送 ${released.agentName} 的 App Server 释放卡片。请在飞书中确认释放。\n`,
|
|
1349
1348
|
));
|
|
1350
1349
|
}
|
|
1351
1350
|
return;
|
|
@@ -281,7 +281,7 @@ export interface AppServerReleaseCardView {
|
|
|
281
281
|
scheduleId: number;
|
|
282
282
|
agentName: string;
|
|
283
283
|
blockingTaskCount?: number;
|
|
284
|
-
|
|
284
|
+
blockingTaskTitles?: string[];
|
|
285
285
|
forced?: boolean;
|
|
286
286
|
error?: string;
|
|
287
287
|
}
|
|
@@ -405,16 +405,20 @@ export class CardRenderer {
|
|
|
405
405
|
}
|
|
406
406
|
|
|
407
407
|
const blockingTaskCount = Math.max(0, view.blockingTaskCount ?? 0);
|
|
408
|
-
const
|
|
409
|
-
|
|
408
|
+
const blockingTaskLines = (view.blockingTaskTitles ?? []).map((title, index) => {
|
|
409
|
+
const normalizedTitle = title.replace(/\s+/g, " ").trim() || "未命名任务";
|
|
410
|
+
return `${index + 1}. ${inlineCode(truncateText(normalizedTitle, 80))}`;
|
|
411
|
+
});
|
|
412
|
+
return sectionCard(blockingTaskCount > 0 ? "等待释放" : "确认释放", [
|
|
410
413
|
markdown([
|
|
411
414
|
`**Agent**:${agent}`,
|
|
412
415
|
blockingTaskCount > 0
|
|
413
416
|
? `**等待任务**:${blockingTaskCount}`
|
|
414
|
-
:
|
|
417
|
+
: "**状态**:可以释放",
|
|
418
|
+
...blockingTaskLines,
|
|
415
419
|
blockingTaskCount > 0
|
|
416
|
-
? ">
|
|
417
|
-
: ">
|
|
420
|
+
? "> 点击 **Release Now** 会中断执行;也可等待任务结束后再释放。"
|
|
421
|
+
: "> 点击 **Release** 释放,或取消。",
|
|
418
422
|
].join("\n")),
|
|
419
423
|
{
|
|
420
424
|
tag: "column_set",
|
|
@@ -428,7 +432,7 @@ export class CardRenderer {
|
|
|
428
432
|
vertical_align: "center",
|
|
429
433
|
elements: [{
|
|
430
434
|
tag: "button",
|
|
431
|
-
text: { tag: "plain_text", content: "Release Now" },
|
|
435
|
+
text: { tag: "plain_text", content: blockingTaskCount > 0 ? "Release Now" : "Release" },
|
|
432
436
|
type: "danger",
|
|
433
437
|
size: "small",
|
|
434
438
|
behaviors: [{
|
|
@@ -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
|
|
|
@@ -6974,7 +6970,6 @@ export class ProxySessionController {
|
|
|
6974
6970
|
agentName: string;
|
|
6975
6971
|
status: "waiting" | "released" | "failed";
|
|
6976
6972
|
blockingTaskCount: number;
|
|
6977
|
-
releaseInSeconds?: number;
|
|
6978
6973
|
error?: string;
|
|
6979
6974
|
}> {
|
|
6980
6975
|
const record = requestedRecord ?? this.requireCurrentSession(contextKey);
|
|
@@ -6986,20 +6981,17 @@ export class ProxySessionController {
|
|
|
6986
6981
|
let schedule = this.appServerReleaseSchedules.get(record.agentName);
|
|
6987
6982
|
const created = !schedule;
|
|
6988
6983
|
if (!schedule) {
|
|
6989
|
-
const
|
|
6984
|
+
const blockers = this.appServerReleaseBlockers(record.agentName, runtime);
|
|
6985
|
+
const blockingTaskCount = blockers.length;
|
|
6990
6986
|
schedule = {
|
|
6991
6987
|
id: this.nextAppServerReleaseScheduleId++,
|
|
6992
6988
|
agentName: record.agentName,
|
|
6993
6989
|
runtime,
|
|
6994
6990
|
status: "waiting",
|
|
6995
6991
|
blockingTaskCount,
|
|
6992
|
+
blockingTaskTitles: this.appServerReleaseTaskTitles(blockers),
|
|
6996
6993
|
targets: new Map(),
|
|
6997
6994
|
forced: false,
|
|
6998
|
-
...(blockingTaskCount === 0
|
|
6999
|
-
? {
|
|
7000
|
-
releaseCountdownSeconds: Math.ceil(APP_SERVER_RELEASE_IDLE_DELAY_MS / 1_000),
|
|
7001
|
-
}
|
|
7002
|
-
: {}),
|
|
7003
6995
|
};
|
|
7004
6996
|
this.appServerReleaseSchedules.set(record.agentName, schedule);
|
|
7005
6997
|
}
|
|
@@ -7012,14 +7004,6 @@ export class ProxySessionController {
|
|
|
7012
7004
|
if (messageId) {
|
|
7013
7005
|
schedule.targets.set(`${contextKey}\u0000${messageId}`, { contextKey, messageId });
|
|
7014
7006
|
}
|
|
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
7007
|
} catch (error) {
|
|
7024
7008
|
if (created && schedule.targets.size === 0) {
|
|
7025
7009
|
this.clearAppServerReleaseSchedule(schedule);
|
|
@@ -7032,9 +7016,6 @@ export class ProxySessionController {
|
|
|
7032
7016
|
agentName: schedule.agentName,
|
|
7033
7017
|
status: schedule.status === "failed" ? "failed" : schedule.status === "released" ? "released" : "waiting",
|
|
7034
7018
|
blockingTaskCount: schedule.blockingTaskCount,
|
|
7035
|
-
...(schedule.releaseCountdownSeconds !== undefined
|
|
7036
|
-
? { releaseInSeconds: schedule.releaseCountdownSeconds }
|
|
7037
|
-
: {}),
|
|
7038
7019
|
...(schedule.error ? { error: schedule.error } : {}),
|
|
7039
7020
|
};
|
|
7040
7021
|
}
|
|
@@ -7046,7 +7027,7 @@ export class ProxySessionController {
|
|
|
7046
7027
|
if (!Number.isSafeInteger(scheduleId) || !schedule || schedule.id !== scheduleId || schedule.status !== "waiting") {
|
|
7047
7028
|
throw new Error("释放卡片已失效,请重新发送 /release。");
|
|
7048
7029
|
}
|
|
7049
|
-
await this.performAppServerRelease(schedule
|
|
7030
|
+
await this.performAppServerRelease(schedule);
|
|
7050
7031
|
}
|
|
7051
7032
|
|
|
7052
7033
|
private async cancelAppServerRelease(action: CardAction): Promise<void> {
|
|
@@ -7081,6 +7062,10 @@ export class ProxySessionController {
|
|
|
7081
7062
|
});
|
|
7082
7063
|
}
|
|
7083
7064
|
|
|
7065
|
+
private appServerReleaseTaskTitles(blockers: SessionRecord[]): string[] {
|
|
7066
|
+
return blockers.map((session) => session.title?.trim() || "未命名任务");
|
|
7067
|
+
}
|
|
7068
|
+
|
|
7084
7069
|
private armAppServerReleaseCheck(schedule: AppServerReleaseSchedule): void {
|
|
7085
7070
|
if (schedule.status !== "waiting" || schedule.timer || schedule.inFlight) return;
|
|
7086
7071
|
schedule.timer = setTimeout(() => {
|
|
@@ -7095,36 +7080,22 @@ export class ProxySessionController {
|
|
|
7095
7080
|
|
|
7096
7081
|
private async refreshAppServerReleaseSchedule(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7097
7082
|
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
|
-
}
|
|
7083
|
+
const blockers = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime);
|
|
7084
|
+
const blockingTaskCount = blockers.length;
|
|
7085
|
+
const blockingTaskTitles = this.appServerReleaseTaskTitles(blockers);
|
|
7086
|
+
const titlesChanged = schedule.blockingTaskTitles.length !== blockingTaskTitles.length
|
|
7087
|
+
|| schedule.blockingTaskTitles.some((title, index) => title !== blockingTaskTitles[index]);
|
|
7088
|
+
if (schedule.blockingTaskCount !== blockingTaskCount || titlesChanged) {
|
|
7089
|
+
schedule.blockingTaskCount = blockingTaskCount;
|
|
7090
|
+
schedule.blockingTaskTitles = blockingTaskTitles;
|
|
7091
|
+
await this.publishAppServerReleaseSchedule(schedule);
|
|
7121
7092
|
}
|
|
7122
|
-
|
|
7093
|
+
this.armAppServerReleaseCheck(schedule);
|
|
7123
7094
|
}
|
|
7124
7095
|
|
|
7125
|
-
private async performAppServerRelease(schedule: AppServerReleaseSchedule
|
|
7096
|
+
private async performAppServerRelease(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7126
7097
|
if (schedule.inFlight) return schedule.inFlight;
|
|
7127
|
-
const operation = this.performAppServerReleaseNow(schedule
|
|
7098
|
+
const operation = this.performAppServerReleaseNow(schedule);
|
|
7128
7099
|
schedule.inFlight = operation;
|
|
7129
7100
|
try {
|
|
7130
7101
|
await operation;
|
|
@@ -7134,31 +7105,17 @@ export class ProxySessionController {
|
|
|
7134
7105
|
}
|
|
7135
7106
|
}
|
|
7136
7107
|
|
|
7137
|
-
private async performAppServerReleaseNow(schedule: AppServerReleaseSchedule
|
|
7108
|
+
private async performAppServerReleaseNow(schedule: AppServerReleaseSchedule): Promise<void> {
|
|
7138
7109
|
if (schedule.timer) {
|
|
7139
7110
|
clearTimeout(schedule.timer);
|
|
7140
7111
|
schedule.timer = undefined;
|
|
7141
7112
|
}
|
|
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
|
-
}
|
|
7113
|
+
const interruptedWork = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime).length > 0;
|
|
7114
|
+
await this.cancelQueuedPromptsForAppServerRelease(schedule.agentName);
|
|
7157
7115
|
|
|
7158
7116
|
schedule.status = "releasing";
|
|
7159
7117
|
schedule.blockingTaskCount = 0;
|
|
7160
|
-
schedule.
|
|
7161
|
-
schedule.releaseCountdownSeconds = undefined;
|
|
7118
|
+
schedule.blockingTaskTitles = [];
|
|
7162
7119
|
schedule.releaseStarted = false;
|
|
7163
7120
|
schedule.forced = interruptedWork;
|
|
7164
7121
|
await this.publishAppServerReleaseSchedule(schedule);
|
|
@@ -7168,18 +7125,18 @@ export class ProxySessionController {
|
|
|
7168
7125
|
) return;
|
|
7169
7126
|
schedule.releaseStarted = true;
|
|
7170
7127
|
try {
|
|
7171
|
-
const result = await schedule.runtime.release?.({ force });
|
|
7128
|
+
const result = await schedule.runtime.release?.({ force: true });
|
|
7172
7129
|
if (!result) throw new Error("当前 Agent 不支持释放 App Server。");
|
|
7173
7130
|
if (result.status === "busy") {
|
|
7131
|
+
const blockers = this.appServerReleaseBlockers(schedule.agentName, schedule.runtime);
|
|
7174
7132
|
schedule.status = "waiting";
|
|
7175
7133
|
schedule.blockingTaskCount = Math.max(
|
|
7176
7134
|
result.activeSessionIds?.length ?? 0,
|
|
7177
|
-
|
|
7135
|
+
blockers.length,
|
|
7178
7136
|
1,
|
|
7179
7137
|
);
|
|
7138
|
+
schedule.blockingTaskTitles = this.appServerReleaseTaskTitles(blockers);
|
|
7180
7139
|
schedule.forced = false;
|
|
7181
|
-
schedule.releaseAt = undefined;
|
|
7182
|
-
schedule.releaseCountdownSeconds = undefined;
|
|
7183
7140
|
schedule.releaseStarted = false;
|
|
7184
7141
|
await this.publishAppServerReleaseSchedule(schedule);
|
|
7185
7142
|
this.armAppServerReleaseCheck(schedule);
|
|
@@ -7239,9 +7196,7 @@ export class ProxySessionController {
|
|
|
7239
7196
|
scheduleId: schedule.id,
|
|
7240
7197
|
agentName: schedule.agentName,
|
|
7241
7198
|
...(schedule.blockingTaskCount > 0 ? { blockingTaskCount: schedule.blockingTaskCount } : {}),
|
|
7242
|
-
...(schedule.
|
|
7243
|
-
? { releaseInSeconds: schedule.releaseCountdownSeconds }
|
|
7244
|
-
: {}),
|
|
7199
|
+
...(schedule.blockingTaskTitles.length > 0 ? { blockingTaskTitles: schedule.blockingTaskTitles } : {}),
|
|
7245
7200
|
...(schedule.forced ? { forced: true } : {}),
|
|
7246
7201
|
...(schedule.error ? { error: schedule.error } : {}),
|
|
7247
7202
|
};
|