@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
@@ -1,7 +1,9 @@
1
1
  import { basename, sep } from 'node:path';
2
2
  import type { MemoryRecord } from '@pellux/goodvibes-sdk/platform/state';
3
3
  import type { CommandContext } from './command-registry.ts';
4
+ import { AgentNoteRegistry, type AgentNoteRecord } from '../agent/note-registry.ts';
4
5
  import { AgentPersonaRegistry, type AgentPersonaRecord } from '../agent/persona-registry.ts';
6
+ import { formatAgentRecordOrigin } from '../agent/record-labels.ts';
5
7
  import { AgentRoutineRegistry, evaluateAgentRoutineReadiness, type AgentRoutineRecord } from '../agent/routine-registry.ts';
6
8
  import {
7
9
  AgentSkillRegistry,
@@ -14,23 +16,24 @@ import {
14
16
  import { summarizeAgentBehaviorDiscovery } from '../agent/behavior-discovery-summary.ts';
15
17
  import { isPromptActiveMemory } from '../agent/memory-prompt.ts';
16
18
  import { getAgentRuntimeProfilesRoot, listAgentRuntimeProfiles, listAgentRuntimeProfileTemplates, readAgentRuntimeProfileSelection } from '../agent/runtime-profile.ts';
19
+ import { RoutineScheduleReceiptStore } from '../agent/routine-schedule-receipts.ts';
20
+ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
21
+ import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken, type ConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
17
22
  import { buildAgentWorkspaceChannels } from './agent-workspace-channels.ts';
23
+ import { getAgentWorkspaceConfigReader } from './agent-workspace-config-reader.ts';
18
24
  import { buildAgentWorkspaceSetupChecklist } from './agent-workspace-setup.ts';
19
25
  import { buildAgentWorkspaceVoiceMediaReadiness, type AgentWorkspaceVoiceMediaProviderDescriptor } from './agent-workspace-voice-media.ts';
20
26
  import type {
21
27
  AgentWorkspaceLocalLibraryItem,
28
+ AgentWorkspaceRoutineScheduleReceiptSummary,
22
29
  AgentWorkspaceRuntimeProfileItem,
23
30
  AgentWorkspaceRuntimeSnapshot,
24
31
  AgentWorkspaceRuntimeStarterTemplateItem,
25
32
  } from './agent-workspace-types.ts';
26
33
 
27
- type AgentWorkspaceConfigReader = {
28
- get(key: string): unknown;
29
- };
30
-
31
34
  function readConfigString(context: CommandContext, key: string, fallback: string): string {
32
35
  try {
33
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
36
+ const configManager = getAgentWorkspaceConfigReader(context);
34
37
  const value = configManager?.get(key);
35
38
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : fallback;
36
39
  } catch {
@@ -40,7 +43,7 @@ function readConfigString(context: CommandContext, key: string, fallback: string
40
43
 
41
44
  function readConfigNumber(context: CommandContext, key: string, fallback: number): number {
42
45
  try {
43
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
46
+ const configManager = getAgentWorkspaceConfigReader(context);
44
47
  const value = configManager?.get(key);
45
48
  const numberValue = typeof value === 'number' ? value : Number(value);
46
49
  return Number.isFinite(numberValue) ? numberValue : fallback;
@@ -51,7 +54,7 @@ function readConfigNumber(context: CommandContext, key: string, fallback: number
51
54
 
52
55
  function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
53
56
  try {
54
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
57
+ const configManager = getAgentWorkspaceConfigReader(context);
55
58
  const value = configManager?.get(key);
56
59
  if (typeof value === 'boolean') return value;
57
60
  if (typeof value === 'string') {
@@ -82,7 +85,7 @@ function summarizePersonaItem(persona: AgentPersonaRecord, activePersonaId: stri
82
85
  name: persona.name,
83
86
  description: persona.description,
84
87
  reviewState: persona.reviewState,
85
- source: persona.source,
88
+ source: formatAgentRecordOrigin(persona.source, persona.provenance),
86
89
  tags: persona.tags,
87
90
  triggers: persona.triggers,
88
91
  active: persona.id === activePersonaId,
@@ -96,7 +99,7 @@ function summarizeSkillItem(skill: AgentSkillRecord): AgentWorkspaceLocalLibrary
96
99
  name: skill.name,
97
100
  description: skill.description,
98
101
  reviewState: skill.reviewState,
99
- source: skill.source,
102
+ source: formatAgentRecordOrigin(skill.source, skill.provenance),
100
103
  tags: skill.tags,
101
104
  triggers: skill.triggers,
102
105
  enabled: skill.enabled,
@@ -117,7 +120,7 @@ function summarizeSkillBundleItem(bundle: AgentSkillBundleRecord, skills: readon
117
120
  name: bundle.name,
118
121
  description: `${bundle.description} Skills: ${bundle.skillIds.join(', ')}`,
119
122
  reviewState: bundle.reviewState,
120
- source: bundle.source,
123
+ source: formatAgentRecordOrigin(bundle.source, bundle.provenance),
121
124
  tags: bundle.skillIds,
122
125
  triggers: [],
123
126
  enabled: bundle.enabled,
@@ -134,7 +137,7 @@ function summarizeRoutineItem(routine: AgentRoutineRecord): AgentWorkspaceLocalL
134
137
  name: routine.name,
135
138
  description: routine.description,
136
139
  reviewState: routine.reviewState,
137
- source: routine.source,
140
+ source: formatAgentRecordOrigin(routine.source, routine.provenance),
138
141
  tags: routine.tags,
139
142
  triggers: routine.triggers,
140
143
  enabled: routine.enabled,
@@ -145,6 +148,21 @@ function summarizeRoutineItem(routine: AgentRoutineRecord): AgentWorkspaceLocalL
145
148
  };
146
149
  }
147
150
 
151
+ function summarizeRoutineScheduleReceipt(
152
+ receipt: ReturnType<RoutineScheduleReceiptStore['snapshot']>['receipts'][number],
153
+ ): AgentWorkspaceRoutineScheduleReceiptSummary {
154
+ return {
155
+ id: receipt.id,
156
+ status: receipt.status,
157
+ routineId: receipt.routineId,
158
+ routineName: receipt.routineName,
159
+ scheduleName: receipt.scheduleName,
160
+ scheduleKind: receipt.scheduleKind,
161
+ scheduleValue: receipt.scheduleValue,
162
+ createdAt: receipt.createdAt,
163
+ };
164
+ }
165
+
148
166
  function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryItem {
149
167
  const detail = record.detail?.trim();
150
168
  return {
@@ -152,7 +170,7 @@ function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryIt
152
170
  name: record.summary,
153
171
  description: detail && detail.length > 0 ? detail : `${record.scope}/${record.cls}`,
154
172
  reviewState: record.reviewState,
155
- source: 'agent-memory',
173
+ source: 'Agent memory',
156
174
  tags: record.tags,
157
175
  triggers: [],
158
176
  scope: record.scope,
@@ -161,6 +179,22 @@ function summarizeMemoryItem(record: MemoryRecord): AgentWorkspaceLocalLibraryIt
161
179
  };
162
180
  }
163
181
 
182
+ function summarizeNoteItem(note: AgentNoteRecord): AgentWorkspaceLocalLibraryItem {
183
+ const preview = note.body.replace(/\s+/g, ' ').trim();
184
+ const description = note.sourceUrl
185
+ ? `${preview.slice(0, 160)}${preview.length > 160 ? '...' : ''} Origin URL ${note.sourceUrl}`
186
+ : preview;
187
+ return {
188
+ id: note.id,
189
+ name: note.title,
190
+ description,
191
+ reviewState: note.reviewState,
192
+ source: formatAgentRecordOrigin(note.source, note.provenance),
193
+ tags: note.tags,
194
+ triggers: [],
195
+ };
196
+ }
197
+
164
198
  function summarizeRuntimeProfile(profile: ReturnType<typeof listAgentRuntimeProfiles>[number]): AgentWorkspaceRuntimeProfileItem {
165
199
  return {
166
200
  id: profile.id,
@@ -231,6 +265,20 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
231
265
  return { count: 0, activeName: '(unavailable)', items: [] };
232
266
  }
233
267
  })();
268
+ const noteSnapshot = (() => {
269
+ try {
270
+ const shellPaths = context.workspace?.shellPaths;
271
+ if (!shellPaths) return { count: 0, reviewQueueCount: 0, items: [] };
272
+ const snapshot = AgentNoteRegistry.fromShellPaths(shellPaths).snapshot();
273
+ return {
274
+ count: snapshot.notes.length,
275
+ reviewQueueCount: snapshot.reviewQueue.length,
276
+ items: snapshot.notes.map(summarizeNoteItem),
277
+ };
278
+ } catch {
279
+ return { count: 0, reviewQueueCount: 0, items: [] };
280
+ }
281
+ })();
234
282
  const skillSnapshot = (() => {
235
283
  try {
236
284
  const shellPaths = context.workspace?.shellPaths;
@@ -263,6 +311,21 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
263
311
  return { count: 0, enabled: 0, items: [] };
264
312
  }
265
313
  })();
314
+ const routineScheduleReceipts = (() => {
315
+ try {
316
+ const shellPaths = context.workspace?.shellPaths;
317
+ if (!shellPaths) return { count: 0, successful: 0, failed: 0, latest: null };
318
+ const receipts = RoutineScheduleReceiptStore.fromShellPaths(shellPaths).snapshot().receipts;
319
+ return {
320
+ count: receipts.length,
321
+ successful: receipts.filter((receipt) => receipt.status === 'created').length,
322
+ failed: receipts.filter((receipt) => receipt.status === 'failed').length,
323
+ latest: receipts[0] ? summarizeRoutineScheduleReceipt(receipts[0]) : null,
324
+ };
325
+ } catch {
326
+ return { count: 0, successful: 0, failed: 0, latest: null };
327
+ }
328
+ })();
266
329
  const discoveredBehavior = summarizeAgentBehaviorDiscovery(context.workspace?.shellPaths);
267
330
  const profileBaseHome = inferRuntimeProfileBaseHome(context.workspace?.shellPaths?.homeDirectory ?? '');
268
331
  const runtimeProfiles = (() => {
@@ -336,6 +399,32 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
336
399
  const ttsLlmProvider = readConfigString(context, 'tts.llmProvider', '');
337
400
  const ttsLlmModel = readConfigString(context, 'tts.llmModel', '');
338
401
  const runtimeBaseUrl = `http://${host}:${port}`;
402
+ const companionAccess = (() => {
403
+ const homeDirectory = context.workspace?.shellPaths?.homeDirectory ?? '';
404
+ const tokenRecord: ConnectedHostOperatorToken = homeDirectory.length > 0
405
+ ? readConnectedHostOperatorToken(homeDirectory)
406
+ : { path: '(Agent home unavailable)', present: false, token: null };
407
+ const tokenFingerprint = tokenRecord.token ? connectedHostOperatorTokenFingerprint(tokenRecord.token) : null;
408
+ const pairingReady = Boolean(tokenRecord.token);
409
+ const nextStep = tokenRecord.error
410
+ ? 'Repair the connected-host operator token file through the owning GoodVibes host, then rerun /pair.'
411
+ : pairingReady
412
+ ? 'Use /pair to scan the QR code. Manual token display stays hidden unless /pair --show-token --yes is used.'
413
+ : 'Pair or provision connected-host access through the owning GoodVibes host, then rerun /pair.';
414
+ return {
415
+ surface: GOODVIBES_AGENT_PAIRING_SURFACE,
416
+ hostUrl: runtimeBaseUrl,
417
+ tokenPath: tokenRecord.path,
418
+ tokenPresent: tokenRecord.present,
419
+ tokenReadable: Boolean(tokenRecord.token),
420
+ tokenFingerprint,
421
+ tokenError: tokenRecord.error ?? null,
422
+ pairingReady,
423
+ qrCommand: '/pair',
424
+ manualTokenCommand: '/pair --show-token --yes',
425
+ nextStep,
426
+ } as const;
427
+ })();
339
428
  const channels = buildAgentWorkspaceChannels(context);
340
429
  const voiceMediaReadiness = buildAgentWorkspaceVoiceMediaReadiness({
341
430
  context,
@@ -349,6 +438,8 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
349
438
  sessionMemoryCount,
350
439
  localMemoryCount: memorySnapshot.count,
351
440
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
441
+ localNoteCount: noteSnapshot.count,
442
+ localNoteReviewQueueCount: noteSnapshot.reviewQueueCount,
352
443
  routineCount: routineSnapshot.count,
353
444
  enabledRoutineCount: routineSnapshot.enabled,
354
445
  missingRoutineRequirementCount: routineSnapshot.items.reduce((total, item) => total + (item.missingRequirementCount ?? 0), 0),
@@ -382,9 +473,16 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
382
473
  localMemoryReviewQueueCount: memorySnapshot.reviewQueueCount,
383
474
  localMemoryPromptActiveCount: memorySnapshot.promptActiveCount,
384
475
  localMemories: memorySnapshot.items,
476
+ localNoteCount: noteSnapshot.count,
477
+ localNoteReviewQueueCount: noteSnapshot.reviewQueueCount,
478
+ localNotes: noteSnapshot.items,
385
479
  localRoutineCount: routineSnapshot.count,
386
480
  enabledRoutineCount: routineSnapshot.enabled,
387
481
  localRoutines: routineSnapshot.items,
482
+ routineScheduleReceiptCount: routineScheduleReceipts.count,
483
+ successfulRoutineScheduleReceiptCount: routineScheduleReceipts.successful,
484
+ failedRoutineScheduleReceiptCount: routineScheduleReceipts.failed,
485
+ latestRoutineScheduleReceipt: routineScheduleReceipts.latest,
388
486
  localSkillCount: skillSnapshot.count,
389
487
  enabledSkillCount: skillSnapshot.enabled,
390
488
  localSkillBundleCount: skillSnapshot.bundleCount,
@@ -399,7 +497,8 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
399
497
  knowledgeRoute: '/api/goodvibes-agent/knowledge',
400
498
  knowledgeIsolation: 'agent-only',
401
499
  executionPolicy: 'serial-proactive',
402
- wrfcPolicy: 'explicit-build-delegation-only',
500
+ delegatedReviewPolicy: 'explicit-build-delegation-only',
501
+ companionAccess,
403
502
  channels,
404
503
  voiceProviderCount: voiceProviders.length,
405
504
  voiceStreamingProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('tts-stream')).length,
@@ -14,7 +14,7 @@ export function createAgentWorkspaceTaskCommandEditor(kind: AgentWorkspaceTaskCo
14
14
  return {
15
15
  kind,
16
16
  mode: 'create',
17
- title: 'Filter Runtime Tasks',
17
+ title: 'Filter Host Tasks',
18
18
  selectedFieldIndex: 0,
19
19
  message: 'List connected-host tasks filtered by status or kind. This is read-only and never creates, retries, or cancels tasks.',
20
20
  fields: [
@@ -30,18 +30,18 @@ export function createAgentWorkspaceTaskCommandEditor(kind: AgentWorkspaceTaskCo
30
30
  selectedFieldIndex: 0,
31
31
  message: 'Print one connected-host task output from the Agent workspace. This is read-only and does not retry, cancel, or mutate the task.',
32
32
  fields: [
33
- { id: 'taskId', label: 'Task id', value: '', required: true, multiline: false, hint: 'Connected-host task id from Runtime tasks.' },
33
+ { id: 'taskId', label: 'Task id', value: '', required: true, multiline: false, hint: 'Connected-host task id from Host tasks.' },
34
34
  ],
35
35
  };
36
36
  }
37
37
  return {
38
38
  kind,
39
39
  mode: 'create',
40
- title: 'Inspect Runtime Task',
40
+ title: 'Inspect Host Task',
41
41
  selectedFieldIndex: 0,
42
42
  message: 'Inspect one connected-host task from the Agent workspace. This is read-only and does not retry, cancel, or mutate the task.',
43
43
  fields: [
44
- { id: 'taskId', label: 'Task id', value: '', required: true, multiline: false, hint: 'Connected-host task id from Runtime tasks.' },
44
+ { id: 'taskId', label: 'Task id', value: '', required: true, multiline: false, hint: 'Connected-host task id from Host tasks.' },
45
45
  ],
46
46
  };
47
47
  }
@@ -25,11 +25,25 @@ export function handleAgentWorkspaceToken(
25
25
  }
26
26
 
27
27
  if (token.type === 'key') {
28
+ if (workspace.actionSearchActive) {
29
+ if (token.logicalName === 'escape') workspace.clearActionSearch();
30
+ else if (token.logicalName === 'enter') workspace.activateSelected(requestRender);
31
+ else if (token.logicalName === 'up') workspace.moveUp();
32
+ else if (token.logicalName === 'down') workspace.moveDown();
33
+ else if (token.logicalName === 'home') workspace.jumpHome();
34
+ else if (token.logicalName === 'end') workspace.jumpEnd();
35
+ else if (token.logicalName === 'backspace' || token.logicalName === 'delete') workspace.actionSearchBackspace();
36
+ else if (token.logicalName === 'space') workspace.appendActionSearchText(' ');
37
+ requestRender();
38
+ return true;
39
+ }
28
40
  if (token.logicalName === 'escape') {
29
41
  handleEscape();
30
42
  return true;
31
43
  }
32
- if (token.logicalName === 'enter' || token.logicalName === 'space') workspace.activateSelected(requestRender);
44
+ if (token.ctrl === true && token.logicalName === ']') workspace.cycleCategory('next');
45
+ else if (token.ctrl === true && token.logicalName === '[') workspace.cycleCategory('prev');
46
+ else if (token.logicalName === 'enter' || token.logicalName === 'space') workspace.activateSelected(requestRender);
33
47
  else if (token.logicalName === 'left') workspace.focusCategories();
34
48
  else if (token.logicalName === 'right') workspace.focusActions();
35
49
  else if (token.logicalName === 'up') workspace.moveUp();
@@ -38,7 +52,9 @@ export function handleAgentWorkspaceToken(
38
52
  else if (token.logicalName === 'home') workspace.jumpHome();
39
53
  else if (token.logicalName === 'end') workspace.jumpEnd();
40
54
  } else if (token.type === 'text') {
41
- if (token.value === 'h') workspace.focusCategories();
55
+ if (workspace.actionSearchActive) workspace.appendActionSearchText(token.value);
56
+ else if (token.value === '/') workspace.beginActionSearch();
57
+ else if (token.value === 'h') workspace.focusCategories();
42
58
  else if (token.value === 'l') workspace.focusActions();
43
59
  else if (token.value === 'j') workspace.moveDown();
44
60
  else if (token.value === 'k') workspace.moveUp();
@@ -7,12 +7,38 @@ export const AGENT_WORKSPACE_MODAL_NAME = 'agentWorkspace';
7
7
 
8
8
  export type AgentWorkspaceFocusPane = 'categories' | 'actions';
9
9
 
10
+ export const AGENT_WORKSPACE_CATEGORY_IDS = [
11
+ 'home',
12
+ 'setup',
13
+ 'research',
14
+ 'artifacts',
15
+ 'conversation',
16
+ 'channels',
17
+ 'tools',
18
+ 'knowledge',
19
+ 'voice-media',
20
+ 'profiles',
21
+ 'memory',
22
+ 'notes',
23
+ 'personas',
24
+ 'skills',
25
+ 'routines',
26
+ 'work',
27
+ 'host',
28
+ 'automation',
29
+ 'delegate',
30
+ ] as const;
31
+
32
+ export type AgentWorkspaceCategoryId = (typeof AGENT_WORKSPACE_CATEGORY_IDS)[number];
33
+
10
34
  export type AgentWorkspaceActionKind = 'command' | 'guidance' | 'workspace' | 'editor' | 'local-selection' | 'local-operation';
11
35
 
12
- export type AgentWorkspaceLocalEditorKind = 'memory' | 'persona' | 'skill' | 'routine' | 'profile';
36
+ export type AgentWorkspaceLocalEditorKind = 'memory' | 'note' | 'persona' | 'skill' | 'routine' | 'profile';
13
37
 
14
38
  export type AgentWorkspaceEditorKind =
15
39
  | AgentWorkspaceLocalEditorKind
40
+ | 'web-research'
41
+ | 'web-fetch'
16
42
  | 'knowledge-url'
17
43
  | 'knowledge-urls'
18
44
  | 'knowledge-file'
@@ -55,12 +81,14 @@ export type AgentWorkspaceEditorKind =
55
81
  | 'notify-webhook-remove'
56
82
  | 'notify-webhook-clear'
57
83
  | 'notify-webhook-test'
84
+ | 'notify-send'
58
85
  | 'secret-set'
59
86
  | 'secret-link'
60
87
  | 'secret-test'
61
88
  | 'secret-delete'
62
89
  | 'tts-prompt'
63
90
  | 'image-input'
91
+ | 'media-generate'
64
92
  | 'skill-bundle'
65
93
  | 'skill-bundle-search'
66
94
  | 'skill-bundle-show'
@@ -116,6 +144,7 @@ export type AgentWorkspaceEditorKind =
116
144
  | 'channel-show'
117
145
  | 'channel-doctor'
118
146
  | 'channel-setup'
147
+ | 'channel-send'
119
148
  | 'session-save'
120
149
  | 'session-load'
121
150
  | 'session-rename'
@@ -135,6 +164,15 @@ export type AgentWorkspaceEditorKind =
135
164
  | 'plan-clear'
136
165
  | 'health-repair'
137
166
  | 'approval-review'
167
+ | 'approval-approve'
168
+ | 'approval-deny'
169
+ | 'approval-cancel'
170
+ | 'automation-job-run'
171
+ | 'automation-job-pause'
172
+ | 'automation-job-resume'
173
+ | 'automation-run-cancel'
174
+ | 'automation-run-retry'
175
+ | 'schedule-run'
138
176
  | 'routine-receipt'
139
177
  | 'schedule-receipt'
140
178
  | 'mode-preset'
@@ -155,6 +193,15 @@ export type AgentWorkspaceLocalOperation =
155
193
  | 'memory-review'
156
194
  | 'memory-stale'
157
195
  | 'memory-delete'
196
+ | 'note-edit'
197
+ | 'note-review'
198
+ | 'note-stale'
199
+ | 'note-delete'
200
+ | 'note-promote-memory'
201
+ | 'note-promote-persona'
202
+ | 'note-promote-skill'
203
+ | 'note-promote-routine'
204
+ | 'note-promote-knowledge-url'
158
205
  | 'persona-edit'
159
206
  | 'persona-use'
160
207
  | 'persona-review'
@@ -197,7 +244,7 @@ export interface AgentWorkspaceAction {
197
244
  readonly label: string;
198
245
  readonly detail: string;
199
246
  readonly command?: string;
200
- readonly targetCategoryId?: string;
247
+ readonly targetCategoryId?: AgentWorkspaceCategoryId;
201
248
  readonly editorKind?: AgentWorkspaceEditorKind;
202
249
  readonly localKind?: AgentWorkspaceLocalEditorKind;
203
250
  readonly selectionDelta?: number;
@@ -207,7 +254,7 @@ export interface AgentWorkspaceAction {
207
254
  }
208
255
 
209
256
  export interface AgentWorkspaceCategory {
210
- readonly id: string;
257
+ readonly id: AgentWorkspaceCategoryId;
211
258
  readonly group: string;
212
259
  readonly label: string;
213
260
  readonly summary: string;
@@ -215,7 +262,15 @@ export interface AgentWorkspaceCategory {
215
262
  readonly actions: readonly AgentWorkspaceAction[];
216
263
  }
217
264
 
265
+ export interface AgentWorkspaceActionSearchResult {
266
+ readonly category: AgentWorkspaceCategory;
267
+ readonly categoryIndex: number;
268
+ readonly action: AgentWorkspaceAction;
269
+ readonly actionIndex: number;
270
+ }
271
+
218
272
  export type AgentWorkspaceCommandDispatcher = (command: string) => void;
273
+ export type AgentWorkspacePromptDispatcher = (prompt: string) => void;
219
274
 
220
275
  export type AgentWorkspaceActionResultKind = 'guidance' | 'blocked' | 'dispatched' | 'refreshed' | 'error';
221
276
 
@@ -264,6 +319,31 @@ export interface AgentWorkspaceRuntimeStarterTemplateItem {
264
319
  readonly source: string;
265
320
  }
266
321
 
322
+ export interface AgentWorkspaceRoutineScheduleReceiptSummary {
323
+ readonly id: string;
324
+ readonly status: string;
325
+ readonly routineId: string;
326
+ readonly routineName: string;
327
+ readonly scheduleName: string;
328
+ readonly scheduleKind: string;
329
+ readonly scheduleValue: string;
330
+ readonly createdAt: string;
331
+ }
332
+
333
+ export interface AgentWorkspaceCompanionAccessSummary {
334
+ readonly surface: 'goodvibes-agent';
335
+ readonly hostUrl: string;
336
+ readonly tokenPath: string;
337
+ readonly tokenPresent: boolean;
338
+ readonly tokenReadable: boolean;
339
+ readonly tokenFingerprint: string | null;
340
+ readonly tokenError: string | null;
341
+ readonly pairingReady: boolean;
342
+ readonly qrCommand: '/pair';
343
+ readonly manualTokenCommand: '/pair --show-token --yes';
344
+ readonly nextStep: string;
345
+ }
346
+
267
347
  export interface AgentWorkspaceRuntimeSnapshot {
268
348
  readonly provider: string;
269
349
  readonly model: string;
@@ -278,9 +358,16 @@ export interface AgentWorkspaceRuntimeSnapshot {
278
358
  readonly localMemoryReviewQueueCount: number;
279
359
  readonly localMemoryPromptActiveCount: number;
280
360
  readonly localMemories: readonly AgentWorkspaceLocalLibraryItem[];
361
+ readonly localNoteCount: number;
362
+ readonly localNoteReviewQueueCount: number;
363
+ readonly localNotes: readonly AgentWorkspaceLocalLibraryItem[];
281
364
  readonly localRoutineCount: number;
282
365
  readonly enabledRoutineCount: number;
283
366
  readonly localRoutines: readonly AgentWorkspaceLocalLibraryItem[];
367
+ readonly routineScheduleReceiptCount: number;
368
+ readonly successfulRoutineScheduleReceiptCount: number;
369
+ readonly failedRoutineScheduleReceiptCount: number;
370
+ readonly latestRoutineScheduleReceipt: AgentWorkspaceRoutineScheduleReceiptSummary | null;
284
371
  readonly localSkillCount: number;
285
372
  readonly enabledSkillCount: number;
286
373
  readonly localSkillBundleCount: number;
@@ -295,7 +382,8 @@ export interface AgentWorkspaceRuntimeSnapshot {
295
382
  readonly knowledgeRoute: '/api/goodvibes-agent/knowledge';
296
383
  readonly knowledgeIsolation: 'agent-only';
297
384
  readonly executionPolicy: 'serial-proactive';
298
- readonly wrfcPolicy: 'explicit-build-delegation-only';
385
+ readonly delegatedReviewPolicy: 'explicit-build-delegation-only';
386
+ readonly companionAccess: AgentWorkspaceCompanionAccessSummary;
299
387
  readonly channels: readonly AgentWorkspaceChannelStatus[];
300
388
  readonly voiceProviderCount: number;
301
389
  readonly voiceStreamingProviderCount: number;
@@ -1,4 +1,5 @@
1
1
  import type { CommandContext } from './command-registry.ts';
2
+ import { getAgentWorkspaceConfigReader } from './agent-workspace-config-reader.ts';
2
3
 
3
4
  export type AgentWorkspaceVoiceMediaDomain = 'voice' | 'media';
4
5
  export type AgentWorkspaceVoiceMediaSetupState = 'ready' | 'registered' | 'needs-secret' | 'not-registered';
@@ -36,10 +37,6 @@ export interface AgentWorkspaceVoiceMediaReadiness {
36
37
  readonly nextSteps: readonly string[];
37
38
  }
38
39
 
39
- type AgentWorkspaceConfigReader = {
40
- get(key: string): unknown;
41
- };
42
-
43
40
  type ProviderSecretSpec = {
44
41
  readonly id: string;
45
42
  readonly secretKeyOptions: readonly string[];
@@ -66,7 +63,7 @@ const MEDIA_SECRET_SPECS: readonly ProviderSecretSpec[] = [
66
63
 
67
64
  function readConfigString(context: CommandContext, key: string, fallback: string): string {
68
65
  try {
69
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
66
+ const configManager = getAgentWorkspaceConfigReader(context);
70
67
  const value = configManager?.get(key);
71
68
  return typeof value === 'string' && value.trim().length > 0 ? value.trim() : fallback;
72
69
  } catch {
@@ -76,7 +73,7 @@ function readConfigString(context: CommandContext, key: string, fallback: string
76
73
 
77
74
  function readConfigBoolean(context: CommandContext, key: string, fallback: boolean): boolean {
78
75
  try {
79
- const configManager = context.platform?.configManager as unknown as AgentWorkspaceConfigReader | undefined;
76
+ const configManager = getAgentWorkspaceConfigReader(context);
80
77
  const value = configManager?.get(key);
81
78
  if (typeof value === 'boolean') return value;
82
79
  if (typeof value === 'string') {
@@ -0,0 +1,104 @@
1
+ import type { AgentWorkspaceActionResult, AgentWorkspaceLocalEditor } from './agent-workspace-types.ts';
2
+
3
+ type AgentWorkspaceFieldReader = (fieldId: string) => string;
4
+ export type AgentWorkspaceWebResearchMode = 'research' | 'fetch';
5
+
6
+ export type AgentWorkspaceWebResearchSubmission =
7
+ | {
8
+ readonly kind: 'editor';
9
+ readonly editor: AgentWorkspaceLocalEditor;
10
+ readonly status: string;
11
+ readonly actionResult?: AgentWorkspaceActionResult;
12
+ }
13
+ | {
14
+ readonly kind: 'prompt';
15
+ readonly prompt: string;
16
+ readonly status: string;
17
+ readonly actionResult: AgentWorkspaceActionResult;
18
+ };
19
+
20
+ export function createAgentWorkspaceWebResearchEditor(mode: AgentWorkspaceWebResearchMode): AgentWorkspaceLocalEditor {
21
+ if (mode === 'fetch') {
22
+ return {
23
+ kind: 'web-fetch',
24
+ mode: 'create',
25
+ title: 'Fetch or Inspect URL',
26
+ selectedFieldIndex: 0,
27
+ message: 'Submit a normal Agent conversation turn that inspects one URL with connected read-only web tools. This does not ingest the URL into Agent Knowledge unless you explicitly ask for that.',
28
+ fields: [
29
+ { id: 'url', label: 'URL', value: '', required: true, multiline: false, hint: 'https://example.com/page' },
30
+ { id: 'goal', label: 'Question or goal', value: '', required: false, multiline: true, hint: 'What should Agent extract, compare, summarize, or verify? Ctrl-J inserts a new line.' },
31
+ ],
32
+ };
33
+ }
34
+ return {
35
+ kind: 'web-research',
36
+ mode: 'create',
37
+ title: 'Web Research Request',
38
+ selectedFieldIndex: 0,
39
+ message: 'Submit a normal Agent conversation turn that searches or reads the web through connected read-only tools. Agent should answer in the main conversation and remember only durable facts that belong in Agent memory.',
40
+ fields: [
41
+ { id: 'query', label: 'Research request', value: '', required: true, multiline: true, hint: 'Ask for the outcome you want, not just keywords. Ctrl-J inserts a new line.' },
42
+ { id: 'scope', label: 'Source or freshness hints', value: '', required: false, multiline: false, hint: 'Optional filters such as official docs only, last 30 days, primary sources, or compare products.' },
43
+ ],
44
+ };
45
+ }
46
+
47
+ export function buildAgentWorkspaceWebResearchSubmission(
48
+ editor: AgentWorkspaceLocalEditor,
49
+ readField: AgentWorkspaceFieldReader,
50
+ promptDispatchAvailable: boolean,
51
+ ): AgentWorkspaceWebResearchSubmission {
52
+ if (!promptDispatchAvailable) {
53
+ return {
54
+ kind: 'editor',
55
+ editor: { ...editor, message: 'Main-conversation submission is unavailable; cannot send this request from the workspace.' },
56
+ status: 'Main-conversation submission unavailable.',
57
+ actionResult: {
58
+ kind: 'error',
59
+ title: 'Conversation submission unavailable',
60
+ detail: 'The Agent workspace cannot hand this request back to the main conversation route.',
61
+ },
62
+ };
63
+ }
64
+
65
+ if (editor.kind === 'web-fetch') {
66
+ const url = readField('url');
67
+ const goal = readField('goal');
68
+ const prompt = [
69
+ `Use connected read-only web tools to inspect this URL: ${url}`,
70
+ goal.length > 0 ? `Goal: ${goal}` : 'Goal: summarize the useful facts, source title, and any caveats.',
71
+ 'Do not ingest this into Agent Knowledge unless I explicitly ask you to.',
72
+ ].join('\n');
73
+ return {
74
+ kind: 'prompt',
75
+ prompt,
76
+ status: 'Submitting URL inspection to the main conversation.',
77
+ actionResult: {
78
+ kind: 'dispatched',
79
+ title: 'Submitting URL inspection',
80
+ detail: 'The workspace closed and handed a read-only URL inspection request to the normal Agent conversation.',
81
+ safety: 'read-only',
82
+ },
83
+ };
84
+ }
85
+
86
+ const query = readField('query');
87
+ const scope = readField('scope');
88
+ const prompt = [
89
+ `Use connected read-only web tools to research this request: ${query}`,
90
+ scope.length > 0 ? `Source and freshness guidance: ${scope}` : 'Prefer current, primary, or official sources when they are available.',
91
+ 'Answer in the main conversation. Do not ingest sources into Agent Knowledge unless I explicitly ask you to.',
92
+ ].join('\n');
93
+ return {
94
+ kind: 'prompt',
95
+ prompt,
96
+ status: 'Submitting web research to the main conversation.',
97
+ actionResult: {
98
+ kind: 'dispatched',
99
+ title: 'Submitting web research',
100
+ detail: 'The workspace closed and handed a read-only web research request to the normal Agent conversation.',
101
+ safety: 'read-only',
102
+ },
103
+ };
104
+ }