@pellux/goodvibes-agent 0.1.31 → 0.1.32

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to GoodVibes Agent will be recorded here.
4
4
 
5
+ ## 0.1.32 - 2026-05-31
6
+
7
+ - 8af3cbd Add voice media node workspace coverage
8
+
5
9
  ## 0.1.31 - 2026-05-31
6
10
 
7
11
  - 2bc4887 Expand Agent Knowledge workspace flows
@@ -55,7 +55,7 @@ Primary sources used for the benchmark:
55
55
  | Skills/procedural memory | Skills directories, registries, skill lifecycle | Local Agent skills with review/stale/source/provenance fields |
56
56
  | Scheduling | Natural-language cron, run/pause/resume/edit/remove, delivery | Guarded automation/schedule routes plus local routines; hidden model scheduling blocked |
57
57
  | Tools/MCP | Broad toolsets, MCP, browser, media, terminal, files | GoodVibes SDK tools with Agent policy guards and MCP/provider integrations |
58
- | Voice/media/canvas/nodes | Voice, TTS, mobile nodes, live canvas, browser automation | GoodVibes media/voice/browser primitives copied in; Agent-first setup still being wired |
58
+ | Voice/media/canvas/nodes | Voice, TTS, mobile nodes, live canvas, browser automation | GoodVibes media/voice/browser/node primitives with an Agent workspace for setup, image input, browser posture, MCP, and remote/node inspection |
59
59
  | Build/code work | Direct terminal/file/code tools and subagents | Explicit delegation to GoodVibes TUI; local WRFC/spawn fanout blocked |
60
60
  | Profiles | Independent profiles with own config/memory/skills/gateway | `GOODVIBES_AGENT_HOME` and named `--agent-profile` homes isolate Agent-local state; daemon remains external |
61
61
  | Security | DM pairing, approvals, sandboxing, allowlists | Daemon approvals, auth diagnostics, secret refs, confirmation gates, model-tool policy |
@@ -76,7 +76,7 @@ GoodVibes Agent should exceed OpenClaw/Hermes by making these properties true fr
76
76
  - Live daemon account health and last delivery errors in the Channels workspace once a stable read-only route is available.
77
77
  - Artifact and multimodal Agent Knowledge ingest affordances once Agent-specific routes are stable.
78
78
  - Profile-aware onboarding summaries and profile export/import shortcuts from the Agent workspace.
79
- - Voice/media/browser/node setup workspaces.
79
+ - Artifact and multimodal Agent Knowledge ingestion when the isolated Agent route accepts artifact-backed media.
80
80
  - Delegation receipts and artifact review inside the operator workspace.
81
81
  - Approval center with route risk labels and saved policy presets.
82
82
  - Intent-gated tool exposure so the model sees fewer irrelevant tools per turn while retaining broad capability coverage.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-agent",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "private": false,
5
5
  "description": "Near-fork GoodVibes operator assistant with the GoodVibes TUI shell, renderer, input, fullscreen workspace, and daemon-connected Agent product brain.",
6
6
  "type": "module",
@@ -79,6 +79,19 @@ export interface AgentWorkspaceRuntimeSnapshot {
79
79
  readonly executionPolicy: 'serial-proactive';
80
80
  readonly wrfcPolicy: 'explicit-build-delegation-only';
81
81
  readonly channels: readonly AgentWorkspaceChannelStatus[];
82
+ readonly voiceProviderCount: number;
83
+ readonly voiceStreamingProviderCount: number;
84
+ readonly voiceSttProviderCount: number;
85
+ readonly voiceRealtimeProviderCount: number;
86
+ readonly ttsProvider: string;
87
+ readonly ttsVoice: string;
88
+ readonly ttsResponseModel: string;
89
+ readonly voiceSurfaceEnabled: boolean;
90
+ readonly mediaProviderCount: number;
91
+ readonly mediaUnderstandingProviderCount: number;
92
+ readonly mediaGenerationProviderCount: number;
93
+ readonly browserSurfaceEnabled: boolean;
94
+ readonly browserSurfacePublicBaseUrl: string;
82
95
  readonly warnings: readonly string[];
83
96
  }
