@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
|
@@ -148,10 +148,23 @@ interface ResolvedThreadForkAnchor {
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
interface CreatedFeishuGroupContext {
|
|
151
|
+
chatId: string;
|
|
151
152
|
contextKey: string;
|
|
152
153
|
name: string;
|
|
153
154
|
}
|
|
154
155
|
|
|
156
|
+
interface CreatedFeishuTaskGroup {
|
|
157
|
+
group: CreatedFeishuGroupContext;
|
|
158
|
+
task: SessionRecord;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export interface ControlTaskGroupResult {
|
|
162
|
+
sourceLocalSessionId: string;
|
|
163
|
+
sourceTurnId?: string;
|
|
164
|
+
group: CreatedFeishuGroupContext;
|
|
165
|
+
task: SessionRecord;
|
|
166
|
+
}
|
|
167
|
+
|
|
155
168
|
export interface ProxyLifecycle {
|
|
156
169
|
supervised?: boolean;
|
|
157
170
|
restart(contextKey: string, force: boolean): Promise<void>;
|
|
@@ -551,7 +564,7 @@ export class ProxySessionController {
|
|
|
551
564
|
try {
|
|
552
565
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
553
566
|
} catch (error) {
|
|
554
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect
|
|
567
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect App Server task status for CLI.");
|
|
555
568
|
}
|
|
556
569
|
}
|
|
557
570
|
}
|
|
@@ -615,6 +628,7 @@ export class ProxySessionController {
|
|
|
615
628
|
responseContextKey,
|
|
616
629
|
scopedRecord.title,
|
|
617
630
|
scopedRecord.cwd,
|
|
631
|
+
this.agentLabel(scopedRecord.agentName),
|
|
618
632
|
);
|
|
619
633
|
const promptMessageId = await this.outbound.withReplyTarget(
|
|
620
634
|
responseContextKey,
|
|
@@ -641,6 +655,82 @@ export class ProxySessionController {
|
|
|
641
655
|
return `The Prompt was posted to the original chat and submitted to the task: ${record.title ?? record.remoteSessionId ?? record.localSessionId}`;
|
|
642
656
|
}
|
|
643
657
|
|
|
658
|
+
async controlCreateTaskGroup(
|
|
659
|
+
localSessionId: string,
|
|
660
|
+
requestedTitle: string | undefined,
|
|
661
|
+
userOpenId: string | undefined,
|
|
662
|
+
requestedProjectCwd?: string,
|
|
663
|
+
forceProjectless = false,
|
|
664
|
+
requestedAgentName?: string,
|
|
665
|
+
): Promise<ControlTaskGroupResult> {
|
|
666
|
+
const source = this.store.getSession(localSessionId);
|
|
667
|
+
if (!source || source.status === "closed") throw new Error(`Task not found: ${localSessionId}`);
|
|
668
|
+
const agentName = requestedAgentName?.trim() || source.agentName;
|
|
669
|
+
const agent = this.ensureAgent(agentName);
|
|
670
|
+
if (forceProjectless && agent.kind !== "app-server") {
|
|
671
|
+
throw new Error("task newgroup --nodir is only available for App Server agents.");
|
|
672
|
+
}
|
|
673
|
+
const sourceContextKey = this.outbound.getSessionContextKey(localSessionId) ?? source.contextKey;
|
|
674
|
+
const replyTarget = this.outbound.getSessionReplyTarget(localSessionId);
|
|
675
|
+
const boundProjectCwd = forceProjectless
|
|
676
|
+
? undefined
|
|
677
|
+
: requestedProjectCwd === undefined
|
|
678
|
+
? detectProjectlessWorkspace(source.cwd) ? undefined : source.cwd
|
|
679
|
+
: resolveUserPath(requestedProjectCwd);
|
|
680
|
+
const created = await this.outbound.withReplyTarget(sourceContextKey, replyTarget, () =>
|
|
681
|
+
this.createFeishuGroupWithTask(
|
|
682
|
+
sourceContextKey,
|
|
683
|
+
agentName,
|
|
684
|
+
requestedTitle,
|
|
685
|
+
userOpenId,
|
|
686
|
+
boundProjectCwd,
|
|
687
|
+
source.agentName === agentName
|
|
688
|
+
? {
|
|
689
|
+
modelProvider: source.modelProvider,
|
|
690
|
+
model: source.model,
|
|
691
|
+
reasoningEffort: source.reasoningEffort,
|
|
692
|
+
permissionMode: source.permissionMode,
|
|
693
|
+
}
|
|
694
|
+
: {},
|
|
695
|
+
));
|
|
696
|
+
return {
|
|
697
|
+
sourceLocalSessionId: source.localSessionId,
|
|
698
|
+
group: created.group,
|
|
699
|
+
task: created.task,
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
async controlForkTaskGroup(
|
|
704
|
+
localSessionId: string,
|
|
705
|
+
requestedTitle: string | undefined,
|
|
706
|
+
userOpenId: string | undefined,
|
|
707
|
+
): Promise<ControlTaskGroupResult> {
|
|
708
|
+
const source = this.store.getSession(localSessionId);
|
|
709
|
+
if (!source || source.status === "closed") throw new Error(`Task not found: ${localSessionId}`);
|
|
710
|
+
const sourceContextKey = this.outbound.getSessionContextKey(localSessionId) ?? source.contextKey;
|
|
711
|
+
const replyTarget = this.outbound.getSessionReplyTarget(localSessionId);
|
|
712
|
+
const plan = await this.prepareForkSession(sourceContextKey, localSessionId, requestedTitle);
|
|
713
|
+
const prepared: ForkGroupSessionPlan = {
|
|
714
|
+
plan,
|
|
715
|
+
sourceDescription: plan.forkedFromHistoricalTurn
|
|
716
|
+
? "当前任务最近已完成轮次"
|
|
717
|
+
: "当前任务最新轮次",
|
|
718
|
+
};
|
|
719
|
+
const forked = await this.outbound.withReplyTarget(sourceContextKey, replyTarget, () =>
|
|
720
|
+
this.forkPreparedSessionToFeishuGroup(
|
|
721
|
+
sourceContextKey,
|
|
722
|
+
prepared,
|
|
723
|
+
userOpenId ?? "",
|
|
724
|
+
"当前任务",
|
|
725
|
+
));
|
|
726
|
+
return {
|
|
727
|
+
sourceLocalSessionId: source.localSessionId,
|
|
728
|
+
sourceTurnId: plan.lastTurnId,
|
|
729
|
+
group: forked.group,
|
|
730
|
+
task: forked.task,
|
|
731
|
+
};
|
|
732
|
+
}
|
|
733
|
+
|
|
644
734
|
private cardActionContextKey(action: CardAction): string {
|
|
645
735
|
const explicit = typeof action.value.contextKey === "string" ? action.value.contextKey : undefined;
|
|
646
736
|
if (explicit && baseChatContextKey(explicit) === baseChatContextKey(action.contextKey)) return explicit;
|
|
@@ -676,8 +766,8 @@ export class ProxySessionController {
|
|
|
676
766
|
await this.runShellCommand(contextKey, command.command);
|
|
677
767
|
return;
|
|
678
768
|
case "new":
|
|
679
|
-
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "
|
|
680
|
-
throw new Error("/new --nodir 仅支持
|
|
769
|
+
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "app-server") {
|
|
770
|
+
throw new Error("/new --nodir 仅支持 App Server Agent。");
|
|
681
771
|
}
|
|
682
772
|
await this.createSession(
|
|
683
773
|
contextKey,
|
|
@@ -696,8 +786,8 @@ export class ProxySessionController {
|
|
|
696
786
|
);
|
|
697
787
|
return;
|
|
698
788
|
case "newgroup":
|
|
699
|
-
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "
|
|
700
|
-
throw new Error("/newgroup --nodir 仅支持
|
|
789
|
+
if (command.projectless && this.ensureAgent(context.defaultAgent).kind !== "app-server") {
|
|
790
|
+
throw new Error("/newgroup --nodir 仅支持 App Server Agent。");
|
|
701
791
|
}
|
|
702
792
|
await this.createFeishuGroup(
|
|
703
793
|
contextKey,
|
|
@@ -772,7 +862,13 @@ export class ProxySessionController {
|
|
|
772
862
|
const turnContextKey = session.lastTurnId
|
|
773
863
|
? this.store.getTurnContextKey(session.lastTurnId) ?? context.contextKey
|
|
774
864
|
: context.contextKey;
|
|
775
|
-
this.outbound.registerSession(
|
|
865
|
+
this.outbound.registerSession(
|
|
866
|
+
session.localSessionId,
|
|
867
|
+
turnContextKey,
|
|
868
|
+
session.title,
|
|
869
|
+
session.cwd,
|
|
870
|
+
this.agentLabel(session.agentName),
|
|
871
|
+
);
|
|
776
872
|
if (!session.lastTurnId) continue;
|
|
777
873
|
void this.outbound.resumeDelivery(session.localSessionId, turnContextKey, session.lastTurnId).catch((error: unknown) => {
|
|
778
874
|
this.logger.warn({ error, sessionId: session.localSessionId }, "Failed to restore persisted turn delivery.");
|
|
@@ -811,7 +907,7 @@ export class ProxySessionController {
|
|
|
811
907
|
replyTarget?: MessageReplyTarget,
|
|
812
908
|
localImagePaths?: string[],
|
|
813
909
|
): Promise<void> {
|
|
814
|
-
if (!text.trim()) throw new Error("请输入要交给
|
|
910
|
+
if (!text.trim()) throw new Error("请输入要交给 Agent 的内容。");
|
|
815
911
|
let record = this.currentSession(contextKey);
|
|
816
912
|
if (!record) {
|
|
817
913
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent!);
|
|
@@ -838,7 +934,13 @@ export class ProxySessionController {
|
|
|
838
934
|
): Promise<void> {
|
|
839
935
|
const configuredRuntime = this.runtimes.forAgent(record.agentName);
|
|
840
936
|
if (!configuredRuntime.getSession(record.localSessionId)) {
|
|
841
|
-
this.outbound.registerSession(
|
|
937
|
+
this.outbound.registerSession(
|
|
938
|
+
record.localSessionId,
|
|
939
|
+
contextKey,
|
|
940
|
+
record.title,
|
|
941
|
+
record.cwd,
|
|
942
|
+
this.agentLabel(record.agentName),
|
|
943
|
+
);
|
|
842
944
|
await this.outbound.startPendingTurn(record.localSessionId, contextKey, record.title, replyTarget, text);
|
|
843
945
|
}
|
|
844
946
|
let loaded: LoadedSession;
|
|
@@ -879,7 +981,7 @@ export class ProxySessionController {
|
|
|
879
981
|
if (messageId) await this.bindMessageReactionToTurn(messageId, record.localSessionId, activeTurnId);
|
|
880
982
|
return;
|
|
881
983
|
} catch (error) {
|
|
882
|
-
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the
|
|
984
|
+
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the App Server thread.");
|
|
883
985
|
let current = loaded.runtime.getSession(record.localSessionId);
|
|
884
986
|
try {
|
|
885
987
|
current = await loaded.runtime.synchronizeSession(record.localSessionId);
|
|
@@ -904,7 +1006,7 @@ export class ProxySessionController {
|
|
|
904
1006
|
} catch (retryError) {
|
|
905
1007
|
this.logger.warn(
|
|
906
1008
|
{ error: retryError, sessionId: record.localSessionId, activeTurnId: current.activeTurnId },
|
|
907
|
-
"Failed to steer the reconciled
|
|
1009
|
+
"Failed to steer the reconciled App Server turn; queueing prompt.",
|
|
908
1010
|
);
|
|
909
1011
|
}
|
|
910
1012
|
}
|
|
@@ -1074,7 +1176,7 @@ export class ProxySessionController {
|
|
|
1074
1176
|
const agent = this.ensureAgent(source.agentName);
|
|
1075
1177
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
1076
1178
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1077
|
-
throw new Error("当前
|
|
1179
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1078
1180
|
}
|
|
1079
1181
|
|
|
1080
1182
|
const context = this.store.getOrCreateUserContext(message.contextKey, source.agentName);
|
|
@@ -1098,7 +1200,13 @@ export class ProxySessionController {
|
|
|
1098
1200
|
permissionMode: source.permissionMode ?? "auto",
|
|
1099
1201
|
});
|
|
1100
1202
|
this.store.setCurrentSession(message.contextKey, localSessionId);
|
|
1101
|
-
this.outbound.registerSession(
|
|
1203
|
+
this.outbound.registerSession(
|
|
1204
|
+
localSessionId,
|
|
1205
|
+
message.contextKey,
|
|
1206
|
+
forkTitle,
|
|
1207
|
+
source.cwd,
|
|
1208
|
+
this.agentLabel(source.agentName),
|
|
1209
|
+
);
|
|
1102
1210
|
|
|
1103
1211
|
try {
|
|
1104
1212
|
const forked = await runtime.forkSession({
|
|
@@ -1145,14 +1253,14 @@ export class ProxySessionController {
|
|
|
1145
1253
|
.map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
|
|
1146
1254
|
.find((candidate) => candidate !== undefined);
|
|
1147
1255
|
if (!anchor) {
|
|
1148
|
-
throw new Error("无法确定这个话题对应的
|
|
1256
|
+
throw new Error("无法确定这个话题对应的 App Server 轮次,因此没有创建分支任务。请从该轮的用户消息、思考卡片或最终回答创建话题。");
|
|
1149
1257
|
}
|
|
1150
1258
|
|
|
1151
1259
|
const source = anchor.contextKey
|
|
1152
1260
|
? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
|
|
1153
1261
|
: this.store.getSession(anchor.localSessionId);
|
|
1154
1262
|
if (!source || !source.remoteSessionId || !this.isCodexSession(source)) {
|
|
1155
|
-
throw new Error("这个话题的来源不是可 fork 的
|
|
1263
|
+
throw new Error("这个话题的来源不是可 fork 的 App Server 任务。");
|
|
1156
1264
|
}
|
|
1157
1265
|
if (baseChatContextKey(anchor.contextKey ?? source.contextKey) !== `chat_id:${message.chatId}`) {
|
|
1158
1266
|
throw new Error("话题来源任务不属于当前会话,已拒绝创建分支。");
|
|
@@ -1161,7 +1269,7 @@ export class ProxySessionController {
|
|
|
1161
1269
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(anchor.turnId));
|
|
1162
1270
|
if (isTurnStillRunning(snapshot?.status)
|
|
1163
1271
|
|| (source.lastTurnId === anchor.turnId && source.lastTurnStatus === "running")) {
|
|
1164
|
-
throw new Error("话题对应的轮次仍在执行,
|
|
1272
|
+
throw new Error("话题对应的轮次仍在执行,App Server 暂时不能从这一轮 fork。请等待该轮完成后再在话题中发送消息。");
|
|
1165
1273
|
}
|
|
1166
1274
|
|
|
1167
1275
|
return { anchor, source, snapshot };
|
|
@@ -1203,7 +1311,7 @@ export class ProxySessionController {
|
|
|
1203
1311
|
}
|
|
1204
1312
|
|
|
1205
1313
|
if (source && (!source.remoteSessionId || !this.isCodexSession(source))) {
|
|
1206
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
1314
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
1207
1315
|
}
|
|
1208
1316
|
|
|
1209
1317
|
let runtime: AgentRuntime;
|
|
@@ -1213,20 +1321,20 @@ export class ProxySessionController {
|
|
|
1213
1321
|
agentName = source.agentName;
|
|
1214
1322
|
runtime = this.runtimes.forAgent(agentName);
|
|
1215
1323
|
} else {
|
|
1216
|
-
if (!taskId) throw new Error("缺少要 fork 的
|
|
1324
|
+
if (!taskId) throw new Error("缺少要 fork 的 App Server 任务 ID。");
|
|
1217
1325
|
const resolved = await this.resolveRemoteCodexSession(taskId);
|
|
1218
1326
|
agentName = resolved.agentName;
|
|
1219
1327
|
runtime = resolved.runtime;
|
|
1220
1328
|
remote = resolved.remote;
|
|
1221
1329
|
}
|
|
1222
1330
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1223
|
-
throw new Error("当前
|
|
1331
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1224
1332
|
}
|
|
1225
1333
|
|
|
1226
1334
|
const remoteSessionId = source?.remoteSessionId ?? remote?.id ?? taskId;
|
|
1227
|
-
if (!remoteSessionId) throw new Error("当前任务尚未创建
|
|
1335
|
+
if (!remoteSessionId) throw new Error("当前任务尚未创建 App Server 任务 ID,暂时不能 fork。");
|
|
1228
1336
|
if (!runtime.readRemoteSession && !source) {
|
|
1229
|
-
throw new Error("当前
|
|
1337
|
+
throw new Error("当前 App Server Agent 不支持读取指定任务。");
|
|
1230
1338
|
}
|
|
1231
1339
|
remote ??= runtime.readRemoteSession
|
|
1232
1340
|
? await runtime.readRemoteSession(remoteSessionId)
|
|
@@ -1251,7 +1359,7 @@ export class ProxySessionController {
|
|
|
1251
1359
|
const forkedFromHistoricalTurn = isRunning && lastTurnId !== latestTurnId;
|
|
1252
1360
|
|
|
1253
1361
|
const cwd = remote?.cwd || source?.cwd;
|
|
1254
|
-
if (!cwd) throw new Error("指定的
|
|
1362
|
+
if (!cwd) throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能 fork。");
|
|
1255
1363
|
const sourceTitle = remote?.title ?? source?.title ?? remote?.preview;
|
|
1256
1364
|
const forkTitle = normalizeTaskTitle(requestedTitle) ?? this.store.nextForkTitle(sourceTitle);
|
|
1257
1365
|
const modelProvider = remote?.modelProvider ?? source?.modelProvider;
|
|
@@ -1332,16 +1440,16 @@ export class ProxySessionController {
|
|
|
1332
1440
|
sourceLabel: string,
|
|
1333
1441
|
): ForkSessionPlan {
|
|
1334
1442
|
if (!source.remoteSessionId || !this.isCodexSession(source)) {
|
|
1335
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
1443
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
1336
1444
|
}
|
|
1337
1445
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
1338
1446
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1339
|
-
throw new Error("当前
|
|
1447
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1340
1448
|
}
|
|
1341
1449
|
|
|
1342
1450
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(lastTurnId));
|
|
1343
1451
|
if (isTurnStillRunning(snapshot?.status)) {
|
|
1344
|
-
throw new Error(`${sourceLabel}仍在执行,
|
|
1452
|
+
throw new Error(`${sourceLabel}仍在执行,App Server 暂时不能从这一轮 fork。`);
|
|
1345
1453
|
}
|
|
1346
1454
|
const sourceWasRunning = Boolean(
|
|
1347
1455
|
runtime.getSession(source.localSessionId)?.activeTurnId
|
|
@@ -1411,7 +1519,13 @@ export class ProxySessionController {
|
|
|
1411
1519
|
lastTurnStatus: plan.lastTurnStatus,
|
|
1412
1520
|
});
|
|
1413
1521
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
1414
|
-
this.outbound.registerSession(
|
|
1522
|
+
this.outbound.registerSession(
|
|
1523
|
+
localSessionId,
|
|
1524
|
+
contextKey,
|
|
1525
|
+
forked.title ?? plan.forkTitle,
|
|
1526
|
+
plan.cwd,
|
|
1527
|
+
this.agentLabel(plan.agentName),
|
|
1528
|
+
);
|
|
1415
1529
|
this.store.audit(contextKey, "session_forked", {
|
|
1416
1530
|
sourceLocalSessionId: plan.source?.localSessionId,
|
|
1417
1531
|
sourceRemoteSessionId: plan.remoteSessionId,
|
|
@@ -1464,7 +1578,7 @@ export class ProxySessionController {
|
|
|
1464
1578
|
}
|
|
1465
1579
|
const source = direct ?? this.findStoredSessionByReference(taskId);
|
|
1466
1580
|
if (source && !this.isCodexSession(source)) {
|
|
1467
|
-
throw new Error("指定任务不是
|
|
1581
|
+
throw new Error("指定任务不是 App Server 任务,暂时不能按项目创建新任务。");
|
|
1468
1582
|
}
|
|
1469
1583
|
|
|
1470
1584
|
let agentName: string;
|
|
@@ -1495,7 +1609,7 @@ export class ProxySessionController {
|
|
|
1495
1609
|
|
|
1496
1610
|
const cwd = remote?.cwd || source?.cwd;
|
|
1497
1611
|
if (!cwd) {
|
|
1498
|
-
throw new Error("指定的
|
|
1612
|
+
throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能按项目创建新任务。");
|
|
1499
1613
|
}
|
|
1500
1614
|
const executionSettings: SessionExecutionSettings = {
|
|
1501
1615
|
modelProvider: remote?.modelProvider ?? source?.modelProvider,
|
|
@@ -1566,7 +1680,7 @@ export class ProxySessionController {
|
|
|
1566
1680
|
const agent = this.ensureAgent(agentName);
|
|
1567
1681
|
const localSessionId = createId("sess");
|
|
1568
1682
|
const initialTitle = normalizeTaskTitle(requestedTitle ?? prompt ?? "");
|
|
1569
|
-
const sessionCwd = cwd === undefined && agent.kind === "
|
|
1683
|
+
const sessionCwd = cwd === undefined && agent.kind === "app-server"
|
|
1570
1684
|
? createProjectlessWorkspace({ prompt: initialTitle }).cwd
|
|
1571
1685
|
: path.resolve(cwd ?? this.config.defaults.cwd);
|
|
1572
1686
|
const record = this.store.createSession({ localSessionId, contextKey, agentName, cwd: sessionCwd, status: "starting" });
|
|
@@ -1580,7 +1694,13 @@ export class ProxySessionController {
|
|
|
1580
1694
|
});
|
|
1581
1695
|
}
|
|
1582
1696
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
1583
|
-
this.outbound.registerSession(
|
|
1697
|
+
this.outbound.registerSession(
|
|
1698
|
+
localSessionId,
|
|
1699
|
+
contextKey,
|
|
1700
|
+
initialTitle,
|
|
1701
|
+
sessionCwd,
|
|
1702
|
+
this.agentLabel(agentName),
|
|
1703
|
+
);
|
|
1584
1704
|
const runtime = this.runtimes.forAgent(agentName);
|
|
1585
1705
|
try {
|
|
1586
1706
|
if (prepareTurn) {
|
|
@@ -1666,9 +1786,9 @@ export class ProxySessionController {
|
|
|
1666
1786
|
userId: string | undefined,
|
|
1667
1787
|
boundProjectCwd: string | undefined,
|
|
1668
1788
|
executionSettings: SessionExecutionSettings,
|
|
1669
|
-
): Promise<
|
|
1789
|
+
): Promise<CreatedFeishuTaskGroup> {
|
|
1670
1790
|
const explicitTitle = normalizeTaskTitle(requestedTitle);
|
|
1671
|
-
const taskTitle = explicitTitle ??
|
|
1791
|
+
const taskTitle = explicitTitle ?? `新任务 (${formatGroupDateSuffix(new Date())})`;
|
|
1672
1792
|
const group = await this.createFeishuGroupContext(
|
|
1673
1793
|
sourceContextKey,
|
|
1674
1794
|
agentName,
|
|
@@ -1676,7 +1796,7 @@ export class ProxySessionController {
|
|
|
1676
1796
|
userId,
|
|
1677
1797
|
boundProjectCwd,
|
|
1678
1798
|
"/newgroup",
|
|
1679
|
-
|
|
1799
|
+
false,
|
|
1680
1800
|
);
|
|
1681
1801
|
|
|
1682
1802
|
let task: SessionRecord;
|
|
@@ -1709,7 +1829,7 @@ export class ProxySessionController {
|
|
|
1709
1829
|
"群和新任务已创建。",
|
|
1710
1830
|
`当前任务:${taskDescription}`,
|
|
1711
1831
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1712
|
-
`当前 Provider:${task.modelProvider ?? "
|
|
1832
|
+
`当前 Provider:${task.modelProvider ?? "Agent 默认"}`,
|
|
1713
1833
|
`当前模型:${task.model ?? "默认"}`,
|
|
1714
1834
|
`思考强度:${task.reasoningEffort ?? "自动"}`,
|
|
1715
1835
|
`权限类型:${task.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
@@ -1719,6 +1839,7 @@ export class ProxySessionController {
|
|
|
1719
1839
|
sourceContextKey,
|
|
1720
1840
|
`已创建飞书群:${group.name},并创建新任务 ${taskDescription}。`,
|
|
1721
1841
|
);
|
|
1842
|
+
return { group, task };
|
|
1722
1843
|
}
|
|
1723
1844
|
|
|
1724
1845
|
private async forkCurrentSessionToFeishuGroup(
|
|
@@ -1766,7 +1887,7 @@ export class ProxySessionController {
|
|
|
1766
1887
|
prepared: ForkGroupSessionPlan,
|
|
1767
1888
|
userId: string,
|
|
1768
1889
|
sourceSummary: string,
|
|
1769
|
-
): Promise<
|
|
1890
|
+
): Promise<CreatedFeishuTaskGroup> {
|
|
1770
1891
|
const { plan } = prepared;
|
|
1771
1892
|
const boundProjectCwd = detectProjectlessWorkspace(plan.cwd) ? undefined : plan.cwd;
|
|
1772
1893
|
const group = await this.createFeishuGroupContext(
|
|
@@ -1799,7 +1920,7 @@ export class ProxySessionController {
|
|
|
1799
1920
|
`已从${prepared.sourceDescription}创建分支。`,
|
|
1800
1921
|
`当前任务:${taskDescription}`,
|
|
1801
1922
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1802
|
-
`当前 Provider:${forked.session.modelProvider ?? "
|
|
1923
|
+
`当前 Provider:${forked.session.modelProvider ?? "Agent 默认"}`,
|
|
1803
1924
|
`当前模型:${forked.session.model ?? "默认"}`,
|
|
1804
1925
|
`思考强度:${forked.session.reasoningEffort ?? "自动"}`,
|
|
1805
1926
|
`权限类型:${forked.session.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
@@ -1809,6 +1930,7 @@ export class ProxySessionController {
|
|
|
1809
1930
|
sourceContextKey,
|
|
1810
1931
|
`已将${sourceSummary} Fork 到飞书群:${group.name};新群当前任务为 ${taskDescription}。`,
|
|
1811
1932
|
);
|
|
1933
|
+
return { group, task: forked.record };
|
|
1812
1934
|
}
|
|
1813
1935
|
|
|
1814
1936
|
private async createFeishuGroupContext(
|
|
@@ -1836,7 +1958,7 @@ export class ProxySessionController {
|
|
|
1836
1958
|
this.store.recordChatContext(groupContextKey, "group");
|
|
1837
1959
|
this.store.getOrCreateUserContext(groupContextKey, agentName);
|
|
1838
1960
|
if (boundProjectCwd) this.store.setBoundProjectCwd(groupContextKey, boundProjectCwd);
|
|
1839
|
-
return { contextKey: groupContextKey, name: group.name };
|
|
1961
|
+
return { chatId: group.chatId, contextKey: groupContextKey, name: group.name };
|
|
1840
1962
|
}
|
|
1841
1963
|
|
|
1842
1964
|
private async loadSession(record: SessionRecord): Promise<LoadedSession> {
|
|
@@ -1847,7 +1969,13 @@ export class ProxySessionController {
|
|
|
1847
1969
|
const pending = this.sessionLoads.get(record.localSessionId);
|
|
1848
1970
|
if (pending) return pending;
|
|
1849
1971
|
|
|
1850
|
-
this.outbound.registerSession(
|
|
1972
|
+
this.outbound.registerSession(
|
|
1973
|
+
record.localSessionId,
|
|
1974
|
+
record.contextKey,
|
|
1975
|
+
record.title,
|
|
1976
|
+
record.cwd,
|
|
1977
|
+
this.agentLabel(record.agentName),
|
|
1978
|
+
);
|
|
1851
1979
|
const loading = (async (): Promise<LoadedSession> => {
|
|
1852
1980
|
if (record.lastTurnId) {
|
|
1853
1981
|
try {
|
|
@@ -1874,15 +2002,15 @@ export class ProxySessionController {
|
|
|
1874
2002
|
model: record.model,
|
|
1875
2003
|
reasoningEffort: record.reasoningEffort,
|
|
1876
2004
|
permissionMode,
|
|
1877
|
-
activeTurnId: agent.kind === "
|
|
2005
|
+
activeTurnId: agent.kind === "app-server" && record.status === "running" && record.lastTurnStatus === "running"
|
|
1878
2006
|
? record.lastTurnId
|
|
1879
2007
|
: undefined,
|
|
1880
2008
|
lastTurnId: record.lastTurnId,
|
|
1881
2009
|
lastTurnStatus: record.lastTurnStatus,
|
|
1882
2010
|
});
|
|
1883
2011
|
} catch (error) {
|
|
1884
|
-
if (!(agent.kind === "
|
|
1885
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "
|
|
2012
|
+
if (!(agent.kind === "app-server" && !record.lastTurnId && isMissingRolloutError(error))) throw error;
|
|
2013
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "App Server task has no rollout; creating a replacement task.");
|
|
1886
2014
|
session = await runtime.createSession({
|
|
1887
2015
|
localSessionId: record.localSessionId,
|
|
1888
2016
|
agentName: record.agentName,
|
|
@@ -2102,7 +2230,7 @@ export class ProxySessionController {
|
|
|
2102
2230
|
} catch (error) {
|
|
2103
2231
|
this.logger.warn(
|
|
2104
2232
|
{ error, sessionId: record.localSessionId },
|
|
2105
|
-
"Failed to pause the active
|
|
2233
|
+
"Failed to pause the active Agent goal before interrupting its turn.",
|
|
2106
2234
|
);
|
|
2107
2235
|
}
|
|
2108
2236
|
}
|
|
@@ -2116,7 +2244,7 @@ export class ProxySessionController {
|
|
|
2116
2244
|
} catch (error) {
|
|
2117
2245
|
this.logger.warn(
|
|
2118
2246
|
{ error, sessionId: record.localSessionId, remoteSessionId: record.remoteSessionId },
|
|
2119
|
-
"Failed to inspect the current
|
|
2247
|
+
"Failed to inspect the current App Server turn before interrupting; using the locally tracked turn.",
|
|
2120
2248
|
);
|
|
2121
2249
|
}
|
|
2122
2250
|
}
|
|
@@ -2130,7 +2258,7 @@ export class ProxySessionController {
|
|
|
2130
2258
|
remoteSessionId: record.remoteSessionId,
|
|
2131
2259
|
turnId,
|
|
2132
2260
|
});
|
|
2133
|
-
await this.outbound.sendText(record.contextKey, `已向
|
|
2261
|
+
await this.outbound.sendText(record.contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
2134
2262
|
return;
|
|
2135
2263
|
}
|
|
2136
2264
|
|
|
@@ -2480,7 +2608,7 @@ export class ProxySessionController {
|
|
|
2480
2608
|
}
|
|
2481
2609
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent!);
|
|
2482
2610
|
const agent = this.ensureAgent(context.defaultAgent);
|
|
2483
|
-
if (agent.kind !== "
|
|
2611
|
+
if (agent.kind !== "app-server") throw new Error("Goal 模式仅支持 App Server 任务。");
|
|
2484
2612
|
record = await this.createSession(
|
|
2485
2613
|
contextKey,
|
|
2486
2614
|
context.defaultAgent,
|
|
@@ -2493,7 +2621,7 @@ export class ProxySessionController {
|
|
|
2493
2621
|
|
|
2494
2622
|
const loaded = await this.loadSession(record);
|
|
2495
2623
|
if (loaded.runtime.kind !== "codex" || !loaded.runtime.getGoal || !loaded.runtime.setGoal || !loaded.runtime.clearGoal) {
|
|
2496
|
-
throw new Error("
|
|
2624
|
+
throw new Error("当前 Agent 不支持 Goal 模式。");
|
|
2497
2625
|
}
|
|
2498
2626
|
|
|
2499
2627
|
if (command.action === "show") {
|
|
@@ -2520,7 +2648,7 @@ export class ProxySessionController {
|
|
|
2520
2648
|
goal,
|
|
2521
2649
|
command.action === "pause"
|
|
2522
2650
|
? "Goal 已暂停;当前轮次可以完成,但不会继续自动执行。"
|
|
2523
|
-
: "Goal 已恢复,
|
|
2651
|
+
: "Goal 已恢复,Agent 会继续自动执行。",
|
|
2524
2652
|
record,
|
|
2525
2653
|
);
|
|
2526
2654
|
return;
|
|
@@ -2541,7 +2669,7 @@ export class ProxySessionController {
|
|
|
2541
2669
|
await this.sendGoalCard(
|
|
2542
2670
|
contextKey,
|
|
2543
2671
|
goal,
|
|
2544
|
-
command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,
|
|
2672
|
+
command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,Agent 会持续执行直到完成、暂停或遇到阻塞。",
|
|
2545
2673
|
record,
|
|
2546
2674
|
);
|
|
2547
2675
|
}
|
|
@@ -2562,7 +2690,7 @@ export class ProxySessionController {
|
|
|
2562
2690
|
title: "任务",
|
|
2563
2691
|
lines: [
|
|
2564
2692
|
`**标题**:${cardText(record.title ?? "未命名任务")}`,
|
|
2565
|
-
`**
|
|
2693
|
+
`**App Server 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
|
|
2566
2694
|
],
|
|
2567
2695
|
});
|
|
2568
2696
|
}
|
|
@@ -2573,7 +2701,7 @@ export class ProxySessionController {
|
|
|
2573
2701
|
"**/goal edit <新目标>** 修改 **/goal clear** 清除",
|
|
2574
2702
|
],
|
|
2575
2703
|
});
|
|
2576
|
-
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("
|
|
2704
|
+
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("Agent Goal", sections));
|
|
2577
2705
|
}
|
|
2578
2706
|
|
|
2579
2707
|
private async runShellCommand(contextKey: string, command: string): Promise<void> {
|
|
@@ -2717,7 +2845,7 @@ export class ProxySessionController {
|
|
|
2717
2845
|
remoteSessions.push(...page.sessions.map((session) => ({ agentName, session })));
|
|
2718
2846
|
remoteHasMore ||= Boolean(page.nextCursor);
|
|
2719
2847
|
} catch (error) {
|
|
2720
|
-
this.logger.warn({ error, contextKey, agentName }, "Failed to list
|
|
2848
|
+
this.logger.warn({ error, contextKey, agentName }, "Failed to list App Server sessions for an Agent.");
|
|
2721
2849
|
remoteErrors.push(`${agentName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2722
2850
|
}
|
|
2723
2851
|
}));
|
|
@@ -2809,7 +2937,7 @@ export class ProxySessionController {
|
|
|
2809
2937
|
};
|
|
2810
2938
|
});
|
|
2811
2939
|
const card = this.cardRenderer.renderTaskListCard(
|
|
2812
|
-
searchTerm ? `
|
|
2940
|
+
searchTerm ? `App Server 任务:${searchTerm}` : "App Server 任务",
|
|
2813
2941
|
activeCount > 0 ? `任务(${activeCount} 个活跃)` : "任务",
|
|
2814
2942
|
cardEntries,
|
|
2815
2943
|
[
|
|
@@ -2878,7 +3006,7 @@ export class ProxySessionController {
|
|
|
2878
3006
|
const candidates = scoped
|
|
2879
3007
|
? [[scoped.agentName, this.runtimes.forAgent(scoped.agentName)] as const]
|
|
2880
3008
|
: this.runtimes.entries("codex");
|
|
2881
|
-
if (candidates.length === 0) throw new Error("未配置
|
|
3009
|
+
if (candidates.length === 0) throw new Error("未配置 App Server Agent。");
|
|
2882
3010
|
|
|
2883
3011
|
const reads = await Promise.allSettled(candidates.map(async ([agentName, runtime]) => {
|
|
2884
3012
|
if (runtime.kind !== "codex" || !runtime.readRemoteSession) {
|
|
@@ -2903,7 +3031,7 @@ export class ProxySessionController {
|
|
|
2903
3031
|
: undefined)
|
|
2904
3032
|
.filter((detail): detail is string => Boolean(detail))
|
|
2905
3033
|
.join(";");
|
|
2906
|
-
throw new Error(`找不到
|
|
3034
|
+
throw new Error(`找不到 App Server 任务:${scoped?.remoteSessionId ?? reference}${details ? `(${details})` : ""}`);
|
|
2907
3035
|
}
|
|
2908
3036
|
|
|
2909
3037
|
private async switchSession(contextKey: string, reference?: string): Promise<void> {
|
|
@@ -2919,16 +3047,22 @@ export class ProxySessionController {
|
|
|
2919
3047
|
await this.assertSessionTurnOwnership(existing, runtime);
|
|
2920
3048
|
this.store.attachSessionToContext(contextKey, existing.localSessionId);
|
|
2921
3049
|
this.store.setCurrentSession(contextKey, existing.localSessionId);
|
|
2922
|
-
this.outbound.registerSession(
|
|
3050
|
+
this.outbound.registerSession(
|
|
3051
|
+
existing.localSessionId,
|
|
3052
|
+
contextKey,
|
|
3053
|
+
existing.title,
|
|
3054
|
+
existing.cwd,
|
|
3055
|
+
this.agentLabel(existing.agentName),
|
|
3056
|
+
);
|
|
2923
3057
|
await this.outbound.sendText(contextKey, `已切换到任务:${existing.title ?? existing.remoteSessionId ?? taskId}`);
|
|
2924
3058
|
return;
|
|
2925
3059
|
}
|
|
2926
3060
|
|
|
2927
3061
|
const { agentName, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
2928
3062
|
if (remote.status === "active" || remote.lastTurnStatus === "inProgress") {
|
|
2929
|
-
throw new Error(`这个任务正在外部
|
|
3063
|
+
throw new Error(`这个任务正在外部 Agent 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
|
|
2930
3064
|
}
|
|
2931
|
-
if (!remote.cwd) throw new Error("这个
|
|
3065
|
+
if (!remote.cwd) throw new Error("这个 App Server 任务没有可用的工作目录,暂时无法切换。");
|
|
2932
3066
|
const localSessionId = createId("sess");
|
|
2933
3067
|
this.store.createSession({
|
|
2934
3068
|
localSessionId,
|
|
@@ -2946,7 +3080,13 @@ export class ProxySessionController {
|
|
|
2946
3080
|
lastTurnStatus: mapRemoteTurnStatus(remote.lastTurnStatus),
|
|
2947
3081
|
});
|
|
2948
3082
|
this.store.setCurrentSession(contextKey, localSessionId);
|
|
2949
|
-
this.outbound.registerSession(
|
|
3083
|
+
this.outbound.registerSession(
|
|
3084
|
+
localSessionId,
|
|
3085
|
+
contextKey,
|
|
3086
|
+
remote.title ?? remote.preview,
|
|
3087
|
+
remote.cwd,
|
|
3088
|
+
this.agentLabel(agentName),
|
|
3089
|
+
);
|
|
2950
3090
|
await this.outbound.sendText(
|
|
2951
3091
|
contextKey,
|
|
2952
3092
|
`已切换到任务:${remote.title ?? remote.preview ?? remote.id}。历史消息不会重新发送。`,
|
|
@@ -2969,7 +3109,7 @@ export class ProxySessionController {
|
|
|
2969
3109
|
|
|
2970
3110
|
const { runtime, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
2971
3111
|
if (!runtime.readRemoteSession || !runtime.interruptRemoteTurn) {
|
|
2972
|
-
throw new Error("当前
|
|
3112
|
+
throw new Error("当前 App Server Agent 不支持停止外部任务。");
|
|
2973
3113
|
}
|
|
2974
3114
|
const turnId = remote.status === "active" || remote.lastTurnStatus === "inProgress"
|
|
2975
3115
|
? remote.lastTurnId
|
|
@@ -2984,7 +3124,7 @@ export class ProxySessionController {
|
|
|
2984
3124
|
turnId,
|
|
2985
3125
|
source: "sessions_card",
|
|
2986
3126
|
});
|
|
2987
|
-
await this.outbound.sendText(contextKey, `已向
|
|
3127
|
+
await this.outbound.sendText(contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
2988
3128
|
}
|
|
2989
3129
|
|
|
2990
3130
|
private resolveSessionReference(contextKey: string, reference?: string): string {
|
|
@@ -3025,7 +3165,7 @@ export class ProxySessionController {
|
|
|
3025
3165
|
&& activity.activeTurnId === record.lastTurnId;
|
|
3026
3166
|
const botOwnsActiveTurn = runtimeOwnsActiveTurn || persistedTurnMatches;
|
|
3027
3167
|
if (activity.active && !botOwnsActiveTurn) {
|
|
3028
|
-
throw new Error("这个任务正在外部
|
|
3168
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
3029
3169
|
}
|
|
3030
3170
|
return activity;
|
|
3031
3171
|
}
|
|
@@ -3033,14 +3173,14 @@ export class ProxySessionController {
|
|
|
3033
3173
|
try {
|
|
3034
3174
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
3035
3175
|
} catch (error) {
|
|
3036
|
-
//
|
|
3176
|
+
// App Server does not materialize a new thread until its first user message.
|
|
3037
3177
|
// Such a thread has no turn to take over, so allow turn/start to create it.
|
|
3038
3178
|
if (!record.lastTurnId && isUnmaterializedCodexThreadError(error)) return;
|
|
3039
3179
|
throw error;
|
|
3040
3180
|
}
|
|
3041
3181
|
const botOwnsActiveTurn = isBotOwnedActiveTurn(record, remote);
|
|
3042
3182
|
if ((remote.status === "active" || remote.lastTurnStatus === "inProgress") && !botOwnsActiveTurn) {
|
|
3043
|
-
throw new Error("这个任务正在外部
|
|
3183
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
3044
3184
|
}
|
|
3045
3185
|
return undefined;
|
|
3046
3186
|
}
|
|
@@ -3105,7 +3245,7 @@ export class ProxySessionController {
|
|
|
3105
3245
|
try {
|
|
3106
3246
|
remote = await runtime.readRemoteSession(current.remoteSessionId);
|
|
3107
3247
|
} catch (error) {
|
|
3108
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
3248
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect App Server task status.");
|
|
3109
3249
|
}
|
|
3110
3250
|
}
|
|
3111
3251
|
if (runtime.kind === "codex" && runtime.getGoal) {
|
|
@@ -3113,7 +3253,7 @@ export class ProxySessionController {
|
|
|
3113
3253
|
const loaded = runtime.getSession(current.localSessionId) ?? (await this.loadSession(current)).session;
|
|
3114
3254
|
goal = await runtime.getGoal(loaded.localSessionId);
|
|
3115
3255
|
} catch (error) {
|
|
3116
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
3256
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect Agent goal status.");
|
|
3117
3257
|
}
|
|
3118
3258
|
}
|
|
3119
3259
|
}
|
|
@@ -3125,7 +3265,7 @@ export class ProxySessionController {
|
|
|
3125
3265
|
let activeTurnId: string | undefined;
|
|
3126
3266
|
let queued = 0;
|
|
3127
3267
|
if (!current) {
|
|
3128
|
-
taskLines.push("无。直接发送消息即可创建一个未指定项目的
|
|
3268
|
+
taskLines.push("无。直接发送消息即可创建一个未指定项目的 Agent 任务。");
|
|
3129
3269
|
} else {
|
|
3130
3270
|
const agent = this.ensureAgent(current.agentName);
|
|
3131
3271
|
const runtimeSession = this.runtimes.forAgent(current.agentName).getSession(current.localSessionId);
|
|
@@ -3143,11 +3283,11 @@ export class ProxySessionController {
|
|
|
3143
3283
|
taskLines.push(
|
|
3144
3284
|
`**标题**:${cardCode(current.title ?? "未命名任务")}`,
|
|
3145
3285
|
`**工作目录**:${cardCode(current.cwd)}`,
|
|
3146
|
-
`**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "
|
|
3286
|
+
`**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "Agent 默认")} / ${cardCode(current.model ?? "默认")} / ${cardCode(current.reasoningEffort ?? "自动")}`,
|
|
3147
3287
|
`**状态 / 最近结果**:${statusLabel} / ${resultLabel}`,
|
|
3148
3288
|
`**Agent**:${cardCode(agent.title)}`,
|
|
3149
3289
|
`**权限 / 任务范围**:${current.permissionMode === "confirm" ? "执行前确认" : "自动执行"} / ${detectProjectlessWorkspace(current.cwd) ? "未指定项目" : "指定项目"}`,
|
|
3150
|
-
`**
|
|
3290
|
+
`**App Server 任务 ID**:${cardCode(current.remoteSessionId ?? "尚未创建")}`,
|
|
3151
3291
|
`**当前执行 / 排队消息**:${activeTurnId ? cardCode(activeTurnId) : "无"} / ${queued} 条`,
|
|
3152
3292
|
`**创建时间 / 最近活动**:${formatStatusTime(current.createdAt)} / ${formatStatusTime(current.updatedAt)}`,
|
|
3153
3293
|
);
|
|
@@ -3178,8 +3318,8 @@ export class ProxySessionController {
|
|
|
3178
3318
|
},
|
|
3179
3319
|
];
|
|
3180
3320
|
const title = targetSessionId && current
|
|
3181
|
-
? `
|
|
3182
|
-
: "
|
|
3321
|
+
? `Agent 状态:${truncateText((current.title ?? current.remoteSessionId ?? current.localSessionId).replace(/\s+/g, " "), 40)}`
|
|
3322
|
+
: "Agent 状态";
|
|
3183
3323
|
const taskId = current?.remoteSessionId
|
|
3184
3324
|
? remoteSessionReference(current.agentName, current.remoteSessionId)
|
|
3185
3325
|
: current?.localSessionId;
|
|
@@ -3223,7 +3363,7 @@ export class ProxySessionController {
|
|
|
3223
3363
|
`**工作目录**:${cardCode(remote.cwd || "目录未知")}`,
|
|
3224
3364
|
`**状态 / 当前任务**:${remoteSessionDetailStatus(remote)} / 未切换`,
|
|
3225
3365
|
`**Agent**:${cardCode(agentName)}`,
|
|
3226
|
-
`**
|
|
3366
|
+
`**App Server 任务 ID**:${cardCode(remote.id)}`,
|
|
3227
3367
|
`**最近回合**:${cardCode(remote.lastTurnId ?? "无")} ${remoteTurnStatusLabel(remote.lastTurnStatus)}`,
|
|
3228
3368
|
`**创建时间 / 最近活动**:${formatRemoteTime(remote.createdAt)} / ${formatRemoteTime(latestRemoteTimestamp(remote.recencyAt, remote.updatedAt))}`,
|
|
3229
3369
|
],
|
|
@@ -3234,14 +3374,14 @@ export class ProxySessionController {
|
|
|
3234
3374
|
lines: [
|
|
3235
3375
|
`**当前 / 最后步骤**:${statusExcerpt(remote.lastActivity ?? remoteStatusStep(remote), 500)}`,
|
|
3236
3376
|
isRemoteSessionActive(remote)
|
|
3237
|
-
? "外部
|
|
3377
|
+
? "外部 Agent 正在执行;Agent Bot 只读取状态,不会接管。"
|
|
3238
3378
|
: `发送 **/switch ${cardText(remote.id)}** 切换到此任务。`,
|
|
3239
3379
|
],
|
|
3240
3380
|
collapsible: true,
|
|
3241
3381
|
elementId: "status_execution_details",
|
|
3242
3382
|
},
|
|
3243
3383
|
];
|
|
3244
|
-
const title = `
|
|
3384
|
+
const title = `Agent 状态:${truncateText((remote.title ?? remote.preview ?? remote.id).replace(/\s+/g, " "), 40)}`;
|
|
3245
3385
|
const showStop = isRemoteSessionActive(remote)
|
|
3246
3386
|
&& options.forceSwitchTaskId !== actionReference
|
|
3247
3387
|
&& options.forceSwitchTaskId !== remote.id;
|
|
@@ -3320,9 +3460,13 @@ export class ProxySessionController {
|
|
|
3320
3460
|
return agent;
|
|
3321
3461
|
}
|
|
3322
3462
|
|
|
3463
|
+
private agentLabel(agentName: string): string {
|
|
3464
|
+
return this.ensureAgent(agentName).title;
|
|
3465
|
+
}
|
|
3466
|
+
|
|
3323
3467
|
private isCodexSession(session: SessionRecord): boolean {
|
|
3324
3468
|
if (session.runtimeKind) return session.runtimeKind === "codex";
|
|
3325
|
-
return this.config.agents[session.agentName]?.kind === "
|
|
3469
|
+
return this.config.agents[session.agentName]?.kind === "app-server";
|
|
3326
3470
|
}
|
|
3327
3471
|
|
|
3328
3472
|
private currentSession(contextKey: string): SessionRecord | undefined {
|