@pellux/goodvibes-agent 1.1.6 → 1.2.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 (256) hide show
  1. package/CHANGELOG.md +176 -0
  2. package/README.md +46 -30
  3. package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
  4. package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
  5. package/dist/package/main.js +132662 -91399
  6. package/docs/README.md +14 -7
  7. package/docs/channels-remote-and-api.md +8 -5
  8. package/docs/connected-host.md +14 -12
  9. package/docs/getting-started.md +56 -30
  10. package/docs/knowledge-artifacts-and-multimodal.md +7 -5
  11. package/docs/project-planning.md +2 -2
  12. package/docs/providers-and-routing.md +11 -3
  13. package/docs/tools-and-commands.md +114 -45
  14. package/docs/voice-and-live-tts.md +3 -1
  15. package/package.json +3 -2
  16. package/release/release-notes.md +130 -5
  17. package/release/release-readiness.json +120 -90
  18. package/src/agent/assistant-cockpit.ts +247 -0
  19. package/src/agent/autonomy-schedule-format.ts +96 -0
  20. package/src/agent/autonomy-schedule.ts +514 -0
  21. package/src/agent/channel-delivery-receipts.ts +292 -0
  22. package/src/agent/competitive-feature-inventory.ts +296 -0
  23. package/src/agent/document-registry-types.ts +106 -0
  24. package/src/agent/document-registry.ts +734 -0
  25. package/src/agent/harness-control.ts +2 -2
  26. package/src/agent/memory-prompt.ts +2 -2
  27. package/src/agent/operator-actions.ts +50 -6
  28. package/src/agent/persona-registry.ts +8 -0
  29. package/src/agent/project-context-files.ts +273 -0
  30. package/src/agent/prompt-context-receipts.ts +502 -0
  31. package/src/agent/reminder-schedule-format.ts +16 -2
  32. package/src/agent/research-run-registry.ts +582 -0
  33. package/src/agent/research-source-registry.ts +441 -0
  34. package/src/agent/routine-registry.ts +19 -3
  35. package/src/agent/routine-schedule-format.ts +27 -2
  36. package/src/agent/runtime-profile-starters.ts +7 -0
  37. package/src/agent/runtime-profile.ts +106 -4
  38. package/src/agent/schedule-edit-format.ts +129 -0
  39. package/src/agent/schedule-edit.ts +496 -0
  40. package/src/agent/schedule-next-routes.ts +42 -0
  41. package/src/agent/setup-wizard-checkpoint.ts +140 -0
  42. package/src/agent/setup-wizard.ts +447 -0
  43. package/src/agent/skill-registry-types.ts +102 -0
  44. package/src/agent/skill-registry.ts +81 -107
  45. package/src/agent/vibe-confirmation-routes.ts +62 -0
  46. package/src/agent/vibe-file.ts +285 -0
  47. package/src/cli/agent-knowledge-command.ts +45 -2
  48. package/src/cli/help.ts +3 -0
  49. package/src/cli/profiles-command.ts +25 -11
  50. package/src/config/agent-settings-policy.ts +1 -18
  51. package/src/input/agent-workspace-activation.ts +53 -0
  52. package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
  53. package/src/input/agent-workspace-artifact-metadata.ts +17 -0
  54. package/src/input/agent-workspace-basic-command-editors.ts +5 -1
  55. package/src/input/agent-workspace-categories.ts +153 -155
  56. package/src/input/agent-workspace-channel-triage.ts +481 -0
  57. package/src/input/agent-workspace-channels.ts +263 -0
  58. package/src/input/agent-workspace-command-editor.ts +152 -0
  59. package/src/input/agent-workspace-context-snapshot.ts +349 -0
  60. package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
  61. package/src/input/agent-workspace-document-editor.ts +502 -0
  62. package/src/input/agent-workspace-document-ops-editor.ts +523 -0
  63. package/src/input/agent-workspace-host-category.ts +1 -1
  64. package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
  65. package/src/input/agent-workspace-model-compare-editor.ts +376 -0
  66. package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
  67. package/src/input/agent-workspace-model-compare-types.ts +82 -0
  68. package/src/input/agent-workspace-model-compare-utils.ts +35 -0
  69. package/src/input/agent-workspace-onboarding-categories.ts +141 -0
  70. package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
  71. package/src/input/agent-workspace-operations-command-editors.ts +22 -0
  72. package/src/input/agent-workspace-research-report-editor.ts +212 -0
  73. package/src/input/agent-workspace-research-run-editor.ts +144 -0
  74. package/src/input/agent-workspace-research-source-editor.ts +167 -0
  75. package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
  76. package/src/input/agent-workspace-review-packet-utils.ts +265 -0
  77. package/src/input/agent-workspace-settings.ts +262 -30
  78. package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
  79. package/src/input/agent-workspace-setup-snapshot.ts +198 -0
  80. package/src/input/agent-workspace-setup.ts +34 -1
  81. package/src/input/agent-workspace-snapshot.ts +162 -147
  82. package/src/input/agent-workspace-types.ts +287 -2
  83. package/src/input/agent-workspace.ts +18 -0
  84. package/src/input/command-registry.ts +9 -2
  85. package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
  86. package/src/input/commands/channels-runtime.ts +102 -114
  87. package/src/input/commands/delegation-runtime.ts +87 -24
  88. package/src/input/commands/knowledge-browser-flags.ts +12 -0
  89. package/src/input/commands/knowledge.ts +28 -14
  90. package/src/input/commands/operator-actions-runtime.ts +6 -3
  91. package/src/input/commands/schedule-runtime.ts +71 -14
  92. package/src/input/commands/session-content.ts +2 -2
  93. package/src/input/commands/shell-core.ts +2 -0
  94. package/src/input/commands/vibe-runtime.ts +140 -0
  95. package/src/input/commands.ts +2 -0
  96. package/src/input/connected-host-routes.ts +123 -0
  97. package/src/input/settings-modal-types.ts +14 -0
  98. package/src/main.ts +15 -15
  99. package/src/panels/qr-panel.ts +2 -2
  100. package/src/renderer/agent-workspace-context-lines.ts +686 -0
  101. package/src/renderer/agent-workspace.ts +30 -419
  102. package/src/renderer/settings-modal-helpers.ts +12 -0
  103. package/src/renderer/settings-modal.ts +12 -0
  104. package/src/runtime/bootstrap-command-context.ts +11 -1
  105. package/src/runtime/bootstrap-command-parts.ts +14 -3
  106. package/src/runtime/bootstrap-core.ts +43 -1
  107. package/src/runtime/bootstrap-shell.ts +6 -0
  108. package/src/runtime/bootstrap.ts +113 -30
  109. package/src/runtime/connected-host-auth.ts +3 -2
  110. package/src/runtime/execution-ledger.ts +231 -0
  111. package/src/runtime/services.ts +88 -10
  112. package/src/runtime/tool-permission-safety.ts +287 -0
  113. package/src/shell/session-continuity-hints.ts +39 -0
  114. package/src/tools/agent-artifacts-tool.ts +606 -0
  115. package/src/tools/agent-audit-tool.ts +155 -0
  116. package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
  117. package/src/tools/agent-autonomy-tool.ts +140 -0
  118. package/src/tools/agent-channel-send-tool.ts +24 -2
  119. package/src/tools/agent-channels-tool.ts +140 -0
  120. package/src/tools/agent-computer-tool.ts +168 -0
  121. package/src/tools/agent-context-policy.ts +267 -10
  122. package/src/tools/agent-context-tool.ts +143 -0
  123. package/src/tools/agent-delegation-tool.ts +128 -0
  124. package/src/tools/agent-device-tool.ts +240 -0
  125. package/src/tools/agent-documents-tool.ts +684 -0
  126. package/src/tools/agent-execution-tool.ts +230 -0
  127. package/src/tools/agent-harness-agent-orchestration.ts +703 -0
  128. package/src/tools/agent-harness-autonomy-intake.ts +785 -0
  129. package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
  130. package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
  131. package/src/tools/agent-harness-autonomy-queue.ts +560 -0
  132. package/src/tools/agent-harness-background-processes-types.ts +35 -0
  133. package/src/tools/agent-harness-background-processes.ts +794 -0
  134. package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
  135. package/src/tools/agent-harness-browser-control.ts +338 -0
  136. package/src/tools/agent-harness-channel-metadata.ts +168 -10
  137. package/src/tools/agent-harness-cli-command-policy.ts +110 -0
  138. package/src/tools/agent-harness-command-catalog.ts +4 -2
  139. package/src/tools/agent-harness-command-runner.ts +42 -0
  140. package/src/tools/agent-harness-connected-host-status.ts +7 -4
  141. package/src/tools/agent-harness-delegation-posture.ts +234 -19
  142. package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
  143. package/src/tools/agent-harness-document-ops-types.ts +72 -0
  144. package/src/tools/agent-harness-document-ops.ts +671 -0
  145. package/src/tools/agent-harness-execution-history.ts +489 -0
  146. package/src/tools/agent-harness-execution-posture.ts +382 -0
  147. package/src/tools/agent-harness-file-recovery.ts +135 -0
  148. package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
  149. package/src/tools/agent-harness-learning-curator-common.ts +102 -0
  150. package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
  151. package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
  152. package/src/tools/agent-harness-learning-curator-types.ts +151 -0
  153. package/src/tools/agent-harness-learning-curator.ts +417 -0
  154. package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
  155. package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
  156. package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
  157. package/src/tools/agent-harness-media-posture.ts +208 -2
  158. package/src/tools/agent-harness-memory-posture.ts +556 -0
  159. package/src/tools/agent-harness-metadata.ts +100 -168
  160. package/src/tools/agent-harness-mode-catalog.ts +84 -33
  161. package/src/tools/agent-harness-model-catalog.ts +162 -0
  162. package/src/tools/agent-harness-model-provider-health.ts +186 -0
  163. package/src/tools/agent-harness-model-readiness.ts +406 -0
  164. package/src/tools/agent-harness-model-routing-types.ts +266 -0
  165. package/src/tools/agent-harness-model-routing-utils.ts +30 -0
  166. package/src/tools/agent-harness-model-routing.ts +137 -190
  167. package/src/tools/agent-harness-operator-methods.ts +115 -133
  168. package/src/tools/agent-harness-pairing-posture.ts +431 -18
  169. package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
  170. package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
  171. package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
  172. package/src/tools/agent-harness-personal-ops-records.ts +732 -0
  173. package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
  174. package/src/tools/agent-harness-personal-ops-types.ts +222 -0
  175. package/src/tools/agent-harness-personal-ops.ts +606 -0
  176. package/src/tools/agent-harness-project-context.ts +144 -0
  177. package/src/tools/agent-harness-prompt-context.ts +589 -0
  178. package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
  179. package/src/tools/agent-harness-release-evidence.ts +9 -7
  180. package/src/tools/agent-harness-release-readiness.ts +9 -7
  181. package/src/tools/agent-harness-research-briefing.ts +427 -0
  182. package/src/tools/agent-harness-research-queue.ts +250 -0
  183. package/src/tools/agent-harness-research-runs.ts +295 -0
  184. package/src/tools/agent-harness-research-workflow.ts +322 -0
  185. package/src/tools/agent-harness-security-posture.ts +2 -2
  186. package/src/tools/agent-harness-service-posture.ts +9 -9
  187. package/src/tools/agent-harness-session-metadata.ts +3 -3
  188. package/src/tools/agent-harness-setup-connected-host.ts +501 -0
  189. package/src/tools/agent-harness-setup-describe.ts +557 -0
  190. package/src/tools/agent-harness-setup-handoffs.ts +502 -0
  191. package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
  192. package/src/tools/agent-harness-setup-plan.ts +253 -0
  193. package/src/tools/agent-harness-setup-posture-types.ts +218 -0
  194. package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
  195. package/src/tools/agent-harness-setup-posture.ts +449 -221
  196. package/src/tools/agent-harness-setup-smoke.ts +508 -0
  197. package/src/tools/agent-harness-sudo-posture.ts +114 -0
  198. package/src/tools/agent-harness-tool-schema.ts +120 -7
  199. package/src/tools/agent-harness-tool-types.ts +78 -0
  200. package/src/tools/agent-harness-tool-utils.ts +43 -0
  201. package/src/tools/agent-harness-tool.ts +311 -370
  202. package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
  203. package/src/tools/agent-harness-ui-surface-types.ts +46 -0
  204. package/src/tools/agent-harness-vibe-health.ts +105 -0
  205. package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
  206. package/src/tools/agent-harness-workspace-actions.ts +114 -8
  207. package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
  208. package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
  209. package/src/tools/agent-host-tool.ts +159 -0
  210. package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
  211. package/src/tools/agent-learning-consolidation-core.ts +327 -0
  212. package/src/tools/agent-learning-consolidation-tool.ts +758 -0
  213. package/src/tools/agent-memory-tool.ts +214 -0
  214. package/src/tools/agent-model-compare-export.ts +315 -0
  215. package/src/tools/agent-model-compare-handoff.ts +592 -0
  216. package/src/tools/agent-model-compare-judgment.ts +633 -0
  217. package/src/tools/agent-model-compare-run.ts +722 -0
  218. package/src/tools/agent-model-compare-tool.ts +698 -0
  219. package/src/tools/agent-model-compare-types.ts +191 -0
  220. package/src/tools/agent-model-compare-utils.ts +93 -0
  221. package/src/tools/agent-models-tool.ts +208 -0
  222. package/src/tools/agent-operator-action-tool.ts +1 -1
  223. package/src/tools/agent-operator-method-tool.ts +643 -0
  224. package/src/tools/agent-personal-ops-tool.ts +197 -0
  225. package/src/tools/agent-policy-explanation.ts +415 -0
  226. package/src/tools/agent-research-report-tool.ts +608 -0
  227. package/src/tools/agent-research-runs-tool.ts +434 -0
  228. package/src/tools/agent-research-sources-tool.ts +443 -0
  229. package/src/tools/agent-research-tool.ts +687 -0
  230. package/src/tools/agent-review-packet-presets-core.ts +757 -0
  231. package/src/tools/agent-review-packet-presets-tool.ts +466 -0
  232. package/src/tools/agent-review-packet-share-tool.ts +305 -0
  233. package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
  234. package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
  235. package/src/tools/agent-route-planner-candidates-work.ts +251 -0
  236. package/src/tools/agent-route-planner-helpers.ts +667 -0
  237. package/src/tools/agent-route-planner.ts +185 -0
  238. package/src/tools/agent-route-tool.ts +105 -0
  239. package/src/tools/agent-schedule-edit-tool.ts +210 -0
  240. package/src/tools/agent-schedule-tool.ts +282 -0
  241. package/src/tools/agent-security-tool.ts +145 -0
  242. package/src/tools/agent-sessions-tool.ts +122 -0
  243. package/src/tools/agent-settings-import-tool.ts +104 -0
  244. package/src/tools/agent-settings-tool.ts +176 -0
  245. package/src/tools/agent-setup-tool.ts +226 -0
  246. package/src/tools/agent-support-tool.ts +122 -0
  247. package/src/tools/agent-terminal-process-tools.ts +167 -0
  248. package/src/tools/agent-tool-policy-guard-types.ts +77 -0
  249. package/src/tools/agent-tool-policy-guard.ts +110 -89
  250. package/src/tools/agent-vibe-tool.ts +297 -0
  251. package/src/tools/agent-work-plan-tool.ts +265 -6
  252. package/src/tools/agent-workspace-tool.ts +305 -0
  253. package/src/tools/artifact-archive.ts +169 -0
  254. package/src/tools/tool-definition-compaction.ts +36 -0
  255. package/src/tools/tool-execution-safety.ts +41 -0
  256. package/src/version.ts +1 -1