84
97
 
@@ -340,9 +353,27 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
340
353
  return { count: 0, enabled: 0 };
341
354
  }
342
355
  })();
356
+ const voiceProviders = (() => {
357
+ try {
358
+ return context.platform?.voiceProviderRegistry?.list?.() ?? [];
359
+ } catch {
360
+ return [];
361
+ }
362
+ })();
363
+ const mediaProviders = (() => {
364
+ try {
365
+ return context.platform?.mediaProviderRegistry?.list?.() ?? [];
366
+ } catch {
367
+ return [];
368
+ }
369
+ })();
343
370
  const warnings: string[] = [];
344
371
  if (provider === 'unknown' || model === 'unknown') warnings.push('Provider/model unavailable in this runtime context.');
345
372
  if (!context.executeCommand) warnings.push('Command dispatch is unavailable; workspace actions will show guidance only.');
373
+ const ttsProvider = readConfigString(context, 'tts.provider', '(provider default)');
374
+ const ttsVoice = readConfigString(context, 'tts.voice', '(voice default)');
375
+ const ttsLlmProvider = readConfigString(context, 'tts.llmProvider', '');
376
+ const ttsLlmModel = readConfigString(context, 'tts.llmModel', '');
346
377
 
347
378
  return {
348
379
  provider,
@@ -365,6 +396,19 @@ export function buildAgentWorkspaceRuntimeSnapshot(context: CommandContext): Age
365
396
  executionPolicy: 'serial-proactive',
366
397
  wrfcPolicy: 'explicit-build-delegation-only',
367
398
  channels: AGENT_WORKSPACE_CHANNEL_SPECS.map((spec) => buildChannelStatus(context, spec)),
399
+ voiceProviderCount: voiceProviders.length,
400
+ voiceStreamingProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('tts-stream')).length,
401
+ voiceSttProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('stt')).length,
402
+ voiceRealtimeProviderCount: voiceProviders.filter((entry) => entry.capabilities.includes('realtime')).length,
403
+ ttsProvider,
404
+ ttsVoice,
405
+ ttsResponseModel: ttsLlmProvider && ttsLlmModel ? `${ttsLlmProvider}/${ttsLlmModel}` : '(chat route)',
406
+ voiceSurfaceEnabled: readConfigBoolean(context, 'ui.voiceEnabled', false),
407
+ mediaProviderCount: mediaProviders.length,
408
+ mediaUnderstandingProviderCount: mediaProviders.filter((entry) => entry.capabilities.includes('understand')).length,
409
+ mediaGenerationProviderCount: mediaProviders.filter((entry) => entry.capabilities.includes('generate')).length,
410
+ browserSurfaceEnabled: readConfigBoolean(context, 'web.enabled', false),
411
+ browserSurfacePublicBaseUrl: readConfigString(context, 'web.publicBaseUrl', '(not configured)'),
368
412
  warnings,
369
413
  };
370
414
  }
@@ -425,6 +469,22 @@ export const AGENT_WORKSPACE_CATEGORIES: readonly AgentWorkspaceCategory[] = [
425
469
  { id: 'knowledge-ask', label: 'Ask Agent knowledge', detail: 'Close this workspace and run /knowledge ask <question> or ask normally in chat.', kind: 'guidance', safety: 'read-only' },
426
470
  ],
427
471
  },
