@keyou007/agent-bot 0.1.24-alpha.4 → 0.1.24-alpha.6

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 (108) hide show
  1. package/CHANGELOG.md +59 -0
  2. package/README.md +42 -6
  3. package/README.zh.md +42 -6
  4. package/SECURITY.md +12 -0
  5. package/config.example.yaml +5 -0
  6. package/dist/cli/controlProtocol.js.map +1 -1
  7. package/dist/cli/serverStatus.js +1 -0
  8. package/dist/cli/serverStatus.js.map +1 -1
  9. package/dist/cli.js +6 -1
  10. package/dist/cli.js.map +1 -1
  11. package/dist/codex/AppServerPermissions.js +34 -0
  12. package/dist/codex/AppServerPermissions.js.map +1 -0
  13. package/dist/codex/CodexLocalActivityDetector.js +37 -5
  14. package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
  15. package/dist/codex/CodexRuntime.js +238 -127
  16. package/dist/codex/CodexRuntime.js.map +1 -1
  17. package/dist/codex/ProviderSwitch.js +12 -13
  18. package/dist/codex/ProviderSwitch.js.map +1 -1
  19. package/dist/codex/ThreadWriterProcess.js +19 -5
  20. package/dist/codex/ThreadWriterProcess.js.map +1 -1
  21. package/dist/config/AgentExecutionDefaultsStore.js +4 -0
  22. package/dist/config/AgentExecutionDefaultsStore.js.map +1 -1
  23. package/dist/config/loadConfig.js +4 -0
  24. package/dist/config/loadConfig.js.map +1 -1
  25. package/dist/config/schema.js +3 -0
  26. package/dist/config/schema.js.map +1 -1
  27. package/dist/feishu/CardRenderer.js +146 -72
  28. package/dist/feishu/CardRenderer.js.map +1 -1
  29. package/dist/feishu/FeishuConnector.js +1 -0
  30. package/dist/feishu/FeishuConnector.js.map +1 -1
  31. package/dist/feishu/FeishuTurnPresenter.js +121 -17
  32. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  33. package/dist/index.js +43 -6
  34. package/dist/index.js.map +1 -1
  35. package/dist/local-files/CsvPreview.js +148 -0
  36. package/dist/local-files/CsvPreview.js.map +1 -0
  37. package/dist/local-files/LocalFileViewerServer.js +104 -14
  38. package/dist/local-files/LocalFileViewerServer.js.map +1 -1
  39. package/dist/local-files/TurnPreviewPage.js +128 -12
  40. package/dist/local-files/TurnPreviewPage.js.map +1 -1
  41. package/dist/presentation/TurnStateReducer.js +80 -6
  42. package/dist/presentation/TurnStateReducer.js.map +1 -1
  43. package/dist/proxy/ProxySessionController.js +767 -260
  44. package/dist/proxy/ProxySessionController.js.map +1 -1
  45. package/dist/proxy/SessionOperationQueue.js +14 -0
  46. package/dist/proxy/SessionOperationQueue.js.map +1 -0
  47. package/dist/runtime/AcpRuntimeAdapter.js +4 -2
  48. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  49. package/dist/state/StateStore.js +22 -0
  50. package/dist/state/StateStore.js.map +1 -1
  51. package/dist/state/TurnPreviewJournal.js +19 -7
  52. package/dist/state/TurnPreviewJournal.js.map +1 -1
  53. package/dist/state/migrations.js +6 -0
  54. package/dist/state/migrations.js.map +1 -1
  55. package/dist/supervision/SafeRestartNotifier.js +1 -0
  56. package/dist/supervision/SafeRestartNotifier.js.map +1 -1
  57. package/dist/supervision/SafeRestartScheduler.js +19 -6
  58. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  59. package/dist/terminal/TerminalCards.js +13 -0
  60. package/dist/terminal/TerminalCards.js.map +1 -0
  61. package/dist/terminal/TerminalLinks.js +76 -0
  62. package/dist/terminal/TerminalLinks.js.map +1 -0
  63. package/dist/terminal/TerminalPage.js +212 -0
  64. package/dist/terminal/TerminalPage.js.map +1 -0
  65. package/dist/terminal/TerminalProcess.js +71 -0
  66. package/dist/terminal/TerminalProcess.js.map +1 -0
  67. package/dist/terminal/TerminalServer.js +639 -0
  68. package/dist/terminal/TerminalServer.js.map +1 -0
  69. package/docs/technical-reference.md +53 -3
  70. package/docs/technical-reference.zh.md +52 -2
  71. package/npm-shrinkwrap.json +55 -5
  72. package/package.json +11 -4
  73. package/skills/agent-bot/SKILL.md +15 -2
  74. package/src/cli/controlProtocol.ts +2 -1
  75. package/src/cli/serverStatus.ts +1 -0
  76. package/src/cli.ts +6 -1
  77. package/src/codex/AppServerPermissions.ts +39 -0
  78. package/src/codex/CodexLocalActivityDetector.ts +34 -4
  79. package/src/codex/CodexRuntime.ts +243 -139
  80. package/src/codex/ProviderSwitch.ts +11 -12
  81. package/src/codex/ThreadWriterProcess.ts +17 -9
  82. package/src/config/AgentExecutionDefaultsStore.ts +2 -0
  83. package/src/config/loadConfig.ts +4 -0
  84. package/src/config/schema.ts +5 -1
  85. package/src/feishu/CardRenderer.ts +159 -72
  86. package/src/feishu/FeishuConnector.ts +1 -0
  87. package/src/feishu/FeishuTurnPresenter.ts +108 -16
  88. package/src/feishu/types.ts +1 -0
  89. package/src/index.ts +44 -7
  90. package/src/local-files/CsvPreview.ts +132 -0
  91. package/src/local-files/LocalFileViewerServer.ts +102 -15
  92. package/src/local-files/TurnPreviewPage.ts +131 -13
  93. package/src/presentation/TurnStateReducer.ts +87 -7
  94. package/src/presentation/turnViewTypes.ts +9 -0
  95. package/src/proxy/ProxySessionController.ts +762 -259
  96. package/src/proxy/SessionOperationQueue.ts +13 -0
  97. package/src/runtime/AcpRuntimeAdapter.ts +5 -3
  98. package/src/runtime/types.ts +10 -3
  99. package/src/state/StateStore.ts +38 -1
  100. package/src/state/TurnPreviewJournal.ts +19 -7
  101. package/src/state/migrations.ts +6 -0
  102. package/src/supervision/SafeRestartNotifier.ts +1 -0
  103. package/src/supervision/SafeRestartScheduler.ts +18 -6
  104. package/src/terminal/TerminalCards.ts +18 -0
  105. package/src/terminal/TerminalLinks.ts +61 -0
  106. package/src/terminal/TerminalPage.ts +213 -0
  107. package/src/terminal/TerminalProcess.ts +71 -0
  108. package/src/terminal/TerminalServer.ts +513 -0
