@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.
- package/CHANGELOG.md +13 -4
- package/README.md +35 -14
- package/bin/goodvibes-agent.ts +16 -2
- package/dist/package/main.js +176073 -170980
- package/docs/README.md +11 -5
- package/docs/channels-remote-and-api.md +50 -0
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +29 -15
- package/docs/knowledge-artifacts-and-multimodal.md +91 -0
- package/docs/project-planning.md +79 -0
- package/docs/providers-and-routing.md +46 -0
- package/docs/release-and-publishing.md +44 -9
- package/docs/tools-and-commands.md +123 -0
- package/docs/voice-and-live-tts.md +51 -0
- package/package.json +2 -5
- package/src/agent/channel-delivery.ts +201 -0
- package/src/agent/media-generation.ts +159 -0
- package/src/agent/memory-prompt.ts +0 -1
- package/src/agent/note-registry.ts +329 -0
- package/src/agent/operator-actions.ts +343 -0
- package/src/agent/persona-registry.ts +15 -14
- package/src/agent/record-labels.ts +107 -0
- package/src/agent/reminder-schedule-format.ts +33 -24
- package/src/agent/reminder-schedule.ts +26 -25
- package/src/agent/routine-registry.ts +13 -12
- package/src/agent/routine-schedule-args.ts +2 -1
- package/src/agent/routine-schedule-format.ts +77 -53
- package/src/agent/routine-schedule-promotion.ts +34 -32
- package/src/agent/routine-schedule-receipts.ts +28 -26
- package/src/agent/runtime-profile-starters.ts +2 -2
- package/src/agent/runtime-profile.ts +18 -17
- package/src/agent/skill-registry.ts +25 -24
- package/src/cli/agent-knowledge-args.ts +5 -1
- package/src/cli/agent-knowledge-command.ts +39 -33
- package/src/cli/agent-knowledge-format.ts +80 -67
- package/src/cli/agent-knowledge-methods.ts +1 -1
- package/src/cli/agent-knowledge-runtime.ts +32 -26
- package/src/cli/bundle-command.ts +13 -8
- package/src/cli/config-overrides.ts +37 -36
- package/src/cli/external-runtime.ts +10 -4
- package/src/cli/help.ts +29 -11
- package/src/cli/local-library-command.ts +134 -68
- package/src/cli/management-commands.ts +98 -62
- package/src/cli/management.ts +52 -26
- package/src/cli/memory-command.ts +66 -32
- package/src/cli/parser.ts +37 -24
- package/src/cli/profiles-command.ts +52 -35
- package/src/cli/provider-auth-routes.ts +2 -1
- package/src/cli/routines-command.ts +44 -36
- package/src/cli/service-posture.ts +6 -6
- package/src/cli/status.ts +46 -121
- package/src/core/conversation-message-snapshot.ts +131 -0
- package/src/input/agent-workspace-activation.ts +33 -7
- package/src/input/agent-workspace-basic-command-editor-submission.ts +7 -3
- package/src/input/agent-workspace-basic-command-editors.ts +30 -10
- package/src/input/agent-workspace-categories.ts +276 -64
- package/src/input/agent-workspace-channel-command-editor-submission.ts +34 -0
- package/src/input/agent-workspace-channel-command-editors.ts +23 -5
- package/src/input/agent-workspace-channels.ts +35 -2
- package/src/input/agent-workspace-command-editor.ts +18 -2
- package/src/input/agent-workspace-config-reader.ts +16 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +1 -1
- package/src/input/agent-workspace-editors.ts +140 -2
- package/src/input/agent-workspace-knowledge-query-editor.ts +1 -1
- package/src/input/agent-workspace-learned-behavior.ts +2 -2
- package/src/input/agent-workspace-library-command-editor-submission.ts +1 -1
- package/src/input/agent-workspace-library-command-editors.ts +2 -2
- package/src/input/agent-workspace-local-operations.ts +218 -0
- package/src/input/agent-workspace-local-selection.ts +75 -0
- package/src/input/agent-workspace-media-command-editor-submission.ts +62 -0
- package/src/input/agent-workspace-media-command-editors.ts +27 -0
- package/src/input/agent-workspace-memory-command-editors.ts +1 -1
- package/src/input/agent-workspace-memory-editor.ts +2 -2
- package/src/input/agent-workspace-navigation.ts +38 -2
- package/src/input/agent-workspace-notify-editor-submission.ts +16 -2
- package/src/input/agent-workspace-operations-command-editor-submission.ts +63 -1
- package/src/input/agent-workspace-operations-command-editors.ts +80 -3
- package/src/input/agent-workspace-panel-route.ts +43 -0
- package/src/input/agent-workspace-reminder-schedule-editor.ts +1 -1
- package/src/input/agent-workspace-routine-schedule-editor.ts +2 -2
- package/src/input/agent-workspace-search.ts +169 -0
- package/src/input/agent-workspace-setup.ts +22 -11
- package/src/input/agent-workspace-skill-bundle-command-editor-submission.ts +6 -6
- package/src/input/agent-workspace-skill-bundle-command-editors.ts +10 -10
- package/src/input/agent-workspace-snapshot.ts +112 -13
- package/src/input/agent-workspace-task-command-editors.ts +4 -4
- package/src/input/agent-workspace-token.ts +18 -2
- package/src/input/agent-workspace-types.ts +92 -4
- package/src/input/agent-workspace-voice-media.ts +3 -6
- package/src/input/agent-workspace-web-research-editor.ts +104 -0
- package/src/input/agent-workspace.ts +136 -208
- package/src/input/command-registry.ts +4 -1
- package/src/input/commands/agent-runtime-profile-runtime.ts +45 -41
- package/src/input/commands/agent-skills-runtime.ts +83 -70
- package/src/input/commands/agent-workspace-runtime.ts +23 -7
- package/src/input/commands/brief-runtime.ts +25 -24
- package/src/input/commands/channels-runtime.ts +145 -31
- package/src/input/commands/delegation-runtime.ts +29 -23
- package/src/input/commands/experience-runtime.ts +6 -4
- package/src/input/commands/guidance-runtime.ts +4 -4
- package/src/input/commands/health-runtime.ts +140 -115
- package/src/input/commands/knowledge.ts +57 -56
- package/src/input/commands/local-provider-runtime.ts +36 -18
- package/src/input/commands/local-runtime.ts +138 -16
- package/src/input/commands/local-setup-review.ts +7 -7
- package/src/input/commands/mcp-runtime.ts +56 -35
- package/src/input/commands/notify-runtime.ts +38 -9
- package/src/input/commands/operator-actions-runtime.ts +138 -0
- package/src/input/commands/operator-runtime.ts +6 -17
- package/src/input/commands/personas-runtime.ts +45 -30
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/platform-access-runtime.ts +29 -29
- package/src/input/commands/provider-accounts-runtime.ts +60 -39
- package/src/input/commands/qrcode-runtime.ts +45 -6
- package/src/input/commands/recall-bundle.ts +11 -11
- package/src/input/commands/recall-capture.ts +13 -11
- package/src/input/commands/recall-query.ts +29 -21
- package/src/input/commands/recall-review.ts +2 -1
- package/src/input/commands/routines-runtime.ts +59 -43
- package/src/input/commands/schedule-runtime.ts +33 -20
- package/src/input/commands/security-runtime.ts +4 -4
- package/src/input/commands/session-content.ts +80 -78
- package/src/input/commands/session-workflow.ts +132 -93
- package/src/input/commands/session.ts +3 -174
- package/src/input/commands/shell-core.ts +32 -17
- package/src/input/commands/subscription-runtime.ts +53 -179
- package/src/input/commands/tasks-runtime.ts +20 -20
- package/src/input/commands/work-plan-runtime.ts +33 -8
- package/src/input/commands.ts +2 -2
- package/src/input/feed-context-factory.ts +2 -1
- package/src/input/file-picker.ts +3 -2
- package/src/input/handler-command-route.ts +4 -7
- package/src/input/handler-content-actions.ts +89 -1
- package/src/input/handler-feed-routes.ts +19 -12
- package/src/input/handler-feed.ts +6 -3
- package/src/input/handler-interactions.ts +7 -5
- package/src/input/handler-modal-stack.ts +3 -3
- package/src/input/handler-onboarding.ts +24 -80
- package/src/input/handler-shortcuts.ts +15 -4
- package/src/input/handler.ts +47 -17
- package/src/input/input-history.ts +5 -6
- package/src/input/keybindings.ts +22 -11
- package/src/input/onboarding/onboarding-wizard-apply.ts +13 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +1 -0
- package/src/input/onboarding/onboarding-wizard-operator-steps.ts +147 -57
- package/src/input/onboarding/onboarding-wizard-steps.ts +46 -29
- package/src/input/onboarding/onboarding-wizard-types.ts +3 -1
- package/src/input/onboarding/onboarding-wizard.ts +68 -0
- package/src/input/profile-picker-modal.ts +31 -12
- package/src/input/session-picker-modal.ts +21 -4
- package/src/input/settings-modal-behavior.ts +0 -3
- package/src/input/settings-modal-subscriptions.ts +3 -3
- package/src/input/settings-modal-types.ts +2 -13
- package/src/input/settings-modal.ts +6 -52
- package/src/input/submission-intent.ts +0 -1
- package/src/input/submission-router.ts +3 -3
- package/src/main.ts +18 -8
- package/src/panels/approval-panel.ts +8 -8
- package/src/panels/automation-control-panel.ts +2 -2
- package/src/panels/base-panel.ts +1 -1
- package/src/panels/builtin/agent.ts +1 -1
- package/src/panels/builtin/operations.ts +1 -10
- package/src/panels/builtin/session.ts +9 -9
- package/src/panels/builtin/shared.ts +2 -2
- package/src/panels/cost-tracker-panel.ts +1 -1
- package/src/panels/docs-panel.ts +5 -3
- package/src/panels/index.ts +0 -1
- package/src/panels/knowledge-panel.ts +6 -5
- package/src/panels/memory-panel.ts +7 -6
- package/src/panels/panel-list-panel.ts +36 -80
- package/src/panels/project-planning-panel.ts +18 -11
- package/src/panels/provider-account-snapshot.ts +51 -25
- package/src/panels/provider-accounts-panel.ts +33 -18
- package/src/panels/provider-health-domains.ts +45 -4
- package/src/panels/provider-health-panel.ts +5 -4
- package/src/panels/qr-panel.ts +1 -1
- package/src/panels/schedule-panel.ts +9 -17
- package/src/panels/security-panel.ts +8 -8
- package/src/panels/session-browser-panel.ts +10 -10
- package/src/panels/subscription-panel.ts +3 -3
- package/src/panels/system-messages-panel.ts +1 -1
- package/src/panels/tasks-panel.ts +20 -13
- package/src/panels/tool-inspector-panel.ts +19 -12
- package/src/panels/work-plan-panel.ts +5 -5
- package/src/planning/project-planning-coordinator.ts +1 -1
- package/src/provider-auth-route-display.ts +9 -0
- package/src/renderer/agent-workspace-style.ts +34 -0
- package/src/renderer/agent-workspace.ts +228 -52
- package/src/renderer/autocomplete-overlay.ts +25 -6
- package/src/renderer/bookmark-modal.ts +19 -4
- package/src/renderer/buffer.ts +4 -2
- package/src/renderer/context-inspector.ts +50 -13
- package/src/renderer/diff.ts +1 -1
- package/src/renderer/file-picker-overlay.ts +19 -6
- package/src/renderer/help-overlay.ts +106 -33
- package/src/renderer/history-search-overlay.ts +19 -4
- package/src/renderer/live-tail-modal.ts +27 -5
- package/src/renderer/mcp-workspace.ts +164 -50
- package/src/renderer/model-picker-overlay.ts +58 -2
- package/src/renderer/model-workspace.ts +104 -20
- package/src/renderer/process-modal.ts +27 -6
- package/src/renderer/profile-picker-modal.ts +20 -4
- package/src/renderer/search-overlay.ts +25 -5
- package/src/renderer/selection-modal-overlay.ts +46 -14
- package/src/renderer/session-picker-modal.ts +18 -1
- package/src/renderer/settings-modal-helpers.ts +2 -40
- package/src/renderer/settings-modal.ts +83 -50
- package/src/renderer/tool-call.ts +20 -11
- package/src/runtime/agent-runtime-events.ts +6 -6
- package/src/runtime/bootstrap-command-context.ts +7 -1
- package/src/runtime/bootstrap-command-parts.ts +9 -7
- package/src/runtime/bootstrap-core.ts +19 -1
- package/src/runtime/bootstrap-hook-bridge.ts +7 -18
- package/src/runtime/bootstrap-shell.ts +4 -4
- package/src/runtime/bootstrap.ts +31 -22
- package/src/runtime/connected-host-auth.ts +7 -2
- package/src/runtime/diagnostics/panels/index.ts +2 -2
- package/src/runtime/diagnostics/panels/policy.ts +7 -7
- package/src/runtime/index.ts +2 -1
- package/src/runtime/onboarding/apply-file-helpers.ts +66 -0
- package/src/runtime/onboarding/apply.ts +80 -79
- package/src/runtime/onboarding/derivation.ts +5 -8
- package/src/runtime/onboarding/snapshot.ts +0 -15
- package/src/runtime/onboarding/types.ts +8 -19
- package/src/runtime/onboarding/verify.ts +32 -10
- package/src/runtime/operator-token-cleanup.ts +1 -1
- package/src/runtime/services.ts +91 -22
- package/src/runtime/store/selectors/index.ts +3 -3
- package/src/runtime/store/state.ts +1 -4
- package/src/runtime/surface-feature-flags.ts +41 -6
- package/src/runtime/ui-read-models.ts +3 -4
- package/src/runtime/ui-services.ts +6 -6
- package/src/shell/blocking-input.ts +2 -1
- package/src/shell/ui-openers.ts +3 -13
- package/src/tools/agent-analysis-registry-policy.ts +0 -1
- package/src/tools/agent-channel-send-tool.ts +133 -0
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/agent-knowledge-ingest-tool.ts +405 -0
- package/src/tools/agent-knowledge-tool.ts +170 -0
- package/src/tools/agent-local-registry-tool.ts +269 -69
- package/src/tools/agent-media-generate-tool.ts +133 -0
- package/src/tools/agent-notify-tool.ts +143 -0
- package/src/tools/agent-operator-action-tool.ts +137 -0
- package/src/tools/agent-operator-briefing-tool.ts +217 -0
- package/src/tools/agent-reminder-schedule-tool.ts +237 -0
- package/src/tools/agent-tool-policy-guard.ts +8 -8
- package/src/tools/agent-work-plan-tool.ts +256 -0
- package/src/version.ts +1 -1
- package/src/input/commands/policy-dispatch.ts +0 -339
- package/src/input/commands/policy.ts +0 -13
- package/src/panels/panel-picker.ts +0 -105
- package/src/panels/policy-panel.ts +0 -308
- package/src/renderer/panel-picker-overlay.ts +0 -202
package/src/runtime/services.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { join } from 'node:path';
|
|
2
2
|
import { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
3
|
+
import { shell as runtimeShell } from '@pellux/goodvibes-sdk/platform/runtime';
|
|
4
|
+
import type { shell as RuntimeShell } from '@pellux/goodvibes-sdk/platform/runtime';
|
|
3
5
|
import { SecretsManager } from '../config/secrets.ts';
|
|
4
6
|
import { ServiceRegistry } from '@pellux/goodvibes-sdk/platform/config';
|
|
5
7
|
import { SubscriptionManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
@@ -11,6 +13,8 @@ import { WatcherRegistry } from '@pellux/goodvibes-sdk/platform/watchers';
|
|
|
11
13
|
import { ArtifactStore } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
12
14
|
import {
|
|
13
15
|
GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
|
|
16
|
+
HOME_GRAPH_KNOWLEDGE_DB_FILE,
|
|
17
|
+
HOME_GRAPH_KNOWLEDGE_EXTENSION,
|
|
14
18
|
KnowledgeService,
|
|
15
19
|
KnowledgeSemanticService,
|
|
16
20
|
KnowledgeStore,
|
|
@@ -19,11 +23,12 @@ import {
|
|
|
19
23
|
createWebKnowledgeGapRepairer,
|
|
20
24
|
projectPlanningProjectIdFromPath,
|
|
21
25
|
} from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
26
|
+
import * as KnowledgePlatform from '@pellux/goodvibes-sdk/platform/knowledge';
|
|
22
27
|
import { MediaProviderRegistry, ensureBuiltinMediaProviders } from '@pellux/goodvibes-sdk/platform/media';
|
|
23
28
|
import { MultimodalService } from '@pellux/goodvibes-sdk/platform/multimodal';
|
|
24
29
|
import { AgentManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
25
30
|
import { AgentMessageBus } from '@pellux/goodvibes-sdk/platform/agents';
|
|
26
|
-
import
|
|
31
|
+
import { WrfcController } from '@pellux/goodvibes-sdk/platform/agents';
|
|
27
32
|
import { AgentOrchestrator } from '@pellux/goodvibes-sdk/platform/agents';
|
|
28
33
|
import { ArchetypeLoader } from '@pellux/goodvibes-sdk/platform/agents';
|
|
29
34
|
import { ProcessManager } from '@pellux/goodvibes-sdk/platform/tools';
|
|
@@ -73,11 +78,10 @@ import { IdempotencyStore } from '@/runtime/index.ts';
|
|
|
73
78
|
import { OverflowHandler } from '@pellux/goodvibes-sdk/platform/tools';
|
|
74
79
|
import { ToolLLM } from '@pellux/goodvibes-sdk/platform/config';
|
|
75
80
|
import { ComponentHealthMonitor } from '@/runtime/index.ts';
|
|
76
|
-
import type { WorktreeRegistry } from '@/runtime/index.ts';
|
|
77
81
|
import { SandboxSessionRegistry } from '@/runtime/index.ts';
|
|
78
82
|
import { createShellPathService, type ShellPathService } from '@/runtime/index.ts';
|
|
79
83
|
import { GOODVIBES_AGENT_SURFACE_ROOT } from '../config/surface.ts';
|
|
80
|
-
import type { FeatureFlagManager } from '@/runtime/index.ts';
|
|
84
|
+
import type { FeatureFlagManager, RuntimeFoundationClientsOptions } from '@/runtime/index.ts';
|
|
81
85
|
import { createFeatureFlagManager } from '@/runtime/index.ts';
|
|
82
86
|
import { PolicyRuntimeState } from '@/runtime/index.ts';
|
|
83
87
|
import {
|
|
@@ -86,6 +90,19 @@ import {
|
|
|
86
90
|
} from '@pellux/goodvibes-sdk/platform/tools';
|
|
87
91
|
import { WorkPlanStore } from '../work-plans/work-plan-store.ts';
|
|
88
92
|
|
|
93
|
+
type WorktreeRegistry = RuntimeShell.WorktreeRegistry;
|
|
94
|
+
type SdkRuntimeServices = RuntimeFoundationClientsOptions['runtimeServices'];
|
|
95
|
+
type SdkCompanionGraphService = NonNullable<SdkRuntimeServices>['homeGraphService'];
|
|
96
|
+
type KnowledgeServiceConstructor = new (
|
|
97
|
+
store: KnowledgeStore,
|
|
98
|
+
artifactStore: ArtifactStore,
|
|
99
|
+
options?: unknown,
|
|
100
|
+
) => SdkCompanionGraphService;
|
|
101
|
+
|
|
102
|
+
const companionGraphServiceConstructor = KnowledgePlatform[
|
|
103
|
+
['Home', 'GraphService'].join('') as keyof typeof KnowledgePlatform
|
|
104
|
+
] as unknown as KnowledgeServiceConstructor;
|
|
105
|
+
|
|
89
106
|
function buildFallbackModelDefinition(provider: string, modelId: string): ModelDefinition {
|
|
90
107
|
const providerLower = provider.toLowerCase();
|
|
91
108
|
const isReasoningProvider = providerLower.includes('openai')
|
|
@@ -113,22 +130,52 @@ function buildFallbackModelDefinition(provider: string, modelId: string): ModelD
|
|
|
113
130
|
};
|
|
114
131
|
}
|
|
115
132
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
133
|
+
class DisabledAgentWorktreeRegistry extends runtimeShell.WorktreeRegistry {
|
|
134
|
+
public override async list(): Promise<Awaited<ReturnType<WorktreeRegistry['list']>>> {
|
|
135
|
+
return [] as Awaited<ReturnType<WorktreeRegistry['list']>>;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public override attach(_path: string, _target: { sessionId?: string; taskId?: string }): void {
|
|
139
|
+
throw new Error('GoodVibes Agent does not own local worktree attachment. Delegate build, fix, and review work to GoodVibes TUI.');
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public override setState(_path: string, _state: Parameters<WorktreeRegistry['setState']>[1]): void {
|
|
143
|
+
throw new Error('GoodVibes Agent does not own local worktree state. Delegate build, fix, and review work to GoodVibes TUI.');
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public override async cleanup(_path: string): Promise<void> {
|
|
147
|
+
throw new Error('GoodVibes Agent does not own local worktree cleanup. Delegate build, fix, and review work to GoodVibes TUI.');
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function createDisabledAgentWorktreeRegistry(workingDirectory: string): WorktreeRegistry {
|
|
152
|
+
return new DisabledAgentWorktreeRegistry(workingDirectory, {
|
|
153
|
+
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
type AgentWrfcWorktreeFactory = NonNullable<ConstructorParameters<typeof WrfcController>[2]['createWorktree']>;
|
|
158
|
+
type AgentWrfcWorktreeOps = ReturnType<AgentWrfcWorktreeFactory>;
|
|
159
|
+
|
|
160
|
+
function agentWrfcWorktreeError(operation: string): Error {
|
|
161
|
+
return new Error(`GoodVibes Agent does not own local review worktree ${operation}. Delegate build, fix, and review work to GoodVibes TUI.`);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function createDisabledAgentWrfcWorktreeOps(): AgentWrfcWorktreeOps {
|
|
165
|
+
return {
|
|
166
|
+
async merge(_agentId: string): Promise<boolean> {
|
|
167
|
+
throw agentWrfcWorktreeError('merge');
|
|
120
168
|
},
|
|
121
|
-
|
|
122
|
-
throw
|
|
169
|
+
async cleanup(_agentId: string): Promise<void> {
|
|
170
|
+
throw agentWrfcWorktreeError('cleanup');
|
|
123
171
|
},
|
|
124
|
-
|
|
125
|
-
throw
|
|
172
|
+
async commitWorkingTree(_message: string): Promise<string | null> {
|
|
173
|
+
throw agentWrfcWorktreeError('commit');
|
|
126
174
|
},
|
|
127
|
-
async
|
|
128
|
-
|
|
175
|
+
async currentHead(): Promise<string | null> {
|
|
176
|
+
return null;
|
|
129
177
|
},
|
|
130
178
|
};
|
|
131
|
-
return registry as unknown as WorktreeRegistry;
|
|
132
179
|
}
|
|
133
180
|
|
|
134
181
|
function ensureConfiguredModelIsRoutable(providerRegistry: ProviderRegistry, configManager: ConfigManager): void {
|
|
@@ -272,7 +319,7 @@ export interface RuntimeServicesOptions {
|
|
|
272
319
|
readonly homeDirectory: string;
|
|
273
320
|
}
|
|
274
321
|
|
|
275
|
-
export interface RuntimeServices {
|
|
322
|
+
export interface RuntimeServices extends SdkRuntimeServices {
|
|
276
323
|
readonly workingDirectory: string;
|
|
277
324
|
readonly homeDirectory: string;
|
|
278
325
|
readonly shellPaths: ShellPathService;
|
|
@@ -294,9 +341,10 @@ export interface RuntimeServices {
|
|
|
294
341
|
readonly automationManager: AutomationManager;
|
|
295
342
|
readonly gatewayMethods: GatewayMethodCatalog;
|
|
296
343
|
readonly artifactStore: ArtifactStore;
|
|
297
|
-
/** Compatibility alias that intentionally points at the isolated Agent Knowledge service, not default
|
|
344
|
+
/** Compatibility alias that intentionally points at the isolated Agent Knowledge service, not default knowledge. */
|
|
298
345
|
readonly knowledgeService: KnowledgeService;
|
|
299
346
|
readonly agentKnowledgeService: KnowledgeService;
|
|
347
|
+
readonly homeGraphService: SdkCompanionGraphService;
|
|
300
348
|
readonly projectPlanningService: ProjectPlanningService;
|
|
301
349
|
readonly projectPlanningProjectId: string;
|
|
302
350
|
readonly workPlanStore: WorkPlanStore;
|
|
@@ -353,7 +401,7 @@ export interface RuntimeServices {
|
|
|
353
401
|
readonly agentManager: AgentManager;
|
|
354
402
|
readonly agentMessageBus: AgentMessageBus;
|
|
355
403
|
readonly agentOrchestrator: AgentOrchestrator;
|
|
356
|
-
readonly wrfcController:
|
|
404
|
+
readonly wrfcController: WrfcController;
|
|
357
405
|
readonly processManager: ProcessManager;
|
|
358
406
|
readonly modeManager: ModeManager;
|
|
359
407
|
readonly fileUndoManager: FileUndoManager;
|
|
@@ -461,9 +509,13 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
461
509
|
configManager,
|
|
462
510
|
});
|
|
463
511
|
agentManager.setRuntimeBus(options.runtimeBus);
|
|
464
|
-
const wrfcController
|
|
465
|
-
|
|
466
|
-
|
|
512
|
+
const wrfcController = Reflect.construct(WrfcController, [options.runtimeBus, agentMessageBus, {
|
|
513
|
+
agentManager,
|
|
514
|
+
configManager,
|
|
515
|
+
projectRoot: workingDirectory,
|
|
516
|
+
surfaceRoot: GOODVIBES_AGENT_SURFACE_ROOT,
|
|
517
|
+
createWorktree: createDisabledAgentWrfcWorktreeOps,
|
|
518
|
+
}]) as WrfcController;
|
|
467
519
|
const hookDispatcher = new HookDispatcher({ toolLLM, projectRoot: workingDirectory }, hookActivityTracker);
|
|
468
520
|
configManager.attachHookDispatcher(hookDispatcher);
|
|
469
521
|
const hookWorkbench = createHookWorkbench({
|
|
@@ -511,7 +563,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
511
563
|
deliveryManager,
|
|
512
564
|
spawnTask: (input) => {
|
|
513
565
|
throw new Error([
|
|
514
|
-
'GoodVibes Agent does not spawn local automation agents.',
|
|
566
|
+
'GoodVibes Agent does not create local automation jobs and does not spawn local automation agents.',
|
|
515
567
|
`Received automation prompt: ${input.prompt}`,
|
|
516
568
|
'Use read-only automation observability here; explicit build/fix/review execution belongs to GoodVibes TUI delegation.',
|
|
517
569
|
].join(' '));
|
|
@@ -521,6 +573,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
521
573
|
configManager,
|
|
522
574
|
dbFileName: GOODVIBES_AGENT_KNOWLEDGE_DB_FILE,
|
|
523
575
|
});
|
|
576
|
+
const homeGraphKnowledgeStore = new KnowledgeStore({
|
|
577
|
+
configManager,
|
|
578
|
+
dbFileName: HOME_GRAPH_KNOWLEDGE_DB_FILE,
|
|
579
|
+
});
|
|
524
580
|
const knowledgeSemanticLlm = createProviderBackedKnowledgeSemanticLlm(providerRegistry, {
|
|
525
581
|
timeoutMs: 20_000,
|
|
526
582
|
maxConcurrent: 1,
|
|
@@ -529,12 +585,20 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
529
585
|
llm: knowledgeSemanticLlm,
|
|
530
586
|
maxLlmSourcesPerReindex: 3,
|
|
531
587
|
});
|
|
588
|
+
const homeGraphSemanticService = new KnowledgeSemanticService(homeGraphKnowledgeStore, {
|
|
589
|
+
llm: knowledgeSemanticLlm,
|
|
590
|
+
maxLlmSourcesPerReindex: 3,
|
|
591
|
+
objectProfiles: HOME_GRAPH_KNOWLEDGE_EXTENSION.objectProfiles,
|
|
592
|
+
});
|
|
532
593
|
const agentKnowledgeService = new KnowledgeService(agentKnowledgeStore, artifactStore, undefined, {
|
|
533
594
|
memoryRegistry,
|
|
534
595
|
runtimeBus: options.runtimeBus,
|
|
535
596
|
semanticService: agentKnowledgeSemanticService,
|
|
536
597
|
});
|
|
537
598
|
agentKnowledgeService.attachRuntimeBus(options.runtimeBus);
|
|
599
|
+
const homeGraphService = new companionGraphServiceConstructor(homeGraphKnowledgeStore, artifactStore, {
|
|
600
|
+
semanticService: homeGraphSemanticService,
|
|
601
|
+
});
|
|
538
602
|
const projectPlanningProjectId = projectPlanningProjectIdFromPath(workingDirectory);
|
|
539
603
|
const projectPlanningService = new ProjectPlanningService(agentKnowledgeStore, {
|
|
540
604
|
defaultProjectId: projectPlanningProjectId,
|
|
@@ -559,6 +623,10 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
559
623
|
searchService: webSearchService,
|
|
560
624
|
ingestService: agentKnowledgeService,
|
|
561
625
|
}));
|
|
626
|
+
homeGraphSemanticService.setGapRepairer(createWebKnowledgeGapRepairer({
|
|
627
|
+
searchService: webSearchService,
|
|
628
|
+
ingestService: homeGraphService,
|
|
629
|
+
}));
|
|
562
630
|
const mediaProviders = new MediaProviderRegistry();
|
|
563
631
|
ensureBuiltinMediaProviders(mediaProviders, artifactStore, providerRegistry);
|
|
564
632
|
const multimodalService = new MultimodalService(artifactStore, mediaProviders, voiceService, agentKnowledgeService);
|
|
@@ -593,7 +661,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
593
661
|
mcpRegistry.setSandboxRuntime(configManager, sandboxSessionRegistry);
|
|
594
662
|
const tokenAuditor = new ApiTokenAuditor({ managed: false });
|
|
595
663
|
const componentHealthMonitor = new ComponentHealthMonitor();
|
|
596
|
-
const worktreeRegistry = createDisabledAgentWorktreeRegistry();
|
|
664
|
+
const worktreeRegistry = createDisabledAgentWorktreeRegistry(workingDirectory);
|
|
597
665
|
const webhookNotifier = new WebhookNotifier();
|
|
598
666
|
const replayEngine = new DeterministicReplayEngine(workingDirectory);
|
|
599
667
|
const providerOptimizer = new ProviderOptimizer(providerRegistry, providerCapabilityRegistry, false);
|
|
@@ -687,6 +755,7 @@ export function createRuntimeServices(options: RuntimeServicesOptions): RuntimeS
|
|
|
687
755
|
artifactStore,
|
|
688
756
|
knowledgeService: agentKnowledgeService,
|
|
689
757
|
agentKnowledgeService,
|
|
758
|
+
homeGraphService,
|
|
690
759
|
projectPlanningService,
|
|
691
760
|
projectPlanningProjectId,
|
|
692
761
|
workPlanStore,
|
|
@@ -53,7 +53,7 @@ export function selectOverlays(state: RuntimeState): OverlayDomainState {
|
|
|
53
53
|
return state.overlays;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
/** Select the full panels domain slice.
|
|
56
|
+
/** Select the full panels domain slice. */
|
|
57
57
|
export function selectPanels(state: RuntimeState): PanelDomainState {
|
|
58
58
|
return state.panels as unknown as PanelDomainState;
|
|
59
59
|
}
|
|
@@ -274,7 +274,7 @@ export function selectPermissionMode(state: RuntimeState): PermissionMode {
|
|
|
274
274
|
*/
|
|
275
275
|
export function selectActivePanels(state: RuntimeState): PanelState[] {
|
|
276
276
|
const result: PanelState[] = [];
|
|
277
|
-
const panelDomain = state
|
|
277
|
+
const panelDomain = selectPanels(state);
|
|
278
278
|
for (const panel of panelDomain.panels.values()) {
|
|
279
279
|
if (panel.open) {
|
|
280
280
|
result.push(panel);
|
|
@@ -287,7 +287,7 @@ export function selectActivePanels(state: RuntimeState): PanelState[] {
|
|
|
287
287
|
* Returns the panel currently holding focus.
|
|
288
288
|
*/
|
|
289
289
|
export function selectFocusedPanel(state: RuntimeState): PanelState | undefined {
|
|
290
|
-
const panelDomain = state
|
|
290
|
+
const panelDomain = selectPanels(state);
|
|
291
291
|
return panelDomain.panels.get(panelDomain.focusedPanelId);
|
|
292
292
|
}
|
|
293
293
|
|
|
@@ -76,10 +76,7 @@ export interface RuntimeState {
|
|
|
76
76
|
model: ModelDomainState;
|
|
77
77
|
conversation: ConversationDomainState;
|
|
78
78
|
overlays: OverlayDomainState;
|
|
79
|
-
/**
|
|
80
|
-
* TUI panel state. Typed as Record<string,unknown> for SDK RuntimeState
|
|
81
|
-
* compatibility. Use selectPanels() which casts to PanelDomainState.
|
|
82
|
-
*/
|
|
79
|
+
/** TUI panel state, exposed through the SDK-compatible runtime store shape. */
|
|
83
80
|
panels: Record<string, unknown>;
|
|
84
81
|
permissions: PermissionDomainState;
|
|
85
82
|
tasks: TaskDomainState;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ConfigManager, PersistedFlagState } from '../config/index.ts';
|
|
2
2
|
import { surfaceFeatureGateId } from '@/runtime/index.ts';
|
|
3
3
|
|
|
4
4
|
export const CONTROL_PLANE_FEATURE_FLAG = 'control-plane-gateway';
|
|
@@ -14,6 +14,42 @@ const CORE_CHANNEL_FEATURE_FLAGS = [
|
|
|
14
14
|
|
|
15
15
|
export type FeatureFlagConfigKey = 'featureFlags' | `featureFlags.${string}`;
|
|
16
16
|
|
|
17
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
18
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isFeatureFlagConfigKey(key: string): key is FeatureFlagConfigKey {
|
|
22
|
+
return key === 'featureFlags' || key.startsWith('featureFlags.');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function isPersistedFlagState(value: unknown): value is PersistedFlagState {
|
|
26
|
+
return value === 'enabled' || value === 'disabled';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function readFeatureFlagConfigValue(config: Pick<ConfigManager, 'getCategory'>, key: FeatureFlagConfigKey): unknown {
|
|
30
|
+
const flags = config.getCategory('featureFlags');
|
|
31
|
+
if (key === 'featureFlags') return flags;
|
|
32
|
+
return flags[key.slice('featureFlags.'.length)];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function mergeFeatureFlagConfigValue(config: Pick<ConfigManager, 'mergeCategory'>, key: FeatureFlagConfigKey, value: unknown): void {
|
|
36
|
+
if (key === 'featureFlags') {
|
|
37
|
+
if (!isRecord(value)) throw new Error('featureFlags expects an object value.');
|
|
38
|
+
const patch: Partial<Record<string, PersistedFlagState>> = {};
|
|
39
|
+
for (const [flagId, state] of Object.entries(value)) {
|
|
40
|
+
if (!isPersistedFlagState(state)) throw new Error(`featureFlags.${flagId} expects enabled or disabled.`);
|
|
41
|
+
patch[flagId] = state;
|
|
42
|
+
}
|
|
43
|
+
config.mergeCategory('featureFlags', patch);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!isPersistedFlagState(value)) throw new Error(`${key} expects enabled or disabled.`);
|
|
48
|
+
config.mergeCategory('featureFlags', {
|
|
49
|
+
[key.slice('featureFlags.'.length)]: value,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
17
53
|
export function getSurfaceFeatureFlag(surfaceId: string): string | null {
|
|
18
54
|
return surfaceFeatureGateId(surfaceId);
|
|
19
55
|
}
|
|
@@ -47,7 +83,7 @@ export function getServerSurfaceFeatureFlags(options: {
|
|
|
47
83
|
}
|
|
48
84
|
|
|
49
85
|
export function isFeatureFlagEnabled(config: Pick<ConfigManager, 'getCategory'>, flagId: string): boolean {
|
|
50
|
-
const flags =
|
|
86
|
+
const flags = config.getCategory('featureFlags');
|
|
51
87
|
return flags[flagId] === 'enabled';
|
|
52
88
|
}
|
|
53
89
|
|
|
@@ -58,8 +94,7 @@ export function getMissingSurfaceFeatureFlags(config: Pick<ConfigManager, 'getCa
|
|
|
58
94
|
return required.filter((flagId) => !isFeatureFlagEnabled(config, flagId));
|
|
59
95
|
}
|
|
60
96
|
|
|
61
|
-
export function enableFeatureFlags(config: Pick<ConfigManager, '
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
}
|
|
97
|
+
export function enableFeatureFlags(config: Pick<ConfigManager, 'mergeCategory'>, flagIds: readonly string[]): void {
|
|
98
|
+
const patch = Object.fromEntries(flagIds.map((flagId) => [flagId, 'enabled'] as const));
|
|
99
|
+
config.mergeCategory('featureFlags', patch);
|
|
65
100
|
}
|
|
@@ -53,10 +53,9 @@ export function createUiReadModels(
|
|
|
53
53
|
runtimeServices: RuntimeServices,
|
|
54
54
|
options: UiReadModelOptions = {},
|
|
55
55
|
): UiReadModels {
|
|
56
|
-
const sdkRuntimeServices = runtimeServices as unknown as Parameters<typeof createCoreReadModels>[0];
|
|
57
56
|
return {
|
|
58
|
-
...createCoreReadModels(
|
|
59
|
-
...createOperationsReadModels(
|
|
60
|
-
...createObservabilityReadModels(
|
|
57
|
+
...createCoreReadModels(runtimeServices),
|
|
58
|
+
...createOperationsReadModels(runtimeServices, options),
|
|
59
|
+
...createObservabilityReadModels(runtimeServices, options),
|
|
61
60
|
};
|
|
62
61
|
}
|
|
@@ -58,19 +58,19 @@ export interface UiPlatformServices {
|
|
|
58
58
|
readonly policyRuntimeState: RuntimeServices['policyRuntimeState'];
|
|
59
59
|
readonly externalServices?: {
|
|
60
60
|
inspect(): {
|
|
61
|
-
readonly
|
|
62
|
-
readonly
|
|
61
|
+
readonly connectedHostRunning: boolean;
|
|
62
|
+
readonly connectedHostPortInUse?: boolean;
|
|
63
63
|
readonly httpListenerRunning: boolean;
|
|
64
64
|
readonly httpListenerPortInUse?: boolean;
|
|
65
|
-
readonly
|
|
65
|
+
readonly connectedHostStatus?: HostServiceStatus;
|
|
66
66
|
readonly httpListenerStatus?: HostServiceStatus;
|
|
67
67
|
};
|
|
68
68
|
restart(): Promise<{
|
|
69
|
-
readonly
|
|
70
|
-
readonly
|
|
69
|
+
readonly connectedHostRunning: boolean;
|
|
70
|
+
readonly connectedHostPortInUse?: boolean;
|
|
71
71
|
readonly httpListenerRunning: boolean;
|
|
72
72
|
readonly httpListenerPortInUse?: boolean;
|
|
73
|
-
readonly
|
|
73
|
+
readonly connectedHostStatus?: HostServiceStatus;
|
|
74
74
|
readonly httpListenerStatus?: HostServiceStatus;
|
|
75
75
|
}>;
|
|
76
76
|
};
|
|
@@ -2,6 +2,7 @@ import type { ConversationManager } from '../core/conversation';
|
|
|
2
2
|
import type { PermissionRequest } from '@pellux/goodvibes-sdk/platform/permissions';
|
|
3
3
|
import type { SessionSnapshot } from '@/runtime/index.ts';
|
|
4
4
|
import type { SystemMessageRouter } from '../core/system-message-router.ts';
|
|
5
|
+
import { readConversationMessageSnapshots } from '../core/conversation-message-snapshot.ts';
|
|
5
6
|
|
|
6
7
|
export type PendingPermissionState = PermissionRequest & {
|
|
7
8
|
resolve: (approved: boolean, remember?: boolean) => void;
|
|
@@ -71,7 +72,7 @@ export function handleBlockingShellInput(
|
|
|
71
72
|
if (data === '\x12') {
|
|
72
73
|
const recovery = loadRecoveryConversation();
|
|
73
74
|
if (recovery) {
|
|
74
|
-
conversation.fromJSON({ messages: recovery.messages
|
|
75
|
+
conversation.fromJSON({ messages: readConversationMessageSnapshots(recovery.messages) });
|
|
75
76
|
systemMessageRouter.high('[Recovery] Session restored.');
|
|
76
77
|
} else {
|
|
77
78
|
systemMessageRouter.high('[Recovery] Failed to restore saved data.');
|
package/src/shell/ui-openers.ts
CHANGED
|
@@ -13,6 +13,7 @@ import type { SecretsManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
|
13
13
|
import type { ServiceInspectionQuery } from '../runtime/ui-service-queries.ts';
|
|
14
14
|
import type { ModelPickerTargetInfo } from '../input/model-picker.ts';
|
|
15
15
|
import { syncServiceSettingToPlatform } from './service-settings-sync.ts';
|
|
16
|
+
import { agentWorkspaceCategoryForPanel } from '../input/agent-workspace-panel-route.ts';
|
|
16
17
|
|
|
17
18
|
type WireShellUiOpenersOptions = {
|
|
18
19
|
commandContext: CommandContext;
|
|
@@ -78,17 +79,6 @@ function buildConfiguredViaMap(
|
|
|
78
79
|
return map;
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
function agentWorkspaceCategoryForPanel(panelId: string): string {
|
|
82
|
-
if (panelId === 'knowledge') return 'knowledge';
|
|
83
|
-
if (panelId === 'memory') return 'memory';
|
|
84
|
-
if (panelId === 'work-plan' || panelId === 'tasks' || panelId === 'approval') return 'work';
|
|
85
|
-
if (panelId === 'automation' || panelId === 'schedule') return 'automation';
|
|
86
|
-
if (panelId === 'provider-health' || panelId === 'providers' || panelId === 'accounts' || panelId === 'subscription') return 'setup';
|
|
87
|
-
if (panelId === 'security' || panelId === 'policy') return 'tools';
|
|
88
|
-
if (panelId === 'qr-code') return 'channels';
|
|
89
|
-
return 'home';
|
|
90
|
-
}
|
|
91
|
-
|
|
92
82
|
export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
93
83
|
const {
|
|
94
84
|
commandContext,
|
|
@@ -310,7 +300,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
310
300
|
panelManager.hide();
|
|
311
301
|
input.panelFocused = false;
|
|
312
302
|
conversation.setSplashSuppressed(false);
|
|
313
|
-
conversation.log('Panel picker is
|
|
303
|
+
conversation.log('Panel picker is handled through Agent Workspace. Use /agent for current operator controls.', { fg: '214' });
|
|
314
304
|
input.openAgentWorkspace(commandContext, 'home');
|
|
315
305
|
conversation.rebuildHistory();
|
|
316
306
|
render();
|
|
@@ -333,7 +323,7 @@ export function wireShellUiOpeners(options: WireShellUiOpenersOptions): void {
|
|
|
333
323
|
panelManager.hide();
|
|
334
324
|
input.panelFocused = false;
|
|
335
325
|
conversation.setSplashSuppressed(false);
|
|
336
|
-
conversation.log(`Panel "${panelId}" is
|
|
326
|
+
conversation.log(`Panel route "${panelId}" is handled through Agent Workspace. Opening the matching operator area.`, { fg: '214' });
|
|
337
327
|
input.openAgentWorkspace(commandContext, agentWorkspaceCategoryForPanel(panelId));
|
|
338
328
|
conversation.rebuildHistory();
|
|
339
329
|
render();
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { ChannelDeliveryRouter } from '@pellux/goodvibes-sdk/platform/channels';
|
|
2
|
+
import type { Tool } from '@pellux/goodvibes-sdk/platform/types';
|
|
3
|
+
import type { ToolRegistry } from '@pellux/goodvibes-sdk/platform/tools';
|
|
4
|
+
import {
|
|
5
|
+
buildAgentChannelDeliveryPreview,
|
|
6
|
+
deliverAgentChannelMessage,
|
|
7
|
+
formatAgentChannelDeliveryPreview,
|
|
8
|
+
formatAgentChannelDeliveryResult,
|
|
9
|
+
} from '../agent/channel-delivery.ts';
|
|
10
|
+
|
|
11
|
+
export interface AgentChannelSendToolArgs {
|
|
12
|
+
readonly message?: unknown;
|
|
13
|
+
readonly title?: unknown;
|
|
14
|
+
readonly channel?: unknown;
|
|
15
|
+
readonly route?: unknown;
|
|
16
|
+
readonly webhook?: unknown;
|
|
17
|
+
readonly link?: unknown;
|
|
18
|
+
readonly confirm?: unknown;
|
|
19
|
+
readonly explicitUserRequest?: unknown;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function readString(value: unknown): string | undefined {
|
|
23
|
+
return typeof value === 'string' && value.trim() ? value.trim() : undefined;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function readBoolean(value: unknown): boolean {
|
|
27
|
+
return value === true || value === 'true' || value === 'yes';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function failure(error: string): { readonly success: false; readonly error: string } {
|
|
31
|
+
return { success: false, error };
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function output(text: string): { readonly success: true; readonly output: string } {
|
|
35
|
+
return { success: true, output: text };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function createAgentChannelSendTool(
|
|
39
|
+
channelDeliveryRouter: Pick<ChannelDeliveryRouter, 'deliver' | 'listStrategies'>,
|
|
40
|
+
): Tool {
|
|
41
|
+
return {
|
|
42
|
+
definition: {
|
|
43
|
+
name: 'agent_channel_send',
|
|
44
|
+
description: [
|
|
45
|
+
'Send one explicitly confirmed message through a configured GoodVibes Agent delivery target from the main conversation.',
|
|
46
|
+
'Use only when the user explicitly asks Agent to send, message, alert, or notify a channel target.',
|
|
47
|
+
'Exactly one target must be supplied: channel, route, webhook, or link.',
|
|
48
|
+
'This tool does not create channel routes, authorize accounts, manage connected-host hosting, use default knowledge, use non-Agent knowledge segments, create separate Agent jobs, run delegated review, or invoke arbitrary routes.',
|
|
49
|
+
'Set confirm:true only for an explicit user request. Otherwise return the preview/confirmation error.',
|
|
50
|
+
].join(' '),
|
|
51
|
+
parameters: {
|
|
52
|
+
type: 'object',
|
|
53
|
+
properties: {
|
|
54
|
+
message: {
|
|
55
|
+
type: 'string',
|
|
56
|
+
description: 'Plain-text message to deliver.',
|
|
57
|
+
},
|
|
58
|
+
title: {
|
|
59
|
+
type: 'string',
|
|
60
|
+
description: 'Optional delivery title.',
|
|
61
|
+
},
|
|
62
|
+
channel: {
|
|
63
|
+
type: 'string',
|
|
64
|
+
description: 'Optional channel target surface[:route[:label]], such as slack:ops:Ops or telephony:+15551234567. Use exactly one target field.',
|
|
65
|
+
},
|
|
66
|
+
route: {
|
|
67
|
+
type: 'string',
|
|
68
|
+
description: 'Optional route id or route:label. Use exactly one target field.',
|
|
69
|
+
},
|
|
70
|
+
webhook: {
|
|
71
|
+
type: 'string',
|
|
72
|
+
description: 'Optional http(s) webhook URL. Use exactly one target field.',
|
|
73
|
+
},
|
|
74
|
+
link: {
|
|
75
|
+
type: 'string',
|
|
76
|
+
description: 'Optional link delivery target. Use exactly one target field.',
|
|
77
|
+
},
|
|
78
|
+
confirm: {
|
|
79
|
+
type: 'boolean',
|
|
80
|
+
description: 'Required true only when the user explicitly asked for this exact channel delivery.',
|
|
81
|
+
},
|
|
82
|
+
explicitUserRequest: {
|
|
83
|
+
type: 'string',
|
|
84
|
+
description: 'Short quote or summary of the user request that authorized this delivery.',
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
required: ['message', 'confirm', 'explicitUserRequest'],
|
|
88
|
+
additionalProperties: false,
|
|
89
|
+
},
|
|
90
|
+
sideEffects: ['network'],
|
|
91
|
+
},
|
|
92
|
+
execute: async (rawArgs: Record<string, unknown>) => {
|
|
93
|
+
const args = rawArgs as AgentChannelSendToolArgs;
|
|
94
|
+
const explicitUserRequest = readString(args.explicitUserRequest);
|
|
95
|
+
if (!explicitUserRequest) {
|
|
96
|
+
return failure('explicitUserRequest is required so channel delivery stays tied to a direct user request.');
|
|
97
|
+
}
|
|
98
|
+
const input = {
|
|
99
|
+
message: readString(args.message) ?? '',
|
|
100
|
+
...(readString(args.title) ? { title: readString(args.title) } : {}),
|
|
101
|
+
...(readString(args.channel) ? { channel: readString(args.channel) } : {}),
|
|
102
|
+
...(readString(args.route) ? { route: readString(args.route) } : {}),
|
|
103
|
+
...(readString(args.webhook) ? { webhook: readString(args.webhook) } : {}),
|
|
104
|
+
...(readString(args.link) ? { link: readString(args.link) } : {}),
|
|
105
|
+
};
|
|
106
|
+
let preview: ReturnType<typeof buildAgentChannelDeliveryPreview>;
|
|
107
|
+
try {
|
|
108
|
+
preview = buildAgentChannelDeliveryPreview(input);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
return failure(error instanceof Error ? error.message : String(error));
|
|
111
|
+
}
|
|
112
|
+
if (!readBoolean(args.confirm)) {
|
|
113
|
+
return failure([
|
|
114
|
+
formatAgentChannelDeliveryPreview(preview, channelDeliveryRouter.listStrategies().length),
|
|
115
|
+
'',
|
|
116
|
+
'Model tool confirmation required. Call this tool with confirm:true only when the user explicitly asked GoodVibes Agent to send this channel message.',
|
|
117
|
+
].join('\n'));
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
return output(formatAgentChannelDeliveryResult(await deliverAgentChannelMessage(channelDeliveryRouter, input)));
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return failure(error instanceof Error ? error.message : String(error));
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function registerAgentChannelSendTool(
|
|
129
|
+
registry: ToolRegistry,
|
|
130
|
+
channelDeliveryRouter: Pick<ChannelDeliveryRouter, 'deliver' | 'listStrategies'>,
|
|
131
|
+
): void {
|
|
132
|
+
registry.register(createAgentChannelSendTool(channelDeliveryRouter));
|
|
133
|
+
}
|
|
@@ -10,7 +10,7 @@ export function wrapBlockedContextToolForAgentPolicy(tool: Tool): void {
|
|
|
10
10
|
tool.definition.description = [
|
|
11
11
|
'Blocked in GoodVibes Agent main conversation: non-Agent runtime context.',
|
|
12
12
|
'Use explicit Agent CLI/slash status, compat, setup, and Agent Knowledge commands for product-scoped context.',
|
|
13
|
-
'Default
|
|
13
|
+
'Default knowledge, non-Agent knowledge segments, and non-Agent runtime assumptions are not Agent fallbacks.',
|
|
14
14
|
].join(' ');
|
|
15
15
|
tool.definition.sideEffects = [];
|
|
16
16
|
tool.definition.parameters = {
|