@pellux/goodvibes-agent 0.1.117 → 1.0.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 (253) hide show
  1. package/CHANGELOG.md +13 -4
  2. package/README.md +35 -14
  3. package/bin/goodvibes-agent.ts +16 -2
  4. package/dist/package/main.js +176073 -170980
  5. package/docs/README.md +11 -5
  6. package/docs/channels-remote-and-api.md +50 -0
  7. package/docs/connected-host.md +3 -3
  8. package/docs/getting-started.md +29 -15
  9. package/docs/knowledge-artifacts-and-multimodal.md +91 -0
  10. package/docs/project-planning.md +79 -0
  11. package/docs/providers-and-routing.md +46 -0
  12. package/docs/release-and-publishing.md +44 -9
  13. package/docs/tools-and-commands.md +123 -0
  14. package/docs/voice-and-live-tts.md +51 -0
  15. package/package.json +2 -5
  16. package/src/agent/channel-delivery.ts +201 -0
  17. package/src/agent/media-generation.ts +159 -0
  18. package/src/agent/memory-prompt.ts +0 -1
  19. package/src/agent/note-registry.ts +329 -0
  20. package/src/agent/operator-actions.ts +343 -0
  21. package/src/agent/persona-registry.ts +15 -14
  22. package/src/agent/record-labels.ts +107 -0
  23. package/src/agent/reminder-schedule-format.ts +33 -24
  24. package/src/agent/reminder-schedule.ts +26 -25
  25. package/src/agent/routine-registry.ts +13 -12
  26. package/src/agent/routine-schedule-args.ts +2 -1
  27. package/src/agent/routine-schedule-format.ts +77 -53
  28. package/src/agent/routine-schedule-promotion.ts +34 -32
  29. package/src/agent/routine-schedule-receipts.ts +28 -26
  30. package/src/agent/runtime-profile-starters.ts +2 -2
  31. package/src/agent/runtime-profile.ts +18 -17
  32. package/src/agent/skill-registry.ts +25 -24
  33. package/src/cli/agent-knowledge-args.ts +5 -1
  34. package/src/cli/agent-knowledge-command.ts +39 -33
  35. package/src/cli/agent-knowledge-format.ts +80 -67
  36. package/src/cli/agent-knowledge-methods.ts +1 -1
  37. package/src/cli/agent-knowledge-runtime.ts +32 -26
  38. package/src/cli/bundle-command.ts +13 -8
  39. package/src/cli/config-overrides.ts +37 -36
  40. package/src/cli/external-runtime.ts +10 -4
  41. package/src/cli/help.ts +29 -11
  42. package/src/cli/local-library-command.ts +134 -68
  43. package/src/cli/management-commands.ts +98 -62
  44. package/src/cli/management.ts +52 -26
  45. package/src/cli/memory-command.ts +66 -32
  46. package/src/cli/parser.ts +37 -24
  47. package/src/cli/profiles-command.ts +52 -35
  48. package/src/cli/provider-auth-routes.ts +2 -1
  49. package/src/cli/routines-command.ts +44 -36
  50. package/src/cli/service-posture.ts +6 -6
  51. package/src/cli/status.ts +46 -121
  52. package/src/core/conversation-message-snapshot.ts +131 -0
  53. package/src/input/agent-workspace-activation.ts +33 -7
  54. package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
  55. package/src/input/agent-workspace-basic-command-editors.ts +30 -10
  56. package/src/input/agent-workspace-categories.ts +276 -64
  57. package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
  58. package/src/input/agent-workspace-channel-command-editors.ts +23 -5
  59. package/src/input/agent-workspace-channels.ts +35 -2
  60. package/src/input/agent-workspace-command-editor.ts +18 -2
  61. package/src/input/agent-workspace-config-reader.ts +16 -0
  62. package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
  63. package/src/input/agent-workspace-editors.ts +140 -2
  64. package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
  65. package/src/input/agent-workspace-learned-behavior.ts +2 -2
  66. package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
  67. package/src/input/agent-workspace-library-command-editors.ts +2 -2
  68. package/src/input/agent-workspace-local-operations.ts +218 -0
  69. package/src/input/agent-workspace-local-selection.ts +75 -0
  70. package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
  71. package/src/input/agent-workspace-media-command-editors.ts +27 -0
  72. package/src/input/agent-workspace-memory-command-editors.ts +1 -1
  73. package/src/input/agent-workspace-memory-editor.ts +2 -2
  74. package/src/input/agent-workspace-navigation.ts +38 -2
  75. package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
  76. package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
  77. package/src/input/agent-workspace-operations-command-editors.ts +80 -3
  78. package/src/input/agent-workspace-panel-route.ts +43 -0
  79. package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
  80. package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
  81. package/src/input/agent-workspace-search.ts +169 -0
  82. package/src/input/agent-workspace-setup.ts +22 -11
  83. package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
  84. package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
  85. package/src/input/agent-workspace-snapshot.ts +112 -13
  86. package/src/input/agent-workspace-task-command-editors.ts +4 -4
  87. package/src/input/agent-workspace-token.ts +18 -2
  88. package/src/input/agent-workspace-types.ts +92 -4
  89. package/src/input/agent-workspace-voice-media.ts +3 -6
  90. package/src/input/agent-workspace-web-research-editor.ts +104 -0
  91. package/src/input/agent-workspace.ts +136 -208
  92. package/src/input/command-registry.ts +4 -1
  93. package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
  94. package/src/input/commands/agent-skills-runtime.ts +83 -70
  95. package/src/input/commands/agent-workspace-runtime.ts +23 -7
  96. package/src/input/commands/brief-runtime.ts +25 -24
  97. package/src/input/commands/channels-runtime.ts +145 -31
  98. package/src/input/commands/delegation-runtime.ts +29 -23
  99. package/src/input/commands/experience-runtime.ts +6 -4
  100. package/src/input/commands/guidance-runtime.ts +4 -4
  101. package/src/input/commands/health-runtime.ts +140 -115
  102. package/src/input/commands/knowledge.ts +57 -56
  103. package/src/input/commands/local-provider-runtime.ts +36 -18
  104. package/src/input/commands/local-runtime.ts +138 -16
  105. package/src/input/commands/local-setup-review.ts +7 -7
  106. package/src/input/commands/mcp-runtime.ts +56 -35
  107. package/src/input/commands/notify-runtime.ts +38 -9
  108. package/src/input/commands/operator-actions-runtime.ts +138 -0
  109. package/src/input/commands/operator-runtime.ts +6 -17
  110. package/src/input/commands/personas-runtime.ts +45 -30
  111. package/src/input/commands/planning-runtime.ts +1 -1
  112. package/src/input/commands/platform-access-runtime.ts +29 -29
  113. package/src/input/commands/provider-accounts-runtime.ts +60 -39
  114. package/src/input/commands/qrcode-runtime.ts +45 -6
  115. package/src/input/commands/recall-bundle.ts +11 -11
  116. package/src/input/commands/recall-capture.ts +13 -11
  117. package/src/input/commands/recall-query.ts +29 -21
  118. package/src/input/commands/recall-review.ts +2 -1
  119. package/src/input/commands/routines-runtime.ts +59 -43
  120. package/src/input/commands/schedule-runtime.ts +33 -20
  121. package/src/input/commands/security-runtime.ts +4 -4
  122. package/src/input/commands/session-content.ts +80 -78
  123. package/src/input/commands/session-workflow.ts +132 -93
  124. package/src/input/commands/session.ts +3 -174
  125. package/src/input/commands/shell-core.ts +32 -17
  126. package/src/input/commands/subscription-runtime.ts +53 -179
  127. package/src/input/commands/tasks-runtime.ts +20 -20
  128. package/src/input/commands/work-plan-runtime.ts +33 -8
  129. package/src/input/commands.ts +2 -2
  130. package/src/input/feed-context-factory.ts +2 -1
  131. package/src/input/file-picker.ts +3 -2
  132. package/src/input/handler-command-route.ts +4 -7
  133. package/src/input/handler-content-actions.ts +89 -1
  134. package/src/input/handler-feed-routes.ts +19 -12
  135. package/src/input/handler-feed.ts +6 -3
  136. package/src/input/handler-interactions.ts +7 -5
  137. package/src/input/handler-modal-stack.ts +3 -3
  138. package/src/input/handler-onboarding.ts +24 -80
  139. package/src/input/handler-shortcuts.ts +15 -4
  140. package/src/input/handler.ts +47 -17
  141. package/src/input/input-history.ts +5 -6
  142. package/src/input/keybindings.ts +22 -11
  143. package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
  144. package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
  145. package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
  146. package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
  147. package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
  148. package/src/input/onboarding/onboarding-wizard.ts +68 -0
  149. package/src/input/profile-picker-modal.ts +31 -12
  150. package/src/input/session-picker-modal.ts +21 -4
  151. package/src/input/settings-modal-behavior.ts +0 -3
  152. package/src/input/settings-modal-subscriptions.ts +3 -3
  153. package/src/input/settings-modal-types.ts +2 -13
  154. package/src/input/settings-modal.ts +6 -52
  155. package/src/input/submission-intent.ts +0 -1
  156. package/src/input/submission-router.ts +3 -3
  157. package/src/main.ts +18 -8
  158. package/src/panels/approval-panel.ts +8 -8
  159. package/src/panels/automation-control-panel.ts +2 -2
  160. package/src/panels/base-panel.ts +1 -1
  161. package/src/panels/builtin/agent.ts +1 -1
  162. package/src/panels/builtin/operations.ts +1 -10
  163. package/src/panels/builtin/session.ts +9 -9
  164. package/src/panels/builtin/shared.ts +2 -2
  165. package/src/panels/cost-tracker-panel.ts +1 -1
  166. package/src/panels/docs-panel.ts +5 -3
  167. package/src/panels/index.ts +0 -1
  168. package/src/panels/knowledge-panel.ts +6 -5
  169. package/src/panels/memory-panel.ts +7 -6
  170. package/src/panels/panel-list-panel.ts +36 -80
  171. package/src/panels/project-planning-panel.ts +18 -11
  172. package/src/panels/provider-account-snapshot.ts +51 -25
  173. package/src/panels/provider-accounts-panel.ts +33 -18
  174. package/src/panels/provider-health-domains.ts +45 -4
  175. package/src/panels/provider-health-panel.ts +5 -4
  176. package/src/panels/qr-panel.ts +1 -1
  177. package/src/panels/schedule-panel.ts +9 -17
  178. package/src/panels/security-panel.ts +8 -8
  179. package/src/panels/session-browser-panel.ts +10 -10
  180. package/src/panels/subscription-panel.ts +3 -3
  181. package/src/panels/system-messages-panel.ts +1 -1
  182. package/src/panels/tasks-panel.ts +20 -13
  183. package/src/panels/tool-inspector-panel.ts +19 -12
  184. package/src/panels/work-plan-panel.ts +5 -5
  185. package/src/planning/project-planning-coordinator.ts +1 -1
  186. package/src/provider-auth-route-display.ts +9 -0
  187. package/src/renderer/agent-workspace-style.ts +34 -0
  188. package/src/renderer/agent-workspace.ts +228 -52
  189. package/src/renderer/autocomplete-overlay.ts +25 -6
  190. package/src/renderer/bookmark-modal.ts +19 -4
  191. package/src/renderer/buffer.ts +4 -2
  192. package/src/renderer/context-inspector.ts +50 -13
  193. package/src/renderer/diff.ts +1 -1
  194. package/src/renderer/file-picker-overlay.ts +19 -6
  195. package/src/renderer/help-overlay.ts +106 -33
  196. package/src/renderer/history-search-overlay.ts +19 -4
  197. package/src/renderer/live-tail-modal.ts +27 -5
  198. package/src/renderer/mcp-workspace.ts +164 -50
  199. package/src/renderer/model-picker-overlay.ts +58 -2
  200. package/src/renderer/model-workspace.ts +104 -20
  201. package/src/renderer/process-modal.ts +27 -6
  202. package/src/renderer/profile-picker-modal.ts +20 -4
  203. package/src/renderer/search-overlay.ts +25 -5
  204. package/src/renderer/selection-modal-overlay.ts +46 -14
  205. package/src/renderer/session-picker-modal.ts +18 -1
  206. package/src/renderer/settings-modal-helpers.ts +2 -40
  207. package/src/renderer/settings-modal.ts +83 -50
  208. package/src/renderer/tool-call.ts +20 -11
  209. package/src/runtime/agent-runtime-events.ts +6 -6
  210. package/src/runtime/bootstrap-command-context.ts +7 -1
  211. package/src/runtime/bootstrap-command-parts.ts +9 -7
  212. package/src/runtime/bootstrap-core.ts +19 -1
  213. package/src/runtime/bootstrap-hook-bridge.ts +7 -18
  214. package/src/runtime/bootstrap-shell.ts +4 -4
  215. package/src/runtime/bootstrap.ts +31 -22
  216. package/src/runtime/connected-host-auth.ts +7 -2
  217. package/src/runtime/diagnostics/panels/index.ts +2 -2
  218. package/src/runtime/diagnostics/panels/policy.ts +7 -7
  219. package/src/runtime/index.ts +2 -1
  220. package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
  221. package/src/runtime/onboarding/apply.ts +80 -79
  222. package/src/runtime/onboarding/derivation.ts +5 -8
  223. package/src/runtime/onboarding/snapshot.ts +0 -15
  224. package/src/runtime/onboarding/types.ts +8 -19
  225. package/src/runtime/onboarding/verify.ts +32 -10
  226. package/src/runtime/operator-token-cleanup.ts +1 -1
  227. package/src/runtime/services.ts +91 -22
  228. package/src/runtime/store/selectors/index.ts +3 -3
  229. package/src/runtime/store/state.ts +1 -4
  230. package/src/runtime/surface-feature-flags.ts +41 -6
  231. package/src/runtime/ui-read-models.ts +3 -4
  232. package/src/runtime/ui-services.ts +6 -6
  233. package/src/shell/blocking-input.ts +2 -1
  234. package/src/shell/ui-openers.ts +3 -13
  235. package/src/tools/agent-analysis-registry-policy.ts +0 -1
  236. package/src/tools/agent-channel-send-tool.ts +133 -0
  237. package/src/tools/agent-context-policy.ts +1 -1
  238. package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
  239. package/src/tools/agent-knowledge-tool.ts +170 -0
  240. package/src/tools/agent-local-registry-tool.ts +269 -69
  241. package/src/tools/agent-media-generate-tool.ts +133 -0
  242. package/src/tools/agent-notify-tool.ts +143 -0
  243. package/src/tools/agent-operator-action-tool.ts +137 -0
  244. package/src/tools/agent-operator-briefing-tool.ts +217 -0
  245. package/src/tools/agent-reminder-schedule-tool.ts +237 -0
  246. package/src/tools/agent-tool-policy-guard.ts +8 -8
  247. package/src/tools/agent-work-plan-tool.ts +256 -0
  248. package/src/version.ts +1 -1
  249. package/src/input/commands/policy-dispatch.ts +0 -339
  250. package/src/input/commands/policy.ts +0 -13
  251. package/src/panels/panel-picker.ts +0 -105
  252. package/src/panels/policy-panel.ts +0 -308
  253. package/src/renderer/panel-picker-overlay.ts +0 -202
