@keyou007/agent-bot 0.1.10 → 0.1.12

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 (121) hide show
  1. package/.env.example +1 -1
  2. package/CHANGELOG.md +25 -0
  3. package/README.md +55 -43
  4. package/README.zh.md +55 -43
  5. package/assets/agent-bot-logo.png +0 -0
  6. package/config.example.yaml +11 -1
  7. package/dist/acp/AcpSessionManager.js +78 -46
  8. package/dist/acp/AcpSessionManager.js.map +1 -1
  9. package/dist/cli/FeishuAppConfiguration.js +1 -1
  10. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  11. package/dist/cli/FeishuAppRegistration.js +2 -2
  12. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  13. package/dist/cli/Initializer.js +1 -1
  14. package/dist/cli/Initializer.js.map +1 -1
  15. package/dist/cli/ServerStarter.js +7 -2
  16. package/dist/cli/ServerStarter.js.map +1 -1
  17. package/dist/cli/controlProtocol.js.map +1 -1
  18. package/dist/cli/help.js +20 -16
  19. package/dist/cli/help.js.map +1 -1
  20. package/dist/cli/taskGroupOptions.js +95 -0
  21. package/dist/cli/taskGroupOptions.js.map +1 -0
  22. package/dist/cli.js +74 -2
  23. package/dist/cli.js.map +1 -1
  24. package/dist/codex/AppServerConnection.js +15 -1
  25. package/dist/codex/AppServerConnection.js.map +1 -1
  26. package/dist/codex/CodexLocalActivityDetector.js +4 -1
  27. package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
  28. package/dist/codex/CodexProcessManager.js +1 -0
  29. package/dist/codex/CodexProcessManager.js.map +1 -1
  30. package/dist/codex/CodexRuntime.js +112 -11
  31. package/dist/codex/CodexRuntime.js.map +1 -1
  32. package/dist/commands/CommandRouter.js +64 -49
  33. package/dist/commands/CommandRouter.js.map +1 -1
  34. package/dist/config/loadConfig.js +11 -1
  35. package/dist/config/loadConfig.js.map +1 -1
  36. package/dist/config/schema.js +6 -1
  37. package/dist/config/schema.js.map +1 -1
  38. package/dist/console/ConsoleConnector.js +1 -1
  39. package/dist/console/ConsoleConnector.js.map +1 -1
  40. package/dist/console/ConsoleTurnPresenter.js +15 -8
  41. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  42. package/dist/deprecated-cli.js +5 -0
  43. package/dist/deprecated-cli.js.map +1 -0
  44. package/dist/feishu/CardRenderer.js +350 -15
  45. package/dist/feishu/CardRenderer.js.map +1 -1
  46. package/dist/feishu/FeishuMessageClient.js +51 -5
  47. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  48. package/dist/feishu/FeishuTurnPresenter.js +17 -8
  49. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  50. package/dist/feishu/transport.js +1 -1
  51. package/dist/feishu/transport.js.map +1 -1
  52. package/dist/index.js +38 -19
  53. package/dist/index.js.map +1 -1
  54. package/dist/presentation/OutboundRouter.js +2 -2
  55. package/dist/presentation/OutboundRouter.js.map +1 -1
  56. package/dist/presentation/TurnStateReducer.js +2 -1
  57. package/dist/presentation/TurnStateReducer.js.map +1 -1
  58. package/dist/proxy/ProxySessionController.js +665 -225
  59. package/dist/proxy/ProxySessionController.js.map +1 -1
  60. package/dist/runtime/AcpRuntimeAdapter.js +1 -0
  61. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  62. package/dist/runtime/AgentRuntimeRegistry.js +7 -4
  63. package/dist/runtime/AgentRuntimeRegistry.js.map +1 -1
  64. package/dist/runtime/createAgentRuntimeRegistry.js +22 -0
  65. package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -0
  66. package/dist/startup/SessionMetadataHydrator.js +2 -2
  67. package/dist/startup/SessionMetadataHydrator.js.map +1 -1
  68. package/dist/startup/StartupNotifier.js +1 -0
  69. package/dist/startup/StartupNotifier.js.map +1 -1
  70. package/dist/state/StateStore.js +21 -15
  71. package/dist/state/StateStore.js.map +1 -1
  72. package/dist/supervision/SafeRestartScheduler.js +5 -0
  73. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  74. package/dist/supervision/systemEnvironment.js +129 -0
  75. package/dist/supervision/systemEnvironment.js.map +1 -0
  76. package/dist/supervisor.js +13 -1
  77. package/dist/supervisor.js.map +1 -1
  78. package/docs/technical-reference.md +35 -21
  79. package/docs/technical-reference.zh.md +35 -21
  80. package/npm-shrinkwrap.json +4 -3
  81. package/package.json +4 -2
  82. package/skills/agent-bot/SKILL.md +73 -30
  83. package/src/acp/AcpSessionManager.ts +73 -54
  84. package/src/cli/FeishuAppConfiguration.ts +2 -2
  85. package/src/cli/FeishuAppRegistration.ts +4 -4
  86. package/src/cli/Initializer.ts +2 -2
  87. package/src/cli/ServerStarter.ts +8 -3
  88. package/src/cli/controlProtocol.ts +21 -1
  89. package/src/cli/help.ts +20 -16
  90. package/src/cli/taskGroupOptions.ts +149 -0
  91. package/src/cli.ts +98 -4
  92. package/src/codex/AppServerConnection.ts +21 -1
  93. package/src/codex/CodexLocalActivityDetector.ts +8 -1
  94. package/src/codex/CodexProcessManager.ts +1 -0
  95. package/src/codex/CodexRuntime.ts +137 -15
  96. package/src/commands/CommandRouter.ts +71 -49
  97. package/src/commands/commandTypes.ts +6 -11
  98. package/src/config/loadConfig.ts +11 -1
  99. package/src/config/schema.ts +7 -1
  100. package/src/console/ConsoleConnector.ts +1 -1
  101. package/src/console/ConsoleTurnPresenter.ts +21 -8
  102. package/src/deprecated-cli.ts +9 -0
  103. package/src/feishu/CardRenderer.ts +423 -15
  104. package/src/feishu/FeishuMessageClient.ts +66 -3
  105. package/src/feishu/FeishuTurnPresenter.ts +22 -3
  106. package/src/feishu/transport.ts +1 -1
  107. package/src/index.ts +54 -24
  108. package/src/presentation/OutboundRouter.ts +15 -3
  109. package/src/presentation/TurnStateReducer.ts +2 -0
  110. package/src/presentation/turnViewTypes.ts +1 -0
  111. package/src/proxy/ProxySessionController.ts +870 -228
  112. package/src/runtime/AcpRuntimeAdapter.ts +1 -0
  113. package/src/runtime/AgentRuntimeRegistry.ts +7 -6
  114. package/src/runtime/createAgentRuntimeRegistry.ts +25 -0
  115. package/src/runtime/types.ts +18 -0
  116. package/src/startup/SessionMetadataHydrator.ts +2 -2
  117. package/src/startup/StartupNotifier.ts +1 -0
  118. package/src/state/StateStore.ts +29 -15
  119. package/src/supervision/SafeRestartScheduler.ts +5 -0
  120. package/src/supervision/systemEnvironment.ts +174 -0
  121. package/src/supervisor.ts +12 -1
