@keyou007/agent-bot 0.1.17 → 0.1.18-alpha.1

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.
@@ -1302,7 +1302,7 @@ export class ProxySessionController {
1302
1302
  }
1303
1303
  switch (command.type) {
1304
1304
  case "shell":
1305
- await this.runShellCommand(contextKey, command.command, messageId);
1305
+ await this.runShellCommand(contextKey, command.command, messageId, incomingMessage);
1306
1306
  return;
1307
1307
  case "dir":
1308
1308
  await this.openDirectoryBrowser(contextKey, command.directory);
@@ -2163,17 +2163,41 @@ export class ProxySessionController {
2163
2163
  if (!runtime.readRemoteSession && !source) {
2164
2164
  throw new Error("当前 App Server Agent 不支持读取指定任务。");
2165
2165
  }
2166
- remote ??= runtime.readRemoteSession
2167
- ? await runtime.readRemoteSession(remoteSessionId)
2168
- : undefined;
2169
- const latestTurnId = remote?.lastTurnId ?? source?.lastTurnId;
2166
+ const persistedCompletedTurns = source ? this.localForkCompletedTurns(source) : [];
2167
+ const sourceLastSnapshot = turnViewSnapshot(source?.lastTurnId ? this.store.getTurnSnapshot(source.lastTurnId) : undefined);
2168
+ const localCompletedTurns = persistedCompletedTurns.length > 0
2169
+ ? persistedCompletedTurns
2170
+ : source?.lastTurnId
2171
+ && (source.lastTurnStatus === "completed" || sourceLastSnapshot?.status === "completed")
2172
+ ? [{
2173
+ id: source.lastTurnId,
2174
+ prompt: latestUserPromptFromTurnView(sourceLastSnapshot) ?? source.title,
2175
+ startedAt: sourceLastSnapshot?.startedAt ?? parseIsoTimestamp(source.updatedAt),
2176
+ completedAt: sourceLastSnapshot?.completedAt
2177
+ ?? sourceLastSnapshot?.startedAt
2178
+ ?? parseIsoTimestamp(source.updatedAt),
2179
+ }]
2180
+ : [];
2181
+ if (!remote && runtime.readRemoteSession && (!source || persistedCompletedTurns.length === 0)) {
2182
+ try {
2183
+ remote = await runtime.readRemoteSession(remoteSessionId);
2184
+ }
2185
+ catch (error) {
2186
+ if (localCompletedTurns.length === 0)
2187
+ throw error;
2188
+ this.logger.warn({ error, contextKey, remoteSessionId, sourceTurnId: localCompletedTurns.at(-1)?.id }, "Failed to read the complete source task before Fork; using the locally persisted completed Turn.");
2189
+ }
2190
+ }
2191
+ const latestTurnId = remote?.lastTurnId ?? source?.lastTurnId ?? localCompletedTurns.at(-1)?.id;
2170
2192
  const latestSnapshot = turnViewSnapshot(latestTurnId ? this.store.getTurnSnapshot(latestTurnId) : undefined);
2171
2193
  const isRunning = remote
2172
2194
  ? isRemoteSessionActive(remote)
2173
2195
  : Boolean((source && runtime.getSession(source.localSessionId)?.activeTurnId)
2174
2196
  || source?.lastTurnStatus === "running"
2175
2197
  || isTurnStillRunning(latestSnapshot?.status));
2176
- const lastTurnId = isRunning ? remote?.lastCompletedTurnId : latestTurnId;
2198
+ const lastTurnId = remote?.lastCompletedTurnId
2199
+ ?? (remote?.lastTurnStatus === "completed" ? remote.lastTurnId : undefined)
2200
+ ?? localCompletedTurns.at(-1)?.id;
2177
2201
  if (!lastTurnId) {
2178
2202
  if (isRunning) {
2179
2203
  throw new Error(`${sourceLabel}正在执行,且还没有已完成轮次可供 fork。请等待当前轮次完成后重试。`);
@@ -2181,7 +2205,9 @@ export class ProxySessionController {
2181
2205
  throw new Error(`${sourceLabel}还没有可供 fork 的轮次。请先完成至少一轮对话。`);
2182
2206
  }
2183
2207
  const snapshot = turnViewSnapshot(this.store.getTurnSnapshot(lastTurnId));
2184
- const forkedFromHistoricalTurn = isRunning && lastTurnId !== latestTurnId;
2208
+ const forkedFromHistoricalTurn = lastTurnId !== latestTurnId;
2209
+ const completedTurn = (remote?.completedTurns ?? localCompletedTurns)
2210
+ .find((turn) => turn.id === lastTurnId);
2185
2211
  const cwd = remote?.cwd || source?.cwd;
2186
2212
  if (!cwd)
2187
2213
  throw new Error("指定的 App Server 任务没有可用的工作目录,暂时不能 fork。");
@@ -2192,6 +2218,7 @@ export class ProxySessionController {
2192
2218
  const reasoningEffort = source?.reasoningEffort;
2193
2219
  const permissionMode = source?.permissionMode ?? "auto";
2194
2220
  const sourceTurnPrompt = truncateText(latestUserPromptFromTurnView(snapshot)
2221
+ ?? completedTurn?.prompt
2195
2222
  ?? (lastTurnId === latestTurnId ? remote?.lastUserPrompt : undefined)
2196
2223
  ?? remote?.preview
2197
2224
  ?? source?.title
@@ -2199,6 +2226,8 @@ export class ProxySessionController {
2199
2226
  ?? "Fork 来源轮次", 1_000);
2200
2227
  const sourceTurnCompletedAt = snapshot?.completedAt
2201
2228
  ?? snapshot?.startedAt
2229
+ ?? completedTurn?.completedAt
2230
+ ?? completedTurn?.startedAt
2202
2231
  ?? (lastTurnId === latestTurnId
2203
2232
  ? latestRemoteTimestamp(remote?.recencyAt, remote?.updatedAt)
2204
2233
  : undefined)
@@ -2216,19 +2245,31 @@ export class ProxySessionController {
2216
2245
  model,
2217
2246
  reasoningEffort,
2218
2247
  permissionMode,
2219
- lastTurnStatus: forkedFromHistoricalTurn
2220
- ? "completed"
2221
- : mapRemoteTurnStatus(remote?.lastTurnStatus)
2222
- ?? forkedTurnStatus(snapshot?.status)
2223
- ?? source?.lastTurnStatus,
2248
+ lastTurnStatus: "completed",
2224
2249
  sourceTurnPrompt,
2225
2250
  sourceTurnStartedAt: snapshot?.startedAt ?? sourceTurnCompletedAt,
2226
2251
  sourceTurnCompletedAt,
2227
- sourceCompletedTurns: remote?.completedTurns ?? [],
2252
+ sourceCompletedTurns: remote?.completedTurns
2253
+ ?? (persistedCompletedTurns.length > 0 ? [] : localCompletedTurns),
2228
2254
  sourceWasRunning: isRunning,
2229
2255
  forkedFromHistoricalTurn,
2230
2256
  };
2231
2257
  }
2258
+ localForkCompletedTurns(source) {
2259
+ return this.store.listTaskTurnGraph(source.localSessionId)
2260
+ .slice()
2261
+ .reverse()
2262
+ .map((record) => {
2263
+ const snapshot = turnViewSnapshot(record.snapshot);
2264
+ const startedAt = snapshot?.startedAt ?? parseIsoTimestamp(record.updatedAt);
2265
+ return {
2266
+ id: record.turnId,
2267
+ prompt: latestUserPromptFromTurnView(snapshot),
2268
+ startedAt,
2269
+ completedAt: snapshot?.completedAt ?? startedAt,
2270
+ };
2271
+ });
2272
+ }
2232
2273
  async prepareForkGroupSession(contextKey, requestedTitle, incomingMessage) {
2233
2274
  if (!incomingMessage?.threadContext) {
2234
2275
  const plan = await this.prepareForkSession(contextKey, undefined, requestedTitle);
@@ -3863,8 +3904,8 @@ export class ProxySessionController {
3863
3904
  this.logger.warn({ error, localSessionId }, "Failed to read the latest Agent Goal status.");
3864
3905
  }
3865
3906
  }
3866
- async runShellCommand(contextKey, command, sourceMessageId) {
3867
- const cwd = this.currentSession(contextKey)?.cwd ?? this.config.defaults.cwd;
3907
+ async runShellCommand(contextKey, command, sourceMessageId, incomingMessage) {
3908
+ const cwd = await this.shellCommandCwd(contextKey, incomingMessage);
3868
3909
  const created = await this.shellCommandJobs.createJob({ contextKey, sourceMessageId, command, cwd });
3869
3910
  let cardMessageId;
3870
3911
  const initialState = {
@@ -3903,6 +3944,40 @@ export class ProxySessionController {
3903
3944
  throw error;
3904
3945
  }
3905
3946
  }
3947
+ async shellCommandCwd(contextKey, incomingMessage) {
3948
+ const current = this.currentSession(contextKey);
3949
+ if (current)
3950
+ return current.cwd;
3951
+ if (incomingMessage?.threadContext) {
3952
+ const anchorMessageIds = threadForkAnchorMessageIds(incomingMessage);
3953
+ const anchor = anchorMessageIds
3954
+ .map((messageId) => this.store.findTurnAnchorByMessageId(messageId))
3955
+ .find((candidate) => candidate !== undefined);
3956
+ const source = anchor?.contextKey
3957
+ ? this.store.getSessionForContext(anchor.localSessionId, anchor.contextKey)
3958
+ : anchor
3959
+ ? this.store.getSession(anchor.localSessionId)
3960
+ : undefined;
3961
+ const sourceContextKey = anchor?.contextKey ?? source?.contextKey;
3962
+ if (source && sourceContextKey && baseChatContextKey(sourceContextKey) === baseChatContextKey(contextKey)) {
3963
+ return source.cwd;
3964
+ }
3965
+ for (const messageId of anchorMessageIds) {
3966
+ const commandJob = await this.shellCommandJobs.findJobByCardMessageId(messageId);
3967
+ if (commandJob && baseChatContextKey(commandJob.contextKey) === baseChatContextKey(contextKey)) {
3968
+ return commandJob.cwd;
3969
+ }
3970
+ }
3971
+ const baseContextKey = baseChatContextKey(contextKey);
3972
+ const baseSession = this.currentSession(baseContextKey);
3973
+ if (baseSession)
3974
+ return baseSession.cwd;
3975
+ const boundProjectCwd = this.store.getUserContext(baseContextKey)?.boundProjectCwd;
3976
+ if (boundProjectCwd)
3977
+ return boundProjectCwd;
3978
+ }
3979
+ return this.config.defaults.cwd;
3980
+ }
3906
3981
  monitorShellCommandJob(job, seededState) {
3907
3982
  if (!job.cardMessageId || this.shellCommandJobMonitors.has(job.id))
3908
3983
  return;