@@ -0,0 +1,687 @@
1
+ import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
2
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
3
+ import type { CommandContext, CommandRegistry } from '../input/command-registry.ts';
4
+ import { AgentResearchRunRegistry, type AgentResearchRunRecord } from '../agent/research-run-registry.ts';
5
+ import { createAgentArtifactsTool } from './agent-artifacts-tool.ts';
6
+ import { createAgentHarnessTool } from './agent-harness-tool.ts';
7
+ import { createAgentResearchReportTool } from './agent-research-report-tool.ts';
8
+ import { createAgentResearchRunsTool } from './agent-research-runs-tool.ts';
9
+ import { createAgentResearchSourcesTool } from './agent-research-sources-tool.ts';
10
+
11
+ type AgentResearchAction =
12
+ | 'briefing'
13
+ | 'plan'
14
+ | 'runner'
15
+ | 'runs'
16
+ | 'run'
17
+ | 'sources'
18
+ | 'source'
19
+ | 'bundle'
20
+ | 'search'
21
+ | 'reports'
22
+ | 'report_artifact'
23
+ | 'create_run'
24
+ | 'start_run'
25
+ | 'checkpoint'
26
+ | 'pause'
27
+ | 'resume'
28
+ | 'cancel'
29
+ | 'complete'
30
+ | 'fail'
31
+ | 'delete_run'
32
+ | 'add_source'
33
+ | 'review_source'
34
+ | 'reject_source'
35
+ | 'use_source'
36
+ | 'delete_source'
37
+ | 'report';
38
+
39
+ interface AgentResearchToolArgs {
40
+ readonly action?: unknown;
41
+ readonly mode?: unknown;
42
+ readonly id?: unknown;
43
+ readonly runId?: unknown;
44
+ readonly sourceId?: unknown;
45
+ readonly artifactId?: unknown;
46
+ readonly query?: unknown;
47
+ readonly target?: unknown;
48
+ readonly providerId?: unknown;
49
+ readonly maxResults?: unknown;
50
+ readonly region?: unknown;
51
+ readonly safeSearch?: unknown;
52
+ readonly timeRange?: unknown;
53
+ readonly evidenceTopN?: unknown;
54
+ readonly evidenceExtract?: unknown;
55
+ readonly title?: unknown;
56
+ readonly question?: unknown;
57
+ readonly goal?: unknown;
58
+ readonly plan?: unknown;
59
+ readonly nextSteps?: unknown;
60
+ readonly sourceIds?: unknown;
61
+ readonly status?: unknown;
62
+ readonly phase?: unknown;
63
+ readonly progress?: unknown;
64
+ readonly url?: unknown;
65
+ readonly publisher?: unknown;
66
+ readonly publishedAt?: unknown;
67
+ readonly accessedAt?: unknown;
68
+ readonly summary?: unknown;
69
+ readonly evidence?: unknown;
70
+ readonly credibility?: unknown;
71
+ readonly score?: unknown;
72
+ readonly tags?: unknown;
73
+ readonly note?: unknown;
74
+ readonly reportArtifactId?: unknown;
75
+ readonly error?: unknown;
76
+ readonly reportMarkdown?: unknown;
77
+ readonly sources?: unknown;
78
+ readonly findings?: unknown;
79
+ readonly gaps?: unknown;
80
+ readonly recommendations?: unknown;
81
+ readonly methodology?: unknown;
82
+ readonly confidence?: unknown;
83
+ readonly requireCitationCoverage?: unknown;
84
+ readonly visualReport?: unknown;
85
+ readonly includeReportLines?: unknown;
86
+ readonly includeParameters?: unknown;
87
+ readonly includeContent?: unknown;
88
+ readonly previewBytes?: unknown;
89
+ readonly limit?: unknown;
90
+ readonly confirm?: unknown;
91
+ readonly explicitUserRequest?: unknown;
92
+ }
93
+
94
+ interface AgentResearchToolDeps {
95
+ readonly commandRegistry: CommandRegistry;
96
+ readonly commandContext: CommandContext;
97
+ readonly toolRegistry: ToolRegistry;
98
+ readonly harnessTool?: Tool;
99
+ readonly runsTool?: Tool;
100
+ readonly sourcesTool?: Tool;
101
+ readonly reportTool?: Tool;
102
+ readonly artifactTool?: Tool;
103
+ readonly webSearchTool?: Tool;
104
+ }
105
+
106
+ function error(message: string): { readonly success: false; readonly error: string } {
107
+ return { success: false, error: message };
108
+ }
109
+
110
+ function readString(value: unknown): string {
111
+ return typeof value === 'string' ? value.trim() : '';
112
+ }
113
+
114
+ function readNumber(value: unknown, fallback: number, max: number): number {
115
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
116
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
117
+ return Math.max(1, Math.min(max, Math.trunc(parsed)));
118
+ }
119
+
120
+ function normalizeResearchAction(value: unknown): AgentResearchAction | null {
121
+ const action = readString(value).toLowerCase().replace(/-/g, '_');
122
+ if (!action) return null;
123
+ if (action === 'briefing' || action === 'brief' || action === 'status' || action === 'dashboard' || action === 'cockpit' || action === 'next') return 'briefing';
124
+ if (action === 'plan' || action === 'workflow' || action === 'research') return 'plan';
125
+ if (action === 'runner' || action === 'browser' || action === 'browser_runner' || action === 'browser_backed' || action === 'deep_research') return 'runner';
126
+ if (action === 'runs' || action === 'list_runs' || action === 'run_list') return 'runs';
127
+ if (action === 'run' || action === 'show_run' || action === 'inspect_run') return 'run';
128
+ if (action === 'sources' || action === 'queue' || action === 'source_queue') return 'sources';
129
+ if (action === 'source' || action === 'show_source' || action === 'inspect_source') return 'source';
130
+ if (action === 'bundle' || action === 'bundle_sources' || action === 'source_bundle') return 'bundle';
131
+ if (action === 'search' || action === 'public_search' || action === 'collect' || action === 'collect_sources' || action === 'source_candidates') return 'search';
132
+ if (action === 'reports' || action === 'list_reports' || action === 'report_list' || action === 'visual_reports') return 'reports';
133
+ if (action === 'report_artifact' || action === 'show_report' || action === 'inspect_report' || action === 'show_visual_report' || action === 'visual_report_artifact') return 'report_artifact';
134
+ if (action === 'create_run' || action === 'new_run') return 'create_run';
135
+ if (action === 'start' || action === 'start_run' || action === 'begin_run' || action === 'run_start') return 'start_run';
136
+ if (action === 'checkpoint' || action === 'checkpoint_run') return 'checkpoint';
137
+ if (action === 'pause' || action === 'pause_run') return 'pause';
138
+ if (action === 'resume' || action === 'resume_run') return 'resume';
139
+ if (action === 'cancel' || action === 'cancel_run') return 'cancel';
140
+ if (action === 'complete' || action === 'complete_run') return 'complete';
141
+ if (action === 'fail' || action === 'fail_run') return 'fail';
142
+ if (action === 'delete_run' || action === 'remove_run') return 'delete_run';
143
+ if (action === 'add_source' || action === 'capture_source' || action === 'new_source') return 'add_source';
144
+ if (action === 'review_source' || action === 'score_source') return 'review_source';
145
+ if (action === 'reject_source' || action === 'reject') return 'reject_source';
146
+ if (action === 'use_source' || action === 'mark_source_used' || action === 'mark_used') return 'use_source';
147
+ if (action === 'delete_source' || action === 'remove_source') return 'delete_source';
148
+ if (action === 'report' || action === 'save_report' || action === 'visual_report') return 'report';
149
+ return null;
150
+ }
151
+
152
+ function readAction(args: AgentResearchToolArgs): AgentResearchAction {
153
+ const explicit = normalizeResearchAction(args.action) ?? normalizeResearchAction(args.mode);
154
+ if (explicit) return explicit;
155
+ if (readString(args.sourceId)) return 'source';
156
+ if (readString(args.runId)) return 'run';
157
+ if (readString(args.query) || readString(args.target)) return 'plan';
158
+ return 'plan';
159
+ }
160
+
161
+ function compactArgs(entries: Record<string, unknown>): Record<string, unknown> {
162
+ return Object.fromEntries(Object.entries(entries).filter(([, value]) => value !== undefined && value !== ''));
163
+ }
164
+
165
+ function lookupId(args: AgentResearchToolArgs): string {
166
+ return readString(args.id) || readString(args.runId) || readString(args.sourceId) || readString(args.artifactId) || readString(args.reportArtifactId);
167
+ }
168
+
169
+ function planArgs(args: AgentResearchToolArgs): Record<string, unknown> {
170
+ return compactArgs({
171
+ mode: 'research_workflow',
172
+ query: args.query,
173
+ target: args.target,
174
+ runId: args.runId || args.id,
175
+ includeParameters: args.includeParameters,
176
+ });
177
+ }
178
+
179
+ function briefingArgs(args: AgentResearchToolArgs): Record<string, unknown> {
180
+ return compactArgs({
181
+ mode: 'research_briefing',
182
+ query: args.query,
183
+ target: args.target,
184
+ limit: args.limit,
185
+ includeParameters: args.includeParameters,
186
+ });
187
+ }
188
+
189
+ function runsArgs(args: AgentResearchToolArgs): Record<string, unknown> {
190
+ return compactArgs({
191
+ mode: 'research_runs',
192
+ query: args.query,
193
+ limit: args.limit,
194
+ includeParameters: args.includeParameters,
195
+ });
196
+ }
197
+
198
+ function runnerArgs(args: AgentResearchToolArgs): Record<string, unknown> {
199
+ return compactArgs({
200
+ mode: 'research_workflow',
201
+ query: args.query ?? args.target ?? 'browser-backed research runner',
202
+ runId: args.runId || args.id,
203
+ includeParameters: args.includeParameters ?? true,
204
+ });
205
+ }
206
+
207
+ function runArgs(args: AgentResearchToolArgs): Record<string, unknown> {
208
+ return compactArgs({
209
+ mode: 'research_run',
210
+ runId: lookupId(args),
211
+ target: lookupId(args) ? undefined : args.target,
212
+ query: lookupId(args) ? undefined : args.query,
213
+ includeParameters: args.includeParameters,
214
+ });
215
+ }
216
+
217
+ function sourcesArgs(args: AgentResearchToolArgs): Record<string, unknown> {
218
+ return compactArgs({
219
+ mode: 'research_queue',
220
+ query: args.query,
221
+ limit: args.limit,
222
+ includeParameters: args.includeParameters,
223
+ });
224
+ }
225
+
226
+ function sourceArgs(args: AgentResearchToolArgs): Record<string, unknown> {
227
+ return compactArgs({
228
+ mode: 'research_source',
229
+ sourceId: lookupId(args),
230
+ target: lookupId(args) ? undefined : args.target,
231
+ query: lookupId(args) ? undefined : args.query,
232
+ includeParameters: args.includeParameters,
233
+ });
234
+ }
235
+
236
+ function confirmedArgs(args: AgentResearchToolArgs): Record<string, unknown> {
237
+ return compactArgs({
238
+ confirm: args.confirm,
239
+ explicitUserRequest: args.explicitUserRequest,
240
+ });
241
+ }
242
+
243
+ function createRunArgs(args: AgentResearchToolArgs): Record<string, unknown> {
244
+ return compactArgs({
245
+ mode: 'create',
246
+ title: args.title,
247
+ question: args.question ?? args.query,
248
+ goal: args.goal,
249
+ plan: args.plan,
250
+ nextSteps: args.nextSteps,
251
+ sourceIds: args.sourceIds,
252
+ note: args.note,
253
+ ...confirmedArgs(args),
254
+ });
255
+ }
256
+
257
+ function runMutationArgs(args: AgentResearchToolArgs, mode: string): Record<string, unknown> {
258
+ return compactArgs({
259
+ mode,
260
+ id: lookupId(args),
261
+ status: args.status,
262
+ phase: args.phase,
263
+ progress: args.progress,
264
+ note: args.note,
265
+ nextSteps: args.nextSteps,
266
+ sourceIds: args.sourceIds,
267
+ reportArtifactId: args.reportArtifactId,
268
+ error: args.error,
269
+ ...confirmedArgs(args),
270
+ });
271
+ }
272
+
273
+ function bundleArgs(args: AgentResearchToolArgs): Record<string, unknown> {
274
+ return compactArgs({
275
+ mode: 'bundle',
276
+ query: args.query ?? args.target,
277
+ limit: args.limit,
278
+ includeReportLines: args.includeReportLines ?? true,
279
+ });
280
+ }
281
+
282
+ function searchArgs(args: AgentResearchToolArgs): Record<string, unknown> {
283
+ const safeSearch = readString(args.safeSearch).toLowerCase() === 'strict' ? 'strict' : 'moderate';
284
+ return compactArgs({
285
+ query: args.query ?? args.target,
286
+ providerId: args.providerId,
287
+ maxResults: readNumber(args.maxResults, readNumber(args.limit, 5, 10), 10),
288
+ verbosity: 'evidence',
289
+ region: args.region,
290
+ safeSearch,
291
+ timeRange: args.timeRange,
292
+ includeEvidence: true,
293
+ evidenceTopN: readNumber(args.evidenceTopN, 3, 3),
294
+ evidenceExtract: args.evidenceExtract ?? 'readable',
295
+ });
296
+ }
297
+
298
+ function reportsArgs(args: AgentResearchToolArgs): Record<string, unknown> {
299
+ return compactArgs({
300
+ mode: 'list',
301
+ purpose: 'agent-research-report',
302
+ query: args.query ?? args.target,
303
+ limit: args.limit,
304
+ });
305
+ }
306
+
307
+ function reportArtifactArgs(args: AgentResearchToolArgs): Record<string, unknown> {
308
+ return compactArgs({
309
+ mode: 'show',
310
+ artifactId: lookupId(args),
311
+ includeContent: args.includeContent ?? true,
312
+ previewBytes: args.previewBytes,
313
+ });
314
+ }
315
+
316
+ function previewText(value: unknown, limit: number): string {
317
+ const text = typeof value === 'string' ? value.replace(/\s+/g, ' ').trim() : '';
318
+ if (text.length <= limit) return text;
319
+ return `${text.slice(0, Math.max(0, limit - 3)).trimEnd()}...`;
320
+ }
321
+
322
+ function quote(value: string): string {
323
+ return JSON.stringify(value);
324
+ }
325
+
326
+ function readRecord(value: unknown): Record<string, unknown> | null {
327
+ return value && typeof value === 'object' && !Array.isArray(value) ? value as Record<string, unknown> : null;
328
+ }
329
+
330
+ function readRecordArray(value: unknown): readonly Record<string, unknown>[] {
331
+ return Array.isArray(value) ? value.map(readRecord).filter((entry): entry is Record<string, unknown> => Boolean(entry)) : [];
332
+ }
333
+
334
+ function hostname(value: string): string {
335
+ try {
336
+ return new URL(value).hostname.replace(/^www\./i, '');
337
+ } catch {
338
+ return '';
339
+ }
340
+ }
341
+
342
+ function sanitizeUrlForRoute(value: string): string {
343
+ try {
344
+ const url = new URL(value);
345
+ for (const key of [...url.searchParams.keys()]) {
346
+ if (/token|secret|password|authorization|credential|api[-_]?key/i.test(key)) url.searchParams.set(key, '<redacted>');
347
+ }
348
+ return url.toString();
349
+ } catch {
350
+ return value.replace(/([?&\s](?:token|secret|password|authorization|credential|api[-_]?key)=)[^\s&]+/gi, '$1<redacted>');
351
+ }
352
+ }
353
+
354
+ function candidateFromSearchResult(question: string, result: Record<string, unknown>, index: number): Record<string, unknown> {
355
+ const rawUrl = readString(result.url);
356
+ const url = sanitizeUrlForRoute(rawUrl);
357
+ const title = previewText(result.title, 120) || hostname(rawUrl) || `Search result ${index + 1}`;
358
+ const publisher = previewText(result.domain, 80) || hostname(rawUrl);
359
+ const evidenceRecords = readRecordArray(result.evidence);
360
+ const evidenceText = previewText(
361
+ evidenceRecords.map((entry) => readString(entry.content)).filter(Boolean).join('\n\n') || result.snippet,
362
+ 420,
363
+ );
364
+ const summary = previewText(result.snippet, 260) || previewText(evidenceText, 260) || `Public web result for ${question}.`;
365
+ const captureArgs = compactArgs({
366
+ action: 'add_source',
367
+ question,
368
+ title,
369
+ url,
370
+ publisher,
371
+ summary,
372
+ evidence: evidenceText,
373
+ credibility: 'unreviewed',
374
+ tags: ['research', 'web-search'],
375
+ confirm: true,
376
+ explicitUserRequest: '...',
377
+ });
378
+ return {
379
+ rank: typeof result.rank === 'number' ? result.rank : index + 1,
380
+ title,
381
+ url,
382
+ ...(publisher ? { publisher } : {}),
383
+ summary,
384
+ ...(evidenceText ? { evidencePreview: evidenceText } : {}),
385
+ captureArgs,
386
+ captureRoute: [
387
+ 'research action:"add_source"',
388
+ `question:${quote(question)}`,
389
+ `title:${quote(title)}`,
390
+ ...(url ? [`url:${quote(url)}`] : []),
391
+ ...(publisher ? [`publisher:${quote(publisher)}`] : []),
392
+ `summary:${quote(summary)}`,
393
+ ...(evidenceText ? [`evidence:${quote(evidenceText)}`] : []),
394
+ 'credibility:"unreviewed"',
395
+ 'tags:["research","web-search"]',
396
+ 'confirm:true',
397
+ 'explicitUserRequest:"..."',
398
+ ].join(' '),
399
+ };
400
+ }
401
+
402
+ function parseSearchPayload(outputValue: unknown): Record<string, unknown> | null {
403
+ if (typeof outputValue !== 'string') return readRecord(outputValue);
404
+ try {
405
+ return readRecord(JSON.parse(outputValue));
406
+ } catch {
407
+ return null;
408
+ }
409
+ }
410
+
411
+ function resolveSearchRun(args: AgentResearchToolArgs, shellPaths: CommandContext['workspace']['shellPaths'] | undefined): AgentResearchRunRecord | null {
412
+ if (!shellPaths) return null;
413
+ const lookup = readString(args.runId) || readString(args.id);
414
+ if (!lookup) return null;
415
+ return AgentResearchRunRegistry.fromShellPaths(shellPaths).get(lookup);
416
+ }
417
+
418
+ async function runPublicSearch(
419
+ webSearchTool: Tool | undefined,
420
+ args: AgentResearchToolArgs,
421
+ shellPaths: CommandContext['workspace']['shellPaths'] | undefined,
422
+ ): Promise<{ readonly success: true; readonly output: string } | { readonly success: false; readonly error: string }> {
423
+ const run = resolveSearchRun(args, shellPaths);
424
+ const query = readString(args.query) || readString(args.question) || run?.question || readString(args.target);
425
+ if ((readString(args.runId) || readString(args.id)) && !run && !readString(args.query) && !readString(args.question)) {
426
+ return error(`Unknown research run ${readString(args.runId) || readString(args.id)}. Use research action:"runs" to inspect run ids.`);
427
+ }
428
+ if (!query) return error('research action:"search" requires query or target.');
429
+ if (!webSearchTool) {
430
+ return error('Bounded public web search is unavailable because web_search is not registered. Use research action:"briefing" for the offline next-action queue or action:"plan" for the route plan.');
431
+ }
432
+ const webArgs = searchArgs({ ...args, query });
433
+ const webResult = await webSearchTool.execute(webArgs);
434
+ if (!webResult.success) return { success: false, error: readString(webResult.error) || 'web_search failed.' };
435
+ const payload = parseSearchPayload(webResult.output);
436
+ const results = readRecordArray(payload?.results);
437
+ const sourceCandidates = results
438
+ .filter((result) => readString(result.url))
439
+ .map((result, index) => candidateFromSearchResult(query, result, index));
440
+ return {
441
+ success: true,
442
+ output: JSON.stringify({
443
+ status: sourceCandidates.length > 0 ? 'source-candidates-ready' : 'no-source-candidates',
444
+ query,
445
+ providerId: readString(payload?.providerId),
446
+ providerLabel: readString(payload?.providerLabel),
447
+ resultCount: results.length,
448
+ sourceCandidateCount: sourceCandidates.length,
449
+ sourceCandidates,
450
+ nextRoutes: {
451
+ ...(run ? {
452
+ run: `research action:"run" runId:${quote(run.id)}`,
453
+ briefing: `research action:"briefing" target:${quote(run.id)}`,
454
+ startRun: `research action:"start_run" id:${quote(run.id)} confirm:true explicitUserRequest:"..."`,
455
+ checkpointAfterCapture: `research action:"checkpoint" id:${quote(run.id)} phase:"reading" progress:${Math.max(run.progress, 25)} note:"Captured candidate sources for review." sourceIds:["..."] confirm:true explicitUserRequest:"..."`,
456
+ } : {
457
+ createRun: `research action:"create_run" question:${quote(query)} plan:["Search bounded public web sources","Capture candidate sources","Review credibility","Save sourced report"] confirm:true explicitUserRequest:"..."`,
458
+ }),
459
+ sourceQueue: `research action:"sources" query:${quote(query)}`,
460
+ reviewedBundle: `research action:"bundle" query:${quote(query)} includeReportLines:true`,
461
+ saveReport: `research action:"report" question:${quote(query)} sources:[...] visualReport:true requireCitationCoverage:true confirm:true explicitUserRequest:"..."`,
462
+ },
463
+ ...(run ? { run: { id: run.id, title: run.title, status: run.status, phase: run.phase, progress: run.progress } } : {}),
464
+ searchArgs: webArgs,
465
+ policy: 'This route performs bounded read-only public web search only. It does not create or start a run, save sources, checkpoint progress, write a report, ingest Knowledge, or send messages. Use each returned route only after explicit user confirmation.',
466
+ }, null, 2),
467
+ };
468
+ }
469
+
470
+ function addSourceArgs(args: AgentResearchToolArgs): Record<string, unknown> {
471
+ return compactArgs({
472
+ mode: 'add',
473
+ question: args.question ?? args.query,
474
+ title: args.title,
475
+ url: args.url,
476
+ publisher: args.publisher,
477
+ publishedAt: args.publishedAt,
478
+ accessedAt: args.accessedAt,
479
+ summary: args.summary,
480
+ evidence: args.evidence,
481
+ credibility: args.credibility,
482
+ score: args.score,
483
+ tags: args.tags,
484
+ note: args.note,
485
+ ...confirmedArgs(args),
486
+ });
487
+ }
488
+
489
+ function reviewSourceArgs(args: AgentResearchToolArgs): Record<string, unknown> {
490
+ return compactArgs({
491
+ mode: 'review',
492
+ id: lookupId(args),
493
+ credibility: args.credibility,
494
+ score: args.score,
495
+ note: args.note,
496
+ summary: args.summary,
497
+ evidence: args.evidence,
498
+ tags: args.tags,
499
+ ...confirmedArgs(args),
500
+ });
501
+ }
502
+
503
+ function sourceMutationArgs(args: AgentResearchToolArgs, mode: string): Record<string, unknown> {
504
+ return compactArgs({
505
+ mode,
506
+ id: lookupId(args),
507
+ note: args.note,
508
+ reportArtifactId: args.reportArtifactId,
509
+ ...confirmedArgs(args),
510
+ });
511
+ }
512
+
513
+ function reportArgs(args: AgentResearchToolArgs): Record<string, unknown> {
514
+ return compactArgs({
515
+ runId: args.runId ?? args.id,
516
+ title: args.title,
517
+ question: args.question ?? args.query,
518
+ summary: args.summary,
519
+ reportMarkdown: args.reportMarkdown,
520
+ sources: args.sources,
521
+ findings: args.findings,
522
+ gaps: args.gaps,
523
+ recommendations: args.recommendations,
524
+ methodology: args.methodology,
525
+ confidence: args.confidence,
526
+ requireCitationCoverage: args.requireCitationCoverage,
527
+ visualReport: args.visualReport,
528
+ tags: args.tags,
529
+ ...confirmedArgs(args),
530
+ });
531
+ }
532
+
533
+ export function createAgentResearchTool(deps: AgentResearchToolDeps): Tool {
534
+ const shellPaths = deps.commandContext.workspace?.shellPaths;
535
+ const harnessTool = deps.harnessTool ?? createAgentHarnessTool({
536
+ commandRegistry: deps.commandRegistry,
537
+ commandContext: deps.commandContext,
538
+ toolRegistry: deps.toolRegistry,
539
+ });
540
+ const runsTool = deps.runsTool ?? createAgentResearchRunsTool(shellPaths);
541
+ const sourcesTool = deps.sourcesTool ?? createAgentResearchSourcesTool(shellPaths);
542
+ const reportTool = deps.reportTool ?? createAgentResearchReportTool(deps.commandContext.platform?.artifactStore);
543
+ const artifactTool = deps.artifactTool
544
+ ?? deps.toolRegistry.list().find((entry) => entry.definition.name === 'agent_artifacts')
545
+ ?? createAgentArtifactsTool(deps.commandContext.platform?.artifactStore);
546
+ const webSearchTool = deps.webSearchTool
547
+ ?? deps.toolRegistry.list().find((entry) => entry.definition.name === 'web_search');
548
+
549
+ return {
550
+ definition: {
551
+ name: 'research',
552
+ description: 'Plan, track, source, and save research.',
553
+ parameters: {
554
+ type: 'object',
555
+ properties: {
556
+ action: {
557
+ type: 'string',
558
+ enum: [
559
+ 'briefing',
560
+ 'plan',
561
+ 'runner',
562
+ 'runs',
563
+ 'run',
564
+ 'sources',
565
+ 'source',
566
+ 'bundle',
567
+ 'search',
568
+ 'reports',
569
+ 'report_artifact',
570
+ 'create_run',
571
+ 'start_run',
572
+ 'checkpoint',
573
+ 'pause',
574
+ 'resume',
575
+ 'cancel',
576
+ 'complete',
577
+ 'fail',
578
+ 'delete_run',
579
+ 'add_source',
580
+ 'review_source',
581
+ 'reject_source',
582
+ 'use_source',
583
+ 'delete_source',
584
+ 'report',
585
+ ],
586
+ description: 'Read plans/queues; confirm writes.',
587
+ },
588
+ mode: { type: 'string', description: 'Alias for action.' },
589
+ id: { type: 'string', description: 'Run or source id alias.' },
590
+ runId: { type: 'string', description: 'Research run id.' },
591
+ sourceId: { type: 'string', description: 'Research source id.' },
592
+ artifactId: { type: 'string', description: 'Research report artifact id.' },
593
+ query: { type: 'string', description: 'Research request or queue search.' },
594
+ target: { type: 'string', description: 'Lookup target alias.' },
595
+ providerId: { type: 'string', description: 'Optional web_search provider id for action:"search".' },
596
+ maxResults: { type: 'number', maximum: 10, description: 'Maximum public search results for action:"search".' },
597
+ region: { type: 'string', description: 'Provider-specific region for action:"search".' },
598
+ safeSearch: { type: 'string', enum: ['strict', 'moderate'], description: 'Safe-search setting for action:"search".' },
599
+ timeRange: { type: 'string', enum: ['any', 'day', 'week', 'month', 'year'], description: 'Optional search time range.' },
600
+ evidenceTopN: { type: 'number', maximum: 3, description: 'Maximum evidence fetches for action:"search".' },
601
+ evidenceExtract: { type: 'string', enum: ['text', 'markdown', 'readable', 'code_blocks', 'links', 'metadata', 'tables'], description: 'Bounded evidence extraction mode.' },
602
+ title: { type: 'string', description: 'Run, source, or report title.' },
603
+ question: { type: 'string', description: 'Research question.' },
604
+ goal: { type: 'string', description: 'Visible outcome for a new run.' },
605
+ plan: { type: 'array', items: { type: 'string' }, description: 'Run plan steps.' },
606
+ nextSteps: { type: 'array', items: { type: 'string' }, description: 'Next visible run steps.' },
607
+ sourceIds: { type: 'array', items: { type: 'string' }, description: 'Run source ids.' },
608
+ status: { type: 'string', description: 'Mutable run status.' },
609
+ phase: { type: 'string', description: 'Research run phase.' },
610
+ progress: { type: 'number', description: '0-100 run progress.' },
611
+ url: { type: 'string', description: 'Source URL.' },
612
+ publisher: { type: 'string', description: 'Source publisher.' },
613
+ publishedAt: { type: 'string', description: 'Source published date.' },
614
+ accessedAt: { type: 'string', description: 'Source access date.' },
615
+ summary: { type: 'string', description: 'Summary for source or report.' },
616
+ evidence: { type: 'string', description: 'Source evidence notes.' },
617
+ credibility: { type: 'string', enum: ['unreviewed', 'low', 'medium', 'high', 'mixed'], description: 'Source credibility.' },
618
+ score: { type: 'number', description: '0-100 source score.' },
619
+ tags: { type: 'array', items: { type: 'string' }, description: 'Optional tags.' },
620
+ note: { type: 'string', description: 'Run or source note.' },
621
+ reportArtifactId: { type: 'string', description: 'Saved report artifact id.' },
622
+ error: { type: 'string', description: 'Run failure detail.' },
623
+ reportMarkdown: { type: 'string', description: 'Full report markdown.' },
624
+ sources: { type: 'array', items: { type: 'object' }, description: 'Reviewed report sources.' },
625
+ findings: { type: 'array', items: { type: 'string' }, description: 'Key findings.' },
626
+ gaps: { type: 'array', items: { type: 'string' }, description: 'Open caveats.' },
627
+ recommendations: { type: 'array', items: { type: 'string' }, description: 'Recommended actions.' },
628
+ methodology: { type: 'string', description: 'Source selection method.' },
629
+ confidence: { type: 'string', description: 'Overall confidence label.' },
630
+ requireCitationCoverage: { type: 'boolean', description: 'Require cited sources.' },
631
+ visualReport: { type: 'boolean', description: 'Append visual packet sections.' },
632
+ includeReportLines: { type: 'boolean', description: 'Include report source lines.' },
633
+ includeParameters: { type: 'boolean', description: 'Include bounded route details.' },
634
+ includeContent: { type: 'boolean', description: 'Preview saved report artifact content.' },
635
+ previewBytes: { type: 'number', description: 'Maximum saved report preview bytes.' },
636
+ limit: { type: 'number', description: 'Maximum rows.' },
637
+ confirm: { type: 'boolean', description: 'Required true for writes.' },
638
+ explicitUserRequest: { type: 'string', description: 'User request authorizing writes.' },
639
+ },
640
+ additionalProperties: false,
641
+ },
642
+ sideEffects: ['state'],
643
+ concurrency: 'serial',
644
+ },
645
+ execute: async (rawArgs: unknown) => {
646
+ const args = (rawArgs && typeof rawArgs === 'object' && !Array.isArray(rawArgs) ? rawArgs : {}) as AgentResearchToolArgs;
647
+ const action = readAction(args);
648
+
649
+ if (action === 'briefing') return harnessTool.execute(briefingArgs(args));
650
+ if (action === 'plan') return harnessTool.execute(planArgs(args));
651
+ if (action === 'runner') return harnessTool.execute(runnerArgs(args));
652
+ if (action === 'runs') return harnessTool.execute(runsArgs(args));
653
+ if (action === 'run') return harnessTool.execute(runArgs(args));
654
+ if (action === 'sources') return harnessTool.execute(sourcesArgs(args));
655
+ if (action === 'source') return harnessTool.execute(sourceArgs(args));
656
+ if (action === 'bundle') return sourcesTool.execute(bundleArgs(args));
657
+ if (action === 'search') return runPublicSearch(webSearchTool, args, shellPaths);
658
+ if (action === 'reports') return artifactTool.execute(reportsArgs(args));
659
+ if (action === 'report_artifact') return artifactTool.execute(reportArtifactArgs(args));
660
+ if (action === 'create_run') return runsTool.execute(createRunArgs(args));
661
+ if (action === 'start_run') return runsTool.execute(runMutationArgs(args, 'start'));
662
+ if (action === 'checkpoint') return runsTool.execute(runMutationArgs(args, 'checkpoint'));
663
+ if (action === 'pause') return runsTool.execute(runMutationArgs(args, 'pause'));
664
+ if (action === 'resume') return runsTool.execute(runMutationArgs(args, 'resume'));
665
+ if (action === 'cancel') return runsTool.execute(runMutationArgs(args, 'cancel'));
666
+ if (action === 'complete') return runsTool.execute(runMutationArgs(args, 'complete'));
667
+ if (action === 'fail') return runsTool.execute(runMutationArgs(args, 'fail'));
668
+ if (action === 'delete_run') return runsTool.execute(runMutationArgs(args, 'delete'));
669
+ if (action === 'add_source') return sourcesTool.execute(addSourceArgs(args));
670
+ if (action === 'review_source') return sourcesTool.execute(reviewSourceArgs(args));
671
+ if (action === 'reject_source') return sourcesTool.execute(sourceMutationArgs(args, 'reject'));
672
+ if (action === 'use_source') return sourcesTool.execute(sourceMutationArgs(args, 'use'));
673
+ if (action === 'delete_source') return sourcesTool.execute(sourceMutationArgs(args, 'delete'));
674
+ if (action === 'report') return reportTool.execute(reportArgs(args));
675
+
676
+ return error('Unknown research action. Use action:"plan" for research routing.');
677
+ },
678
+ };
679
+ }
680
+
681
+ export function registerAgentResearchTool(
682
+ registry: ToolRegistry,
683
+ commandRegistry: CommandRegistry,
684
+ commandContext: CommandContext,
685
+ ): void {
686
+ if (!registry.has('research')) registry.register(createAgentResearchTool({ commandRegistry, commandContext, toolRegistry: registry }));
687
+ }