@@ -1,4 +1,4 @@
1
- import type { AgentEvent, RemoteTurnDetails, ToolState } from "../runtime/types.js";
1
+ import type { AgentEvent, ApprovalDecision, ApprovalRequest, RemoteTurnDetails, ToolState } from "../runtime/types.js";
2
2
  import { appendGeneratedImageMarkdown } from "../utils/generatedImageMarkdown.js";
3
3
  import type { MessageReplyTarget } from "../feishu/types.js";
4
4
  import { formatStorageSize } from "../utils/formatStorageSize.js";
@@ -113,6 +113,13 @@ export function reduceTurnEvent(state: TurnViewState, event: AgentEvent, complet
113
113
  if (event.type === "turn_completed") next.finalResponse = event.finalResponse;
114
114
  if (event.type === "agent_text_delta") next.assistantText = state.assistantText + event.text;
115
115
  if (event.type === "plan_updated") next.plan = event.steps;
116
+ if (event.type === "approval_requested" || event.type === "approval_resolved") {
117
+ const request = event.type === "approval_requested" ? event.request
118
+ : state.approval?.id === event.requestId ? state.approval : undefined;
119
+ if (request) next.activities = next.activities.map((a) => a.id === approvalActivityId(event.turnId, request.id) && a.kind === "assistant"
120
+ ? { ...a, text: approvalHistoryText(request, event.type === "approval_resolved" ? event.decision : undefined,
121
+ event.type === "approval_resolved" && event.automatic) } : a);
122
+ }
116
123
  if (event.type === "progress") {
117
124
  const id = event.activityId ?? "progress";
118
125
  const old = state.activities.find((a) => a.id === id);
@@ -162,6 +169,7 @@ function reduceEvent(state: TurnViewState, event: AgentEvent): TurnViewState {
162
169
  return {
163
170
  ...state,
164
171
  totalTokens: (state.totalTokens ?? 0) + delta,
172
+ ...countModelCall(state, event),
165
173
  tokenUsageCumulative: Math.max(previousCumulative ?? 0, cumulativeTokens),
166
174
  totalTokensIncludingCache: total.value,
167
175
  tokenUsageTotalCumulative: total.cumulative,
@@ -304,7 +312,7 @@ function reduceEvent(state: TurnViewState, event: AgentEvent): TurnViewState {
304
312
  return {
305
313
  ...state,
306
314
  ...tracking,
307
- status: state.approval ? "waiting_for_approval" : "tool_running",
315
+ status: state.approval && !state.approval.automatic ? "waiting_for_approval" : "tool_running",
308
316
  activeTool: bounded,
309
317
  activities: activityUpdate.activities,
310
318
  activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
@@ -316,10 +324,21 @@ function reduceEvent(state: TurnViewState, event: AgentEvent): TurnViewState {
316
324
  case "tool_output_delta":
317
325
  return reduceToolOutputDelta(state, event.toolId, event.delta);
318
326
  case "approval_requested":
319
- return { ...state, status: "waiting_for_approval", approval: event.request };
327
+ return { ...state, status: event.request.automatic ? state.activeTool ? "tool_running" : "running" : "waiting_for_approval", approval: event.request,
328
+ activities: [...state.activities.filter((a) => a.id !== approvalActivityId(event.turnId, event.request.id)), {
329
+ kind: "assistant", id: approvalActivityId(event.turnId, event.request.id), text: bound(approvalHistoryText(event.request)),
330
+ }],
331
+ };
320
332
  case "approval_resolved":
321
333
  if (state.approval?.id !== event.requestId) return state;
322
- return { ...state, status: state.activeTool ? "tool_running" : "running", approval: undefined };
334
+ return {
335
+ ...state, status: state.activeTool ? "tool_running" : "running", approval: undefined,
336
+ activities: upsertActivity(state.activities,
337
+ state.activities.findIndex((a) => a.id === approvalActivityId(event.turnId, event.requestId)), {
338
+ kind: "assistant", id: approvalActivityId(event.turnId, event.requestId),
339
+ text: bound(approvalHistoryText(state.approval, event.decision, event.automatic)),
340
+ }).activities,
341
+ };
323
342
  case "turn_completed": {
324
343
  const durationMs = Math.max(0, event.durationMs ?? Date.now() - state.startedAt);
325
344
  return {
@@ -362,6 +381,27 @@ function reduceEvent(state: TurnViewState, event: AgentEvent): TurnViewState {
362
381
  }
363
382
  }
364
383
 
384
+ export function approvalActivityId(turnId: string, requestId: string): string {
385
+ return "approval:" + turnId + ":" + requestId;
386
+ }
387
+
388
+ export function continueTurnView(state: TurnViewState, turnId: string, startedAt: number): TurnViewState {
389
+ return { ...state, turnId, previewTurnId: state.previewTurnId ?? state.turnId,
390
+ continuedFromTurnId: state.turnId, continuedToTurnId: undefined, segmentStartedAt: startedAt,
391
+ status: "running", completedAt: undefined, durationMs: undefined, finalResponse: undefined,
392
+ error: undefined, approval: undefined, activeTool: undefined, assistantText: "", progressText: undefined };
393
+ }
394
+
395
+ function approvalHistoryText(request: ApprovalRequest, decision?: ApprovalDecision, automatic = false): string {
396
+ const labels = { accept: "允许一次", acceptForSession: "本会话允许", decline: "拒绝", cancel: "取消请求" };
397
+ const choice = decision ? request.options.find((option) => option.id === decision)?.label ?? labels[decision] : undefined;
398
+ const heading = choice ? automatic ? "自动同意(auto)" : "用户选择:" + choice
399
+ : request.automatic ? "正在自动同意(auto)" : "等待选择";
400
+ return ["**审批请求 · " + heading + "**", request.title, request.reason,
401
+ request.command ? "~~~\n" + request.command + "\n~~~" : undefined,
402
+ ].filter(Boolean).join("\n\n");
403
+ }
404
+
365
405
  export function appendSteerMessage(state: TurnViewState, id: string, text: string, localImagePaths?: string[]): TurnViewState {
366
406
  const normalized = text.trim();
367
407
  if (!normalized && !localImagePaths?.length) return state;
@@ -441,7 +481,7 @@ function reduceToolUpdate(state: TurnViewState, tool: ToolState, fullOutput?: st
441
481
  ...tracking,
442
482
  fullToolOutputs,
443
483
  fullToolErrors,
444
- status: state.approval ? "waiting_for_approval" : "tool_running",
484
+ status: state.approval && !state.approval.automatic ? "waiting_for_approval" : "tool_running",
445
485
  activeTool: bounded,
446
486
  activities: activityUpdate.activities,
447
487
  activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
@@ -457,7 +497,7 @@ function reduceToolUpdate(state: TurnViewState, tool: ToolState, fullOutput?: st
457
497
  ...tracking,
458
498
  fullToolOutputs,
459
499
  fullToolErrors,
460
- status: state.approval ? "waiting_for_approval" : activeTool ? "tool_running" : "running",
500
+ status: state.approval && !state.approval.automatic ? "waiting_for_approval" : activeTool ? "tool_running" : "running",
461
501
  activeTool,
462
502
  activities: activityUpdate.activities,
463
503
  activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
@@ -472,7 +512,7 @@ function reduceToolUpdate(state: TurnViewState, tool: ToolState, fullOutput?: st
472
512
  ...tracking,
473
513
  fullToolOutputs,
474
514
  fullToolErrors,
475
- status: state.approval ? "waiting_for_approval" : activeTool ? "tool_running" : "running",
515
+ status: state.approval && !state.approval.automatic ? "waiting_for_approval" : activeTool ? "tool_running" : "running",
476
516
  activeTool,
477
517
  activities: activityUpdate.activities,
478
518
  activitiesTruncated: state.activitiesTruncated || activityUpdate.truncated,
@@ -609,6 +649,46 @@ function bound(value: string): string {
609
649
  return `${value.slice(0, MAX_TEXT - 1)}…`;
610
650
  }
611
651
 
652
+ function countModelCall(
653
+ state: TurnViewState,
654
+ event: Extract<AgentEvent, { type: "token_usage_updated" }>,
655
+ ): Pick<TurnViewState, "modelCallCount" | "modelCallTokenBaseline"> {
656
+ // A pre-existing snapshot without a counter cannot provide a complete turn count.
657
+ if (state.modelCallCount === undefined && state.modelCallTokenBaseline === undefined
658
+ && state.tokenUsageCumulative !== undefined) return {};
659
+ const nonCached = reportedUsage(event.lastTokens, event.cumulativeTokens);
660
+ const total = reportedUsage(event.lastTotalTokens, event.cumulativeTotalTokens);
661
+ if (!nonCached && !total) return { modelCallTokenBaseline: state.modelCallTokenBaseline ?? {} };
662
+ const previous = state.modelCallTokenBaseline;
663
+ const usage = total ?? nonCached!;
664
+ const staleNonCached = nonCached !== undefined && previous?.nonCached !== undefined
665
+ && nonCached.cumulative < previous.nonCached;
666
+ const nonCachedGrew = nonCached !== undefined && previous?.nonCached !== undefined
667
+ && nonCached.cumulative > previous.nonCached;
668
+ const grew = total && previous?.total !== undefined && !previous.totalNeedsRebase
669
+ ? total.cumulative > previous.total
670
+ : nonCached && previous?.nonCached !== undefined
671
+ ? nonCachedGrew
672
+ : previous?.total === undefined && previous?.nonCached === undefined
673
+ && usage.last > 0 && usage.cumulative > 0;
674
+ return {
675
+ modelCallCount: (state.modelCallCount ?? 0) + (grew ? 1 : 0),
676
+ modelCallTokenBaseline: {
677
+ nonCached: nonCached ? Math.max(previous?.nonCached ?? 0, nonCached.cumulative) : previous?.nonCached,
678
+ total: total ? Math.max(previous?.total ?? 0, total.cumulative) : previous?.total,
679
+ // After a legacy-only update, rebase totals before using them again; keep
680
+ // their high-water mark so stale reports cannot lower the baseline.
681
+ totalNeedsRebase: total && !staleNonCached ? false : nonCachedGrew || previous?.totalNeedsRebase,
682
+ },
683
+ };
684
+ }
685
+
686
+ function reportedUsage(last: number | undefined, cumulative: number | undefined): { last: number; cumulative: number } | undefined {
687
+ if (last === undefined || cumulative === undefined || !Number.isFinite(last) || !Number.isFinite(cumulative)
688
+ || last < 0 || cumulative < 0) return undefined;
689
+ return { last: normalizeTokenCount(last), cumulative: normalizeTokenCount(cumulative) };
690
+ }
691
+
612
692
  function accumulateReportedTokens(
613
693
  last: number | undefined,
614
694
  cumulative: number | undefined,
@@ -36,6 +36,11 @@ export interface TurnViewState {
36
36
  previewJournal?: boolean;
37
37
  /** Byte cursor for the on-demand preview, never needed for recovery. */
38
38
  previewCursor?: number;
39
+ /** Shared presentation journal across a plan/implementation handoff. */
40
+ previewTurnId?: string;
41
+ continuedFromTurnId?: string;
42
+ continuedToTurnId?: string;
43
+ segmentStartedAt?: number;
39
44
  sessionId: string;
40
45
  turnId: string;
41
46
  agentLabel?: string;
@@ -56,6 +61,10 @@ export interface TurnViewState {
56
61
  cachedInputTokens?: number;
57
62
  tokenUsageTotalCumulative?: number;
58
63
  tokenUsageCachedCumulative?: number;
64
+ /** Effective token-usage updates observed for this turn. */
65
+ modelCallCount?: number;
66
+ /** Independent high-water marks; token breakdowns may disappear in partial updates. */
67
+ modelCallTokenBaseline?: { nonCached?: number; total?: number; totalNeedsRebase?: boolean };
59
68
  contextCompactionStatus?: "running" | "completed";
60
69
  contextCompactionCount?: number;
61
70
  contextCompactionId?: string;