@pellux/goodvibes-agent 1.1.7 → 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 (255) hide show
  1. package/CHANGELOG.md +170 -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 +132577 -91483
  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 +39 -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 +199 -5
  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 +137 -7
  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 +106 -85
  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/version.ts +1 -1
@@ -0,0 +1,443 @@
1
+ import type { ShellPathService } from '@/runtime/index.ts';
2
+ import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
3
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
4
+ import {
5
+ AgentResearchSourceRegistry,
6
+ researchSourceReportLine,
7
+ type AgentResearchSourceCreateInput,
8
+ type AgentResearchSourceCredibility,
9
+ type AgentResearchSourceRecord,
10
+ type AgentResearchSourceStatus,
11
+ } from '../agent/research-source-registry.ts';
12
+
13
+ export interface AgentResearchSourcesToolArgs {
14
+ readonly mode?: unknown;
15
+ readonly id?: unknown;
16
+ readonly query?: unknown;
17
+ readonly status?: unknown;
18
+ readonly question?: unknown;
19
+ readonly title?: unknown;
20
+ readonly url?: unknown;
21
+ readonly publisher?: unknown;
22
+ readonly publishedAt?: unknown;
23
+ readonly accessedAt?: unknown;
24
+ readonly summary?: unknown;
25
+ readonly evidence?: unknown;
26
+ readonly credibility?: unknown;
27
+ readonly score?: unknown;
28
+ readonly tags?: unknown;
29
+ readonly note?: unknown;
30
+ readonly reportArtifactId?: unknown;
31
+ readonly includeReportLines?: unknown;
32
+ readonly limit?: unknown;
33
+ readonly confirm?: unknown;
34
+ readonly explicitUserRequest?: unknown;
35
+ }
36
+
37
+ type AgentResearchSourcesMode = 'list' | 'search' | 'show' | 'bundle' | 'add' | 'review' | 'reject' | 'use' | 'delete';
38
+
39
+ const MODES: readonly AgentResearchSourcesMode[] = ['list', 'search', 'show', 'bundle', 'add', 'review', 'reject', 'use', 'delete'];
40
+ const STATUS_VALUES: readonly AgentResearchSourceStatus[] = ['candidate', 'reviewed', 'rejected', 'used'];
41
+ const CREDIBILITY_VALUES: readonly AgentResearchSourceCredibility[] = ['unreviewed', 'low', 'medium', 'high', 'mixed'];
42
+
43
+ function readString(value: unknown): string {
44
+ return typeof value === 'string' ? value.trim() : '';
45
+ }
46
+
47
+ function readMode(value: unknown): AgentResearchSourcesMode {
48
+ return typeof value === 'string' && MODES.includes(value as AgentResearchSourcesMode) ? value as AgentResearchSourcesMode : 'list';
49
+ }
50
+
51
+ function readStatus(value: unknown): AgentResearchSourceStatus | undefined {
52
+ return typeof value === 'string' && STATUS_VALUES.includes(value as AgentResearchSourceStatus) ? value as AgentResearchSourceStatus : undefined;
53
+ }
54
+
55
+ function readCredibility(value: unknown): AgentResearchSourceCredibility | undefined {
56
+ return typeof value === 'string' && CREDIBILITY_VALUES.includes(value as AgentResearchSourceCredibility) ? value as AgentResearchSourceCredibility : undefined;
57
+ }
58
+
59
+ function readScore(value: unknown): number | undefined {
60
+ if (typeof value === 'number' && Number.isFinite(value)) return Math.max(0, Math.min(100, Math.round(value)));
61
+ if (typeof value !== 'string' || !value.trim()) return undefined;
62
+ const parsed = Number(value);
63
+ return Number.isFinite(parsed) ? Math.max(0, Math.min(100, Math.round(parsed))) : undefined;
64
+ }
65
+
66
+ function readLimit(value: unknown, fallback: number): number {
67
+ const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
68
+ if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
69
+ return Math.max(1, Math.min(50, Math.trunc(parsed)));
70
+ }
71
+
72
+ function readStringList(value: unknown): readonly string[] {
73
+ if (typeof value === 'string') {
74
+ return value.split(/[,\n]/).map((entry) => entry.trim()).filter(Boolean);
75
+ }
76
+ if (!Array.isArray(value)) return [];
77
+ return value.filter((entry): entry is string => typeof entry === 'string').map((entry) => entry.trim()).filter(Boolean);
78
+ }
79
+
80
+ function output(text: string): { readonly success: true; readonly output: string } {
81
+ return { success: true, output: text };
82
+ }
83
+
84
+ function failure(error: string): { readonly success: false; readonly error: string } {
85
+ return { success: false, error };
86
+ }
87
+
88
+ function requireId(args: AgentResearchSourcesToolArgs): string {
89
+ const id = readString(args.id);
90
+ if (!id) throw new Error('id is required.');
91
+ return id;
92
+ }
93
+
94
+ function requireExplicitUserRequest(args: AgentResearchSourcesToolArgs, action: string): string {
95
+ const explicitUserRequest = readString(args.explicitUserRequest);
96
+ if (!explicitUserRequest) throw new Error(`${action} requires explicitUserRequest with the user's exact request or a short faithful summary.`);
97
+ return explicitUserRequest;
98
+ }
99
+
100
+ function requireConfirmedWrite(args: AgentResearchSourcesToolArgs, action: string): void {
101
+ requireExplicitUserRequest(args, action);
102
+ if (args.confirm !== true) throw new Error(`${action} requires confirm:true after an explicit user request.`);
103
+ }
104
+
105
+ function sourceOneLine(source: AgentResearchSourceRecord): string {
106
+ const url = source.url ? ` ${source.url}` : '';
107
+ const publisher = source.publisher ? ` publisher ${source.publisher}` : '';
108
+ return `${source.id} ${source.status} ${source.credibility}/${source.score}${publisher}${url} ${source.title}`;
109
+ }
110
+
111
+ function formatSourceList(
112
+ title: string,
113
+ sources: readonly AgentResearchSourceRecord[],
114
+ includeReportLines: boolean,
115
+ ): string {
116
+ if (sources.length === 0) return `${title}\nNo Agent research sources matched.`;
117
+ const lines = [
118
+ title,
119
+ ...sources.map(sourceOneLine),
120
+ ];
121
+ const reportable = sources.filter((source) => source.status === 'reviewed' || source.status === 'used');
122
+ if (includeReportLines && reportable.length > 0) {
123
+ lines.push('', 'Report source lines', ...reportable.map((source) => ` ${researchSourceReportLine(source)}`));
124
+ }
125
+ return lines.join('\n');
126
+ }
127
+
128
+ function formatSourceDetail(source: AgentResearchSourceRecord): string {
129
+ const lines = [
130
+ `Research source ${source.id}`,
131
+ `title ${source.title}`,
132
+ `question ${source.question}`,
133
+ `status ${source.status}`,
134
+ `credibility ${source.credibility}`,
135
+ `score ${source.score}`,
136
+ ...(source.url ? [`url ${source.url}`] : []),
137
+ ...(source.publisher ? [`publisher ${source.publisher}`] : []),
138
+ ...(source.publishedAt ? [`published ${source.publishedAt}`] : []),
139
+ ...(source.accessedAt ? [`accessed ${source.accessedAt}`] : []),
140
+ `tags ${source.tags.join(', ') || '(none)'}`,
141
+ ...(source.usedInReportArtifactId ? [`usedInReportArtifact ${source.usedInReportArtifactId}`] : []),
142
+ `created ${source.createdAt}`,
143
+ `updated ${source.updatedAt}`,
144
+ ...(source.reviewedAt ? [`reviewed ${source.reviewedAt}`] : []),
145
+ ...(source.rejectedAt ? [`rejected ${source.rejectedAt}`] : []),
146
+ ...(source.usedAt ? [`used ${source.usedAt}`] : []),
147
+ '',
148
+ 'Summary',
149
+ source.summary,
150
+ '',
151
+ ...(source.evidence ? ['Evidence', source.evidence, ''] : []),
152
+ ...(source.note ? ['Review note', source.note, ''] : []),
153
+ 'Report source line',
154
+ researchSourceReportLine(source),
155
+ '',
156
+ 'Next routes',
157
+ ...sourceNextRouteLines(source),
158
+ '',
159
+ 'Policy: source queue records are local project state only; use agent_knowledge_ingest separately for durable Agent Knowledge.',
160
+ ];
161
+ return lines.join('\n');
162
+ }
163
+
164
+ function routeString(value: string): string {
165
+ return JSON.stringify(value);
166
+ }
167
+
168
+ function sourceNextRouteLines(source: AgentResearchSourceRecord): readonly string[] {
169
+ const lines = [
170
+ ` inspect research action:"source" sourceId:${routeString(source.id)}`,
171
+ ` queue research action:"sources" query:${routeString(source.question)} includeReportLines:true`,
172
+ ];
173
+ if (source.status === 'candidate') {
174
+ lines.push(
175
+ ` review research action:"review_source" id:${routeString(source.id)} credibility:"high|medium|mixed|low" score:80 note:"..." confirm:true explicitUserRequest:"..."`,
176
+ ` reject research action:"reject_source" id:${routeString(source.id)} note:"..." confirm:true explicitUserRequest:"..."`,
177
+ );
178
+ } else if (source.status === 'reviewed') {
179
+ lines.push(
180
+ ` bundle research action:"bundle" query:${routeString(source.question)} includeReportLines:true`,
181
+ ` report research action:"report" question:${routeString(source.question)} sources:[...] visualReport:true requireCitationCoverage:true confirm:true explicitUserRequest:"..."`,
182
+ ` markUsed research action:"use_source" id:${routeString(source.id)} reportArtifactId:"..." confirm:true explicitUserRequest:"..."`,
183
+ ...(source.url ? [
184
+ ` promoteUrl agent_knowledge_ingest sourceKind:"url" url:${routeString(source.url)} title:${routeString(source.title)} tags:["research"] confirm:true explicitUserRequest:"..."`,
185
+ ] : []),
186
+ );
187
+ } else if (source.status === 'used') {
188
+ lines.push(
189
+ ` bundle research action:"bundle" query:${routeString(source.question)} includeReportLines:true`,
190
+ ...(source.usedInReportArtifactId ? [
191
+ ` reportArtifact research action:"report_artifact" artifactId:${routeString(source.usedInReportArtifactId)}`,
192
+ ` promoteReport agent_knowledge_ingest sourceKind:"artifact" artifactId:${routeString(source.usedInReportArtifactId)} confirm:true explicitUserRequest:"..."`,
193
+ ] : [
194
+ ` attachReport research action:"use_source" id:${routeString(source.id)} reportArtifactId:"..." confirm:true explicitUserRequest:"..."`,
195
+ ]),
196
+ );
197
+ } else {
198
+ lines.push(
199
+ ` search research action:"sources" status:"rejected" query:${routeString(source.question)}`,
200
+ ` reAdd research action:"add_source" question:${routeString(source.question)} title:${routeString(source.title)} summary:${routeString(source.summary)} confirm:true explicitUserRequest:"..."`,
201
+ );
202
+ }
203
+ return lines;
204
+ }
205
+
206
+ function deletedSourceRouteLines(source: AgentResearchSourceRecord): readonly string[] {
207
+ return [
208
+ ` queue research action:"sources" query:${routeString(source.question)} includeReportLines:true`,
209
+ ` reAdd research action:"add_source" question:${routeString(source.question)} title:${routeString(source.title)} summary:${routeString(source.summary)} confirm:true explicitUserRequest:"..."`,
210
+ ];
211
+ }
212
+
213
+ function previewText(value: string, maxLength = 160): string {
214
+ const normalized = value.trim().replace(/\s+/g, ' ');
215
+ if (normalized.length <= maxLength) return normalized;
216
+ return `${normalized.slice(0, Math.max(0, maxLength - 1)).trimEnd()}...`;
217
+ }
218
+
219
+ function reportSourceObject(source: AgentResearchSourceRecord): Record<string, unknown> {
220
+ return {
221
+ title: source.title,
222
+ ...(source.url ? { url: source.url } : {}),
223
+ ...(source.publisher ? { publisher: source.publisher } : {}),
224
+ ...(source.publishedAt ? { publishedAt: source.publishedAt } : {}),
225
+ ...(source.accessedAt ? { accessedAt: source.accessedAt } : {}),
226
+ credibility: source.credibility,
227
+ note: [source.note, source.summary].filter(Boolean).join(' ') || source.summary,
228
+ };
229
+ }
230
+
231
+ function sourceMatchesQuery(source: AgentResearchSourceRecord, query: string): boolean {
232
+ if (!query) return true;
233
+ return [
234
+ source.id,
235
+ source.question,
236
+ source.title,
237
+ source.url ?? '',
238
+ source.publisher ?? '',
239
+ source.summary,
240
+ source.evidence ?? '',
241
+ source.credibility,
242
+ source.status,
243
+ source.note ?? '',
244
+ ...source.tags,
245
+ ].some((field) => field.toLowerCase().includes(query));
246
+ }
247
+
248
+ function formatSourceBundle(sources: readonly AgentResearchSourceRecord[], query: string, limit: number): string {
249
+ if (sources.length === 0) {
250
+ return [
251
+ 'Agent research source bundle',
252
+ 'No reviewed or used Agent research sources matched.',
253
+ 'next Review candidate sources with research action:"review_source", then rerun action:"bundle".',
254
+ ].join('\n');
255
+ }
256
+ const primaryQuestion = sources[0]?.question ?? '(mixed questions)';
257
+ const questions = new Set(sources.map((source) => source.question));
258
+ const reportSources = sources.map(reportSourceObject);
259
+ return [
260
+ 'Agent research source bundle',
261
+ ` sources ${sources.length}`,
262
+ ` query ${query || '(all reviewed/used)'}`,
263
+ ` limit ${limit}`,
264
+ ` question ${questions.size === 1 ? primaryQuestion : '(mixed questions)'}`,
265
+ ' policy read-only source bundle; no report artifact, Knowledge ingest, or external message was created',
266
+ '',
267
+ 'Report source lines',
268
+ ...sources.map((source, index) => ` [S${index + 1}] ${researchSourceReportLine(source)}`),
269
+ '',
270
+ 'Citation plan',
271
+ ...sources.map((source, index) => ` [S${index + 1}] Cite when using: ${previewText(source.summary)}`),
272
+ '',
273
+ 'research action:"report" handoff',
274
+ ' Use requireCitationCoverage:true and cite these sources as [S1], [S2], etc. in summary/reportMarkdown/findings.',
275
+ ' sources:',
276
+ JSON.stringify(reportSources, null, 2),
277
+ ].join('\n');
278
+ }
279
+
280
+ function formatMutationResult(action: string, source: AgentResearchSourceRecord): string {
281
+ const nextRoutes = action.startsWith('Deleted') ? deletedSourceRouteLines(source) : sourceNextRouteLines(source);
282
+ return [
283
+ action,
284
+ ` id ${source.id}`,
285
+ ` status ${source.status}`,
286
+ ` credibility ${source.credibility}`,
287
+ ` score ${source.score}`,
288
+ ` title ${source.title}`,
289
+ ` reportLine ${researchSourceReportLine(source)}`,
290
+ ' nextRoutes',
291
+ ...nextRoutes,
292
+ ' policy local source queue only; no Knowledge ingest or external message was sent',
293
+ ].join('\n');
294
+ }
295
+
296
+ function addInput(args: AgentResearchSourcesToolArgs): AgentResearchSourceCreateInput {
297
+ const url = readString(args.url);
298
+ const publisher = readString(args.publisher);
299
+ const publishedAt = readString(args.publishedAt);
300
+ const accessedAt = readString(args.accessedAt);
301
+ const evidence = readString(args.evidence);
302
+ const credibility = readCredibility(args.credibility);
303
+ const score = readScore(args.score);
304
+ const note = readString(args.note);
305
+ const provenance = readString(args.explicitUserRequest);
306
+ return {
307
+ question: readString(args.question),
308
+ title: readString(args.title),
309
+ ...(url ? { url } : {}),
310
+ ...(publisher ? { publisher } : {}),
311
+ ...(publishedAt ? { publishedAt } : {}),
312
+ ...(accessedAt ? { accessedAt } : {}),
313
+ summary: readString(args.summary),
314
+ ...(evidence ? { evidence } : {}),
315
+ ...(credibility ? { credibility } : {}),
316
+ ...(score === undefined ? {} : { score }),
317
+ tags: readStringList(args.tags),
318
+ ...(note ? { note } : {}),
319
+ provenance: provenance || 'agent-research-sources-tool',
320
+ };
321
+ }
322
+
323
+ function createAgentResearchSourcesTool(shellPaths?: Pick<ShellPathService, 'resolveProjectPath'>): Tool {
324
+ return {
325
+ definition: {
326
+ name: 'agent_research_sources',
327
+ description: 'Manage local research source review queue.',
328
+ parameters: {
329
+ type: 'object',
330
+ properties: {
331
+ mode: { type: 'string', enum: MODES, description: 'Source queue operation.' },
332
+ id: { type: 'string', description: 'Source id, title, or URL for show/review/reject/use/delete.' },
333
+ query: { type: 'string', description: 'Search text for search/list filtering.' },
334
+ status: { type: 'string', enum: STATUS_VALUES, description: 'Optional status filter for list.' },
335
+ question: { type: 'string', description: 'Research question or topic.' },
336
+ title: { type: 'string', description: 'Source title.' },
337
+ url: { type: 'string', description: 'Source URL; secret-like query values are redacted before storage.' },
338
+ publisher: { type: 'string', description: 'Publisher or source owner.' },
339
+ publishedAt: { type: 'string', description: 'Published date if known.' },
340
+ accessedAt: { type: 'string', description: 'Access date; defaults to now.' },
341
+ summary: { type: 'string', description: 'Short source summary.' },
342
+ evidence: { type: 'string', description: 'Useful quoted-or-paraphrased evidence notes within copyright limits.' },
343
+ credibility: { type: 'string', enum: CREDIBILITY_VALUES, description: 'Review credibility label.' },
344
+ score: { type: 'number', description: '0-100 usefulness/credibility score.' },
345
+ tags: { type: 'array', items: { type: 'string' }, description: 'Optional source tags.' },
346
+ note: { type: 'string', description: 'Review note, rejection reason, or use note.' },
347
+ reportArtifactId: { type: 'string', description: 'Optional report artifact id when marking a source used.' },
348
+ includeReportLines: { type: 'boolean', description: 'Include report-form source lines in list/search output.' },
349
+ limit: { type: 'number', description: 'Maximum rows for bundle output.' },
350
+ confirm: { type: 'boolean', description: 'Required true for local source queue writes.' },
351
+ explicitUserRequest: { type: 'string', description: 'User request authorizing source queue writes.' },
352
+ },
353
+ required: ['mode'],
354
+ additionalProperties: false,
355
+ },
356
+ sideEffects: ['state'],
357
+ concurrency: 'serial',
358
+ },
359
+ execute: async (rawArgs: Record<string, unknown>) => {
360
+ if (!shellPaths) return failure('Research source queue is unavailable because this runtime did not provide shell paths.');
361
+ const registry = AgentResearchSourceRegistry.fromShellPaths(shellPaths);
362
+ const args = rawArgs as AgentResearchSourcesToolArgs;
363
+ const mode = readMode(args.mode);
364
+ try {
365
+ if (mode === 'list') {
366
+ const status = readStatus(args.status);
367
+ const sources = registry.list(status);
368
+ return output(formatSourceList(
369
+ status ? `Agent research sources (${status})` : 'Agent research sources',
370
+ sources,
371
+ args.includeReportLines === true,
372
+ ));
373
+ }
374
+ if (mode === 'search') {
375
+ const query = readString(args.query);
376
+ return output(formatSourceList(`Agent research source search ${query || '(all)'}`, registry.search(query), args.includeReportLines === true));
377
+ }
378
+ if (mode === 'show') {
379
+ const source = registry.get(requireId(args));
380
+ return source ? output(formatSourceDetail(source)) : failure(`Unknown research source ${readString(args.id)}`);
381
+ }
382
+ if (mode === 'bundle') {
383
+ const query = readString(args.query).toLowerCase();
384
+ const limit = readLimit(args.limit, 20);
385
+ const sources = registry.list()
386
+ .filter((source) => source.status === 'reviewed' || source.status === 'used')
387
+ .filter((source) => sourceMatchesQuery(source, query))
388
+ .sort((left, right) => right.score - left.score || right.updatedAt.localeCompare(left.updatedAt))
389
+ .slice(0, limit);
390
+ return output(formatSourceBundle(sources, query, limit));
391
+ }
392
+ if (mode === 'add') {
393
+ requireConfirmedWrite(args, 'Research source add');
394
+ return output(formatMutationResult('Added Agent research source', registry.create(addInput(args))));
395
+ }
396
+ if (mode === 'review') {
397
+ requireConfirmedWrite(args, 'Research source review');
398
+ const credibility = readCredibility(args.credibility);
399
+ const score = readScore(args.score);
400
+ const note = readString(args.note);
401
+ const summary = readString(args.summary);
402
+ const evidence = readString(args.evidence);
403
+ const tags = args.tags === undefined ? undefined : readStringList(args.tags);
404
+ const source = registry.review(requireId(args), {
405
+ ...(credibility ? { credibility } : {}),
406
+ ...(score === undefined ? {} : { score }),
407
+ ...(note ? { note } : {}),
408
+ ...(summary ? { summary } : {}),
409
+ ...(evidence ? { evidence } : {}),
410
+ ...(tags === undefined ? {} : { tags }),
411
+ });
412
+ return output(formatMutationResult('Reviewed Agent research source', source));
413
+ }
414
+ if (mode === 'reject') {
415
+ requireConfirmedWrite(args, 'Research source rejection');
416
+ return output(formatMutationResult('Rejected Agent research source', registry.reject(requireId(args), readString(args.note))));
417
+ }
418
+ if (mode === 'use') {
419
+ requireConfirmedWrite(args, 'Research source use');
420
+ const reportArtifactId = readString(args.reportArtifactId);
421
+ const note = readString(args.note);
422
+ return output(formatMutationResult('Marked Agent research source used', registry.markUsed(requireId(args), {
423
+ ...(reportArtifactId ? { reportArtifactId } : {}),
424
+ ...(note ? { note } : {}),
425
+ })));
426
+ }
427
+ requireConfirmedWrite(args, 'Research source deletion');
428
+ return output(formatMutationResult('Deleted Agent research source', registry.delete(requireId(args))));
429
+ } catch (error) {
430
+ return failure(error instanceof Error ? error.message : String(error));
431
+ }
432
+ },
433
+ };
434
+ }
435
+
436
+ export { createAgentResearchSourcesTool };
437
+
438
+ export function registerAgentResearchSourcesTool(
439
+ registry: ToolRegistry,
440
+ shellPaths?: Pick<ShellPathService, 'resolveProjectPath'>,
441
+ ): void {
442
+ registry.register(createAgentResearchSourcesTool(shellPaths));
443
+ }