@keyou007/agent-bot 0.1.12 → 0.1.13-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +23 -10
- package/README.zh.md +23 -10
- package/config.example.yaml +0 -24
- package/dist/cli/AgentPrerequisites.js +262 -0
- package/dist/cli/AgentPrerequisites.js.map +1 -0
- package/dist/cli/DefaultAgentSelection.js +47 -0
- package/dist/cli/DefaultAgentSelection.js.map +1 -0
- package/dist/cli/Initializer.js +165 -2
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/help.js +4 -4
- package/dist/cli.js +194 -4
- package/dist/cli.js.map +1 -1
- package/dist/codex/AppServerConnection.js +3 -3
- package/dist/codex/AppServerConnection.js.map +1 -1
- package/dist/codex/CodexProcessManager.js +4 -4
- package/dist/codex/CodexProcessManager.js.map +1 -1
- package/dist/codex/CodexRuntime.js +28 -16
- package/dist/codex/CodexRuntime.js.map +1 -1
- package/dist/config/loadConfig.js +0 -24
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/console/ConsoleConnector.js +2 -2
- package/dist/console/ConsoleConnector.js.map +1 -1
- package/dist/feishu/CardRenderer.js +8 -8
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/proxy/ProxySessionController.js +51 -51
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/runtime/AcpRuntimeAdapter.js +3 -2
- package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
- package/docs/technical-reference.md +32 -17
- package/docs/technical-reference.zh.md +32 -17
- package/npm-shrinkwrap.json +2 -2
- package/package.json +7 -3
- package/skills/agent-bot/SKILL.md +12 -6
- package/src/cli/AgentPrerequisites.ts +377 -0
- package/src/cli/DefaultAgentSelection.ts +56 -0
- package/src/cli/Initializer.ts +204 -3
- package/src/cli/help.ts +4 -4
- package/src/cli.ts +293 -5
- package/src/codex/AppServerConnection.ts +3 -3
- package/src/codex/CodexProcessManager.ts +4 -4
- package/src/codex/CodexRuntime.ts +38 -18
- package/src/config/loadConfig.ts +0 -24
- package/src/console/ConsoleConnector.ts +2 -2
- package/src/feishu/CardRenderer.ts +8 -8
- package/src/index.ts +1 -1
- package/src/proxy/ProxySessionController.ts +52 -52
- package/src/runtime/AcpRuntimeAdapter.ts +3 -1
|
@@ -163,7 +163,7 @@ export class CardRenderer {
|
|
|
163
163
|
: `**默认 Agent**:${inlineCode(view.currentAgent)}`,
|
|
164
164
|
...(view.runtimeSettingsAvailable
|
|
165
165
|
? [
|
|
166
|
-
`**Provider / 模型**:${inlineCode(view.currentProvider ?? "
|
|
166
|
+
`**Provider / 模型**:${inlineCode(view.currentProvider ?? "Agent 默认")} / ${inlineCode(view.currentModel ?? "默认")}`,
|
|
167
167
|
`**思考强度 / 权限**:${inlineCode(view.currentEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.currentPermissionMode))}`,
|
|
168
168
|
]
|
|
169
169
|
: []),
|
|
@@ -190,7 +190,7 @@ export class CardRenderer {
|
|
|
190
190
|
if (!view.providerSupported) {
|
|
191
191
|
elements.push(markdown("当前运行时不支持 Provider 切换;其他设置仍可通过上方 tab 修改。"));
|
|
192
192
|
} else if (view.providers.length === 0) {
|
|
193
|
-
elements.push(markdown("
|
|
193
|
+
elements.push(markdown("当前 Agent 配置中没有可用的 Provider。"));
|
|
194
194
|
} else {
|
|
195
195
|
elements.push(...view.providers.map((provider) => settingsOptionRow({
|
|
196
196
|
label: [
|
|
@@ -270,14 +270,14 @@ export class CardRenderer {
|
|
|
270
270
|
renderProviderSelector(view: ProviderSelectorCardView): Record<string, unknown> {
|
|
271
271
|
const elements: Record<string, unknown>[] = [
|
|
272
272
|
markdown([
|
|
273
|
-
`**当前 Provider**:${inlineCode(view.currentProvider ?? "
|
|
273
|
+
`**当前 Provider**:${inlineCode(view.currentProvider ?? "Agent 默认")}`,
|
|
274
274
|
`**模型 / 思考强度 / 权限**:${inlineCode(view.currentModel ?? "默认")} / ${inlineCode(view.reasoningEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.permissionMode))}`,
|
|
275
275
|
...(view.notice ? [view.notice] : []),
|
|
276
276
|
].join("\n")),
|
|
277
277
|
{ tag: "hr" },
|
|
278
278
|
];
|
|
279
279
|
if (view.providers.length === 0) {
|
|
280
|
-
elements.push(markdown("
|
|
280
|
+
elements.push(markdown("当前 Agent 配置中没有可用的 Provider。"));
|
|
281
281
|
} else {
|
|
282
282
|
elements.push(...view.providers.map((provider) => ({
|
|
283
283
|
tag: "column_set",
|
|
@@ -635,14 +635,14 @@ export class CardRenderer {
|
|
|
635
635
|
? [
|
|
636
636
|
`**当前任务**:${inlineCode(view.currentTask.title ?? view.currentTask.id)}`,
|
|
637
637
|
workspaceLine,
|
|
638
|
-
`**Provider / 模型 / 思考强度 / 权限**:${inlineCode(view.currentTask.modelProvider ?? "
|
|
638
|
+
`**Provider / 模型 / 思考强度 / 权限**:${inlineCode(view.currentTask.modelProvider ?? "Agent 默认")} / ${inlineCode(view.currentTask.model ?? "默认")} / ${inlineCode(view.currentTask.reasoningEffort ?? "自动")} / ${inlineCode(permissionModeLabel(view.currentTask.permissionMode))}`,
|
|
639
639
|
`**任务状态 / Agent**:${persistedTaskStatus(view.currentTask.sessionStatus, view.currentTask.lastTurnStatus)} / ${inlineCode(view.currentTask.agentName)}`,
|
|
640
640
|
`**任务 ID**:${inlineCode(view.currentTask.id)}`,
|
|
641
641
|
]
|
|
642
642
|
: [
|
|
643
643
|
"**当前任务**:无,下一条普通消息会创建新任务",
|
|
644
644
|
workspaceLine,
|
|
645
|
-
`**Provider / 模型 / 思考强度 / 权限**:${inlineCode("
|
|
645
|
+
`**Provider / 模型 / 思考强度 / 权限**:${inlineCode("Agent 默认")} / ${inlineCode("默认")} / ${inlineCode("自动")} / ${inlineCode(permissionModeLabel())}`,
|
|
646
646
|
`**默认 Agent**:${view.defaultAgentTitle} (${inlineCode(view.defaultAgentName)})`,
|
|
647
647
|
];
|
|
648
648
|
lines.push(
|
|
@@ -673,8 +673,8 @@ export class CardRenderer {
|
|
|
673
673
|
|
|
674
674
|
renderTurnDetails(state: TurnViewState): Record<string, unknown> {
|
|
675
675
|
const title = state.taskTitle
|
|
676
|
-
?
|
|
677
|
-
: "
|
|
676
|
+
? `任务执行详情:${truncateText(state.taskTitle.replace(/\s+/g, " ").trim(), 60)}`
|
|
677
|
+
: "任务执行详情";
|
|
678
678
|
return turnCard(title, "blue", renderTurnElements(state, "always"), renderTurnSubtitle(state));
|
|
679
679
|
}
|
|
680
680
|
|
package/src/index.ts
CHANGED
|
@@ -59,7 +59,7 @@ if (feishuOutbound) {
|
|
|
59
59
|
const presenter = new FeishuTurnPresenter(feishuOutbound, store, renderer, {
|
|
60
60
|
normalIntervalMs: 2_000,
|
|
61
61
|
criticalGapMs: 500,
|
|
62
|
-
onError: (error) => logger.warn({ error }, "Failed to update
|
|
62
|
+
onError: (error) => logger.warn({ error }, "Failed to update Agent progress card."),
|
|
63
63
|
});
|
|
64
64
|
routes.push({ matches: (contextKey) => !contextKey.startsWith("console:"), outbound: feishuOutbound, presenter });
|
|
65
65
|
const defaultAgentName = config.defaults.agent!;
|
|
@@ -564,7 +564,7 @@ export class ProxySessionController {
|
|
|
564
564
|
try {
|
|
565
565
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
566
566
|
} catch (error) {
|
|
567
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect
|
|
567
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "Failed to inspect App Server task status for CLI.");
|
|
568
568
|
}
|
|
569
569
|
}
|
|
570
570
|
}
|
|
@@ -668,7 +668,7 @@ export class ProxySessionController {
|
|
|
668
668
|
const agentName = requestedAgentName?.trim() || source.agentName;
|
|
669
669
|
const agent = this.ensureAgent(agentName);
|
|
670
670
|
if (forceProjectless && agent.kind !== "app-server") {
|
|
671
|
-
throw new Error("task newgroup --nodir is only available for
|
|
671
|
+
throw new Error("task newgroup --nodir is only available for App Server agents.");
|
|
672
672
|
}
|
|
673
673
|
const sourceContextKey = this.outbound.getSessionContextKey(localSessionId) ?? source.contextKey;
|
|
674
674
|
const replyTarget = this.outbound.getSessionReplyTarget(localSessionId);
|
|
@@ -907,7 +907,7 @@ export class ProxySessionController {
|
|
|
907
907
|
replyTarget?: MessageReplyTarget,
|
|
908
908
|
localImagePaths?: string[],
|
|
909
909
|
): Promise<void> {
|
|
910
|
-
if (!text.trim()) throw new Error("请输入要交给
|
|
910
|
+
if (!text.trim()) throw new Error("请输入要交给 Agent 的内容。");
|
|
911
911
|
let record = this.currentSession(contextKey);
|
|
912
912
|
if (!record) {
|
|
913
913
|
const context = this.store.getOrCreateUserContext(contextKey, this.config.defaults.agent!);
|
|
@@ -981,7 +981,7 @@ export class ProxySessionController {
|
|
|
981
981
|
if (messageId) await this.bindMessageReactionToTurn(messageId, record.localSessionId, activeTurnId);
|
|
982
982
|
return;
|
|
983
983
|
} catch (error) {
|
|
984
|
-
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the
|
|
984
|
+
this.logger.debug({ error, sessionId: record.localSessionId, activeTurnId }, "Steering failed; reconciling the App Server thread.");
|
|
985
985
|
let current = loaded.runtime.getSession(record.localSessionId);
|
|
986
986
|
try {
|
|
987
987
|
current = await loaded.runtime.synchronizeSession(record.localSessionId);
|
|
@@ -1006,7 +1006,7 @@ export class ProxySessionController {
|
|
|
1006
1006
|
} catch (retryError) {
|
|
1007
1007
|
this.logger.warn(
|
|
1008
1008
|
{ error: retryError, sessionId: record.localSessionId, activeTurnId: current.activeTurnId },
|
|
1009
|
-
"Failed to steer the reconciled
|
|
1009
|
+
"Failed to steer the reconciled App Server turn; queueing prompt.",
|
|
1010
1010
|
);
|
|
1011
1011
|
}
|
|
1012
1012
|
}
|
|
@@ -1176,7 +1176,7 @@ export class ProxySessionController {
|
|
|
1176
1176
|
const agent = this.ensureAgent(source.agentName);
|
|
1177
1177
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
1178
1178
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1179
|
-
throw new Error("当前
|
|
1179
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1180
1180
|
}
|
|
1181
1181
|
|
|
1182
1182
|
const context = this.store.getOrCreateUserContext(message.contextKey, source.agentName);
|
|
@@ -1253,14 +1253,14 @@ export class ProxySessionController {
|
|
|
1253
1253
|
.map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
|
|
1254
1254
|
.find((candidate) => candidate !== undefined);
|
|
1255
1255
|
if (!anchor) {
|
|
1256
|
-
throw new Error("无法确定这个话题对应的
|
|
1256
|
+
throw new Error("无法确定这个话题对应的 App Server 轮次,因此没有创建分支任务。请从该轮的用户消息、思考卡片或最终回答创建话题。");
|
|
1257
1257
|
}
|
|
1258
1258
|
|
|
1259
1259
|
const source = anchor.contextKey
|
|
1260
1260
|
? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
|
|
1261
1261
|
: this.store.getSession(anchor.localSessionId);
|
|
1262
1262
|
if (!source || !source.remoteSessionId || !this.isCodexSession(source)) {
|
|
1263
|
-
throw new Error("这个话题的来源不是可 fork 的
|
|
1263
|
+
throw new Error("这个话题的来源不是可 fork 的 App Server 任务。");
|
|
1264
1264
|
}
|
|
1265
1265
|
if (baseChatContextKey(anchor.contextKey ?? source.contextKey) !== `chat_id:${message.chatId}`) {
|
|
1266
1266
|
throw new Error("话题来源任务不属于当前会话,已拒绝创建分支。");
|
|
@@ -1269,7 +1269,7 @@ export class ProxySessionController {
|
|
|
1269
1269
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(anchor.turnId));
|
|
1270
1270
|
if (isTurnStillRunning(snapshot?.status)
|
|
1271
1271
|
|| (source.lastTurnId === anchor.turnId && source.lastTurnStatus === "running")) {
|
|
1272
|
-
throw new Error("话题对应的轮次仍在执行,
|
|
1272
|
+
throw new Error("话题对应的轮次仍在执行,App Server 暂时不能从这一轮 fork。请等待该轮完成后再在话题中发送消息。");
|
|
1273
1273
|
}
|
|
1274
1274
|
|
|
1275
1275
|
return { anchor, source, snapshot };
|
|
@@ -1311,7 +1311,7 @@ export class ProxySessionController {
|
|
|
1311
1311
|
}
|
|
1312
1312
|
|
|
1313
1313
|
if (source && (!source.remoteSessionId || !this.isCodexSession(source))) {
|
|
1314
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
1314
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
1315
1315
|
}
|
|
1316
1316
|
|
|
1317
1317
|
let runtime: AgentRuntime;
|
|
@@ -1321,20 +1321,20 @@ export class ProxySessionController {
|
|
|
1321
1321
|
agentName = source.agentName;
|
|
1322
1322
|
runtime = this.runtimes.forAgent(agentName);
|
|
1323
1323
|
} else {
|
|
1324
|
-
if (!taskId) throw new Error("缺少要 fork 的
|
|
1324
|
+
if (!taskId) throw new Error("缺少要 fork 的 App Server 任务 ID。");
|
|
1325
1325
|
const resolved = await this.resolveRemoteCodexSession(taskId);
|
|
1326
1326
|
agentName = resolved.agentName;
|
|
1327
1327
|
runtime = resolved.runtime;
|
|
1328
1328
|
remote = resolved.remote;
|
|
1329
1329
|
}
|
|
1330
1330
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1331
|
-
throw new Error("当前
|
|
1331
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1332
1332
|
}
|
|
1333
1333
|
|
|
1334
1334
|
const remoteSessionId = source?.remoteSessionId ?? remote?.id ?? taskId;
|
|
1335
|
-
if (!remoteSessionId) throw new Error("当前任务尚未创建
|
|
1335
|
+
if (!remoteSessionId) throw new Error("当前任务尚未创建 App Server 任务 ID,暂时不能 fork。");
|
|
1336
1336
|
if (!runtime.readRemoteSession && !source) {
|
|
1337
|
-
throw new Error("当前
|
|
1337
|
+
throw new Error("当前 App Server Agent 不支持读取指定任务。");
|
|
1338
1338
|
}
|
|
1339
1339
|
remote ??= runtime.readRemoteSession
|
|
1340
1340
|
? await runtime.readRemoteSession(remoteSessionId)
|
|
@@ -1359,7 +1359,7 @@ export class ProxySessionController {
|
|
|
1359
1359
|
const forkedFromHistoricalTurn = isRunning && lastTurnId !== latestTurnId;
|
|
1360
1360
|
|
|
1361
1361
|
const cwd = remote?.cwd || source?.cwd;
|
|
1362
|
-
if (!cwd) throw new Error("指定的
|
|
1362
|
+
if (!cwd) throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能 fork。");
|
|
1363
1363
|
const sourceTitle = remote?.title ?? source?.title ?? remote?.preview;
|
|
1364
1364
|
const forkTitle = normalizeTaskTitle(requestedTitle) ?? this.store.nextForkTitle(sourceTitle);
|
|
1365
1365
|
const modelProvider = remote?.modelProvider ?? source?.modelProvider;
|
|
@@ -1440,16 +1440,16 @@ export class ProxySessionController {
|
|
|
1440
1440
|
sourceLabel: string,
|
|
1441
1441
|
): ForkSessionPlan {
|
|
1442
1442
|
if (!source.remoteSessionId || !this.isCodexSession(source)) {
|
|
1443
|
-
throw new Error(`${sourceLabel}不是可 fork 的
|
|
1443
|
+
throw new Error(`${sourceLabel}不是可 fork 的 App Server 任务。`);
|
|
1444
1444
|
}
|
|
1445
1445
|
const runtime = this.runtimes.forAgent(source.agentName);
|
|
1446
1446
|
if (runtime.kind !== "codex" || !runtime.forkSession) {
|
|
1447
|
-
throw new Error("当前
|
|
1447
|
+
throw new Error("当前 App Server Agent 不支持 fork 任务。");
|
|
1448
1448
|
}
|
|
1449
1449
|
|
|
1450
1450
|
const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(lastTurnId));
|
|
1451
1451
|
if (isTurnStillRunning(snapshot?.status)) {
|
|
1452
|
-
throw new Error(`${sourceLabel}仍在执行,
|
|
1452
|
+
throw new Error(`${sourceLabel}仍在执行,App Server 暂时不能从这一轮 fork。`);
|
|
1453
1453
|
}
|
|
1454
1454
|
const sourceWasRunning = Boolean(
|
|
1455
1455
|
runtime.getSession(source.localSessionId)?.activeTurnId
|
|
@@ -1578,7 +1578,7 @@ export class ProxySessionController {
|
|
|
1578
1578
|
}
|
|
1579
1579
|
const source = direct ?? this.findStoredSessionByReference(taskId);
|
|
1580
1580
|
if (source && !this.isCodexSession(source)) {
|
|
1581
|
-
throw new Error("指定任务不是
|
|
1581
|
+
throw new Error("指定任务不是 App Server 任务,暂时不能按项目创建新任务。");
|
|
1582
1582
|
}
|
|
1583
1583
|
|
|
1584
1584
|
let agentName: string;
|
|
@@ -1609,7 +1609,7 @@ export class ProxySessionController {
|
|
|
1609
1609
|
|
|
1610
1610
|
const cwd = remote?.cwd || source?.cwd;
|
|
1611
1611
|
if (!cwd) {
|
|
1612
|
-
throw new Error("指定的
|
|
1612
|
+
throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能按项目创建新任务。");
|
|
1613
1613
|
}
|
|
1614
1614
|
const executionSettings: SessionExecutionSettings = {
|
|
1615
1615
|
modelProvider: remote?.modelProvider ?? source?.modelProvider,
|
|
@@ -1829,7 +1829,7 @@ export class ProxySessionController {
|
|
|
1829
1829
|
"群和新任务已创建。",
|
|
1830
1830
|
`当前任务:${taskDescription}`,
|
|
1831
1831
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1832
|
-
`当前 Provider:${task.modelProvider ?? "
|
|
1832
|
+
`当前 Provider:${task.modelProvider ?? "Agent 默认"}`,
|
|
1833
1833
|
`当前模型:${task.model ?? "默认"}`,
|
|
1834
1834
|
`思考强度:${task.reasoningEffort ?? "自动"}`,
|
|
1835
1835
|
`权限类型:${task.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
@@ -1920,7 +1920,7 @@ export class ProxySessionController {
|
|
|
1920
1920
|
`已从${prepared.sourceDescription}创建分支。`,
|
|
1921
1921
|
`当前任务:${taskDescription}`,
|
|
1922
1922
|
`当前 Project 目录:${boundProjectCwd ?? "未绑定(Projectless)"}`,
|
|
1923
|
-
`当前 Provider:${forked.session.modelProvider ?? "
|
|
1923
|
+
`当前 Provider:${forked.session.modelProvider ?? "Agent 默认"}`,
|
|
1924
1924
|
`当前模型:${forked.session.model ?? "默认"}`,
|
|
1925
1925
|
`思考强度:${forked.session.reasoningEffort ?? "自动"}`,
|
|
1926
1926
|
`权限类型:${forked.session.permissionMode === "confirm" ? "执行前确认" : "自动执行"}`,
|
|
@@ -2010,7 +2010,7 @@ export class ProxySessionController {
|
|
|
2010
2010
|
});
|
|
2011
2011
|
} catch (error) {
|
|
2012
2012
|
if (!(agent.kind === "app-server" && !record.lastTurnId && isMissingRolloutError(error))) throw error;
|
|
2013
|
-
this.logger.warn({ error, sessionId: record.localSessionId }, "
|
|
2013
|
+
this.logger.warn({ error, sessionId: record.localSessionId }, "App Server task has no rollout; creating a replacement task.");
|
|
2014
2014
|
session = await runtime.createSession({
|
|
2015
2015
|
localSessionId: record.localSessionId,
|
|
2016
2016
|
agentName: record.agentName,
|
|
@@ -2230,7 +2230,7 @@ export class ProxySessionController {
|
|
|
2230
2230
|
} catch (error) {
|
|
2231
2231
|
this.logger.warn(
|
|
2232
2232
|
{ error, sessionId: record.localSessionId },
|
|
2233
|
-
"Failed to pause the active
|
|
2233
|
+
"Failed to pause the active Agent goal before interrupting its turn.",
|
|
2234
2234
|
);
|
|
2235
2235
|
}
|
|
2236
2236
|
}
|
|
@@ -2244,7 +2244,7 @@ export class ProxySessionController {
|
|
|
2244
2244
|
} catch (error) {
|
|
2245
2245
|
this.logger.warn(
|
|
2246
2246
|
{ error, sessionId: record.localSessionId, remoteSessionId: record.remoteSessionId },
|
|
2247
|
-
"Failed to inspect the current
|
|
2247
|
+
"Failed to inspect the current App Server turn before interrupting; using the locally tracked turn.",
|
|
2248
2248
|
);
|
|
2249
2249
|
}
|
|
2250
2250
|
}
|
|
@@ -2258,7 +2258,7 @@ export class ProxySessionController {
|
|
|
2258
2258
|
remoteSessionId: record.remoteSessionId,
|
|
2259
2259
|
turnId,
|
|
2260
2260
|
});
|
|
2261
|
-
await this.outbound.sendText(record.contextKey, `已向
|
|
2261
|
+
await this.outbound.sendText(record.contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
2262
2262
|
return;
|
|
2263
2263
|
}
|
|
2264
2264
|
|
|
@@ -2621,7 +2621,7 @@ export class ProxySessionController {
|
|
|
2621
2621
|
|
|
2622
2622
|
const loaded = await this.loadSession(record);
|
|
2623
2623
|
if (loaded.runtime.kind !== "codex" || !loaded.runtime.getGoal || !loaded.runtime.setGoal || !loaded.runtime.clearGoal) {
|
|
2624
|
-
throw new Error("
|
|
2624
|
+
throw new Error("当前 Agent 不支持 Goal 模式。");
|
|
2625
2625
|
}
|
|
2626
2626
|
|
|
2627
2627
|
if (command.action === "show") {
|
|
@@ -2648,7 +2648,7 @@ export class ProxySessionController {
|
|
|
2648
2648
|
goal,
|
|
2649
2649
|
command.action === "pause"
|
|
2650
2650
|
? "Goal 已暂停;当前轮次可以完成,但不会继续自动执行。"
|
|
2651
|
-
: "Goal 已恢复,
|
|
2651
|
+
: "Goal 已恢复,Agent 会继续自动执行。",
|
|
2652
2652
|
record,
|
|
2653
2653
|
);
|
|
2654
2654
|
return;
|
|
@@ -2669,7 +2669,7 @@ export class ProxySessionController {
|
|
|
2669
2669
|
await this.sendGoalCard(
|
|
2670
2670
|
contextKey,
|
|
2671
2671
|
goal,
|
|
2672
|
-
command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,
|
|
2672
|
+
command.action === "edit" ? "Goal 已更新。" : "Goal 已启动,Agent 会持续执行直到完成、暂停或遇到阻塞。",
|
|
2673
2673
|
record,
|
|
2674
2674
|
);
|
|
2675
2675
|
}
|
|
@@ -2690,7 +2690,7 @@ export class ProxySessionController {
|
|
|
2690
2690
|
title: "任务",
|
|
2691
2691
|
lines: [
|
|
2692
2692
|
`**标题**:${cardText(record.title ?? "未命名任务")}`,
|
|
2693
|
-
`**
|
|
2693
|
+
`**App Server 任务 ID**:${cardText(record.remoteSessionId ?? "尚未创建")}`,
|
|
2694
2694
|
],
|
|
2695
2695
|
});
|
|
2696
2696
|
}
|
|
@@ -2701,7 +2701,7 @@ export class ProxySessionController {
|
|
|
2701
2701
|
"**/goal edit <新目标>** 修改 **/goal clear** 清除",
|
|
2702
2702
|
],
|
|
2703
2703
|
});
|
|
2704
|
-
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("
|
|
2704
|
+
await this.outbound.sendInteractiveCard(contextKey, this.cardRenderer.renderSectionsCard("Agent Goal", sections));
|
|
2705
2705
|
}
|
|
2706
2706
|
|
|
2707
2707
|
private async runShellCommand(contextKey: string, command: string): Promise<void> {
|
|
@@ -2845,7 +2845,7 @@ export class ProxySessionController {
|
|
|
2845
2845
|
remoteSessions.push(...page.sessions.map((session) => ({ agentName, session })));
|
|
2846
2846
|
remoteHasMore ||= Boolean(page.nextCursor);
|
|
2847
2847
|
} catch (error) {
|
|
2848
|
-
this.logger.warn({ error, contextKey, agentName }, "Failed to list
|
|
2848
|
+
this.logger.warn({ error, contextKey, agentName }, "Failed to list App Server sessions for an Agent.");
|
|
2849
2849
|
remoteErrors.push(`${agentName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
2850
2850
|
}
|
|
2851
2851
|
}));
|
|
@@ -2937,7 +2937,7 @@ export class ProxySessionController {
|
|
|
2937
2937
|
};
|
|
2938
2938
|
});
|
|
2939
2939
|
const card = this.cardRenderer.renderTaskListCard(
|
|
2940
|
-
searchTerm ? `
|
|
2940
|
+
searchTerm ? `App Server 任务:${searchTerm}` : "App Server 任务",
|
|
2941
2941
|
activeCount > 0 ? `任务(${activeCount} 个活跃)` : "任务",
|
|
2942
2942
|
cardEntries,
|
|
2943
2943
|
[
|
|
@@ -3006,7 +3006,7 @@ export class ProxySessionController {
|
|
|
3006
3006
|
const candidates = scoped
|
|
3007
3007
|
? [[scoped.agentName, this.runtimes.forAgent(scoped.agentName)] as const]
|
|
3008
3008
|
: this.runtimes.entries("codex");
|
|
3009
|
-
if (candidates.length === 0) throw new Error("未配置
|
|
3009
|
+
if (candidates.length === 0) throw new Error("未配置 App Server Agent。");
|
|
3010
3010
|
|
|
3011
3011
|
const reads = await Promise.allSettled(candidates.map(async ([agentName, runtime]) => {
|
|
3012
3012
|
if (runtime.kind !== "codex" || !runtime.readRemoteSession) {
|
|
@@ -3031,7 +3031,7 @@ export class ProxySessionController {
|
|
|
3031
3031
|
: undefined)
|
|
3032
3032
|
.filter((detail): detail is string => Boolean(detail))
|
|
3033
3033
|
.join(";");
|
|
3034
|
-
throw new Error(`找不到
|
|
3034
|
+
throw new Error(`找不到 App Server 任务:${scoped?.remoteSessionId ?? reference}${details ? `(${details})` : ""}`);
|
|
3035
3035
|
}
|
|
3036
3036
|
|
|
3037
3037
|
private async switchSession(contextKey: string, reference?: string): Promise<void> {
|
|
@@ -3060,9 +3060,9 @@ export class ProxySessionController {
|
|
|
3060
3060
|
|
|
3061
3061
|
const { agentName, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
3062
3062
|
if (remote.status === "active" || remote.lastTurnStatus === "inProgress") {
|
|
3063
|
-
throw new Error(`这个任务正在外部
|
|
3063
|
+
throw new Error(`这个任务正在外部 Agent 中执行,当前不会切换。可使用 /status ${taskId} 查看进度。`);
|
|
3064
3064
|
}
|
|
3065
|
-
if (!remote.cwd) throw new Error("这个
|
|
3065
|
+
if (!remote.cwd) throw new Error("这个 App Server 任务没有可用的工作目录,暂时无法切换。");
|
|
3066
3066
|
const localSessionId = createId("sess");
|
|
3067
3067
|
this.store.createSession({
|
|
3068
3068
|
localSessionId,
|
|
@@ -3109,7 +3109,7 @@ export class ProxySessionController {
|
|
|
3109
3109
|
|
|
3110
3110
|
const { runtime, remote } = await this.resolveRemoteCodexSession(taskId);
|
|
3111
3111
|
if (!runtime.readRemoteSession || !runtime.interruptRemoteTurn) {
|
|
3112
|
-
throw new Error("当前
|
|
3112
|
+
throw new Error("当前 App Server Agent 不支持停止外部任务。");
|
|
3113
3113
|
}
|
|
3114
3114
|
const turnId = remote.status === "active" || remote.lastTurnStatus === "inProgress"
|
|
3115
3115
|
? remote.lastTurnId
|
|
@@ -3124,7 +3124,7 @@ export class ProxySessionController {
|
|
|
3124
3124
|
turnId,
|
|
3125
3125
|
source: "sessions_card",
|
|
3126
3126
|
});
|
|
3127
|
-
await this.outbound.sendText(contextKey, `已向
|
|
3127
|
+
await this.outbound.sendText(contextKey, `已向 Agent 发送 Interrupt 请求:${turnId}`);
|
|
3128
3128
|
}
|
|
3129
3129
|
|
|
3130
3130
|
private resolveSessionReference(contextKey: string, reference?: string): string {
|
|
@@ -3165,7 +3165,7 @@ export class ProxySessionController {
|
|
|
3165
3165
|
&& activity.activeTurnId === record.lastTurnId;
|
|
3166
3166
|
const botOwnsActiveTurn = runtimeOwnsActiveTurn || persistedTurnMatches;
|
|
3167
3167
|
if (activity.active && !botOwnsActiveTurn) {
|
|
3168
|
-
throw new Error("这个任务正在外部
|
|
3168
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
3169
3169
|
}
|
|
3170
3170
|
return activity;
|
|
3171
3171
|
}
|
|
@@ -3173,14 +3173,14 @@ export class ProxySessionController {
|
|
|
3173
3173
|
try {
|
|
3174
3174
|
remote = await runtime.readRemoteSession(record.remoteSessionId);
|
|
3175
3175
|
} catch (error) {
|
|
3176
|
-
//
|
|
3176
|
+
// App Server does not materialize a new thread until its first user message.
|
|
3177
3177
|
// Such a thread has no turn to take over, so allow turn/start to create it.
|
|
3178
3178
|
if (!record.lastTurnId && isUnmaterializedCodexThreadError(error)) return;
|
|
3179
3179
|
throw error;
|
|
3180
3180
|
}
|
|
3181
3181
|
const botOwnsActiveTurn = isBotOwnedActiveTurn(record, remote);
|
|
3182
3182
|
if ((remote.status === "active" || remote.lastTurnStatus === "inProgress") && !botOwnsActiveTurn) {
|
|
3183
|
-
throw new Error("这个任务正在外部
|
|
3183
|
+
throw new Error("这个任务正在外部 Agent 中执行。Agent Bot 不会接管或追加消息,请等待外部执行完成。");
|
|
3184
3184
|
}
|
|
3185
3185
|
return undefined;
|
|
3186
3186
|
}
|
|
@@ -3245,7 +3245,7 @@ export class ProxySessionController {
|
|
|
3245
3245
|
try {
|
|
3246
3246
|
remote = await runtime.readRemoteSession(current.remoteSessionId);
|
|
3247
3247
|
} catch (error) {
|
|
3248
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
3248
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect App Server task status.");
|
|
3249
3249
|
}
|
|
3250
3250
|
}
|
|
3251
3251
|
if (runtime.kind === "codex" && runtime.getGoal) {
|
|
@@ -3253,7 +3253,7 @@ export class ProxySessionController {
|
|
|
3253
3253
|
const loaded = runtime.getSession(current.localSessionId) ?? (await this.loadSession(current)).session;
|
|
3254
3254
|
goal = await runtime.getGoal(loaded.localSessionId);
|
|
3255
3255
|
} catch (error) {
|
|
3256
|
-
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect
|
|
3256
|
+
this.logger.warn({ error, sessionId: current.localSessionId }, "Failed to inspect Agent goal status.");
|
|
3257
3257
|
}
|
|
3258
3258
|
}
|
|
3259
3259
|
}
|
|
@@ -3265,7 +3265,7 @@ export class ProxySessionController {
|
|
|
3265
3265
|
let activeTurnId: string | undefined;
|
|
3266
3266
|
let queued = 0;
|
|
3267
3267
|
if (!current) {
|
|
3268
|
-
taskLines.push("无。直接发送消息即可创建一个未指定项目的
|
|
3268
|
+
taskLines.push("无。直接发送消息即可创建一个未指定项目的 Agent 任务。");
|
|
3269
3269
|
} else {
|
|
3270
3270
|
const agent = this.ensureAgent(current.agentName);
|
|
3271
3271
|
const runtimeSession = this.runtimes.forAgent(current.agentName).getSession(current.localSessionId);
|
|
@@ -3283,11 +3283,11 @@ export class ProxySessionController {
|
|
|
3283
3283
|
taskLines.push(
|
|
3284
3284
|
`**标题**:${cardCode(current.title ?? "未命名任务")}`,
|
|
3285
3285
|
`**工作目录**:${cardCode(current.cwd)}`,
|
|
3286
|
-
`**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "
|
|
3286
|
+
`**Provider / 模型 / 思考强度**:${cardCode(current.modelProvider ?? "Agent 默认")} / ${cardCode(current.model ?? "默认")} / ${cardCode(current.reasoningEffort ?? "自动")}`,
|
|
3287
3287
|
`**状态 / 最近结果**:${statusLabel} / ${resultLabel}`,
|
|
3288
3288
|
`**Agent**:${cardCode(agent.title)}`,
|
|
3289
3289
|
`**权限 / 任务范围**:${current.permissionMode === "confirm" ? "执行前确认" : "自动执行"} / ${detectProjectlessWorkspace(current.cwd) ? "未指定项目" : "指定项目"}`,
|
|
3290
|
-
`**
|
|
3290
|
+
`**App Server 任务 ID**:${cardCode(current.remoteSessionId ?? "尚未创建")}`,
|
|
3291
3291
|
`**当前执行 / 排队消息**:${activeTurnId ? cardCode(activeTurnId) : "无"} / ${queued} 条`,
|
|
3292
3292
|
`**创建时间 / 最近活动**:${formatStatusTime(current.createdAt)} / ${formatStatusTime(current.updatedAt)}`,
|
|
3293
3293
|
);
|
|
@@ -3318,8 +3318,8 @@ export class ProxySessionController {
|
|
|
3318
3318
|
},
|
|
3319
3319
|
];
|
|
3320
3320
|
const title = targetSessionId && current
|
|
3321
|
-
? `
|
|
3322
|
-
: "
|
|
3321
|
+
? `Agent 状态:${truncateText((current.title ?? current.remoteSessionId ?? current.localSessionId).replace(/\s+/g, " "), 40)}`
|
|
3322
|
+
: "Agent 状态";
|
|
3323
3323
|
const taskId = current?.remoteSessionId
|
|
3324
3324
|
? remoteSessionReference(current.agentName, current.remoteSessionId)
|
|
3325
3325
|
: current?.localSessionId;
|
|
@@ -3363,7 +3363,7 @@ export class ProxySessionController {
|
|
|
3363
3363
|
`**工作目录**:${cardCode(remote.cwd || "目录未知")}`,
|
|
3364
3364
|
`**状态 / 当前任务**:${remoteSessionDetailStatus(remote)} / 未切换`,
|
|
3365
3365
|
`**Agent**:${cardCode(agentName)}`,
|
|
3366
|
-
`**
|
|
3366
|
+
`**App Server 任务 ID**:${cardCode(remote.id)}`,
|
|
3367
3367
|
`**最近回合**:${cardCode(remote.lastTurnId ?? "无")} ${remoteTurnStatusLabel(remote.lastTurnStatus)}`,
|
|
3368
3368
|
`**创建时间 / 最近活动**:${formatRemoteTime(remote.createdAt)} / ${formatRemoteTime(latestRemoteTimestamp(remote.recencyAt, remote.updatedAt))}`,
|
|
3369
3369
|
],
|
|
@@ -3374,14 +3374,14 @@ export class ProxySessionController {
|
|
|
3374
3374
|
lines: [
|
|
3375
3375
|
`**当前 / 最后步骤**:${statusExcerpt(remote.lastActivity ?? remoteStatusStep(remote), 500)}`,
|
|
3376
3376
|
isRemoteSessionActive(remote)
|
|
3377
|
-
? "外部
|
|
3377
|
+
? "外部 Agent 正在执行;Agent Bot 只读取状态,不会接管。"
|
|
3378
3378
|
: `发送 **/switch ${cardText(remote.id)}** 切换到此任务。`,
|
|
3379
3379
|
],
|
|
3380
3380
|
collapsible: true,
|
|
3381
3381
|
elementId: "status_execution_details",
|
|
3382
3382
|
},
|
|
3383
3383
|
];
|
|
3384
|
-
const title = `
|
|
3384
|
+
const title = `Agent 状态:${truncateText((remote.title ?? remote.preview ?? remote.id).replace(/\s+/g, " "), 40)}`;
|
|
3385
3385
|
const showStop = isRemoteSessionActive(remote)
|
|
3386
3386
|
&& options.forceSwitchTaskId !== actionReference
|
|
3387
3387
|
&& options.forceSwitchTaskId !== remote.id;
|
|
@@ -99,7 +99,9 @@ export class AcpRuntimeAdapter implements AgentRuntime {
|
|
|
99
99
|
|
|
100
100
|
async startTurn(sessionId: string, prompt: RuntimePrompt): Promise<string> {
|
|
101
101
|
const { text, localImagePaths } = normalizeRuntimePrompt(prompt);
|
|
102
|
-
if (localImagePaths.length > 0)
|
|
102
|
+
if (localImagePaths.length > 0) {
|
|
103
|
+
throw new Error("当前 ACP Agent 不支持图片输入,请切换到支持图片输入的 App Server Agent 后重试。");
|
|
104
|
+
}
|
|
103
105
|
const session = this.requireSession(sessionId);
|
|
104
106
|
const turnId = createId("turn");
|
|
105
107
|
session.activeTurnId = turnId;
|