@keyou007/agent-bot 0.1.11 → 0.1.13-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/.env.example +1 -1
- package/CHANGELOG.md +19 -0
- package/README.md +63 -44
- package/README.zh.md +63 -44
- package/config.example.yaml +8 -22
- package/dist/cli/AgentPrerequisites.js +262 -0
- package/dist/cli/AgentPrerequisites.js.map +1 -0
- package/dist/cli/DefaultAgentSelection.js +47 -0
- package/dist/cli/DefaultAgentSelection.js.map +1 -0
- package/dist/cli/FeishuAppConfiguration.js +1 -1
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/FeishuAppRegistration.js +2 -2
- package/dist/cli/FeishuAppRegistration.js.map +1 -1
- package/dist/cli/Initializer.js +166 -3
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/ServerStarter.js +7 -2
- package/dist/cli/ServerStarter.js.map +1 -1
- package/dist/cli/controlProtocol.js.map +1 -1
- package/dist/cli/help.js +24 -20
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/taskGroupOptions.js +95 -0
- package/dist/cli/taskGroupOptions.js.map +1 -0
- package/dist/cli.js +268 -6
- package/dist/cli.js.map +1 -1
- package/dist/codex/AppServerConnection.js +3 -3
- package/dist/codex/AppServerConnection.js.map +1 -1
- package/dist/codex/CodexProcessManager.js +4 -4
- package/dist/codex/CodexProcessManager.js.map +1 -1
- package/dist/codex/CodexRuntime.js +63 -25
- package/dist/codex/CodexRuntime.js.map +1 -1
- package/dist/config/loadConfig.js +8 -22
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/config/schema.js +6 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/console/ConsoleConnector.js +3 -3
- package/dist/console/ConsoleConnector.js.map +1 -1
- package/dist/console/ConsoleTurnPresenter.js +14 -7
- package/dist/console/ConsoleTurnPresenter.js.map +1 -1
- package/dist/deprecated-cli.js +5 -0
- package/dist/deprecated-cli.js.map +1 -0
- package/dist/feishu/CardRenderer.js +13 -12
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/feishu/FeishuTurnPresenter.js +9 -5
- package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
- package/dist/feishu/transport.js +1 -1
- package/dist/feishu/transport.js.map +1 -1
- package/dist/index.js +21 -3
- package/dist/index.js.map +1 -1
- package/dist/presentation/OutboundRouter.js +2 -2
- package/dist/presentation/OutboundRouter.js.map +1 -1
- package/dist/presentation/TurnStateReducer.js +2 -1
- package/dist/presentation/TurnStateReducer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +128 -72
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/runtime/AcpRuntimeAdapter.js +3 -2
- package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
- package/dist/runtime/createAgentRuntimeRegistry.js +1 -1
- package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -1
- package/dist/supervision/systemEnvironment.js +129 -0
- package/dist/supervision/systemEnvironment.js.map +1 -0
- package/dist/supervisor.js +13 -1
- package/dist/supervisor.js.map +1 -1
- package/docs/technical-reference.md +53 -34
- package/docs/technical-reference.zh.md +53 -34
- package/npm-shrinkwrap.json +4 -3
- package/package.json +9 -4
- package/skills/agent-bot/SKILL.md +72 -33
- package/src/cli/AgentPrerequisites.ts +377 -0
- package/src/cli/DefaultAgentSelection.ts +56 -0
- package/src/cli/FeishuAppConfiguration.ts +2 -2
- package/src/cli/FeishuAppRegistration.ts +4 -4
- package/src/cli/Initializer.ts +206 -5
- package/src/cli/ServerStarter.ts +8 -3
- package/src/cli/controlProtocol.ts +21 -1
- package/src/cli/help.ts +24 -20
- package/src/cli/taskGroupOptions.ts +149 -0
- package/src/cli.ts +391 -9
- package/src/codex/AppServerConnection.ts +3 -3
- package/src/codex/CodexProcessManager.ts +4 -4
- package/src/codex/CodexRuntime.ts +84 -31
- package/src/config/loadConfig.ts +8 -22
- package/src/config/schema.ts +7 -1
- package/src/console/ConsoleConnector.ts +3 -3
- package/src/console/ConsoleTurnPresenter.ts +20 -7
- package/src/deprecated-cli.ts +9 -0
- package/src/feishu/CardRenderer.ts +13 -12
- package/src/feishu/FeishuTurnPresenter.ts +15 -1
- package/src/feishu/transport.ts +1 -1
- package/src/index.ts +34 -3
- package/src/presentation/OutboundRouter.ts +15 -3
- package/src/presentation/TurnStateReducer.ts +2 -0
- package/src/presentation/turnViewTypes.ts +1 -0
- package/src/proxy/ProxySessionController.ts +217 -73
- package/src/runtime/AcpRuntimeAdapter.ts +3 -1
- package/src/runtime/createAgentRuntimeRegistry.ts +1 -1
- package/src/supervision/systemEnvironment.ts +174 -0
- package/src/supervisor.ts +12 -1
|
@@ -375,7 +375,7 @@ export class ProxySessionController {
|
|
|
375
375
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
376
376
|
}
|
|
377
377
|
catch (error) {
|
|
378
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect
|
|
378
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect App Server task status for CLI.");
|
|
379
379
|
}
|
|
380
380
|
}
|
|
381
381
|
}
|
|
@@ -438,7 +438,7 @@ export class ProxySessionController {
|
|
|
438
438
|
?? { ...record, contextKey: responseContextKey };
|
|
439
439
|
const previous = this.messageQueues.get(responseContextKey) ?? Promise.resolve();
|
|
440
440
|
const next = previous.catch(() => undefined).then(async () => {
|
|
441
|
-
this.outbound.registerSession(scopedRecord.localSessionId, responseContextKey, scopedRecord.title, scopedRecord.cwd);
|
|
441
|
+
this.outbound.registerSession(scopedRecord.localSessionId, responseContextKey, scopedRecord.title, scopedRecord.cwd, this.agentLabel(scopedRecord.agentName));
|
|
442
442
|
const promptMessageId = await this.outbound.withReplyTarget(responseContextKey, existingReplyTarget, () => this.outbound.sendText(responseContextKey, promptText));
|
|
443
443
|
const turnReplyTarget = isThreadContextKey(responseContextKey)
|
|
444
444
|
? promptMessageId
|
|
@@ -461,6 +461,57 @@ export class ProxySessionController {
|
|
|
461
461
|
}
|
|
462
462
|
return `The Prompt was posted to the original chat and submitted to the task: ${record.title ?? record.remoteSessionId ?? record.localSessionId}`;
|
|
463
463
|
}
|
|
464
|
+
async controlCreateTaskGroup(localSessionId, requestedTitle, userOpenId, requestedProjectCwd, forceProjectless = false, requestedAgentName) {
|
|
465
|
+
const source = this.store.getSession(localSessionId);
|
|
466
|
+
if (!source || source.status === "closed")
|
|
467
|
+
throw new Error(`Task not found: ${localSessionId}`);
|
|
468
|
+
const agentName = requestedAgentName?.trim() || source.agentName;
|
|
469
|
+
const agent = this.ensureAgent(agentName);
|
|
470
|
+
if (forceProjectless && agent.kind !== "app-server") {
|
|
471
|
+
throw new Error("task newgroup --nodir is only available for App Server agents.");
|
|
472
|
+
}
|
|
473
|
+
const sourceContextKey = this.outbound.getSessionContextKey(localSessionId) ?? source.contextKey;
|
|
474
|
+
const replyTarget = this.outbound.getSessionReplyTarget(localSessionId);
|
|
475
|
+
const boundProjectCwd = forceProjectless
|
|
476
|
+
? undefined
|
|
477
|
+
: requestedProjectCwd === undefined
|
|
478
|
+
? detectProjectlessWorkspace(source.cwd) ? undefined : source.cwd
|
|
479
|
+
: resolveUserPath(requestedProjectCwd);
|
|
480
|
+
const created = await this.outbound.withReplyTarget(sourceContextKey, replyTarget, () => this.createFeishuGroupWithTask(sourceContextKey, agentName, requestedTitle, userOpenId, boundProjectCwd, source.agentName === agentName
|
|
481
|
+
? {
|
|
482
|
+
modelProvider: source.modelProvider,
|
|
483
|
+
model: source.model,
|
|
484
|
+
reasoningEffort: source.reasoningEffort,
|
|
485
|
+
permissionMode: source.permissionMode,
|
|
486
|
+
}
|
|
487
|
+
: {}));
|
|
488
|
+
return {
|
|
489
|
+
sourceLocalSessionId: source.localSessionId,
|
|
490
|
+
group: created.group,
|
|
491
|
+
task: created.task,
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
async controlForkTaskGroup(localSessionId, requestedTitle, userOpenId) {
|
|
495
|
+
const source = this.store.getSession(localSessionId);
|
|
496
|
+
if (!source || source.status === "closed")
|
|
497
|
+
throw new Error(`Task not found: ${localSessionId}`);
|
|
498
|
+
const sourceContextKey = this.outbound.getSessionContextKey(localSessionId) ?? source.contextKey;
|
|
499
|
+
const replyTarget = this.outbound.getSessionReplyTarget(localSessionId);
|
|
500
|
+
const plan = await this.prepareForkSession(sourceContextKey, localSessionId, requestedTitle);
|
|
501
|
+
const prepared = {
|
|
502
|
+
plan,
|
|
503
|
+
sourceDescription: plan.forkedFromHistoricalTurn
|
|
504
|
+
? "当前任务最近已完成轮次"
|
|
505
|
+
: "当前任务最新轮次",
|
|
506
|
+
};
|
|
507
|
+
const forked = await this.outbound.withReplyTarget(sourceContextKey, replyTarget, () => this.forkPreparedSessionToFeishuGroup(sourceContextKey, prepared, userOpenId ?? "", "当前任务"));
|
|
508
|
+
return {
|
|
509
|
+
sourceLocalSessionId: source.localSessionId,
|
|
510
|
+
sourceTurnId: plan.lastTurnId,
|
|
511
|
+
group: forked.group,
|
|
512
|
+
task: forked.task,
|
|
513
|
+
};
|
|
514
|
+
}
|
|
464
515
|
cardActionContextKey(action) {
|
|
465
516
|
const explicit = typeof action.value.contextKey === "string" ? action.value.contextKey : undefined;
|
|
466
517
|
if (explicit && baseChatContextKey(explicit) === baseChatContextKey(action.contextKey))
|
|
@@ -486,8 +537,8 @@ export class ProxySessionController {
|
|
|
486
537
|
await this.runShellCommand(contextKey, command.command);
|
|
487
538
|
return;
|
|
488
539
|
case "new":
|
|
489
|
-
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "
|
|
490
|
-
throw new Error("/new --nodir 仅支持
|
|
540
|
+
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "app-server") {
|
|
541
|
+
throw new Error("/new --nodir 仅支持 App Server Agent。");
|
|
491
542
|
}
|
|
492
543
|
await this.createSession(contextKey, context.defaultAgent, command.projectless
|
|
493
544
|
? undefined
|
|
@@ -496,8 +547,8 @@ export class ProxySessionController {
|
|
|
496
547
|
: resolveUserPath(command.cwd), true, false, undefined, undefined, command.title, this.inheritedExecutionSettings(contextKey, context.defaultAgent));
|
|
497
548
|
return;
|
|
498
549
|
case "newgroup":
|
|
499
|
-
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "
|
|
500
|
-
throw new Error("/newgroup --nodir 仅支持
|
|
550
|
+
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "app-server") {
|
|
551
|
+
throw new Error("/newgroup --nodir 仅支持 App Server Agent。");
|
|
501
552
|
}
|
|
502
553
|
await this.createFeishuGroup(contextKey, context.defaultAgent, command.title, userId, command.cwd === undefined ? undefined : resolveUserPath(command.cwd), command.projectless === true);
|
|
503
554
|
return;
|
|
@@ -569,7 +620,7 @@ export class ProxySessionController {
|
|
|
569
620
|
const turnContextKey = session.lastTurnId
|
|
570
621
|
? this.store.getTurnContextKey(session.lastTurnId) ?? context.contextKey
|
|
571
622
|
: context.contextKey;
|
|
572
|
-
this.outbound.registerSession(session.localSessionId, turnContextKey, session.title, session.cwd);
|
|
623
|
+
this.outbound.registerSession(session.localSessionId, turnContextKey, session.title, session.cwd, this.agentLabel(session.agentName));
|
|
573
624
|
if (!session.lastTurnId)
|
|
574
625
|
continue;
|
|
575
626
|
void this.outbound.resumeDelivery(session.localSessionId, turnContextKey, session.lastTurnId).catch((error) => {
|
|
@@ -603,7 +654,7 @@ export class ProxySessionController {
|
|
|
603
654
|
}
|
|
604
655
|
async prompt(contextKey, text, messageId, replyTarget, localImagePaths) {
|
|
605
656
|
if (!text.trim())
|
|
606
|
-
throw new Error("请输入要交给
|
|
657
|
+
throw new Error("请输入要交给 Agent 的内容。");
|
|
607
658
|
let record = this.currentSession(contextKey);
|
|
608
659
|
if (!record) {
|
|
609
660
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent);
|
|
@@ -614,7 +665,7 @@ export class ProxySessionController {
|
|
|
614
665
|
async promptSession(record, contextKey, text, messageId, replyTarget, localImagePaths) {
|
|
615
666
|
const configuredRuntime = this.runtimes.forAgent(record.agentName);
|
|
616
667
|
if (!configuredRuntime.getSession(record.localSessionId)) {
|
|
617
|
-
this.outbound.registerSession(record.localSessionId, contextKey, record.title, record.cwd);
|
|
668
|
+
this.outbound.registerSession(record.localSessionId, contextKey, record.title, record.cwd, this.agentLabel(record.agentName));
|
|
618
669
|
await this.outbound.startPendingTurn(record.localSessionId, contextKey, record.title, replyTarget, text);
|
|
619
670
|
}
|
|
620
671
|
let loaded;
|
|
@@ -660,7 +711,7 @@ export class ProxySessionController {
|
|
|
660
711
|
return;
|
|
661
712
|
}
|
|
662
713
|
catch (error) {
|
|
663
|
-
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the
|
|
714
|
+
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the App Server thread.");
|
|
664
715
|
let current = loaded.runtime.getSession(record.localSessionId);
|
|
665
716
|
try {
|
|
666
717
|
current = await loaded.runtime.synchronizeSession(record.localSessionId);
|
|
@@ -683,7 +734,7 @@ export class ProxySessionController {
|
|
|
683
734
|
return;
|
|
684
735
|
}
|
|
685
736
|
catch (retryError) {
|
|
686
|
-
this.logger.warn({ error: retryError, sessionId: record.localSessionId, activeTurnId: current.activeTurnId }, "Failed to steer the reconciled
|
|
737
|
+
this.logger.warn({ error: retryError, sessionId: record.localSessionId, activeTurnId: current.activeTurnId }, "Failed to steer the reconciled App Server turn; queueing prompt.");
|
|
687
738
|
}
|
|
688
739
|
}
|
|
689
740
|
this.persistQueuedPrompt(record.localSessionId, contextKey, text, {
|
|
@@ -828,7 +879,7 @@ export class ProxySessionController {
|
|
|
828
879
|
const agent = this.ensureAgent(source.agentName);
|
|
829
880
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
830
881
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
831
|
-
throw new Error("当前
|
|
882
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
832
883
|
}
|
|
833
884
|
const context = this.store.getOrCreateUserContext(message.contextKey, source.agentName);
|
|
834
885
|
if (context.currentSessionId && this.store.getSession(context.currentSessionId))
|
|
@@ -851,7 +902,7 @@ export class ProxySessionController {
|
|
|
851
902
|
permissionMode: source.permissionMode ?? "auto",
|
|
852
903
|
});
|
|
853
904
|
this.store.setCurrentSession(message.contextKey, localSessionId);
|
|
854
|
-
this.outbound.registerSession(localSessionId, message.contextKey, forkTitle, source.cwd);
|
|
905
|
+
this.outbound.registerSession(localSessionId, message.contextKey, forkTitle, source.cwd, this.agentLabel(source.agentName));
|
|
855
906
|
try {
|
|
856
907
|
const forked = await runtime.forkSession({
|
|
857
908
|
localSessionId,
|
|
@@ -897,13 +948,13 @@ export class ProxySessionController {
|
|
|
897
948
|
.map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
|
|
898
949
|
.find((candidate) => candidate !== undefined);
|
|
899
950
|
if (!anchor) {
|
|
900
|
-
throw new Error("无法确定这个话题对应的
|
|
951
|
+
throw new Error("无法确定这个话题对应的 App Server 轮次,因此没有创建分支任务。请从该轮的用户消息、思考卡片或最终回答创建话题。");
|
|
901
952
|
}
|
|
902
953
|
const source = anchor.contextKey
|
|
903
954
|
? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
|
|
904
955
|
: this.store.getSession(anchor.localSessionId);
|
|
905
956
|
if (!source || !source.remoteSessionId || !this.isCodexSession(source)) {
|
|
906
|
-
throw new Error("这个话题的来源不是可 fork 的
|
|
957
|
+
throw new Error("这个话题的来源不是可 fork 的 App Server 任务。");
|
|
907
958
|
}
|
|
908
959
|
if (baseChatContextKey(anchor.contextKey ?? source.contextKey) !== `chat_id:${message.chatId}`) {
|
|
909
960
|
throw new Error("话题来源任务不属于当前会话,已拒绝创建分支。");
|
|
@@ -911,7 +962,7 @@ export class ProxySessionController {
|
|
|
911
962
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(anchor.turnId));
|
|
912
963
|
if (isTurnStillRunning(snapshot?.status)
|
|
913
964
|
|| (source.lastTurnId === anchor.turnId && source.lastTurnStatus === "running")) {
|
|
914
|
-
throw new Error("话题对应的轮次仍在执行,
|
|
965
|
+
throw new Error("话题对应的轮次仍在执行,App Server 暂时不能从这一轮 fork。请等待该轮完成后再在话题中发送消息。");
|
|
915
966
|
}
|
|
916
967
|
return { anchor, source, snapshot };
|
|
917
968
|
}
|
|
@@ -941,7 +992,7 @@ export class ProxySessionController {
|
|
|
941
992
|
source = global ? { ...global, contextKey } : undefined;
|
|
942
993
|
}
|
|
943
994
|
if (source && (!source.remoteSessionId || !this.isCodexSession(source))) {
|
|
944
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
995
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
945
996
|
}
|
|
946
997
|
let runtime;
|
|
947
998
|
let agentName;
|
|
@@ -952,20 +1003,20 @@ export class ProxySessionController {
|
|
|
952
1003
|
}
|
|
953
1004
|
else {
|
|
954
1005
|
if (!taskId)
|
|
955
|
-
throw new Error("缺少要 fork 的
|
|
1006
|
+
throw new Error("缺少要 fork 的 App Server 任务 ID。");
|
|
956
1007
|
const resolved = await this.resolveRemoteCodexSession(taskId);
|
|
957
1008
|
agentName = resolved.agentName;
|
|
958
1009
|
runtime = resolved.runtime;
|
|
959
1010
|
remote = resolved.remote;
|
|
960
1011
|
}
|
|
961
1012
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
962
|
-
throw new Error("当前
|
|
1013
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
963
1014
|
}
|
|
964
1015
|
const remoteSessionId = source?.remoteSessionId ?? remote?.id ?? taskId;
|
|
965
1016
|
if (!remoteSessionId)
|
|
966
|
-
throw new Error("当前任务尚未创建
|
|
1017
|
+
throw new Error("当前任务尚未创建 App Server 任务 ID,暂时不能 fork。");
|
|
967
1018
|
if (!runtime.readRemoteSession && !source) {
|
|
968
|
-
throw new Error("当前
|
|
1019
|
+
throw new Error("当前 App Server Agent 不支持读取指定任务。");
|
|
969
1020
|
}
|
|
970
1021
|
remote ??= runtime.readRemoteSession
|
|
971
1022
|
? await runtime.readRemoteSession(remoteSessionId)
|
|
@@ -988,7 +1039,7 @@ export class ProxySessionController {
|
|
|
988
1039
|
const forkedFromHistoricalTurn = isRunning && lastTurnId !== latestTurnId;
|
|
989
1040
|
const cwd = remote?.cwd || source?.cwd;
|
|
990
1041
|
if (!cwd)
|
|
991
|
-
throw new Error("指定的
|
|
1042
|
+
throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能 fork。");
|
|
992
1043
|
const sourceTitle = remote?.title ?? source?.title ?? remote?.preview;
|
|
993
1044
|
const forkTitle = normalizeTaskTitle(requestedTitle) ?? this.store.nextForkTitle(sourceTitle);
|
|
994
1045
|
const modelProvider = remote?.modelProvider ?? source?.modelProvider;
|
|
@@ -1045,15 +1096,15 @@ export class ProxySessionController {
|
|
|
1045
1096
|
}
|
|
1046
1097
|
prepareForkSessionFromTurn(source, lastTurnId, requestedTitle, sourceLabel) {
|
|
1047
1098
|
if (!source.remoteSessionId || !this.isCodexSession(source)) {
|
|
1048
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
1099
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
1049
1100
|
}
|
|
1050
1101
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
1051
1102
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1052
|
-
throw new Error("当前
|
|
1103
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1053
1104
|
}
|
|
1054
1105
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(lastTurnId));
|
|
1055
1106
|
if (isTurnStillRunning(snapshot?.status)) {
|
|
1056
|
-
throw new Error(`${sourceLabel}仍在执行,
|
|
1107
|
+
throw new Error(`${sourceLabel}仍在执行,App Server 暂时不能从这一轮 fork。`);
|
|
1057
1108
|
}
|
|
1058
1109
|
const sourceWasRunning = Boolean(runtime.getSession(source.localSessionId)?.activeTurnId
|
|
1059
1110
|
|| source.lastTurnStatus === "running"
|
|
@@ -1115,7 +1166,7 @@ export class ProxySessionController {
|
|
|
1115
1166
|
lastTurnStatus: plan.lastTurnStatus,
|
|
1116
1167
|
});
|
|
1117
1168
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
1118
|
-
this.outbound.registerSession(localSessionId, contextKey, forked.title ?? plan.forkTitle, plan.cwd);
|
|
1169
|
+
this.outbound.registerSession(localSessionId, contextKey, forked.title ?? plan.forkTitle, plan.cwd, this.agentLabel(plan.agentName));
|
|
1119
1170
|
this.store.audit(contextKey, "session_forked", {
|
|
1120
1171
|
sourceLocalSessionId: plan.source?.localSessionId,
|
|
1121
1172
|
sourceRemoteSessionId: plan.remoteSessionId,
|
|
@@ -1154,7 +1205,7 @@ export class ProxySessionController {
|
|
|
1154
1205
|
}
|
|
1155
1206
|
const source = direct ?? this.findStoredSessionByReference(taskId);
|
|
1156
1207
|
if (source && !this.isCodexSession(source)) {
|
|
1157
|
-
throw new Error("指定任务不是
|
|
1208
|
+
throw new Error("指定任务不是 App Server 任务,暂时不能按项目创建新任务。");
|
|
1158
1209
|
}
|
|
1159
1210
|
let agentName;
|
|
1160
1211
|
let runtime;
|
|
@@ -1182,7 +1233,7 @@ export class ProxySessionController {
|
|
|
1182
1233
|
}
|
|
1183
1234
|
const cwd = remote?.cwd || source?.cwd;
|
|
1184
1235
|
if (!cwd) {
|
|
1185
|
-
throw new Error("指定的
|
|
1236
|
+
throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能按项目创建新任务。");
|
|
1186
1237
|
}
|
|
1187
1238
|
const executionSettings = {
|
|
1188
1239
|
modelProvider: remote?.modelProvider ?? source?.modelProvider,
|
|
@@ -1227,7 +1278,7 @@ export class ProxySessionController {
|
|
|
1227
1278
|
const agent = this.ensureAgent(agentName);
|
|
1228
1279
|
const localSessionId = createId("sess");
|
|
1229
1280
|
const initialTitle = normalizeTaskTitle(requestedTitle ?? prompt ?? "");
|
|
1230
|
-
const sessionCwd = cwd === undefined && agent.kind === "
|
|
1281
|
+
const sessionCwd = cwd === undefined && agent.kind === "app-server"
|
|
1231
1282
|
? createProjectlessWorkspace({ prompt: initialTitle }).cwd
|
|
1232
1283
|
: path.resolve(cwd ?? this.config.defaults.cwd);
|
|
1233
1284
|
const record = this.store.createSession({ localSessionId, contextKey, agentName, cwd: sessionCwd, status: "starting" });
|
|
@@ -1241,7 +1292,7 @@ export class ProxySessionController {
|
|
|
1241
1292
|
});
|
|
1242
1293
|
}
|
|
1243
1294
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
1244
|
-
this.outbound.registerSession(localSessionId, contextKey, initialTitle, sessionCwd);
|
|
1295
|
+
this.outbound.registerSession(localSessionId, contextKey, initialTitle, sessionCwd, this.agentLabel(agentName));
|
|
1245
1296
|
const runtime = this.runtimes.forAgent(agentName);
|
|
1246
1297
|
try {
|
|
1247
1298
|
if (prepareTurn) {
|
|
@@ -1295,8 +1346,8 @@ export class ProxySessionController {
|
|
|
1295
1346
|
}
|
|
1296
1347
|
async createFeishuGroupWithTask(sourceContextKey, agentName, requestedTitle, userId, boundProjectCwd, executionSettings) {
|
|
1297
1348
|
const explicitTitle = normalizeTaskTitle(requestedTitle);
|
|
1298
|
-
const taskTitle = explicitTitle ??
|
|
1299
|
-
const group = await this.createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, "/newgroup",
|
|
1349
|
+
const taskTitle = explicitTitle ?? `新任务 (${formatGroupDateSuffix(new Date())})`;
|
|
1350
|
+
const group = await this.createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, "/newgroup", false);
|
|
1300
1351
|
let task;
|
|
1301
1352
|
try {
|
|
1302
1353
|
task = await this.createSession(group.contextKey, agentName, boundProjectCwd, false, false, undefined, undefined, taskTitle, executionSettings);
|
|
@@ -1312,12 +1363,13 @@ export class ProxySessionController {
|
|
|
1312
1363
|
"群和新任务已创建。",
|
|
1313
1364
|
`当前任务:${taskDescription}`,
|
|
1314
1365
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1315
|
-
`当前 Provider:${task.modelProvider ?? "
|
|
1366
|
+
`当前 Provider:${task.modelProvider ?? "Agent 默认"}`,
|
|
1316
1367
|
`当前模型:${task.model ?? "默认"}`,
|
|
1317
1368
|
`思考强度:${task.reasoningEffort ?? "自动"}`,
|
|
1318
1369
|
`权限类型:${task.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
1319
1370
|
].join("\n"));
|
|
1320
1371
|
await this.outbound.sendText(sourceContextKey, `已创建飞书群:${group.name},并创建新任务 ${taskDescription}。`);
|
|
1372
|
+
return { group, task };
|
|
1321
1373
|
}
|
|
1322
1374
|
async forkCurrentSessionToFeishuGroup(sourceContextKey, requestedTitle, userId, incomingMessage) {
|
|
1323
1375
|
if (!userId?.startsWith("ou_")) {
|
|
@@ -1357,12 +1409,13 @@ export class ProxySessionController {
|
|
|
1357
1409
|
`已从${prepared.sourceDescription}创建分支。`,
|
|
1358
1410
|
`当前任务:${taskDescription}`,
|
|
1359
1411
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1360
|
-
`当前 Provider:${forked.session.modelProvider ?? "
|
|
1412
|
+
`当前 Provider:${forked.session.modelProvider ?? "Agent 默认"}`,
|
|
1361
1413
|
`当前模型:${forked.session.model ?? "默认"}`,
|
|
1362
1414
|
`思考强度:${forked.session.reasoningEffort ?? "自动"}`,
|
|
1363
1415
|
`权限类型:${forked.session.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
1364
1416
|
].join("\n"));
|
|
1365
1417
|
await this.outbound.sendText(sourceContextKey, `已将${sourceSummary} Fork 到飞书群:${group.name};新群当前任务为 ${taskDescription}。`);
|
|
1418
|
+
return { group, task: forked.record };
|
|
1366
1419
|
}
|
|
1367
1420
|
async createFeishuGroupContext(sourceContextKey, agentName, taskTitle, userId, boundProjectCwd, commandName, includeTimestamp) {
|
|
1368
1421
|
if (!userId?.startsWith("ou_")) {
|
|
@@ -1379,7 +1432,7 @@ export class ProxySessionController {
|
|
|
1379
1432
|
this.store.getOrCreateUserContext(groupContextKey, agentName);
|
|
1380
1433
|
if (boundProjectCwd)
|
|
1381
1434
|
this.store.setBoundProjectCwd(groupContextKey, boundProjectCwd);
|
|
1382
|
-
return { contextKey: groupContextKey, name: group.name };
|
|
1435
|
+
return { chatId: group.chatId, contextKey: groupContextKey, name: group.name };
|
|
1383
1436
|
}
|
|
1384
1437
|
async loadSession(record) {
|
|
1385
1438
|
const agent = this.ensureAgent(record.agentName);
|
|
@@ -1390,7 +1443,7 @@ export class ProxySessionController {
|
|
|
1390
1443
|
const pending = this.sessionLoads.get(record.localSessionId);
|
|
1391
1444
|
if (pending)
|
|
1392
1445
|
return pending;
|
|
1393
|
-
this.outbound.registerSession(record.localSessionId, record.contextKey, record.title, record.cwd);
|
|
1446
|
+
this.outbound.registerSession(record.localSessionId, record.contextKey, record.title, record.cwd, this.agentLabel(record.agentName));
|
|
1394
1447
|
const loading = (async () => {
|
|
1395
1448
|
if (record.lastTurnId) {
|
|
1396
1449
|
try {
|
|
@@ -1416,7 +1469,7 @@ export class ProxySessionController {
|
|
|
1416
1469
|
model: record.model,
|
|
1417
1470
|
reasoningEffort: record.reasoningEffort,
|
|
1418
1471
|
permissionMode,
|
|
1419
|
-
activeTurnId: agent.kind === "
|
|
1472
|
+
activeTurnId: agent.kind === "app-server" && record.status === "running" && record.lastTurnStatus === "running"
|
|
1420
1473
|
? record.lastTurnId
|
|
1421
1474
|
: undefined,
|
|
1422
1475
|
lastTurnId: record.lastTurnId,
|
|
@@ -1424,9 +1477,9 @@ export class ProxySessionController {
|
|
|
1424
1477
|
});
|
|
1425
1478
|
}
|
|
1426
1479
|
catch (error) {
|
|
1427
|
-
if (!(agent.kind === "
|
|
1480
|
+
if (!(agent.kind === "app-server" && !record.lastTurnId && isMissingRolloutError(error)))
|
|
1428
1481
|
throw error;
|
|
1429
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "
|
|
1482
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "App Server task has no rollout; creating a replacement task.");
|
|
1430
1483
|
session = await runtime.createSession({
|
|
1431
1484
|
localSessionId: record.localSessionId,
|
|
1432
1485
|
agentName: record.agentName,
|
|
@@ -1629,7 +1682,7 @@ export class ProxySessionController {
|
|
|
1629
1682
|
await runtime.setGoal(record.localSessionId, { status: "paused" });
|
|
1630
1683
|
}
|
|
1631
1684
|
catch (error) {
|
|
1632
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to pause the active
|
|
1685
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to pause the active Agent goal before interrupting its turn.");
|
|
1633
1686
|
}
|
|
1634
1687
|
}
|
|
1635
1688
|
let turnId = runtime.getSession(record.localSessionId)?.activeTurnId;
|
|
@@ -1641,7 +1694,7 @@ export class ProxySessionController {
|
|
|
1641
1694
|
: undefined;
|
|
1642
1695
|
}
|
|
1643
1696
|
catch (error) {
|
|
1644
|
-
this.logger.warn({ error, sessionId: record.localSessionId, remoteSessionId: record.remoteSessionId }, "Failed to inspect the current
|
|
1697
|
+
this.logger.warn({ error, sessionId: record.localSessionId, remoteSessionId: record.remoteSessionId }, "Failed to inspect the current App Server turn before interrupting; using the locally tracked turn.");
|
|
1645
1698
|
}
|
|
1646
1699
|
}
|
|
1647
1700
|
if (!turnId) {
|
|
@@ -1654,7 +1707,7 @@ export class ProxySessionController {
|
|
|
1654
1707
|
remoteSessionId: record.remoteSessionId,
|
|
1655
1708
|
turnId,
|
|
1656
1709
|
});
|
|
1657
|
-
await this.outbound.sendText(record.contextKey, `已向
|
|
1710
|
+
await this.outbound.sendText(record.contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
1658
1711
|
return;
|
|
1659
1712
|
}
|
|
1660
1713
|
const loaded = await this.loadSession(record);
|
|
@@ -1943,13 +1996,13 @@ export class ProxySessionController {
|
|
|
1943
1996
|
}
|
|
1944
1997
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent);
|
|
1945
1998
|
const agent = this.ensureAgent(context.defaultAgent);
|
|
1946
|
-
if (agent.kind !== "
|
|
1947
|
-
throw new Error("Goal 模式仅支持
|
|
1999
|
+
if (agent.kind !== "app-server")
|
|
2000
|
+
throw new Error("Goal 模式仅支持 App Server 任务。");
|
|
1948
2001
|
record = await this.createSession(contextKey, context.defaultAgent, this.inheritedNewTaskCwd(contextKey), false, false, objective);
|
|
1949
2002
|
}
|
|
1950
2003
|
const loaded = await this.loadSession(record);
|
|
1951
2004
|
if (loaded.runtime.kind !== "codex" || !loaded.runtime.getGoal || !loaded.runtime.setGoal || !loaded.runtime.clearGoal) {
|
|
1952
|
-
throw new Error("
|
|
2005
|
+
throw new Error("当前 Agent 不支持 Goal 模式。");
|
|
1953
2006
|
}
|
|
1954
2007
|
if (command.action === "show") {
|
|
1955
2008
|
await this.sendGoalCard(contextKey, await loaded.runtime.getGoal(record.localSessionId));
|
|
@@ -1972,7 +2025,7 @@ export class ProxySessionController {
|
|
|
1972
2025
|
const goal = await loaded.runtime.setGoal(record.localSessionId, { status });
|
|
1973
2026
|
await this.sendGoalCard(contextKey, goal, command.action === "pause"
|
|
1974
2027
|
? "Goal 已暂停;当前轮次可以完成,但不会继续自动执行。"
|
|
1975
|
-
: "Goal 已恢复,
|
|
2028
|
+
: "Goal 已恢复,Agent 会继续自动执行。", record);
|
|
1976
2029
|
return;
|
|
1977
2030
|
}
|
|
1978
2031
|
if (objective === undefined)
|
|
@@ -1988,7 +2041,7 @@ export class ProxySessionController {
|
|
|
1988
2041
|
status: command.action === "edit" ? current.status : "active",
|
|
1989
2042
|
...(command.action === "edit" ? { tokenBudget: current.tokenBudget } : {}),
|
|
1990
2043
|
});
|
|
1991
|
-
await this.sendGoalCard(contextKey, goal, command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,
|
|
2044
|
+
await this.sendGoalCard(contextKey, goal, command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,Agent 会持续执行直到完成、暂停或遇到阻塞。", record);
|
|
1992
2045
|
}
|
|
1993
2046
|
async sendGoalCard(contextKey, goal, notice, record = this.currentSession(contextKey)) {
|
|
1994
2047
|
const sections = [];
|
|
@@ -2002,7 +2055,7 @@ export class ProxySessionController {
|
|
|
2002
2055
|
title: "任务",
|
|
2003
2056
|
lines: [
|
|
2004
2057
|
`**标题**:${cardText(record.title ?? "未命名任务")}`,
|
|
2005
|
-
`**
|
|
2058
|
+
`**App Server 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
|
|
2006
2059
|
],
|
|
2007
2060
|
});
|
|
2008
2061
|
}
|
|
@@ -2013,7 +2066,7 @@ export class ProxySessionController {
|
|
|
2013
2066
|
"**/goal edit <新目标>** 修改 **/goal clear** 清除",
|
|
2014
2067
|
],
|
|
2015
2068
|
});
|
|
2016
|
-
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("
|
|
2069
|
+
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("Agent Goal", sections));
|
|
2017
2070
|
}
|
|
2018
2071
|
async runShellCommand(contextKey, command) {
|
|
2019
2072
|
const cwd = this.currentSession(contextKey)?.cwd ?? this.config.defaults.cwd;
|
|
@@ -2149,7 +2202,7 @@ export class ProxySessionController {
|
|
|
2149
2202
|
remoteHasMore ||= Boolean(page.nextCursor);
|
|
2150
2203
|
}
|
|
2151
2204
|
catch (error) {
|
|
2152
|
-
this.logger.warn({ error, contextKey, agentName }, "Failed to list
|
|
2205
|
+
this.logger.warn({ error, contextKey, agentName }, "Failed to list App Server sessions for an Agent.");
|
|
2153
2206
|
remoteErrors.push(`${agentName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2154
2207
|
}
|
|
2155
2208
|
}));
|
|
@@ -2239,7 +2292,7 @@ export class ProxySessionController {
|
|
|
2239
2292
|
actions,
|
|
2240
2293
|
};
|
|
2241
2294
|
});
|
|
2242
|
-
const card = this.cardRenderer.renderTaskListCard(searchTerm ? `
|
|
2295
|
+
const card = this.cardRenderer.renderTaskListCard(searchTerm ? `App Server 任务:${searchTerm}` : "App Server 任务", activeCount > 0 ? `任务(${activeCount} 个活跃)` : "任务", cardEntries, [
|
|
2243
2296
|
...(remoteHint ? [remoteHint] : []),
|
|
2244
2297
|
"点击 **New** 在对应任务的项目中创建新任务;点击 **Switch** 快速切换;点击 **Fork** 从任务最新已完成轮次创建分支;外部正在运行的任务显示 **Stop**,点击后发送 Interrupt 并变为 **Switch**。",
|
|
2245
2298
|
"点击 **NewGroup** 在对应任务的项目中创建新群和新任务;点击 **ForkGroup** 从对应任务最新已完成轮次创建分支群。",
|
|
@@ -2299,7 +2352,7 @@ export class ProxySessionController {
|
|
|
2299
2352
|
? [[scoped.agentName, this.runtimes.forAgent(scoped.agentName)]]
|
|
2300
2353
|
: this.runtimes.entries("codex");
|
|
2301
2354
|
if (candidates.length === 0)
|
|
2302
|
-
throw new Error("未配置
|
|
2355
|
+
throw new Error("未配置 App Server Agent。");
|
|
2303
2356
|
const reads = await Promise.allSettled(candidates.map(async ([agentName, runtime]) => {
|
|
2304
2357
|
if (runtime.kind !== "codex" || !runtime.readRemoteSession) {
|
|
2305
2358
|
throw new Error(`Agent ${agentName} 不支持读取远端任务。`);
|
|
@@ -2324,7 +2377,7 @@ export class ProxySessionController {
|
|
|
2324
2377
|
: undefined)
|
|
2325
2378
|
.filter((detail) => Boolean(detail))
|
|
2326
2379
|
.join(";");
|
|
2327
|
-
throw new Error(`找不到
|
|
2380
|
+
throw new Error(`找不到 App Server 任务:${scoped?.remoteSessionId ?? reference}${details ? `(${details})` : ""}`);
|
|
2328
2381
|
}
|
|
2329
2382
|
async switchSession(contextKey, reference) {
|
|
2330
2383
|
this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent);
|
|
@@ -2339,16 +2392,16 @@ export class ProxySessionController {
|
|
|
2339
2392
|
await this.assertSessionTurnOwnership(existing, runtime);
|
|
2340
2393
|
this.store.attachSessionToContext(contextKey, existing.localSessionId);
|
|
2341
2394
|
this.store.setCurrentSession(contextKey, existing.localSessionId);
|
|
2342
|
-
this.outbound.registerSession(existing.localSessionId, contextKey, existing.title, existing.cwd);
|
|
2395
|
+
this.outbound.registerSession(existing.localSessionId, contextKey, existing.title, existing.cwd, this.agentLabel(existing.agentName));
|
|
2343
2396
|
await this.outbound.sendText(contextKey, `已切换到任务:${existing.title ?? existing.remoteSessionId ?? taskId}`);
|
|
2344
2397
|
return;
|
|
2345
2398
|
}
|
|
2346
2399
|
const { agentName, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
2347
2400
|
if (remote.status === "active" || remote.lastTurnStatus === "inProgress") {
|
|
2348
|
-
throw new Error(`这个任务正在外部
|
|
2401
|
+
throw new Error(`这个任务正在外部 Agent 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
|
|
2349
2402
|
}
|
|
2350
2403
|
if (!remote.cwd)
|
|
2351
|
-
throw new Error("这个
|
|
2404
|
+
throw new Error("这个 App Server 任务没有可用的工作目录,暂时无法切换。");
|
|
2352
2405
|
const localSessionId = createId("sess");
|
|
2353
2406
|
this.store.createSession({
|
|
2354
2407
|
localSessionId,
|
|
@@ -2366,7 +2419,7 @@ export class ProxySessionController {
|
|
|
2366
2419
|
lastTurnStatus: mapRemoteTurnStatus(remote.lastTurnStatus),
|
|
2367
2420
|
});
|
|
2368
2421
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
2369
|
-
this.outbound.registerSession(localSessionId, contextKey, remote.title ?? remote.preview, remote.cwd);
|
|
2422
|
+
this.outbound.registerSession(localSessionId, contextKey, remote.title ?? remote.preview, remote.cwd, this.agentLabel(agentName));
|
|
2370
2423
|
await this.outbound.sendText(contextKey, `已切换到任务:${remote.title ?? remote.preview ?? remote.id}。历史消息不会重新发送。`);
|
|
2371
2424
|
}
|
|
2372
2425
|
async stopSessionReference(contextKey, taskId) {
|
|
@@ -2384,7 +2437,7 @@ export class ProxySessionController {
|
|
|
2384
2437
|
}
|
|
2385
2438
|
const { runtime, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
2386
2439
|
if (!runtime.readRemoteSession || !runtime.interruptRemoteTurn) {
|
|
2387
|
-
throw new Error("当前
|
|
2440
|
+
throw new Error("当前 App Server Agent 不支持停止外部任务。");
|
|
2388
2441
|
}
|
|
2389
2442
|
const turnId = remote.status === "active" || remote.lastTurnStatus === "inProgress"
|
|
2390
2443
|
? remote.lastTurnId
|
|
@@ -2399,7 +2452,7 @@ export class ProxySessionController {
|
|
|
2399
2452
|
turnId,
|
|
2400
2453
|
source: "sessions_card",
|
|
2401
2454
|
});
|
|
2402
|
-
await this.outbound.sendText(contextKey, `已向
|
|
2455
|
+
await this.outbound.sendText(contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
2403
2456
|
}
|
|
2404
2457
|
resolveSessionReference(contextKey, reference) {
|
|
2405
2458
|
if (reference === undefined) {
|
|
@@ -2441,7 +2494,7 @@ export class ProxySessionController {
|
|
|
2441
2494
|
&& activity.activeTurnId === record.lastTurnId;
|
|
2442
2495
|
const botOwnsActiveTurn = runtimeOwnsActiveTurn || persistedTurnMatches;
|
|
2443
2496
|
if (activity.active && !botOwnsActiveTurn) {
|
|
2444
|
-
throw new Error("这个任务正在外部
|
|
2497
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
2445
2498
|
}
|
|
2446
2499
|
return activity;
|
|
2447
2500
|
}
|
|
@@ -2450,7 +2503,7 @@ export class ProxySessionController {
|
|
|
2450
2503
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
2451
2504
|
}
|
|
2452
2505
|
catch (error) {
|
|
2453
|
-
//
|
|
2506
|
+
// App Server does not materialize a new thread until its first user message.
|
|
2454
2507
|
// Such a thread has no turn to take over, so allow turn/start to create it.
|
|
2455
2508
|
if (!record.lastTurnId && isUnmaterializedCodexThreadError(error))
|
|
2456
2509
|
return;
|
|
@@ -2458,7 +2511,7 @@ export class ProxySessionController {
|
|
|
2458
2511
|
}
|
|
2459
2512
|
const botOwnsActiveTurn = isBotOwnedActiveTurn(record, remote);
|
|
2460
2513
|
if ((remote.status === "active" || remote.lastTurnStatus === "inProgress") && !botOwnsActiveTurn) {
|
|
2461
|
-
throw new Error("这个任务正在外部
|
|
2514
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
2462
2515
|
}
|
|
2463
2516
|
return undefined;
|
|
2464
2517
|
}
|
|
@@ -2514,7 +2567,7 @@ export class ProxySessionController {
|
|
|
2514
2567
|
remote = await runtime.readRemoteSession(current.remoteSessionId);
|
|
2515
2568
|
}
|
|
2516
2569
|
catch (error) {
|
|
2517
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
2570
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect App Server task status.");
|
|
2518
2571
|
}
|
|
2519
2572
|
}
|
|
2520
2573
|
if (runtime.kind === "codex" && runtime.getGoal) {
|
|
@@ -2523,7 +2576,7 @@ export class ProxySessionController {
|
|
|
2523
2576
|
goal = await runtime.getGoal(loaded.localSessionId);
|
|
2524
2577
|
}
|
|
2525
2578
|
catch (error) {
|
|
2526
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
2579
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect Agent goal status.");
|
|
2527
2580
|
}
|
|
2528
2581
|
}
|
|
2529
2582
|
}
|
|
@@ -2534,7 +2587,7 @@ export class ProxySessionController {
|
|
|
2534
2587
|
let activeTurnId;
|
|
2535
2588
|
let queued = 0;
|
|
2536
2589
|
if (!current) {
|
|
2537
|
-
taskLines.push("无。直接发送消息即可创建一个未指定项目的
|
|
2590
|
+
taskLines.push("无。直接发送消息即可创建一个未指定项目的 Agent 任务。");
|
|
2538
2591
|
}
|
|
2539
2592
|
else {
|
|
2540
2593
|
const agent = this.ensureAgent(current.agentName);
|
|
@@ -2550,7 +2603,7 @@ export class ProxySessionController {
|
|
|
2550
2603
|
const resultLabel = remoteActive
|
|
2551
2604
|
? "执行中"
|
|
2552
2605
|
: remoteTurnStatusLabel(remote?.lastTurnStatus ?? current.lastTurnStatus);
|
|
2553
|
-
taskLines.push(`**标题**:${cardCode(current.title ?? "未命名任务")}`, `**工作目录**:${cardCode(current.cwd)}`, `**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "
|
|
2606
|
+
taskLines.push(`**标题**:${cardCode(current.title ?? "未命名任务")}`, `**工作目录**:${cardCode(current.cwd)}`, `**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "Agent 默认")} / ${cardCode(current.model ?? "默认")} / ${cardCode(current.reasoningEffort ?? "自动")}`, `**状态 / 最近结果**:${statusLabel} / ${resultLabel}`, `**Agent**:${cardCode(agent.title)}`, `**权限 / 任务范围**:${current.permissionMode === "confirm" ? "执行前确认" : "自动执行"} / ${detectProjectlessWorkspace(current.cwd) ? "未指定项目" : "指定项目"}`, `**App Server 任务 ID**:${cardCode(current.remoteSessionId ?? "尚未创建")}`, `**当前执行 / 排队消息**:${activeTurnId ? cardCode(activeTurnId) : "无"} / ${queued} 条`, `**创建时间 / 最近活动**:${formatStatusTime(current.createdAt)} / ${formatStatusTime(current.updatedAt)}`);
|
|
2554
2607
|
}
|
|
2555
2608
|
const sections = [
|
|
2556
2609
|
{ title: targetSessionId ? "指定任务" : "当前任务", lines: taskLines },
|
|
@@ -2577,8 +2630,8 @@ export class ProxySessionController {
|
|
|
2577
2630
|
},
|
|
2578
2631
|
];
|
|
2579
2632
|
const title = targetSessionId && current
|
|
2580
|
-
? `
|
|
2581
|
-
: "
|
|
2633
|
+
? `Agent 状态:${truncateText((current.title ?? current.remoteSessionId ?? current.localSessionId).replace(/\s+/g, " "), 40)}`
|
|
2634
|
+
: "Agent 状态";
|
|
2582
2635
|
const taskId = current?.remoteSessionId
|
|
2583
2636
|
? remoteSessionReference(current.agentName, current.remoteSessionId)
|
|
2584
2637
|
: current?.localSessionId;
|
|
@@ -2617,7 +2670,7 @@ export class ProxySessionController {
|
|
|
2617
2670
|
`**工作目录**:${cardCode(remote.cwd || "目录未知")}`,
|
|
2618
2671
|
`**状态 / 当前任务**:${remoteSessionDetailStatus(remote)} / 未切换`,
|
|
2619
2672
|
`**Agent**:${cardCode(agentName)}`,
|
|
2620
|
-
`**
|
|
2673
|
+
`**App Server 任务 ID**:${cardCode(remote.id)}`,
|
|
2621
2674
|
`**最近回合**:${cardCode(remote.lastTurnId ?? "无")} ${remoteTurnStatusLabel(remote.lastTurnStatus)}`,
|
|
2622
2675
|
`**创建时间 / 最近活动**:${formatRemoteTime(remote.createdAt)} / ${formatRemoteTime(latestRemoteTimestamp(remote.recencyAt, remote.updatedAt))}`,
|
|
2623
2676
|
],
|
|
@@ -2628,14 +2681,14 @@ export class ProxySessionController {
|
|
|
2628
2681
|
lines: [
|
|
2629
2682
|
`**当前 / 最后步骤**:${statusExcerpt(remote.lastActivity ?? remoteStatusStep(remote), 500)}`,
|
|
2630
2683
|
isRemoteSessionActive(remote)
|
|
2631
|
-
? "外部
|
|
2684
|
+
? "外部 Agent 正在执行;Agent Bot 只读取状态,不会接管。"
|
|
2632
2685
|
: `发送 **/switch ${cardText(remote.id)}** 切换到此任务。`,
|
|
2633
2686
|
],
|
|
2634
2687
|
collapsible: true,
|
|
2635
2688
|
elementId: "status_execution_details",
|
|
2636
2689
|
},
|
|
2637
2690
|
];
|
|
2638
|
-
const title = `
|
|
2691
|
+
const title = `Agent 状态:${truncateText((remote.title ?? remote.preview ?? remote.id).replace(/\s+/g, " "), 40)}`;
|
|
2639
2692
|
const showStop = isRemoteSessionActive(remote)
|
|
2640
2693
|
&& options.forceSwitchTaskId !== actionReference
|
|
2641
2694
|
&& options.forceSwitchTaskId !== remote.id;
|
|
@@ -2708,10 +2761,13 @@ export class ProxySessionController {
|
|
|
2708
2761
|
throw new Error(`未知 agent:${agentName}`);
|
|
2709
2762
|
return agent;
|
|
2710
2763
|
}
|
|
2764
|
+
agentLabel(agentName) {
|
|
2765
|
+
return this.ensureAgent(agentName).title;
|
|
2766
|
+
}
|
|
2711
2767
|
isCodexSession(session) {
|
|
2712
2768
|
if (session.runtimeKind)
|
|
2713
2769
|
return session.runtimeKind === "codex";
|
|
2714
|
-
return this.config.agents[session.agentName]?.kind === "
|
|
2770
|
+
return this.config.agents[session.agentName]?.kind === "app-server";
|
|
2715
2771
|
}
|
|
2716
2772
|
currentSession(contextKey) {
|
|
2717
2773
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent);
|