@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.
Files changed (97) hide show
  1. package/.env.example +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +63 -44
  4. package/README.zh.md +63 -44
  5. package/config.example.yaml +8 -22
  6. package/dist/cli/AgentPrerequisites.js +262 -0
  7. package/dist/cli/AgentPrerequisites.js.map +1 -0
  8. package/dist/cli/DefaultAgentSelection.js +47 -0
  9. package/dist/cli/DefaultAgentSelection.js.map +1 -0
  10. package/dist/cli/FeishuAppConfiguration.js +1 -1
  11. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  12. package/dist/cli/FeishuAppRegistration.js +2 -2
  13. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  14. package/dist/cli/Initializer.js +166 -3
  15. package/dist/cli/Initializer.js.map +1 -1
  16. package/dist/cli/ServerStarter.js +7 -2
  17. package/dist/cli/ServerStarter.js.map +1 -1
  18. package/dist/cli/controlProtocol.js.map +1 -1
  19. package/dist/cli/help.js +24 -20
  20. package/dist/cli/help.js.map +1 -1
  21. package/dist/cli/taskGroupOptions.js +95 -0
  22. package/dist/cli/taskGroupOptions.js.map +1 -0
  23. package/dist/cli.js +268 -6
  24. package/dist/cli.js.map +1 -1
  25. package/dist/codex/AppServerConnection.js +3 -3
  26. package/dist/codex/AppServerConnection.js.map +1 -1
  27. package/dist/codex/CodexProcessManager.js +4 -4
  28. package/dist/codex/CodexProcessManager.js.map +1 -1
  29. package/dist/codex/CodexRuntime.js +63 -25
  30. package/dist/codex/CodexRuntime.js.map +1 -1
  31. package/dist/config/loadConfig.js +8 -22
  32. package/dist/config/loadConfig.js.map +1 -1
  33. package/dist/config/schema.js +6 -1
  34. package/dist/config/schema.js.map +1 -1
  35. package/dist/console/ConsoleConnector.js +3 -3
  36. package/dist/console/ConsoleConnector.js.map +1 -1
  37. package/dist/console/ConsoleTurnPresenter.js +14 -7
  38. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  39. package/dist/deprecated-cli.js +5 -0
  40. package/dist/deprecated-cli.js.map +1 -0
  41. package/dist/feishu/CardRenderer.js +13 -12
  42. package/dist/feishu/CardRenderer.js.map +1 -1
  43. package/dist/feishu/FeishuTurnPresenter.js +9 -5
  44. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  45. package/dist/feishu/transport.js +1 -1
  46. package/dist/feishu/transport.js.map +1 -1
  47. package/dist/index.js +21 -3
  48. package/dist/index.js.map +1 -1
  49. package/dist/presentation/OutboundRouter.js +2 -2
  50. package/dist/presentation/OutboundRouter.js.map +1 -1
  51. package/dist/presentation/TurnStateReducer.js +2 -1
  52. package/dist/presentation/TurnStateReducer.js.map +1 -1
  53. package/dist/proxy/ProxySessionController.js +128 -72
  54. package/dist/proxy/ProxySessionController.js.map +1 -1
  55. package/dist/runtime/AcpRuntimeAdapter.js +3 -2
  56. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  57. package/dist/runtime/createAgentRuntimeRegistry.js +1 -1
  58. package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -1
  59. package/dist/supervision/systemEnvironment.js +129 -0
  60. package/dist/supervision/systemEnvironment.js.map +1 -0
  61. package/dist/supervisor.js +13 -1
  62. package/dist/supervisor.js.map +1 -1
  63. package/docs/technical-reference.md +53 -34
  64. package/docs/technical-reference.zh.md +53 -34
  65. package/npm-shrinkwrap.json +4 -3
  66. package/package.json +9 -4
  67. package/skills/agent-bot/SKILL.md +72 -33
  68. package/src/cli/AgentPrerequisites.ts +377 -0
  69. package/src/cli/DefaultAgentSelection.ts +56 -0
  70. package/src/cli/FeishuAppConfiguration.ts +2 -2
  71. package/src/cli/FeishuAppRegistration.ts +4 -4
  72. package/src/cli/Initializer.ts +206 -5
  73. package/src/cli/ServerStarter.ts +8 -3
  74. package/src/cli/controlProtocol.ts +21 -1
  75. package/src/cli/help.ts +24 -20
  76. package/src/cli/taskGroupOptions.ts +149 -0
  77. package/src/cli.ts +391 -9
  78. package/src/codex/AppServerConnection.ts +3 -3
  79. package/src/codex/CodexProcessManager.ts +4 -4
  80. package/src/codex/CodexRuntime.ts +84 -31
  81. package/src/config/loadConfig.ts +8 -22
  82. package/src/config/schema.ts +7 -1
  83. package/src/console/ConsoleConnector.ts +3 -3
  84. package/src/console/ConsoleTurnPresenter.ts +20 -7
  85. package/src/deprecated-cli.ts +9 -0
  86. package/src/feishu/CardRenderer.ts +13 -12
  87. package/src/feishu/FeishuTurnPresenter.ts +15 -1
  88. package/src/feishu/transport.ts +1 -1
  89. package/src/index.ts +34 -3
  90. package/src/presentation/OutboundRouter.ts +15 -3
  91. package/src/presentation/TurnStateReducer.ts +2 -0
  92. package/src/presentation/turnViewTypes.ts +1 -0
  93. package/src/proxy/ProxySessionController.ts +217 -73
  94. package/src/runtime/AcpRuntimeAdapter.ts +3 -1
  95. package/src/runtime/createAgentRuntimeRegistry.ts +1 -1
  96. package/src/supervision/systemEnvironment.ts +174 -0
  97. 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 Codex task status for CLI.");
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 !== "codex") {
680
- throw new Error("/new --nodir 仅支持 Codex Agent。");
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 !== "codex") {
700
- throw new Error("/newgroup --nodir 仅支持 Codex Agent。");
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(session.localSessionId, turnContextKey, session.title, session.cwd);
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("请输入要交给 Codex 的内容。");
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(record.localSessionId, contextKey, record.title, record.cwd);
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 Codex thread.");
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 Codex turn; queueing prompt.",
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("当前 Codex 运行时不支持 fork 任务。");
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(localSessionId, message.contextKey, forkTitle, source.cwd);
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("无法确定这个话题对应的 Codex 轮次,因此没有创建分支任务。请从该轮的用户消息、思考卡片或最终回答创建话题。");
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 的 Codex 任务。");
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("话题对应的轮次仍在执行,Codex 暂时不能从这一轮 fork。请等待该轮完成后再在话题中发送消息。");
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 的 Codex 任务。`);
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 的 Codex 任务 ID。");
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("当前 Codex 运行时不支持 fork 任务。");
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("当前任务尚未创建 Codex 任务 ID,暂时不能 fork。");
1335
+ if (!remoteSessionId) throw new Error("当前任务尚未创建 App Server 任务 ID,暂时不能 fork。");
1228
1336
  if (!runtime.readRemoteSession && !source) {
1229
- throw new Error("当前 Codex 运行时不支持读取指定任务。");
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("指定的 Codex 任务没有可用的工作目录,暂时不能 fork。");
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 的 Codex 任务。`);
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("当前 Codex 运行时不支持 fork 任务。");
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}仍在执行,Codex 暂时不能从这一轮 fork。`);
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(localSessionId, contextKey, forked.title ?? plan.forkTitle, plan.cwd);
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("指定任务不是 Codex 任务,暂时不能按项目创建新任务。");
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("指定的 Codex 任务没有可用的工作目录,暂时不能按项目创建新任务。");
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 === "codex"
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(localSessionId, contextKey, initialTitle, sessionCwd);
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<void> {
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
- !explicitTitle,
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 ?? "Codex 默认"}`,
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<void> {
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 ?? "Codex 默认"}`,
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(record.localSessionId, record.contextKey, record.title, record.cwd);
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 === "codex" && record.status === "running" && record.lastTurnStatus === "running"
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 === "codex" && !record.lastTurnId && isMissingRolloutError(error))) throw error;
1885
- this.logger.warn({ error, sessionId: record.localSessionId }, "Codex task has no rollout; creating a replacement task.");
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 Codex goal before interrupting its turn.",
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 Codex turn before interrupting; using the locally tracked turn.",
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, `已向 Codex 发送 Interrupt 请求:${turnId}`);
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 !== "codex") throw new Error("Goal 模式仅支持 Codex App Server 任务。");
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("当前任务不支持 Codex Goal 模式。");
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 已恢复,Codex 会继续自动执行。",
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 已启动,Codex 会持续执行直到完成、暂停或遇到阻塞。",
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
- `**Codex 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
2693
+ `**App Server 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
2566
2694
  ],
2567
2695
  });
2568
2696
  }
@@ -2573,7 +2701,7 @@ export class ProxySessionController {
2573
2701
  "**/goal edit &#60;新目标&#62;** 修改  **/goal clear** 清除",
2574
2702
  ],
2575
2703
  });
2576
- await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("Codex Goal", sections));
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 Codex sessions for an Agent.");
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 ? `Codex 任务:${searchTerm}` : "Codex 任务",
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("未配置 Codex Agent。");
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(`找不到 Codex 任务:${scoped?.remoteSessionId ?? reference}${details ? `(${details})` : ""}`);
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(existing.localSessionId, contextKey, existing.title, existing.cwd);
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(`这个任务正在外部 Codex 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
3063
+ throw new Error(`这个任务正在外部 Agent 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
2930
3064
  }
2931
- if (!remote.cwd) throw new Error("这个 Codex 任务没有可用的工作目录,暂时无法切换。");
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(localSessionId, contextKey, remote.title ?? remote.preview, remote.cwd);
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("当前 Codex 运行时不支持停止外部任务。");
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, `已向 Codex 发送 Interrupt 请求:${turnId}`);
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("这个任务正在外部 Codex 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
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
- // Codex does not materialize a new thread until its first user message.
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("这个任务正在外部 Codex 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
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 Codex task status.");
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 Codex goal status.");
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("无。直接发送消息即可创建一个未指定项目的 Codex 任务。");
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 ?? "Codex 默认")} / ${cardCode(current.model ?? "默认")} / ${cardCode(current.reasoningEffort ?? "自动")}`,
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
- `**Codex 任务 ID**:${cardCode(current.remoteSessionId ?? "尚未创建")}`,
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
- ? `Codex 状态:${truncateText((current.title ?? current.remoteSessionId ?? current.localSessionId).replace(/\s+/g, " "), 40)}`
3182
- : "Codex 状态";
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
- `**Codex 任务 ID**:${cardCode(remote.id)}`,
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
- ? "外部 Codex 正在执行;Agent Bot 只读取状态,不会接管。"
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 = `Codex 状态:${truncateText((remote.title ?? remote.preview ?? remote.id).replace(/\s+/g, " "), 40)}`;
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 === "codex";
3469
+ return this.config.agents[session.agentName]?.kind === "app-server";
3326
3470
  }
3327
3471
 
3328
3472
  private currentSession(contextKey: string): SessionRecord | undefined {