@@ -0,0 +1,405 @@
1
+ import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
2
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
3
+ import type { ShellPathService } from '@/runtime/index.ts';
4
+ import type { AgentConnectedHostConfigReader } from '../agent/routine-schedule-promotion.ts';
5
+ import { resolveAgentConnectedHostConnection } from '../agent/routine-schedule-promotion.ts';
6
+ import {
7
+ classifyKnowledgeError,
8
+ postAgentKnowledgeJson,
9
+ type AgentKnowledgeFailure,
10
+ } from '../cli/agent-knowledge-runtime.ts';
11
+ import { AGENT_KNOWLEDGE_METHODS } from '../cli/agent-knowledge-methods.ts';
12
+ import { formatBatchIngest, formatFailure, formatIngest } from '../cli/agent-knowledge-format.ts';
13
+
14
+ export type AgentKnowledgeIngestSourceKind =
15
+ | 'url'
16
+ | 'file'
17
+ | 'urls_file'
18
+ | 'bookmarks_file'
19
+ | 'browser_history'
20
+ | 'connector';
21
+
22
+ export interface AgentKnowledgeIngestToolArgs {
23
+ readonly sourceKind?: unknown;
24
+ readonly url?: unknown;
25
+ readonly path?: unknown;
26
+ readonly title?: unknown;
27
+ readonly tags?: unknown;
28
+ readonly folderPath?: unknown;
29
+ readonly connectorId?: unknown;
30
+ readonly input?: unknown;
31
+ readonly content?: unknown;
32
+ readonly browsers?: unknown;
33
+ readonly sourceKinds?: unknown;
34
+ readonly homeOverride?: unknown;
35
+ readonly limit?: unknown;
36
+ readonly sinceDays?: unknown;
37
+ readonly allowPrivateHosts?: unknown;
38
+ readonly confirm?: unknown;
39
+ readonly explicitUserRequest?: unknown;
40
+ }
41
+
42
+ type JsonRecord = Record<string, unknown>;
43
+
44
+ interface AgentKnowledgeIngestRequest {
45
+ readonly method: typeof AGENT_KNOWLEDGE_METHODS[keyof typeof AGENT_KNOWLEDGE_METHODS];
46
+ readonly target: string;
47
+ readonly label: string;
48
+ readonly payload: JsonRecord;
49
+ readonly batch: boolean;
50
+ }
51
+
52
+ const SOURCE_KINDS: readonly AgentKnowledgeIngestSourceKind[] = [
53
+ 'url',
54
+ 'file',
55
+ 'urls_file',
56
+ 'bookmarks_file',
57
+ 'browser_history',
58
+ 'connector',
59
+ ];
60
+
61
+ function isSourceKind(value: unknown): value is AgentKnowledgeIngestSourceKind {
62
+ return typeof value === 'string' && SOURCE_KINDS.includes(value as AgentKnowledgeIngestSourceKind);
63
+ }
64
+
65
+ function readString(value: unknown): string {
66
+ return typeof value === 'string' ? value.trim() : '';
67
+ }
68
+
69
+ function readOptionalString(value: unknown): string | undefined {
70
+ const text = readString(value);
71
+ return text.length > 0 ? text : undefined;
72
+ }
73
+
74
+ function readStringList(value: unknown): readonly string[] {
75
+ if (typeof value === 'string') return value.split(',').map((entry) => entry.trim()).filter(Boolean);
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 readBoolean(value: unknown): boolean {
81
+ return value === true || value === 'true' || value === 'yes';
82
+ }
83
+
84
+ function readPositiveInt(value: unknown, fallback: number): number {
85
+ if (typeof value === 'number' && Number.isInteger(value) && value > 0) return Math.min(value, 10_000);
86
+ if (typeof value === 'string' && value.trim()) {
87
+ const parsed = Number(value);
88
+ if (Number.isInteger(parsed) && parsed > 0) return Math.min(parsed, 10_000);
89
+ }
90
+ return fallback;
91
+ }
92
+
93
+ function readSinceMs(value: unknown): number | undefined {
94
+ if (value === undefined || value === null || readString(value) === '') return undefined;
95
+ const days = readPositiveInt(value, 0);
96
+ return days > 0 ? days * 24 * 60 * 60 * 1000 : undefined;
97
+ }
98
+
99
+ function validateUrl(url: string): string | null {
100
+ try {
101
+ const parsed = new URL(url);
102
+ if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return 'Agent Knowledge URL ingest requires an http(s) URL.';
103
+ return null;
104
+ } catch (error) {
105
+ return error instanceof Error ? error.message : String(error);
106
+ }
107
+ }
108
+
109
+ function failure(error: string): { readonly success: false; readonly error: string } {
110
+ return { success: false, error };
111
+ }
112
+
113
+ function output(text: string): { readonly success: true; readonly output: string } {
114
+ return { success: true, output: text };
115
+ }
116
+
117
+ function formatKnowledgeFailure(failureResult: AgentKnowledgeFailure): string {
118
+ return formatFailure(failureResult, false);
119
+ }
120
+
121
+ function preview(request: AgentKnowledgeIngestRequest): string {
122
+ return [
123
+ `Agent Knowledge ${request.label} preview`,
124
+ ` target ${request.target}`,
125
+ ` route ${request.method.route}`,
126
+ ' policy isolated Agent Knowledge only; no default knowledge or non-Agent fallback',
127
+ ].join('\n');
128
+ }
129
+
130
+ function parseConnectorInput(value: unknown): unknown {
131
+ if (typeof value !== 'string') return value;
132
+ const text = value.trim();
133
+ if (!text) return undefined;
134
+ try {
135
+ return JSON.parse(text) as unknown;
136
+ } catch {
137
+ return text;
138
+ }
139
+ }
140
+
141
+ function requestForArgs(args: AgentKnowledgeIngestToolArgs): AgentKnowledgeIngestRequest {
142
+ const sourceKind = args.sourceKind === undefined || readString(args.sourceKind) === ''
143
+ ? 'url'
144
+ : isSourceKind(args.sourceKind)
145
+ ? args.sourceKind
146
+ : null;
147
+ if (sourceKind === null) throw new Error(`sourceKind must be one of ${SOURCE_KINDS.join(', ')}.`);
148
+
149
+ const title = readString(args.title);
150
+ const tags = readStringList(args.tags);
151
+ const originMetadata = {
152
+ originSurface: 'goodvibes-agent',
153
+ explicitUserRequest: readString(args.explicitUserRequest),
154
+ };
155
+
156
+ if (sourceKind === 'url') {
157
+ const url = readString(args.url);
158
+ if (!url) throw new Error('url is required.');
159
+ const invalidUrl = validateUrl(url);
160
+ if (invalidUrl) throw new Error(invalidUrl);
161
+ return {
162
+ method: AGENT_KNOWLEDGE_METHODS.ingestUrl,
163
+ target: url,
164
+ label: 'URL ingest',
165
+ batch: false,
166
+ payload: {
167
+ url,
168
+ title,
169
+ tags: [...tags],
170
+ sourceType: 'url',
171
+ connectorId: 'goodvibes-agent-main-conversation',
172
+ metadata: originMetadata,
173
+ },
174
+ };
175
+ }
176
+
177
+ if (sourceKind === 'file') {
178
+ const path = readString(args.path);
179
+ if (!path) throw new Error('path is required.');
180
+ return {
181
+ method: AGENT_KNOWLEDGE_METHODS.ingestArtifact,
182
+ target: path,
183
+ label: 'file ingest',
184
+ batch: false,
185
+ payload: {
186
+ path,
187
+ title,
188
+ tags: [...tags],
189
+ folderPath: readOptionalString(args.folderPath),
190
+ connectorId: readOptionalString(args.connectorId) ?? 'goodvibes-agent-main-conversation-file',
191
+ allowPrivateHosts: readBoolean(args.allowPrivateHosts),
192
+ metadata: originMetadata,
193
+ },
194
+ };
195
+ }
196
+
197
+ if (sourceKind === 'urls_file' || sourceKind === 'bookmarks_file') {
198
+ const path = readString(args.path);
199
+ if (!path) throw new Error('path is required.');
200
+ const method = sourceKind === 'urls_file' ? AGENT_KNOWLEDGE_METHODS.ingestUrls : AGENT_KNOWLEDGE_METHODS.ingestBookmarks;
201
+ return {
202
+ method,
203
+ target: path,
204
+ label: sourceKind === 'urls_file' ? 'URL-list import' : 'bookmarks import',
205
+ batch: true,
206
+ payload: {
207
+ path,
208
+ allowPrivateHosts: readBoolean(args.allowPrivateHosts),
209
+ metadata: originMetadata,
210
+ },
211
+ };
212
+ }
213
+
214
+ if (sourceKind === 'browser_history') {
215
+ return {
216
+ method: AGENT_KNOWLEDGE_METHODS.ingestBrowserHistory,
217
+ target: 'local browser history',
218
+ label: 'browser-history import',
219
+ batch: true,
220
+ payload: {
221
+ browsers: [...readStringList(args.browsers)],
222
+ sourceKinds: [...readStringList(args.sourceKinds)],
223
+ homeOverride: readOptionalString(args.homeOverride),
224
+ limit: readPositiveInt(args.limit, 250),
225
+ sinceMs: readSinceMs(args.sinceDays),
226
+ connectorId: 'goodvibes-agent-main-conversation-browser-history',
227
+ metadata: originMetadata,
228
+ },
229
+ };
230
+ }
231
+
232
+ const connectorId = readString(args.connectorId);
233
+ if (!connectorId) throw new Error('connectorId is required.');
234
+ const input = parseConnectorInput(args.input);
235
+ const path = readOptionalString(args.path);
236
+ const content = readOptionalString(args.content);
237
+ if (input === undefined && !path && !content) {
238
+ throw new Error('connector ingest requires input, path, or content.');
239
+ }
240
+ return {
241
+ method: AGENT_KNOWLEDGE_METHODS.ingestConnector,
242
+ target: connectorId,
243
+ label: 'connector ingest',
244
+ batch: true,
245
+ payload: {
246
+ connectorId,
247
+ input,
248
+ path,
249
+ content,
250
+ allowPrivateHosts: readBoolean(args.allowPrivateHosts),
251
+ sessionId: 'goodvibes-agent-main-conversation',
252
+ metadata: originMetadata,
253
+ },
254
+ };
255
+ }
256
+
257
+ export function createAgentKnowledgeIngestTool(
258
+ shellPaths: ShellPathService,
259
+ configManager: AgentConnectedHostConfigReader,
260
+ ): Tool {
261
+ return {
262
+ definition: {
263
+ name: 'agent_knowledge_ingest',
264
+ description: [
265
+ 'Ingest explicit sources into isolated GoodVibes Agent Knowledge from the main conversation.',
266
+ 'Use only when the user explicitly asks Agent to add, remember, import, or ingest a URL, local file, URL-list file, bookmarks file, browser history, or connector input into its Agent Knowledge.',
267
+ 'This writes only to /api/goodvibes-agent/knowledge/* ingest routes on the connected GoodVibes host.',
268
+ 'It must never call default knowledge, non-Agent knowledge spaces, separate Agent jobs, local schedulers, or delegated review.',
269
+ 'Set confirm:true only for an explicit user request. Otherwise return the preview/confirmation error.',
270
+ ].join(' '),
271
+ parameters: {
272
+ type: 'object',
273
+ properties: {
274
+ sourceKind: {
275
+ type: 'string',
276
+ enum: [...SOURCE_KINDS],
277
+ description: 'Source kind. Defaults to url for backwards compatibility.',
278
+ },
279
+ url: {
280
+ type: 'string',
281
+ description: 'HTTP(S) URL when sourceKind is url.',
282
+ },
283
+ path: {
284
+ type: 'string',
285
+ description: 'Local file/import path for file, urls_file, bookmarks_file, or connector source kinds.',
286
+ },
287
+ title: {
288
+ type: 'string',
289
+ description: 'Optional source title for url or file ingest.',
290
+ },
291
+ tags: {
292
+ type: 'array',
293
+ items: { type: 'string' },
294
+ description: 'Optional tags for url or file ingest.',
295
+ },
296
+ folderPath: {
297
+ type: 'string',
298
+ description: 'Optional folder path metadata for file ingest.',
299
+ },
300
+ connectorId: {
301
+ type: 'string',
302
+ description: 'Connector id for connector ingest, or optional connector id override for file ingest.',
303
+ },
304
+ input: {
305
+ description: 'Connector input as JSON-compatible data or a JSON/text string.',
306
+ },
307
+ content: {
308
+ type: 'string',
309
+ description: 'Connector content text.',
310
+ },
311
+ browsers: {
312
+ type: 'array',
313
+ items: { type: 'string' },
314
+ description: 'Optional browser ids for browser_history ingest.',
315
+ },
316
+ sourceKinds: {
317
+ type: 'array',
318
+ items: { type: 'string' },
319
+ description: 'Optional browser-history source kinds such as history or bookmark.',
320
+ },
321
+ homeOverride: {
322
+ type: 'string',
323
+ description: 'Optional browser profile home override for browser_history ingest.',
324
+ },
325
+ limit: {
326
+ type: 'number',
327
+ description: 'Optional browser_history import limit.',
328
+ },
329
+ sinceDays: {
330
+ type: 'number',
331
+ description: 'Optional browser_history lookback window in days.',
332
+ },
333
+ allowPrivateHosts: {
334
+ type: 'boolean',
335
+ description: 'Allow private-host source URLs where the Agent Knowledge route supports it.',
336
+ },
337
+ confirm: {
338
+ type: 'boolean',
339
+ description: 'Required true only when the user explicitly asked to ingest this source.',
340
+ },
341
+ explicitUserRequest: {
342
+ type: 'string',
343
+ description: 'Short quote or summary of the user request that authorized this Agent Knowledge ingest.',
344
+ },
345
+ },
346
+ required: ['confirm', 'explicitUserRequest'],
347
+ additionalProperties: false,
348
+ },
349
+ sideEffects: ['network', 'state'],
350
+ },
351
+ execute: async (rawArgs: unknown) => {
352
+ const args = rawArgs as AgentKnowledgeIngestToolArgs;
353
+ let request: AgentKnowledgeIngestRequest;
354
+ try {
355
+ request = requestForArgs(args);
356
+ } catch (error) {
357
+ return failure(error instanceof Error ? error.message : String(error));
358
+ }
359
+ if (!readString(args.explicitUserRequest)) {
360
+ return failure('explicitUserRequest is required so Agent Knowledge ingest stays tied to a direct user request.');
361
+ }
362
+ if (!readBoolean(args.confirm)) {
363
+ return failure([
364
+ preview(request),
365
+ '',
366
+ 'Model tool confirmation required. Call this tool with confirm:true only when the user explicitly asked GoodVibes Agent to ingest this source.',
367
+ ].join('\n'));
368
+ }
369
+
370
+ const connection = resolveAgentConnectedHostConnection(configManager, shellPaths.homeDirectory);
371
+ if (!connection.token) {
372
+ return failure(formatKnowledgeFailure({
373
+ ok: false,
374
+ kind: 'auth_required',
375
+ error: `No connected-host operator token found at ${connection.tokenPath}`,
376
+ baseUrl: connection.baseUrl,
377
+ route: request.method.route,
378
+ }));
379
+ }
380
+
381
+ try {
382
+ const data = await postAgentKnowledgeJson(connection, request.method.route, request.payload);
383
+ return output(request.batch
384
+ ? formatBatchIngest(data, request.label)
385
+ : formatIngest(
386
+ data,
387
+ request.target,
388
+ request.label,
389
+ request.method.route,
390
+ request.label === 'file ingest' ? 'file' : 'url',
391
+ ));
392
+ } catch (error) {
393
+ return failure(formatKnowledgeFailure(await classifyKnowledgeError(error, connection, request.method.route)));
394
+ }
395
+ },
396
+ };
397
+ }
398
+
399
+ export function registerAgentKnowledgeIngestTool(
400
+ registry: ToolRegistry,
401
+ shellPaths: ShellPathService,
402
+ configManager: AgentConnectedHostConfigReader,
403
+ ): void {
404
+ registry.register(createAgentKnowledgeIngestTool(shellPaths, configManager));
405
+ }
@@ -0,0 +1,170 @@
1
+ import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
2
+ import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
3
+ import type { ShellPathService } from '@/runtime/index.ts';
4
+ import {
5
+ createAgentSdk,
6
+ classifyKnowledgeError,
7
+ resolveConnectedHostConnection,
8
+ type AgentKnowledgeFailure,
9
+ type AgentKnowledgeConnectionRuntime,
10
+ } from '../cli/agent-knowledge-runtime.ts';
11
+ import { AGENT_KNOWLEDGE_METHODS, type ConnectedHostCallMethod } from '../cli/agent-knowledge-methods.ts';
12
+ import {
13
+ formatAsk,
14
+ formatFailure,
15
+ formatSearch,
16
+ formatStatus,
17
+ } from '../cli/agent-knowledge-format.ts';
18
+
19
+ export type AgentKnowledgeToolAction = 'status' | 'ask' | 'search';
20
+ export type AgentKnowledgeAskMode = 'concise' | 'standard' | 'detailed';
21
+
22
+ export interface AgentKnowledgeToolArgs {
23
+ readonly action?: unknown;
24
+ readonly query?: unknown;
25
+ readonly limit?: unknown;
26
+ readonly mode?: unknown;
27
+ }
28
+
29
+ const ACTIONS: readonly AgentKnowledgeToolAction[] = ['status', 'ask', 'search'];
30
+ const ASK_MODES: readonly AgentKnowledgeAskMode[] = ['concise', 'standard', 'detailed'];
31
+
32
+ function isAction(value: unknown): value is AgentKnowledgeToolAction {
33
+ return typeof value === 'string' && ACTIONS.includes(value as AgentKnowledgeToolAction);
34
+ }
35
+
36
+ function readString(value: unknown): string {
37
+ return typeof value === 'string' ? value.trim() : '';
38
+ }
39
+
40
+ function readLimit(value: unknown, fallback: number): number {
41
+ if (typeof value === 'number' && Number.isInteger(value) && value > 0) return Math.min(value, 25);
42
+ if (typeof value === 'string' && value.trim()) {
43
+ const parsed = Number(value);
44
+ if (Number.isInteger(parsed) && parsed > 0) return Math.min(parsed, 25);
45
+ }
46
+ return fallback;
47
+ }
48
+
49
+ function readMode(value: unknown): AgentKnowledgeAskMode {
50
+ return typeof value === 'string' && ASK_MODES.includes(value as AgentKnowledgeAskMode)
51
+ ? value as AgentKnowledgeAskMode
52
+ : 'standard';
53
+ }
54
+
55
+ function toolFailure(error: string): { readonly success: false; readonly error: string } {
56
+ return { success: false, error };
57
+ }
58
+
59
+ function toolOutput(output: string): { readonly success: true; readonly output: string } {
60
+ return { success: true, output };
61
+ }
62
+
63
+ function formatKnowledgeFailure(failure: AgentKnowledgeFailure): string {
64
+ return formatFailure(failure, false);
65
+ }
66
+
67
+ async function classifyToolKnowledgeError(
68
+ error: unknown,
69
+ connection: ReturnType<typeof resolveConnectedHostConnection>,
70
+ method: ConnectedHostCallMethod,
71
+ ): Promise<{ readonly success: false; readonly error: string }> {
72
+ return toolFailure(formatKnowledgeFailure(await classifyKnowledgeError(error, connection, method.route)));
73
+ }
74
+
75
+ export function createAgentKnowledgeTool(
76
+ shellPaths: ShellPathService,
77
+ configManager: AgentKnowledgeConnectionRuntime['configManager'],
78
+ ): Tool {
79
+ return {
80
+ definition: {
81
+ name: 'agent_knowledge',
82
+ description: [
83
+ 'Read isolated GoodVibes Agent Knowledge from the main conversation.',
84
+ 'Use for Agent-owned knowledge status, ask, and search only.',
85
+ 'This tool calls /api/goodvibes-agent/knowledge/* on the connected GoodVibes host and must never fall back to default knowledge or non-Agent knowledge spaces.',
86
+ 'It is read-only and does not ingest, reindex, mutate, or create background work.',
87
+ ].join(' '),
88
+ parameters: {
89
+ type: 'object',
90
+ properties: {
91
+ action: {
92
+ type: 'string',
93
+ enum: [...ACTIONS],
94
+ description: 'Read-only Agent Knowledge action.',
95
+ },
96
+ query: {
97
+ type: 'string',
98
+ description: 'Question/query for ask or search.',
99
+ },
100
+ limit: {
101
+ type: 'number',
102
+ description: 'Maximum source/search results, capped at 25.',
103
+ },
104
+ mode: {
105
+ type: 'string',
106
+ enum: [...ASK_MODES],
107
+ description: 'Answer detail mode for ask.',
108
+ },
109
+ },
110
+ required: ['action'],
111
+ additionalProperties: false,
112
+ },
113
+ sideEffects: ['network'],
114
+ },
115
+ execute: async (rawArgs: unknown) => {
116
+ const args = rawArgs as AgentKnowledgeToolArgs;
117
+ if (!isAction(args.action)) return toolFailure(`Unknown Agent Knowledge action. Valid values ${ACTIONS.join(', ')}.`);
118
+ const connection = resolveConnectedHostConnection({ configManager, homeDirectory: shellPaths.homeDirectory });
119
+ if (!connection.token) {
120
+ return toolFailure(formatKnowledgeFailure({
121
+ ok: false,
122
+ kind: 'auth_required',
123
+ error: `No connected-host operator token found at ${connection.tokenPath}`,
124
+ baseUrl: connection.baseUrl,
125
+ route: '/api/goodvibes-agent/knowledge/*',
126
+ }));
127
+ }
128
+ try {
129
+ const sdk = createAgentSdk(connection);
130
+ if (args.action === 'status') {
131
+ const data = await sdk.knowledge.status();
132
+ return toolOutput(formatStatus(data));
133
+ }
134
+ if (args.action === 'ask') {
135
+ const query = readString(args.query);
136
+ if (!query) return toolFailure('query is required for Agent Knowledge ask.');
137
+ const data = await sdk.knowledge.ask({
138
+ query,
139
+ limit: readLimit(args.limit, 8),
140
+ mode: readMode(args.mode),
141
+ includeSources: true,
142
+ includeConfidence: true,
143
+ includeLinkedObjects: true,
144
+ });
145
+ return toolOutput(formatAsk(data, query));
146
+ }
147
+ const query = readString(args.query);
148
+ if (!query) return toolFailure('query is required for Agent Knowledge search.');
149
+ const method = AGENT_KNOWLEDGE_METHODS.search;
150
+ const data = await sdk.knowledge.search({ query, limit: readLimit(args.limit, 10) });
151
+ return toolOutput(formatSearch(data, query));
152
+ } catch (error) {
153
+ const method = args.action === 'status'
154
+ ? AGENT_KNOWLEDGE_METHODS.status
155
+ : args.action === 'ask'
156
+ ? AGENT_KNOWLEDGE_METHODS.ask
157
+ : AGENT_KNOWLEDGE_METHODS.search;
158
+ return classifyToolKnowledgeError(error, connection, method);
159
+ }
160
+ },
161
+ };
162
+ }
163
+
164
+ export function registerAgentKnowledgeTool(
165
+ registry: ToolRegistry,
166
+ shellPaths: ShellPathService,
167
+ configManager: AgentKnowledgeConnectionRuntime['configManager'],
168
+ ): void {
169
+ registry.register(createAgentKnowledgeTool(shellPaths, configManager));
170
+ }