472
+ {
473
+ id: 'voice-media',
474
+ group: 'SETUP',
475
+ label: 'Voice, Media & Nodes',
476
+ summary: 'Voice, TTS, image input, browser surface, and node/remote posture.',
477
+ detail: 'Hermes and OpenClaw expose voice, media, browser, and node surfaces as first-class operator capabilities. Agent uses the GoodVibes voice/media/provider/browser/remote bones while keeping daemon ownership external and side effects explicit.',
478
+ actions: [
479
+ { id: 'tts-config', label: 'Configure live TTS', detail: 'Open the TUI-derived config workspace at the TTS settings group.', command: '/config tts', kind: 'command', safety: 'safe' },
480
+ { id: 'tts-provider', label: 'Choose TTS provider', detail: 'Open provider/model routing for spoken responses through the settings flow.', command: '/config tts.provider', kind: 'command', safety: 'safe' },
481
+ { id: 'tts-speak', label: 'Speak a prompt', detail: 'Submit a normal assistant turn and play the reply through configured live TTS. Close this workspace and provide real prompt text.', command: '/tts <prompt>', kind: 'command', safety: 'safe' },
482
+ { id: 'image-attach', label: 'Attach image input', detail: 'Attach an image to the next assistant turn. Close this workspace and provide a real path and prompt.', command: '/image <path> <prompt>', kind: 'command', safety: 'safe' },
483
+ { id: 'browser-surface', label: 'Browser surface status', detail: 'Inspect browser/web posture through setup diagnostics without starting listeners or daemon services.', command: '/setup services', kind: 'command', safety: 'read-only' },
484
+ { id: 'mcp-browser', label: 'Browser MCP tools', detail: 'Inspect MCP servers and tools, including browser/automation roles, without mutating server setup.', command: '/mcp servers', kind: 'command', safety: 'read-only' },
485
+ { id: 'node-posture', label: 'Node/remote posture', detail: 'Inspect remote runner/node posture. Dispatch remains blocked unless the task is explicit build delegation to TUI.', command: '/remote list', kind: 'command', safety: 'read-only' },
486
+ ],
487
+ },
428
488
  {
429
489
  id: 'memory',
430
490
  group: 'LEARN',
@@ -20,6 +20,7 @@ import type { OperatorClient } from '@/runtime/index.ts';
20
20
  import type { PeerClient } from '@/runtime/index.ts';
21
21
  import type { DirectTransport } from '@/runtime/index.ts';
22
22
  import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
23
+ import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media';
23
24
  import type {
24
25
  CommandWorkspaceShellServices,
25
26
  } from '@/runtime/index.ts';
@@ -163,6 +164,7 @@ export interface CommandPlatformConfigServices {
163
164
  readonly configManager: ConfigManager;
164
165
  readonly voiceProviderRegistry?: VoiceProviderRegistry;
165
166
  readonly voiceService?: VoiceService;
167
+ readonly mediaProviderRegistry?: MediaProviderRegistry;
166
168
  }
167
169
 
168
170
  export interface CommandPlatformServices
@@ -256,7 +258,7 @@ export class CommandRegistry {
256
258
  }
257
259
 
258
260
  /**
259
- * get - Look up a command by its primary name or any alias. O(1) for both.
261
+ * get - Look up a command by its primary name or alias. O(1) for both.
260
262
  */
261
263
  get(name: string): SlashCommand | undefined {
262
264
  return this.commands.get(name) ?? this.aliasIndex.get(name);
@@ -133,14 +133,14 @@ export const OPERATOR_CAPABILITY_BENCHMARKS: readonly OperatorCapabilityBenchmar
133
133
  {
134
134
  id: 'voice-media-canvas',
135
135
  title: 'Voice, Media, Canvas, And Nodes',
136
- posture: 'in-progress',
136
+ posture: 'configurable',
137
137
  competitors: ['openclaw', 'hermes'],
138
138
  competitorBaseline: 'Voice/TTS, mobile nodes, live canvas, browser automation, image/video generation, and multimodal analysis.',
139
- goodvibesAgent: 'Carries GoodVibes voice/media/browser/node primitives, but Agent-first setup and canvas/workspace UX still needs product wiring.',
140
- configure: ['/tts status', '/provider media', '/agent'],
141
- use: ['/tts speak <text>', '/image', '/media'],
142
- exceedsBy: ['Shared GoodVibes media/provider substrate', 'future fullscreen workspaces can make setup inspectable and reversible'],
143
- next: ['Implement Agent setup workspaces for voice, media, browser, and node surfaces with capability tests and non-leaky credential handling.'],
139
+ goodvibesAgent: 'Uses GoodVibes voice/media/browser/node primitives and exposes an Agent workspace for TTS setup, image input, browser/web posture, MCP browser tools, and node/remote inspection.',
140
+ configure: ['/agent → Voice, Media & Nodes', '/config tts', '/voice review', '/mcp servers'],
141
+ use: ['/tts <prompt>', '/image <path> <prompt>', '/remote list'],
142
+ exceedsBy: ['Shared GoodVibes media/provider substrate', 'fullscreen setup visibility', 'read-only browser/node posture by default', 'template commands that cannot run without real target values'],
143
+ next: ['Add artifact and multimodal Agent Knowledge ingestion once the isolated Agent knowledge route accepts artifact-backed media.'],
144
144
  },
145
145
  {
146
146
  id: 'explicit-build-delegation',
@@ -117,6 +117,16 @@ function snapshotLines(category: AgentWorkspaceCategory, snapshot: AgentWorkspac
117
117
  { text: 'Review: queue, issues, candidates, reports, reindex, and consolidation stay inside the Agent segment.', fg: PALETTE.muted },
118
118
  { text: 'Agent-owned content appears here only after explicit Agent knowledge ingestion.', fg: PALETTE.muted },
119
119
  );
120
+ } else if (category.id === 'voice-media') {
121
+ base.push(
122
+ { text: `Voice providers: ${snapshot.voiceProviderCount}; streaming TTS: ${snapshot.voiceStreamingProviderCount}; STT: ${snapshot.voiceSttProviderCount}; realtime: ${snapshot.voiceRealtimeProviderCount}.`, fg: PALETTE.info },
123
+ { text: `Voice surface: ${snapshot.voiceSurfaceEnabled ? 'enabled' : 'disabled'}; use /voice review for portable voice posture.`, fg: snapshot.voiceSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
124
+ { text: `TTS config: provider ${snapshot.ttsProvider}; voice ${snapshot.ttsVoice}; response model ${snapshot.ttsResponseModel}.`, fg: PALETTE.info },
125
+ { text: `Media providers: ${snapshot.mediaProviderCount}; understanding: ${snapshot.mediaUnderstandingProviderCount}; generation: ${snapshot.mediaGenerationProviderCount}.`, fg: PALETTE.info },
126
+ { text: `Browser surface: ${snapshot.browserSurfaceEnabled ? 'enabled' : 'disabled'}; public base URL ${snapshot.browserSurfacePublicBaseUrl}.`, fg: snapshot.browserSurfaceEnabled ? PALETTE.warn : PALETTE.muted },
127
+ { text: 'Node/remote posture is read-only here; build dispatch remains explicit TUI delegation.', fg: PALETTE.good },
128
+ { text: 'Image input uses prompt attachments; media generation/provider setup stays behind explicit commands and configured providers.', fg: PALETTE.muted },
129
+ );
120
130
  } else if (category.id === 'memory') {
121
131
  base.push(
122
132
  { text: `Session memories: ${snapshot.sessionMemoryCount}`, fg: PALETTE.info },
@@ -38,6 +38,7 @@ import type { OperatorClient } from '@/runtime/index.ts';
38
38
  import type { PeerClient } from '@/runtime/index.ts';
39
39
  import type { DirectTransport } from '@/runtime/index.ts';
40
40
  import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
41
+ import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media';
41
42
  import {
42
43
  createBootstrapCommandActions,
43
44
  createBootstrapCommandClientsSection,
@@ -61,6 +62,7 @@ export type CreateBootstrapCommandContextOptions = {
61
62
  mcpRegistry: McpRegistry;
62
63
  voiceProviderRegistry?: VoiceProviderRegistry;
63
64
  voiceService?: VoiceService;
65
+ mediaProviderRegistry?: MediaProviderRegistry;
64
66
  forensicsRegistry: ForensicsRegistry;
65
67
  policyRuntimeState: PolicyRuntimeState;
66
68
  readModels: UiReadModels;
@@ -130,6 +132,7 @@ export function createBootstrapCommandContext(
130
132
  mcpRegistry,
131
133
  voiceProviderRegistry,
132
134
  voiceService,
135
+ mediaProviderRegistry,
133
136
  forensicsRegistry,
134
137
  policyRuntimeState,
135
138
  readModels,
@@ -237,7 +240,7 @@ export function createBootstrapCommandContext(
237
240
  projectPlanningProjectId,
238
241
  workPlanStore,
239
242
  }, shellServices);
240
- const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService }, shellServices);
243
+ const platform = createBootstrapCommandPlatformSection({ configManager, voiceProviderRegistry, voiceService, mediaProviderRegistry }, shellServices);
241
244
  const extensions = createBootstrapCommandExtensionsSection({
242
245
  toolRegistry,
243
246
  mcpRegistry,
@@ -41,6 +41,7 @@ import type { OperatorClient } from '@/runtime/index.ts';
41
41
  import type { PeerClient } from '@/runtime/index.ts';
42
42
  import type { DirectTransport } from '@/runtime/index.ts';
43
43
  import type { VoiceProviderRegistry, VoiceService } from '@pellux/goodvibes-sdk/platform/voice';
44
+ import type { MediaProviderRegistry } from '@pellux/goodvibes-sdk/platform/media';
44
45
  import { summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
45
46
 
46
47
  export type BootstrapCommandSessionSection = CommandContext['session'];
@@ -77,6 +78,7 @@ export interface BootstrapCommandSectionOptions {
77
78
  readonly mcpRegistry: McpRegistry;
78
79
  readonly voiceProviderRegistry?: VoiceProviderRegistry;
79
80
  readonly voiceService?: VoiceService;
81
+ readonly mediaProviderRegistry?: MediaProviderRegistry;
80
82
  readonly forensicsRegistry: ForensicsRegistry;
81
83
  readonly policyRuntimeState: PolicyRuntimeState;
82
84
  readonly readModels: UiReadModels;
@@ -334,7 +336,7 @@ export function createBootstrapCommandWorkspaceSection(
334
336
  export function createBootstrapCommandPlatformSection(
335
337
  options: Pick<
336
338
  BootstrapCommandSectionOptions,
337
- 'configManager' | 'voiceProviderRegistry' | 'voiceService'
339
+ 'configManager' | 'voiceProviderRegistry' | 'voiceService' | 'mediaProviderRegistry'
338
340
  >,
339
341
  shellServices: BootstrapCommandShellServices,
340
342
  ): BootstrapCommandPlatformSection {
@@ -343,6 +345,7 @@ export function createBootstrapCommandPlatformSection(
343
345
  configManager: options.configManager,
344
346
  voiceProviderRegistry: options.voiceProviderRegistry,
345
347
  voiceService: options.voiceService,
348
+ mediaProviderRegistry: options.mediaProviderRegistry,
346
349
  ...shellServices.platform,
347
350
  };
348
351
  }
@@ -195,6 +195,7 @@ export function createBootstrapShell(options: BootstrapShellOptions): BootstrapS
195
195
  mcpRegistry: services.mcpRegistry,
196
196
  voiceProviderRegistry: services.voiceProviders,
197
197
  voiceService: services.voiceService,
198
+ mediaProviderRegistry: services.mediaProviders,
198
199
  forensicsRegistry,
199
200
  policyRuntimeState,
200
201
  readModels: uiServices.readModels,
package/src/version.ts CHANGED
@@ -6,7 +6,7 @@ import { join } from 'node:path';
6
6
  // The prebuild script updates the fallback value before compilation.
7
7
  // Uses import.meta.dir (Bun) to locate package.json relative to this file,
8
8
  // which is correct regardless of the process working directory.
9
- let _version = '0.1.31';
9
+ let _version = '0.1.32';
10
10
  let _sdkVersion = '0.33.35';
11
11
  try {
12
12
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', 'package.json'), 'utf-8')) as {