@@ -5,6 +5,7 @@ import type { RuntimeSession } from "../acp/AcpSessionManager.js";
5
5
  import type {
6
6
  ApprovalDecision,
7
7
  ModelOption,
8
+ ModelProviderOption,
8
9
  PermissionMode,
9
10
  ReasoningEffortOption,
10
11
  ToolState,
@@ -24,6 +25,7 @@ export interface StartupStatusView {
24
25
  currentTask?: {
25
26
  id: string;
26
27
  title?: string;
28
+ modelProvider?: string;
27
29
  model?: string;
28
30
  reasoningEffort?: string;
29
31
  permissionMode?: PermissionMode;
@@ -60,6 +62,9 @@ export interface ModelSelectorCardView {
60
62
  currentModel?: string;
61
63
  reasoningEffort?: string;
62
64
  models: ModelOption[];
65
+ modelProvider?: string;
66
+ permissionMode?: PermissionMode;
67
+ unifiedSettings?: boolean;
63
68
  notice?: string;
64
69
  }
65
70
 
@@ -69,6 +74,55 @@ export interface ReasoningSelectorCardView {
69
74
  model: string;
70
75
  currentEffort?: string;
71
76
  options: ReasoningEffortOption[];
77
+ modelProvider?: string;
78
+ permissionMode?: PermissionMode;
79
+ unifiedSettings?: boolean;
80
+ notice?: string;
81
+ }
82
+
83
+ export interface ProviderSelectorCardView {
84
+ sessionId: string;
85
+ contextKey: string;
86
+ currentProvider?: string;
87
+ currentModel?: string;
88
+ reasoningEffort?: string;
89
+ permissionMode: PermissionMode;
90
+ providers: ModelProviderOption[];
91
+ notice?: string;
92
+ }
93
+
94
+ export interface PermissionSelectorCardView {
95
+ sessionId: string;
96
+ contextKey: string;
97
+ modelProvider: string;
98
+ model: string;
99
+ reasoningEffort: string;
100
+ currentMode: PermissionMode;
101
+ }
102
+
103
+ export type ExecutionSettingsTab = "agent" | "provider" | "model" | "thinking" | "permission";
104
+
105
+ export interface ExecutionSettingsAgentOption {
106
+ name: string;
107
+ title: string;
108
+ }
109
+
110
+ export interface ExecutionSettingsCardView {
111
+ sessionId?: string;
112
+ contextKey: string;
113
+ activeTab: ExecutionSettingsTab;
114
+ currentAgent: string;
115
+ taskAgent?: string;
116
+ agents: ExecutionSettingsAgentOption[];
117
+ runtimeSettingsAvailable: boolean;
118
+ currentProvider?: string;
119
+ currentModel?: string;
120
+ currentEffort?: string;
121
+ currentPermissionMode: PermissionMode;
122
+ providers: ModelProviderOption[];
123
+ providerSupported: boolean;
124
+ models: ModelOption[];
125
+ reasoningOptions: ReasoningEffortOption[];
72
126
  notice?: string;
73
127
  }
74
128
 
@@ -91,9 +145,183 @@ export interface TaskListCardEntry {
91
145
  }
92
146
 
93
147
  export class CardRenderer {
148
+ renderExecutionSettings(view: ExecutionSettingsCardView): Record<string, unknown> {
149
+ const baseAction: Record<string, string> = {
150
+ contextKey: view.contextKey,
151
+ ...(view.sessionId ? { sessionId: view.sessionId } : {}),
152
+ };
153
+ const tabRow = settingsTabRow(
154
+ view.activeTab,
155
+ baseAction,
156
+ view.agents.length > 1,
157
+ view.runtimeSettingsAvailable,
158
+ );
159
+ const elements: Record<string, unknown>[] = [
160
+ markdown([
161
+ view.taskAgent
162
+ ? `**默认 Agent / 当前任务 Agent**:${inlineCode(view.currentAgent)} / ${inlineCode(view.taskAgent)}`
163
+ : `**默认 Agent**:${inlineCode(view.currentAgent)}`,
164
+ ...(view.runtimeSettingsAvailable
165
+ ? [
166
+ `**Provider / 模型**:${inlineCode(view.currentProvider ?? "Codex 默认")} / ${inlineCode(view.currentModel ?? "默认")}`,
167
+ `**思考强度 / 权限**:${inlineCode(view.currentEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.currentPermissionMode))}`,
168
+ ]
169
+ : []),
170
+ ...(view.notice ? [view.notice] : []),
171
+ ].join("\n")),
172
+ ...(tabRow ? [tabRow] : []),
173
+ { tag: "hr" },
174
+ ];
175
+
176
+ if (view.activeTab === "agent") {
177
+ elements.push(...view.agents.map((agent) => settingsOptionRow({
178
+ label: `${inlineCode(agent.name)} · ${escapeCardHtml(agent.title)}`,
179
+ current: agent.name === view.currentAgent,
180
+ action: {
181
+ text: "Switch",
182
+ value: {
183
+ action: "settings_agent_select",
184
+ ...baseAction,
185
+ agent: agent.name,
186
+ },
187
+ },
188
+ })));
189
+ } else if (view.activeTab === "provider") {
190
+ if (!view.providerSupported) {
191
+ elements.push(markdown("当前运行时不支持 Provider 切换;其他设置仍可通过上方 tab 修改。"));
192
+ } else if (view.providers.length === 0) {
193
+ elements.push(markdown("Codex 配置中没有可用的 Provider。"));
194
+ } else {
195
+ elements.push(...view.providers.map((provider) => settingsOptionRow({
196
+ label: [
197
+ inlineCode(provider.id),
198
+ provider.displayName && provider.displayName !== provider.id
199
+ ? ` · ${escapeCardHtml(provider.displayName)}`
200
+ : "",
201
+ provider.isDefault ? " · 默认" : "",
202
+ ].join(""),
203
+ current: provider.id === view.currentProvider,
204
+ action: {
205
+ text: "Switch",
206
+ value: {
207
+ action: "settings_provider_select",
208
+ ...baseAction,
209
+ provider: provider.id,
210
+ },
211
+ },
212
+ })));
213
+ }
214
+ } else if (view.activeTab === "model") {
215
+ if (view.models.length === 0) {
216
+ elements.push(markdown("当前运行时未返回可用模型。"));
217
+ } else {
218
+ elements.push(...view.models.map((model) => settingsOptionRow({
219
+ label: `${inlineCode(model.id)}${model.isDefault ? " · 默认" : ""}`,
220
+ current: model.id === view.currentModel,
221
+ action: {
222
+ text: "Switch",
223
+ value: {
224
+ action: "settings_model_select",
225
+ ...baseAction,
226
+ model: model.id,
227
+ },
228
+ },
229
+ })));
230
+ }
231
+ } else if (view.activeTab === "thinking") {
232
+ if (!view.currentModel) {
233
+ elements.push(markdown("请先选择模型。"));
234
+ } else if (view.reasoningOptions.length === 0) {
235
+ elements.push(markdown("当前模型没有可配置的思考强度。"));
236
+ } else {
237
+ const currentModel = view.currentModel;
238
+ elements.push(...view.reasoningOptions.map((option) => settingsOptionRow({
239
+ label: inlineCode(option.value),
240
+ current: option.value === view.currentEffort,
241
+ action: {
242
+ text: "Switch",
243
+ value: {
244
+ action: "settings_thinking_select",
245
+ ...baseAction,
246
+ model: currentModel,
247
+ effort: option.value,
248
+ },
249
+ },
250
+ })));
251
+ }
252
+ } else {
253
+ elements.push(...(["auto", "confirm"] as PermissionMode[]).map((mode) => settingsOptionRow({
254
+ label: `${inlineCode(mode)} · ${permissionModeLabel(mode)}`,
255
+ current: mode === view.currentPermissionMode,
256
+ action: {
257
+ text: "Switch",
258
+ value: {
259
+ action: "settings_permission_select",
260
+ ...baseAction,
261
+ permissionMode: mode,
262
+ },
263
+ },
264
+ })));
265
+ }
266
+
267
+ return sectionCard("运行设置", elements, view.notice ? "green" : "blue");
268
+ }
269
+
270
+ renderProviderSelector(view: ProviderSelectorCardView): Record<string, unknown> {
271
+ const elements: Record<string, unknown>[] = [
272
+ markdown([
273
+ `**当前 Provider**:${inlineCode(view.currentProvider ?? "Codex 默认")}`,
274
+ `**模型 / 思考强度 / 权限**:${inlineCode(view.currentModel ?? "默认")} / ${inlineCode(view.reasoningEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.permissionMode))}`,
275
+ ...(view.notice ? [view.notice] : []),
276
+ ].join("\n")),
277
+ { tag: "hr" },
278
+ ];
279
+ if (view.providers.length === 0) {
280
+ elements.push(markdown("Codex 配置中没有可用的 Provider。"));
281
+ } else {
282
+ elements.push(...view.providers.map((provider) => ({
283
+ tag: "column_set",
284
+ flex_mode: "none",
285
+ horizontal_spacing: "8px",
286
+ vertical_align: "center",
287
+ columns: [
288
+ {
289
+ tag: "column",
290
+ width: "weighted",
291
+ weight: 1,
292
+ vertical_align: "center",
293
+ elements: [markdown([
294
+ inlineCode(provider.id),
295
+ provider.displayName && provider.displayName !== provider.id ? ` · ${escapeCardHtml(provider.displayName)}` : "",
296
+ provider.isDefault ? " · 默认" : "",
297
+ provider.id === view.currentProvider ? " · ✅ 当前" : "",
298
+ ].join(""))],
299
+ },
300
+ {
301
+ tag: "column",
302
+ width: "auto",
303
+ vertical_align: "center",
304
+ elements: [taskActionElement({
305
+ text: provider.id === view.currentProvider ? "Configure" : "Select",
306
+ value: {
307
+ action: "provider_select",
308
+ sessionId: view.sessionId,
309
+ contextKey: view.contextKey,
310
+ provider: provider.id,
311
+ permissionMode: view.permissionMode,
312
+ },
313
+ })],
314
+ },
315
+ ],
316
+ })));
317
+ }
318
+ return sectionCard("Provider 设置", elements, view.notice ? "green" : "blue");
319
+ }
320
+
94
321
  renderReasoningSelector(view: ReasoningSelectorCardView): Record<string, unknown> {
95
322
  const elements: Record<string, unknown>[] = [
96
323
  markdown([
324
+ ...(view.modelProvider ? [`**Provider**:${inlineCode(view.modelProvider)}`] : []),
97
325
  `**模型**:${inlineCode(view.model)}`,
98
326
  `**当前思考模式**:${inlineCode(view.currentEffort ?? "默认")}`,
99
327
  ...(view.notice ? [view.notice] : []),
@@ -122,16 +350,18 @@ export class CardRenderer {
122
350
  tag: "column",
123
351
  width: "auto",
124
352
  vertical_align: "center",
125
- elements: isCurrent
353
+ elements: isCurrent && !view.unifiedSettings
126
354
  ? [markdown("✅ 当前")]
127
355
  : [taskActionElement({
128
- text: "Switch",
356
+ text: view.unifiedSettings ? (isCurrent ? "Continue" : "Select") : "Switch",
129
357
  value: {
130
- action: "reasoning_select",
358
+ action: view.unifiedSettings ? "provider_reasoning_select" : "reasoning_select",
131
359
  sessionId: view.sessionId,
132
360
  contextKey: view.contextKey,
361
+ ...(view.modelProvider ? { provider: view.modelProvider } : {}),
133
362
  model: view.model,
134
363
  effort: option.value,
364
+ ...(view.permissionMode ? { permissionMode: view.permissionMode } : {}),
135
365
  },
136
366
  })],
137
367
  },
@@ -144,9 +374,11 @@ export class CardRenderer {
144
374
  taskActionRow([{
145
375
  text: "Back",
146
376
  value: {
147
- action: "model_open",
377
+ action: view.unifiedSettings ? "provider_model_open" : "model_open",
148
378
  sessionId: view.sessionId,
149
379
  contextKey: view.contextKey,
380
+ ...(view.modelProvider ? { provider: view.modelProvider } : {}),
381
+ ...(view.permissionMode ? { permissionMode: view.permissionMode } : {}),
150
382
  },
151
383
  }]),
152
384
  );
@@ -156,6 +388,7 @@ export class CardRenderer {
156
388
  renderModelSelector(view: ModelSelectorCardView): Record<string, unknown> {
157
389
  const elements: Record<string, unknown>[] = [
158
390
  markdown([
391
+ ...(view.modelProvider ? [`**Provider**:${inlineCode(view.modelProvider)}`] : []),
159
392
  `**当前模型**:${inlineCode(view.currentModel ?? "默认")}`,
160
393
  `**思考强度**:${inlineCode(view.reasoningEffort ?? "默认")}`,
161
394
  ...(view.notice ? [view.notice] : []),
@@ -186,15 +419,17 @@ export class CardRenderer {
186
419
  tag: "column",
187
420
  width: "auto",
188
421
  vertical_align: "center",
189
- elements: isCurrent
422
+ elements: isCurrent && !view.unifiedSettings
190
423
  ? [markdown("✅ 当前")]
191
424
  : [taskActionElement({
192
- text: "Switch",
425
+ text: view.unifiedSettings ? (isCurrent ? "Continue" : "Select") : "Switch",
193
426
  value: {
194
- action: "model_select",
427
+ action: view.unifiedSettings ? "provider_model_select" : "model_select",
195
428
  sessionId: view.sessionId,
196
429
  contextKey: view.contextKey,
430
+ ...(view.modelProvider ? { provider: view.modelProvider } : {}),
197
431
  model: model.id,
432
+ ...(view.permissionMode ? { permissionMode: view.permissionMode } : {}),
198
433
  },
199
434
  })],
200
435
  },
@@ -202,7 +437,77 @@ export class CardRenderer {
202
437
  };
203
438
  }));
204
439
  }
205
- return sectionCard("模型", elements, view.notice ? "green" : "blue");
440
+ if (view.unifiedSettings) {
441
+ elements.push(
442
+ { tag: "hr" },
443
+ taskActionRow([{
444
+ text: "Back",
445
+ value: {
446
+ action: "provider_open",
447
+ sessionId: view.sessionId,
448
+ contextKey: view.contextKey,
449
+ },
450
+ }]),
451
+ );
452
+ }
453
+ return sectionCard(view.unifiedSettings ? "Provider 设置 · 模型" : "模型", elements, view.notice ? "green" : "blue");
454
+ }
455
+
456
+ renderPermissionSelector(view: PermissionSelectorCardView): Record<string, unknown> {
457
+ const elements: Record<string, unknown>[] = [
458
+ markdown([
459
+ `**Provider**:${inlineCode(view.modelProvider)}`,
460
+ `**模型**:${inlineCode(view.model)}`,
461
+ `**思考强度**:${inlineCode(view.reasoningEffort)}`,
462
+ `**当前权限**:${inlineCode(permissionModeLabel(view.currentMode))}`,
463
+ ].join("\n")),
464
+ { tag: "hr" },
465
+ ...(["auto", "confirm"] as PermissionMode[]).map((mode) => ({
466
+ tag: "column_set",
467
+ flex_mode: "none",
468
+ horizontal_spacing: "8px",
469
+ vertical_align: "center",
470
+ columns: [
471
+ {
472
+ tag: "column",
473
+ width: "weighted",
474
+ weight: 1,
475
+ vertical_align: "center",
476
+ elements: [markdown(`${inlineCode(mode)} · ${permissionModeLabel(mode)}`)],
477
+ },
478
+ {
479
+ tag: "column",
480
+ width: "auto",
481
+ vertical_align: "center",
482
+ elements: [taskActionElement({
483
+ text: mode === view.currentMode ? "Apply" : "Select",
484
+ value: {
485
+ action: "provider_permission_select",
486
+ sessionId: view.sessionId,
487
+ contextKey: view.contextKey,
488
+ provider: view.modelProvider,
489
+ model: view.model,
490
+ effort: view.reasoningEffort,
491
+ permissionMode: mode,
492
+ },
493
+ })],
494
+ },
495
+ ],
496
+ })),
497
+ { tag: "hr" },
498
+ taskActionRow([{
499
+ text: "Back",
500
+ value: {
501
+ action: "provider_reasoning_open",
502
+ sessionId: view.sessionId,
503
+ contextKey: view.contextKey,
504
+ provider: view.modelProvider,
505
+ model: view.model,
506
+ permissionMode: view.currentMode,
507
+ },
508
+ }]),
509
+ ];
510
+ return sectionCard("Provider 设置 · 权限", elements);
206
511
  }
207
512
 
208
513
  renderPromptQueue(view: PromptQueueCardView): Record<string, unknown> {
@@ -330,14 +635,14 @@ export class CardRenderer {
330
635
  ? [
331
636
  `**当前任务**:${inlineCode(view.currentTask.title ?? view.currentTask.id)}`,
332
637
  workspaceLine,
333
- `**模型 / 思考强度 / 权限**:${inlineCode(view.currentTask.model ?? "默认")} / ${inlineCode(view.currentTask.reasoningEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.currentTask.permissionMode))}`,
638
+ `**Provider / 模型 / 思考强度 / 权限**:${inlineCode(view.currentTask.modelProvider ?? "Codex 默认")} / ${inlineCode(view.currentTask.model ?? "默认")} / ${inlineCode(view.currentTask.reasoningEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.currentTask.permissionMode))}`,
334
639
  `**任务状态 / Agent**:${persistedTaskStatus(view.currentTask.sessionStatus, view.currentTask.lastTurnStatus)} / ${inlineCode(view.currentTask.agentName)}`,
335
640
  `**任务 ID**:${inlineCode(view.currentTask.id)}`,
336
641
  ]
337
642
  : [
338
643
  "**当前任务**:无,下一条普通消息会创建新任务",
339
644
  workspaceLine,
340
- `**模型 / 思考强度 / 权限**:${inlineCode("默认")} / ${inlineCode("自动")} / ${inlineCode(permissionModeLabel())}`,
645
+ `**Provider / 模型 / 思考强度 / 权限**:${inlineCode("Codex 默认")} / ${inlineCode("默认")} / ${inlineCode("自动")} / ${inlineCode(permissionModeLabel())}`,
341
646
  `**默认 Agent**:${view.defaultAgentTitle} (${inlineCode(view.defaultAgentName)})`,
342
647
  ];
343
648
  lines.push(
@@ -623,15 +928,16 @@ function renderTurnElements(
623
928
  const heading = state.status === "completed" ? "回答" : "回答生成中";
624
929
  elements.push(markdown(`**${heading}**\n${truncateText(state.assistantText, 3_000)}`));
625
930
  }
626
- if (elements.length === 0) elements.push(markdown(emptyTurnText(state.status)));
931
+ if (elements.length === 0) elements.push(markdown(emptyTurnText(state.status, state.agentLabel)));
627
932
  return elements;
628
933
  }
629
934
 
630
- function emptyTurnText(status: TurnViewStatus): string {
631
- if (status === "starting") return "正在连接 Codex…";
935
+ function emptyTurnText(status: TurnViewStatus, agentLabel?: string): string {
936
+ const label = agentLabel?.trim().replace(/[\r\n]+/g, " ") || "Agent";
937
+ if (status === "starting") return `正在连接 ${label}…`;
632
938
  if (status === "completed") return "本轮已完成。";
633
939
  if (status === "cancelled") return "本轮已停止。";
634
- return "正在等待 Codex 返回进度…";
940
+ return `正在等待 ${label} 返回进度…`;
635
941
  }
636
942
 
637
943
  function planPanel(plan: TurnViewState["plan"]): Record<string, unknown> {
@@ -646,7 +952,7 @@ function fileSummaryPanel(state: TurnViewState): Record<string, unknown> {
646
952
  return collapsiblePanel(
647
953
  `文件变更 · ${state.fileSummary.length}`,
648
954
  state.fileSummary
649
- .map((file) => `- ${displayFilePath(file.path, state.projectCwd)} +${file.additions ?? 0} -${file.deletions ?? 0}`)
955
+ .map((file) => `- ${escapeMarkdownFilePath(displayFilePath(file.path, state.projectCwd))} +${file.additions ?? 0} -${file.deletions ?? 0}`)
650
956
  .join("\n"),
651
957
  { elementId: "turn_files" },
652
958
  );
@@ -859,6 +1165,10 @@ function displayFilePath(filePath: string, projectCwd?: string): string {
859
1165
  return isInsideProject ? relativePath || "." : absolutePath;
860
1166
  }
861
1167
 
1168
+ function escapeMarkdownFilePath(filePath: string): string {
1169
+ return filePath.replaceAll("\\.", "\\\\.");
1170
+ }
1171
+
862
1172
  function usesWindowsPaths(...values: string[]): boolean {
863
1173
  return values.some((value) => /^[A-Za-z]:[\\/]/.test(value) || /^\\\\/.test(value));
864
1174
  }
@@ -1062,6 +1372,104 @@ function acpPermissionOptionLabel(option: { name: string; kind: string }): strin
1062
1372
  return labels[option.kind] ?? (/^[\x20-\x7E]+$/.test(option.name) ? option.name : "Select");
1063
1373
  }
1064
1374
 
1375
+ function settingsTabRow(
1376
+ activeTab: ExecutionSettingsTab,
1377
+ baseAction: Record<string, string>,
1378
+ showAgentTab: boolean,
1379
+ showRuntimeTabs: boolean,
1380
+ ): Record<string, unknown> | undefined {
1381
+ const tabs: Array<{ id: ExecutionSettingsTab; label: string }> = [
1382
+ ...(showAgentTab ? [{ id: "agent" as const, label: "Agent" }] : []),
1383
+ ...(showRuntimeTabs
1384
+ ? [
1385
+ { id: "provider" as const, label: "Provider" },
1386
+ { id: "model" as const, label: "Model" },
1387
+ { id: "thinking" as const, label: "Thinking" },
1388
+ { id: "permission" as const, label: "Permission" },
1389
+ ]
1390
+ : []),
1391
+ ];
1392
+ if (tabs.length === 0) return undefined;
1393
+ return {
1394
+ tag: "column_set",
1395
+ flex_mode: "none",
1396
+ horizontal_spacing: "2px",
1397
+ margin: "8px 0 0 0",
1398
+ columns: tabs.flatMap((tab, index) => [
1399
+ ...(index > 0
1400
+ ? [{
1401
+ tag: "column",
1402
+ width: "auto",
1403
+ vertical_align: "center",
1404
+ elements: [{ ...markdown("·"), text_align: "center", text_size: "notation" }],
1405
+ }]
1406
+ : []),
1407
+ {
1408
+ tag: "column",
1409
+ width: "auto",
1410
+ vertical_align: "center",
1411
+ elements: [settingsTabElement(tab.label, tab.id === activeTab, {
1412
+ action: "settings_tab_open",
1413
+ ...baseAction,
1414
+ tab: tab.id,
1415
+ })],
1416
+ },
1417
+ ]),
1418
+ };
1419
+ }
1420
+
1421
+ function settingsTabElement(
1422
+ label: string,
1423
+ active: boolean,
1424
+ value: Record<string, string>,
1425
+ ): Record<string, unknown> {
1426
+ if (active) {
1427
+ return {
1428
+ ...markdown(escapeCardHtml(label)),
1429
+ text_align: "center",
1430
+ text_size: "notation",
1431
+ };
1432
+ }
1433
+ const action = taskActionElement({ text: label, value });
1434
+ return {
1435
+ ...action,
1436
+ padding: "6px 0px",
1437
+ elements: (action.elements as Array<Record<string, unknown>>).map((element) => ({
1438
+ ...element,
1439
+ text_align: "center",
1440
+ text_size: "notation",
1441
+ })),
1442
+ };
1443
+ }
1444
+
1445
+ function settingsOptionRow(input: {
1446
+ label: string;
1447
+ current: boolean;
1448
+ action: TaskListCardAction;
1449
+ }): Record<string, unknown> {
1450
+ return {
1451
+ tag: "column_set",
1452
+ flex_mode: "none",
1453
+ horizontal_spacing: "8px",
1454
+ vertical_align: "center",
1455
+ columns: [
1456
+ {
1457
+ tag: "column",
1458
+ width: "weighted",
1459
+ weight: 1,
1460
+ vertical_align: "center",
1461
+ elements: [markdown(input.label)],
1462
+ },
1463
+ {
1464
+ tag: "column",
1465
+ width: "auto",
1466
+ vertical_align: "center",
1467
+ elements: input.current ? [markdown("✅ 当前")] : [taskActionElement(input.action)],
1468
+ },
1469
+ ],
1470
+ };
1471
+ }
1472
+
1065
1473
  function taskActionRow(actions: TaskListCardAction[]): Record<string, unknown> {
1066
1474
  return {
1067
1475
  tag: "column_set",