@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
@@ -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 Codex task status for CLI.");
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 !== "codex") {
490
- throw new Error("/new --nodir 仅支持 Codex Agent。");
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 !== "codex") {
500
- throw new Error("/newgroup --nodir 仅支持 Codex Agent。");
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("请输入要交给 Codex 的内容。");
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 Codex thread.");
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 Codex turn; queueing prompt.");
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("当前 Codex 运行时不支持 fork 任务。");
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("无法确定这个话题对应的 Codex 轮次,因此没有创建分支任务。请从该轮的用户消息、思考卡片或最终回答创建话题。");
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 的 Codex 任务。");
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("话题对应的轮次仍在执行,Codex 暂时不能从这一轮 fork。请等待该轮完成后再在话题中发送消息。");
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 的 Codex 任务。`);
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 的 Codex 任务 ID。");
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("当前 Codex 运行时不支持 fork 任务。");
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("当前任务尚未创建 Codex 任务 ID,暂时不能 fork。");
1017
+ throw new Error("当前任务尚未创建 App Server 任务 ID,暂时不能 fork。");
967
1018
  if (!runtime.readRemoteSession && !source) {
968
- throw new Error("当前 Codex 运行时不支持读取指定任务。");
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("指定的 Codex 任务没有可用的工作目录,暂时不能 fork。");
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 的 Codex 任务。`);
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("当前 Codex 运行时不支持 fork 任务。");
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}仍在执行,Codex 暂时不能从这一轮 fork。`);
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("指定任务不是 Codex 任务,暂时不能按项目创建新任务。");
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("指定的 Codex 任务没有可用的工作目录,暂时不能按项目创建新任务。");
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 === "codex"
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", !explicitTitle);
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 ?? "Codex 默认"}`,
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 ?? "Codex 默认"}`,
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 === "codex" && record.status === "running" && record.lastTurnStatus === "running"
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 === "codex" && !record.lastTurnId && isMissingRolloutError(error)))
1480
+ if (!(agent.kind === "app-server" && !record.lastTurnId && isMissingRolloutError(error)))
1428
1481
  throw error;
1429
- this.logger.warn({ error, sessionId: record.localSessionId }, "Codex task has no rollout; creating a replacement task.");
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 Codex goal before interrupting its turn.");
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 Codex turn before interrupting; using the locally tracked turn.");
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, `已向 Codex 发送 Interrupt 请求:${turnId}`);
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 !== "codex")
1947
- throw new Error("Goal 模式仅支持 Codex App Server 任务。");
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("当前任务不支持 Codex Goal 模式。");
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 已恢复,Codex 会继续自动执行。", record);
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 已启动,Codex 会持续执行直到完成、暂停或遇到阻塞。", record);
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
- `**Codex 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
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("Codex Goal", sections));
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 Codex sessions for an Agent.");
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 ? `Codex 任务:${searchTerm}` : "Codex 任务", activeCount > 0 ? `任务(${activeCount} 个活跃)` : "任务", cardEntries, [
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("未配置 Codex Agent。");
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(`找不到 Codex 任务:${scoped?.remoteSessionId ?? reference}${details ? `(${details})` : ""}`);
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(`这个任务正在外部 Codex 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
2401
+ throw new Error(`这个任务正在外部 Agent 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
2349
2402
  }
2350
2403
  if (!remote.cwd)
2351
- throw new Error("这个 Codex 任务没有可用的工作目录,暂时无法切换。");
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("当前 Codex 运行时不支持停止外部任务。");
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, `已向 Codex 发送 Interrupt 请求:${turnId}`);
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("这个任务正在外部 Codex 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
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
- // Codex does not materialize a new thread until its first user message.
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("这个任务正在外部 Codex 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
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 Codex task status.");
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 Codex goal status.");
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("无。直接发送消息即可创建一个未指定项目的 Codex 任务。");
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 ?? "Codex 默认")} / ${cardCode(current.model ?? "默认")} / ${cardCode(current.reasoningEffort ?? "自动")}`, `**状态 / 最近结果**:${statusLabel} / ${resultLabel}`, `**Agent**:${cardCode(agent.title)}`, `**权限 / 任务范围**:${current.permissionMode === "confirm" ? "执行前确认" : "自动执行"} / ${detectProjectlessWorkspace(current.cwd) ? "未指定项目" : "指定项目"}`, `**Codex 任务 ID**:${cardCode(current.remoteSessionId ?? "尚未创建")}`, `**当前执行 / 排队消息**:${activeTurnId ? cardCode(activeTurnId) : "无"} / ${queued} 条`, `**创建时间 / 最近活动**:${formatStatusTime(current.createdAt)} / ${formatStatusTime(current.updatedAt)}`);
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
- ? `Codex 状态:${truncateText((current.title ?? current.remoteSessionId ?? current.localSessionId).replace(/\s+/g, " "), 40)}`
2581
- : "Codex 状态";
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
- `**Codex 任务 ID**:${cardCode(remote.id)}`,
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
- ? "外部 Codex 正在执行;Agent Bot 只读取状态,不会接管。"
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 = `Codex 状态:${truncateText((remote.title ?? remote.preview ?? remote.id).replace(/\s+/g, " "), 40)}`;
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 === "codex";
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);