@pellux/goodvibes-agent 0.1.56 → 0.1.58
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/.goodvibes/GOODVIBES.md +1 -1
- package/CHANGELOG.md +18 -9
- package/README.md +3 -3
- package/docs/README.md +1 -1
- package/docs/getting-started.md +3 -3
- package/docs/release-and-publishing.md +2 -2
- package/package.json +1 -3
- package/src/agent/routine-schedule-args.ts +219 -0
- package/src/agent/routine-schedule-format.ts +173 -0
- package/src/agent/routine-schedule-promotion.ts +3 -811
- package/src/agent/routine-schedule-receipts.ts +502 -0
- package/src/cli/agent-knowledge-command.ts +6 -6
- package/src/cli/help.ts +3 -25
- package/src/cli/package-verification.ts +23 -16
- package/src/cli/redaction.ts +4 -1
- package/src/cli/routines-command.ts +10 -6
- package/src/cli/service-posture.ts +47 -280
- package/src/cli/status.ts +0 -1
- package/src/cli/tui-startup.ts +23 -0
- package/src/config/secret-config.ts +0 -2
- package/src/input/agent-workspace-categories.ts +219 -0
- package/src/input/agent-workspace-editors.ts +143 -0
- package/src/input/agent-workspace-snapshot.ts +265 -0
- package/src/input/agent-workspace-types.ts +142 -0
- package/src/input/agent-workspace.ts +22 -766
- package/src/input/commands/agent-runtime-profile-runtime.ts +1 -1
- package/src/input/commands/delegation-runtime.ts +1 -1
- package/src/input/commands/experience-runtime.ts +3 -4
- package/src/input/commands/guidance-runtime.ts +1 -2
- package/src/input/commands/health-runtime.ts +3 -65
- package/src/input/commands/knowledge.ts +7 -7
- package/src/input/commands/local-setup-review.ts +0 -61
- package/src/input/commands/local-setup-transfer.ts +0 -3
- package/src/input/commands/local-setup.ts +2 -15
- package/src/input/commands/planning-runtime.ts +4 -1
- package/src/input/commands/platform-access-runtime.ts +1 -10
- package/src/input/commands/platform-services-runtime.ts +0 -1
- package/src/input/commands/recall-query.ts +1 -1
- package/src/input/commands/routines-runtime.ts +10 -6
- package/src/input/commands/schedule-runtime.ts +10 -6
- package/src/input/commands/session-workflow.ts +1 -1
- package/src/input/commands/tasks-runtime.ts +1 -14
- package/src/input/commands.ts +0 -4
- package/src/input/handler-onboarding.ts +10 -120
- package/src/input/onboarding/onboarding-wizard-apply.ts +5 -196
- package/src/input/onboarding/onboarding-wizard-constants.ts +8 -119
- package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -53
- package/src/input/onboarding/onboarding-wizard-rules.ts +2 -236
- package/src/input/onboarding/onboarding-wizard-state.ts +1 -69
- package/src/input/onboarding/onboarding-wizard-steps.ts +584 -737
- package/src/input/onboarding/onboarding-wizard-types.ts +8 -26
- package/src/input/onboarding/onboarding-wizard.ts +4 -109
- package/src/input/settings-modal-agent-policy.ts +10 -0
- package/src/input/settings-modal-types.ts +2 -4
- package/src/input/settings-modal.ts +3 -1
- package/src/input/submission-router.ts +0 -1
- package/src/main.ts +13 -12
- package/src/panels/approval-panel.ts +1 -2
- package/src/panels/builtin/operations.ts +1 -2
- package/src/panels/knowledge-panel.ts +2 -2
- package/src/panels/project-planning-panel.ts +4 -1
- package/src/panels/provider-health-domains.ts +0 -22
- package/src/panels/provider-health-panel.ts +1 -5
- package/src/panels/session-browser-panel.ts +0 -5
- package/src/panels/tasks-panel.ts +2 -64
- package/src/renderer/agent-workspace.ts +1 -1
- package/src/renderer/help-overlay.ts +1 -2
- package/src/renderer/semantic-diff.ts +1 -1
- package/src/renderer/settings-modal-helpers.ts +0 -16
- package/src/renderer/settings-modal.ts +3 -5
- package/src/runtime/bootstrap-hook-bridge.ts +0 -3
- package/src/runtime/bootstrap-shell.ts +2 -1
- package/src/runtime/bootstrap.ts +1 -1
- package/src/runtime/index.ts +0 -1
- package/src/runtime/onboarding/derivation.ts +1 -28
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +1 -4
- package/src/runtime/services.ts +4 -23
- package/src/runtime/ui-read-models.ts +4 -3
- package/src/shell/service-settings-sync.ts +15 -244
- package/src/tools/agent-context-policy.ts +1 -1
- package/src/tools/wrfc-agent-guard.ts +3 -3
- package/src/verification/live-verifier.ts +11 -5
- package/src/verification/verification-ledger.ts +3 -6
- package/src/version.ts +1 -1
- package/src/input/commands/agent-externalized-tui.ts +0 -73
- package/src/input/commands/cloudflare-runtime.ts +0 -385
- package/src/input/handler-onboarding-cloudflare.ts +0 -322
- package/src/input/onboarding/onboarding-runtime-status.ts +0 -87
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +0 -494
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +0 -199
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +0 -130
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +0 -762
- package/src/runtime/cloudflare-control-plane.ts +0 -350
- package/src/runtime/sandbox-public-gaps.ts +0 -358
|
@@ -1,798 +1,645 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { buildCloudflareStep } from './onboarding-wizard-cloudflare-step.ts';
|
|
4
|
-
import {
|
|
5
|
-
EXTERNAL_SURFACE_SPECS,
|
|
6
|
-
getExternalSurfaceAutoStartDefaultValue,
|
|
7
|
-
getExternalSurfaceAutoStartFieldId,
|
|
8
|
-
isExternalSurfaceSelectedByDefault,
|
|
9
|
-
type ExternalSurfaceSpec,
|
|
10
|
-
} from './onboarding-wizard-external-surfaces.ts';
|
|
11
|
-
import { countSelected, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
1
|
+
import { REASONING_OPTIONS, HITL_MODE_OPTIONS, GUIDANCE_MODE_OPTIONS, PERMISSION_MODE_OPTIONS, SECRET_POLICY_OPTIONS } from './onboarding-wizard-constants.ts';
|
|
2
|
+
import { modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
12
3
|
import type { OnboardingWizardController } from './onboarding-wizard.ts';
|
|
13
|
-
import type {
|
|
4
|
+
import type { OnboardingWizardActionFieldDefinition, OnboardingWizardFieldDefinition, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardRadioFieldDefinition, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
14
5
|
|
|
15
6
|
export function buildOnboardingWizardSteps(controller: OnboardingWizardController): readonly OnboardingWizardStepDefinition[] {
|
|
16
7
|
if (controller.hydrationPending || controller.hydrationError !== null) return [buildLoadingStep(controller)];
|
|
17
8
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
for (const surface of getSelectedExternalSurfaceSpecs(controller)) {
|
|
33
|
-
steps.push(buildExternalSurfaceStep(controller, surface));
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
if (shouldShowCloudflareStep(controller)) {
|
|
37
|
-
steps.push(buildCloudflareStep(controller));
|
|
38
|
-
}
|
|
39
|
-
steps.push(buildProviderAccessStep(controller));
|
|
40
|
-
steps.push(buildDefaultModelStep(controller));
|
|
41
|
-
steps.push(buildExperienceStep(controller));
|
|
42
|
-
steps.push(buildReviewStep(controller));
|
|
43
|
-
return steps.map(addApplyAndContinueAction);
|
|
9
|
+
return [
|
|
10
|
+
buildAgentSetupStep(controller),
|
|
11
|
+
buildProviderAccessStep(controller),
|
|
12
|
+
buildDefaultModelStep(controller),
|
|
13
|
+
buildCommunicationStep(),
|
|
14
|
+
buildToolsStep(),
|
|
15
|
+
buildAgentKnowledgeStep(),
|
|
16
|
+
buildLocalStateStep(),
|
|
17
|
+
buildAutomationStep(),
|
|
18
|
+
buildVoiceMediaStep(),
|
|
19
|
+
buildDelegationPolicyStep(),
|
|
20
|
+
buildExperienceStep(controller),
|
|
21
|
+
buildReviewStep(controller),
|
|
22
|
+
].map(addApplyAndContinueAction);
|
|
44
23
|
}
|
|
45
24
|
|
|
46
25
|
function buildApplyAndContinueAction(step: OnboardingWizardStepDefinition): OnboardingWizardActionFieldDefinition {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
26
|
+
return {
|
|
27
|
+
kind: 'action',
|
|
28
|
+
id: `${step.id}.apply-and-continue`,
|
|
29
|
+
action: 'apply-and-continue',
|
|
30
|
+
label: 'Apply & Continue To Next Section',
|
|
31
|
+
hint: 'Save the current wizard selections in this onboarding session and move to the next section. Settings are persisted on the final Review apply.',
|
|
32
|
+
defaultValue: 'Apply & next',
|
|
33
|
+
spacerBeforeRows: 2,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
57
36
|
|
|
58
37
|
function addApplyAndContinueAction(step: OnboardingWizardStepDefinition): OnboardingWizardStepDefinition {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
],
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export function buildLoadingStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
70
|
-
const failed = controller.hydrationError !== null;
|
|
71
|
-
return {
|
|
72
|
-
id: 'loading',
|
|
73
|
-
title: failed ? 'Current settings unavailable' : 'Loading current settings',
|
|
74
|
-
shortLabel: 'Loading',
|
|
75
|
-
description: failed
|
|
76
|
-
? 'The wizard is locked because current runtime settings could not be collected. Close and reopen onboarding after fixing the reported issue.'
|
|
77
|
-
: 'Collecting the current daemon, listener, provider, subscription, auth, and surface settings before the wizard becomes editable.',
|
|
78
|
-
summaryTitle: failed ? 'Preload failed' : 'Preload required',
|
|
79
|
-
summaryLines: [
|
|
80
|
-
failed
|
|
81
|
-
? 'Editable fields remain locked to avoid applying defaults over existing configuration.'
|
|
82
|
-
: 'Editable fields are locked until runtime settings are loaded.',
|
|
83
|
-
failed
|
|
84
|
-
? controller.hydrationError ?? 'Unknown snapshot failure.'
|
|
85
|
-
: 'This prevents the wizard from applying defaults over existing configuration.',
|
|
86
|
-
],
|
|
87
|
-
fields: [
|
|
88
|
-
{
|
|
89
|
-
kind: 'status',
|
|
90
|
-
id: 'loading.runtime-snapshot',
|
|
91
|
-
label: failed ? 'Runtime settings snapshot failed' : 'Runtime settings snapshot',
|
|
92
|
-
hint: failed
|
|
93
|
-
? controller.hydrationError ?? 'The runtime snapshot did not complete.'
|
|
94
|
-
: 'Waiting for the current GoodVibes configuration and account state.',
|
|
95
|
-
defaultValue: failed ? 'Locked' : 'Loading',
|
|
96
|
-
},
|
|
97
|
-
],
|
|
98
|
-
};
|
|
99
|
-
}
|
|
38
|
+
if (step.id === 'loading' || step.id === 'review') return step;
|
|
39
|
+
return {
|
|
40
|
+
...step,
|
|
41
|
+
fields: [...step.fields, buildApplyAndContinueAction(step)],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
100
44
|
|
|
101
|
-
export function
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
45
|
+
export function buildCommunicationStep(): OnboardingWizardStepDefinition {
|
|
46
|
+
return {
|
|
47
|
+
id: 'agent-communication',
|
|
48
|
+
title: 'Channels and notifications',
|
|
49
|
+
shortLabel: 'Channels',
|
|
50
|
+
description: 'Prepare the Agent for companion pairing, messaging-channel awareness, notification delivery, and safe outbound communication without owning daemon listeners.',
|
|
51
|
+
summaryTitle: 'Communication posture',
|
|
52
|
+
summaryLines: [
|
|
53
|
+
'Companion chat: paired through the external GoodVibes service',
|
|
54
|
+
'Channel accounts: inspect readiness before using them',
|
|
55
|
+
'Outbound messages: explicit user action only',
|
|
56
|
+
],
|
|
57
|
+
fields: [
|
|
113
58
|
{
|
|
114
|
-
kind: '
|
|
115
|
-
id: '
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
defaultValue: 'Action',
|
|
59
|
+
kind: 'status',
|
|
60
|
+
id: 'agent-communication.companion',
|
|
61
|
+
label: 'Companion pairing',
|
|
62
|
+
hint: 'Use /pair from the Agent workspace to pair companion clients through the already-running service.',
|
|
63
|
+
defaultValue: 'External service route',
|
|
120
64
|
},
|
|
121
65
|
{
|
|
122
|
-
kind: '
|
|
123
|
-
id: '
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
defaultValue: 'Action',
|
|
66
|
+
kind: 'status',
|
|
67
|
+
id: 'agent-communication.channels',
|
|
68
|
+
label: 'Messaging channels',
|
|
69
|
+
hint: 'Use the Channels workspace to inspect account readiness, delivery posture, and recent communication without changing listener or service lifecycle.',
|
|
70
|
+
defaultValue: 'Inspectable',
|
|
128
71
|
},
|
|
129
|
-
];
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
id: 'capabilities',
|
|
133
|
-
title: 'Choose Agent surfaces',
|
|
134
|
-
shortLabel: 'Surfaces',
|
|
135
|
-
description: 'Choose what Agent should prepare locally. Daemon-backed surfaces are reviewed as external dependencies; Agent does not enable service mode or autostart.',
|
|
136
|
-
summaryTitle: 'Selected surfaces',
|
|
137
|
-
summaryLines: [
|
|
138
|
-
`${selectedCount}/${capabilities.length} surface option(s) selected`,
|
|
139
|
-
`Mode: ${controller.mode === 'edit' ? 'edit existing shell state' : controller.mode === 'reopen' ? 'reopen review flow' : 'new setup'}`,
|
|
140
|
-
controller.runtimeSnapshot?.collectionIssues.length
|
|
141
|
-
? `${controller.runtimeSnapshot.collectionIssues.length} runtime collection issue(s)`
|
|
142
|
-
: 'Runtime snapshot collected cleanly',
|
|
143
|
-
],
|
|
144
|
-
fields,
|
|
145
|
-
};
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
export function buildProvidersStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
149
|
-
const providerAck = controller.runtimeDerived.reopenEditAcknowledgements.providers;
|
|
150
|
-
const activeSubscriptions = controller.runtimeSnapshot?.subscriptions.active ?? [];
|
|
151
|
-
const pendingSubscriptions = controller.runtimeSnapshot?.subscriptions.pending ?? [];
|
|
152
|
-
const openAiActive = activeSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
153
|
-
const openAiPending = pendingSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
154
|
-
const providerSecretCount = controller.runtimeSnapshot?.secrets.records.filter((record) => record.key.endsWith('_API_KEY') || record.key.endsWith('_TOKEN')).length ?? 0;
|
|
155
|
-
const openAiApiKeyConfigured = controller.runtimeSnapshot?.secrets.records.some((record) => record.key === 'OPENAI_API_KEY') ?? false;
|
|
156
|
-
const providerReviewField: OnboardingWizardAcknowledgementFieldDefinition = {
|
|
157
|
-
kind: 'acknowledgement',
|
|
158
|
-
id: 'providers.reviewed',
|
|
159
|
-
label: 'Confirm provider access review',
|
|
160
|
-
hint: providerAck.detail,
|
|
161
|
-
defaultValue: providerAck.accepted,
|
|
162
|
-
required: controller.mode !== 'new' && providerAck.required,
|
|
163
|
-
reason: providerAck.reason,
|
|
164
|
-
target: 'providers',
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const fields: OnboardingWizardFieldDefinition[] = [
|
|
168
72
|
{
|
|
169
73
|
kind: 'status',
|
|
170
|
-
id: '
|
|
171
|
-
label: '
|
|
172
|
-
hint:
|
|
173
|
-
|
|
174
|
-
: openAiPending
|
|
175
|
-
? 'An OpenAI subscription login is pending.'
|
|
176
|
-
: 'No OpenAI subscription session was found in the current runtime state.',
|
|
177
|
-
defaultValue: openAiActive ? 'Active' : openAiPending ? 'Pending' : 'Not detected',
|
|
74
|
+
id: 'agent-communication.notifications',
|
|
75
|
+
label: 'Notification delivery',
|
|
76
|
+
hint: 'Routine, approval, and work-plan notifications require an explicit delivery target and command; Agent never silently sends external messages.',
|
|
77
|
+
defaultValue: 'Explicit only',
|
|
178
78
|
},
|
|
179
79
|
{
|
|
180
80
|
kind: 'status',
|
|
181
|
-
id: '
|
|
182
|
-
label: '
|
|
183
|
-
hint:
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
kind: 'masked',
|
|
190
|
-
id: 'providers.openai-api-key',
|
|
191
|
-
label: 'OpenAI API key',
|
|
192
|
-
hint: openAiApiKeyConfigured
|
|
193
|
-
? 'An OpenAI API key is already stored. Leave blank to keep it; enter a new key to replace it through the secret manager.'
|
|
194
|
-
: 'Optional: enter an OpenAI API key now. The value is stored through the secret manager, not in config.',
|
|
195
|
-
placeholder: openAiApiKeyConfigured ? 'already configured' : 'sk-...',
|
|
196
|
-
defaultValue: '',
|
|
197
|
-
},
|
|
198
|
-
...(openAiActive ? [] : [
|
|
199
|
-
{
|
|
200
|
-
kind: 'action' as const,
|
|
201
|
-
id: 'providers.openai-subscription-start',
|
|
202
|
-
action: 'start-openai-subscription' as const,
|
|
203
|
-
label: openAiPending ? 'Restart OpenAI subscription sign-in' : 'Start OpenAI subscription sign-in',
|
|
204
|
-
hint: 'Opens the OpenAI sign-in flow from the wizard and records pending login state here.',
|
|
205
|
-
defaultValue: openAiPending ? 'Restart' : 'Start',
|
|
206
|
-
},
|
|
207
|
-
...(openAiPending ? [
|
|
208
|
-
{
|
|
209
|
-
kind: 'text' as const,
|
|
210
|
-
id: 'providers.openai-authorization-url',
|
|
211
|
-
label: 'OpenAI authorization URL',
|
|
212
|
-
hint: 'If the browser did not open, use this URL to continue sign-in without leaving the wizard.',
|
|
213
|
-
placeholder: 'authorization URL appears after start',
|
|
214
|
-
defaultValue: '',
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
kind: 'text' as const,
|
|
218
|
-
id: 'providers.openai-callback-code',
|
|
219
|
-
label: 'OpenAI callback code or URL',
|
|
220
|
-
hint: 'Paste the callback code or redirected URL after completing browser sign-in.',
|
|
221
|
-
placeholder: 'code or callback URL',
|
|
222
|
-
defaultValue: '',
|
|
223
|
-
},
|
|
224
|
-
{
|
|
225
|
-
kind: 'action' as const,
|
|
226
|
-
id: 'providers.openai-subscription-finish',
|
|
227
|
-
action: 'finish-openai-subscription' as const,
|
|
228
|
-
label: 'Finish OpenAI subscription sign-in',
|
|
229
|
-
hint: 'Completes the pending OpenAI subscription login using the code above.',
|
|
230
|
-
defaultValue: 'Finish',
|
|
231
|
-
},
|
|
232
|
-
] : []),
|
|
233
|
-
]),
|
|
234
|
-
providerReviewField,
|
|
235
|
-
];
|
|
236
|
-
|
|
237
|
-
return {
|
|
238
|
-
id: 'provider-access',
|
|
239
|
-
title: 'AI provider access',
|
|
240
|
-
shortLabel: 'Providers',
|
|
241
|
-
description: 'Review subscription posture and optionally add an OpenAI API key directly through the wizard.',
|
|
242
|
-
summaryTitle: 'Provider access summary',
|
|
243
|
-
summaryLines: [
|
|
244
|
-
`OpenAI subscription: ${openAiActive ? 'active' : openAiPending ? 'pending' : 'not detected'}`,
|
|
245
|
-
`OpenAI API key: ${openAiApiKeyConfigured ? 'configured' : 'not detected'}`,
|
|
246
|
-
`Provider credential references: ${providerSecretCount}`,
|
|
247
|
-
`Review: ${controller.getFieldValueLabel(providerReviewField)}`,
|
|
248
|
-
],
|
|
249
|
-
fields,
|
|
250
|
-
};
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export function buildProviderAccessStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
254
|
-
return buildProvidersStep(controller);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export function buildDefaultModelStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
258
|
-
const routing = controller.runtimeSnapshot?.providerRouting;
|
|
259
|
-
const primarySelectionField: OnboardingWizardModelPickerFieldDefinition = {
|
|
260
|
-
kind: 'modelPicker',
|
|
261
|
-
id: 'default-model.primary-model',
|
|
262
|
-
label: 'Default provider + model',
|
|
263
|
-
hint: 'Open the nested model picker for the shell’s main routing target.',
|
|
264
|
-
target: 'main',
|
|
265
|
-
defaultSelection: {
|
|
266
|
-
providerId: normalizeText(routing?.primaryProviderId),
|
|
267
|
-
modelId: normalizeText(routing?.primaryModelId),
|
|
268
|
-
enabled: true,
|
|
269
|
-
},
|
|
270
|
-
};
|
|
271
|
-
const reasoningField: OnboardingWizardRadioFieldDefinition = {
|
|
272
|
-
kind: 'radio',
|
|
273
|
-
id: 'default-model.reasoning',
|
|
274
|
-
label: 'Reasoning effort',
|
|
275
|
-
hint: 'Use the shell reasoning default that matches the current provider routing.',
|
|
276
|
-
options: REASONING_OPTIONS,
|
|
277
|
-
defaultValue: normalizeText(routing?.primaryReasoningEffort) || 'medium',
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
return {
|
|
281
|
-
id: 'default-model',
|
|
282
|
-
title: 'Default model',
|
|
283
|
-
shortLabel: 'Model',
|
|
284
|
-
description: 'Choose the default model routing the shell should use after onboarding.',
|
|
285
|
-
summaryTitle: 'Default model summary',
|
|
286
|
-
summaryLines: [
|
|
287
|
-
`Main: ${modelSelectionLabel(controller.modelSelectionState.get('main') ?? primarySelectionField.defaultSelection)}`,
|
|
288
|
-
`Reasoning: ${controller.getFieldValueLabel(reasoningField)}`,
|
|
289
|
-
],
|
|
290
|
-
fields: [
|
|
291
|
-
primarySelectionField,
|
|
292
|
-
reasoningField,
|
|
293
|
-
],
|
|
294
|
-
};
|
|
295
|
-
}
|
|
81
|
+
id: 'agent-communication.inbound-policy',
|
|
82
|
+
label: 'Inbound command policy',
|
|
83
|
+
hint: 'Incoming channel commands stay constrained by daemon-side policy, allowlists, and account posture.',
|
|
84
|
+
defaultValue: 'Policy gated',
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
296
89
|
|
|
297
|
-
export function
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
90
|
+
export function buildToolsStep(): OnboardingWizardStepDefinition {
|
|
91
|
+
return {
|
|
92
|
+
id: 'agent-tools',
|
|
93
|
+
title: 'Tools and MCP',
|
|
94
|
+
shortLabel: 'Tools',
|
|
95
|
+
description: 'Review tool access for the Agent operator: MCP servers, browser/media helpers, safe read-only inspection, and explicit approval before side effects.',
|
|
96
|
+
summaryTitle: 'Tool posture',
|
|
97
|
+
summaryLines: [
|
|
98
|
+
'MCP and tools: inspect before use',
|
|
99
|
+
'Read/search/summarize: safe by default',
|
|
100
|
+
'Writes, installs, external sends, and service changes: require explicit user action',
|
|
101
|
+
],
|
|
102
|
+
fields: [
|
|
103
|
+
{
|
|
104
|
+
kind: 'status',
|
|
105
|
+
id: 'agent-tools.mcp',
|
|
106
|
+
label: 'MCP servers and tools',
|
|
107
|
+
hint: 'Use /mcp servers and the Agent workspace Tools area to inspect connected servers, roles, and tool readiness.',
|
|
108
|
+
defaultValue: 'Inspectable',
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
kind: 'status',
|
|
112
|
+
id: 'agent-tools.browser-media',
|
|
113
|
+
label: 'Browser and media helpers',
|
|
114
|
+
hint: 'Browser, image, audio, and file helpers are capability surfaces. Agent uses them only when the current task needs them and policy allows it.',
|
|
115
|
+
defaultValue: 'Task scoped',
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
kind: 'status',
|
|
119
|
+
id: 'agent-tools.approval-boundary',
|
|
120
|
+
label: 'Power action boundary',
|
|
121
|
+
hint: 'Workspace writes, package installs, external sends, account changes, and service changes require an explicit command or confirmation.',
|
|
122
|
+
defaultValue: 'Approval required',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
kind: 'status',
|
|
126
|
+
id: 'agent-tools.no-hidden-work',
|
|
127
|
+
label: 'Hidden work policy',
|
|
128
|
+
hint: 'Tool use stays visible in the main Agent conversation or explicit command surface; no hidden background work is started from onboarding.',
|
|
129
|
+
defaultValue: 'Visible',
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
};
|
|
133
|
+
}
|
|
305
134
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
135
|
+
export function buildLoadingStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
136
|
+
const failed = controller.hydrationError !== null;
|
|
137
|
+
return {
|
|
138
|
+
id: 'loading',
|
|
139
|
+
title: failed ? 'Current settings unavailable' : 'Loading Agent setup',
|
|
140
|
+
shortLabel: 'Loading',
|
|
141
|
+
description: failed
|
|
142
|
+
? 'The wizard is locked because current Agent settings could not be collected. Close and reopen onboarding after fixing the reported issue.'
|
|
143
|
+
: 'Collecting current Agent settings before the setup workspace becomes editable.',
|
|
144
|
+
summaryTitle: failed ? 'Preload failed' : 'Preload required',
|
|
145
|
+
summaryLines: [
|
|
146
|
+
failed ? controller.hydrationError ?? 'Unknown snapshot failure.' : 'Editable fields are locked until Agent settings are loaded.',
|
|
147
|
+
failed ? 'No setup values were changed.' : 'This prevents the wizard from applying defaults over existing Agent configuration.',
|
|
148
|
+
],
|
|
149
|
+
fields: [
|
|
150
|
+
{
|
|
151
|
+
kind: 'status',
|
|
152
|
+
id: 'loading.runtime-snapshot',
|
|
153
|
+
label: failed ? 'Agent settings snapshot failed' : 'Agent settings snapshot',
|
|
154
|
+
hint: failed ? controller.hydrationError ?? 'The setup snapshot did not complete.' : 'Waiting for current Agent account, provider, and local setup state.',
|
|
155
|
+
defaultValue: failed ? 'Locked' : 'Loading',
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
315
160
|
|
|
316
|
-
|
|
161
|
+
export function buildAgentSetupStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
162
|
+
const collectionIssues = controller.runtimeSnapshot?.collectionIssues.length ?? 0;
|
|
163
|
+
const secretPolicy = controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure';
|
|
164
|
+
return {
|
|
165
|
+
id: 'agent-setup',
|
|
166
|
+
title: 'Agent setup',
|
|
167
|
+
shortLabel: 'Agent',
|
|
168
|
+
description: 'Set up the Agent operator workspace: local identity, provider access, isolated Agent Knowledge, reusable local behavior, and explicit build delegation.',
|
|
169
|
+
summaryTitle: 'Agent setup posture',
|
|
170
|
+
summaryLines: [
|
|
171
|
+
'Agent owns the operator TUI and local behavior registry.',
|
|
172
|
+
'GoodVibes service lifecycle is external to this product.',
|
|
173
|
+
`Secret policy: ${controller.getStringFieldValue('agent-setup.secret-policy', secretPolicy)}`,
|
|
174
|
+
collectionIssues > 0 ? `${collectionIssues} setup snapshot issue(s)` : 'Setup snapshot collected cleanly',
|
|
175
|
+
],
|
|
176
|
+
fields: [
|
|
317
177
|
{
|
|
318
|
-
kind: '
|
|
319
|
-
id: '
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
defaultValue: 'Action',
|
|
178
|
+
kind: 'status',
|
|
179
|
+
id: 'agent-setup.identity',
|
|
180
|
+
label: 'Product identity',
|
|
181
|
+
hint: 'GoodVibes Agent is a personal operator TUI with Agent-local profiles, memory, skills, personas, routines, and isolated Agent Knowledge.',
|
|
182
|
+
defaultValue: 'Agent operator',
|
|
324
183
|
},
|
|
325
184
|
{
|
|
326
|
-
kind: '
|
|
327
|
-
id: '
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
185
|
+
kind: 'status',
|
|
186
|
+
id: 'agent-setup.connection',
|
|
187
|
+
label: 'GoodVibes service connection',
|
|
188
|
+
hint: collectionIssues > 0
|
|
189
|
+
? `${collectionIssues} setup snapshot issue(s) were reported. Status and doctor commands show connection details.`
|
|
190
|
+
: 'Agent connects to an already-running GoodVibes service for companion chat, work plans, approvals, automation, and Agent Knowledge.',
|
|
191
|
+
defaultValue: collectionIssues > 0 ? `${collectionIssues} issue(s)` : 'External service',
|
|
332
192
|
},
|
|
333
193
|
{
|
|
334
194
|
kind: 'radio',
|
|
335
|
-
id: '
|
|
195
|
+
id: 'agent-setup.secret-policy',
|
|
336
196
|
label: 'Secret storage policy',
|
|
337
|
-
hint: 'Choose how
|
|
197
|
+
hint: 'Choose how Agent setup should store provider keys. Secret values are never shown in the wizard.',
|
|
338
198
|
options: SECRET_POLICY_OPTIONS,
|
|
339
|
-
defaultValue:
|
|
199
|
+
defaultValue: secretPolicy,
|
|
340
200
|
},
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
352
|
-
selectedCount > 0 ? 'Selected surfaces appear as separate setup screens.' : 'No external surfaces selected.',
|
|
353
|
-
],
|
|
354
|
-
fields,
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
function getSelectedExternalSurfaceSpecs(controller: OnboardingWizardController): readonly ExternalSurfaceSpec[] {
|
|
359
|
-
return EXTERNAL_SURFACE_SPECS.filter((surface) => (
|
|
360
|
-
controller.getBooleanFieldValue(
|
|
361
|
-
surface.enabledFieldId,
|
|
362
|
-
isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
363
|
-
)
|
|
364
|
-
));
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
const SURFACE_AUTO_START_OPTIONS: readonly OnboardingWizardRadioOption[] = [
|
|
368
|
-
{
|
|
369
|
-
id: 'yes',
|
|
370
|
-
label: 'Yes',
|
|
371
|
-
hint: 'Save the surface as enabled; the external daemon/service owner controls actual startup.',
|
|
372
|
-
},
|
|
373
|
-
{
|
|
374
|
-
id: 'no',
|
|
375
|
-
label: 'No',
|
|
376
|
-
hint: 'Save these settings but leave the surface idle until it is enabled from Settings > Surfaces.',
|
|
377
|
-
},
|
|
378
|
-
];
|
|
379
|
-
|
|
380
|
-
function buildExternalSurfaceStep(
|
|
381
|
-
controller: OnboardingWizardController,
|
|
382
|
-
surface: ExternalSurfaceSpec,
|
|
383
|
-
): OnboardingWizardStepDefinition {
|
|
384
|
-
let setupCount = 0;
|
|
385
|
-
let setupCompleteCount = 0;
|
|
386
|
-
const autoStartFieldId = getExternalSurfaceAutoStartFieldId(surface);
|
|
387
|
-
const autoStartDefault = getExternalSurfaceAutoStartDefaultValue(surface, controller.runtimeSnapshot);
|
|
388
|
-
const autoStartValue = controller.getStringFieldValue(autoStartFieldId, autoStartDefault);
|
|
389
|
-
const setupFields = surface.fields.map((setupField): OnboardingWizardFieldDefinition => {
|
|
390
|
-
const suggested = controller.isRequiredExternalSetupField(setupField.id);
|
|
391
|
-
if (suggested) {
|
|
392
|
-
setupCount += 1;
|
|
393
|
-
if (normalizeText(setupField.defaultValue(controller.runtimeSnapshot)).length > 0
|
|
394
|
-
|| normalizeText(controller.getStringFieldValue(setupField.id, '')).length > 0) {
|
|
395
|
-
setupCompleteCount += 1;
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
const hint = suggested
|
|
400
|
-
? `${setupField.hint} Recommended because ${surface.label} is selected, but it will not block saving.`
|
|
401
|
-
: setupField.hint;
|
|
402
|
-
|
|
403
|
-
if (setupField.kind === 'radio') {
|
|
404
|
-
return {
|
|
405
|
-
kind: 'radio',
|
|
406
|
-
id: setupField.id,
|
|
407
|
-
label: setupField.label,
|
|
408
|
-
hint,
|
|
409
|
-
options: setupField.options ?? [],
|
|
410
|
-
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
411
|
-
};
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
return {
|
|
415
|
-
kind: setupField.kind,
|
|
416
|
-
id: setupField.id,
|
|
417
|
-
label: setupField.label,
|
|
418
|
-
hint,
|
|
419
|
-
placeholder: setupField.placeholder,
|
|
420
|
-
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
421
|
-
};
|
|
422
|
-
});
|
|
423
|
-
const ntfyTopicSummary = surface.id === 'ntfy'
|
|
424
|
-
? [
|
|
425
|
-
`Chat topic: ${controller.getStringFieldValue('external-services.ntfy.chat-topic', 'goodvibes-chat')}`,
|
|
426
|
-
`Agent topic: ${controller.getStringFieldValue('external-services.ntfy.agent-topic', 'goodvibes-agent')}`,
|
|
427
|
-
`Daemon-only remote topic: ${controller.getStringFieldValue('external-services.ntfy.remote-topic', 'goodvibes-ntfy')}`,
|
|
428
|
-
]
|
|
429
|
-
: [];
|
|
430
|
-
const title = `${surface.label.replace(/ surface$/i, '')} setup`;
|
|
431
|
-
const setupSummary = setupCount === 0
|
|
432
|
-
? 'Suggested setup: none'
|
|
433
|
-
: `Suggested setup entered: ${setupCompleteCount}/${setupCount}`;
|
|
434
|
-
|
|
435
|
-
return {
|
|
436
|
-
id: `external-surface:${surface.id}` as OnboardingWizardExternalSurfaceStepId,
|
|
437
|
-
title,
|
|
438
|
-
shortLabel: surface.label.replace(/ surface$/i, ''),
|
|
439
|
-
description: `Configure ${surface.label}. Settings are saved either way; Agent does not start or own the external daemon service.`,
|
|
440
|
-
summaryTitle: `${surface.label} setup`,
|
|
441
|
-
summaryLines: [
|
|
442
|
-
`External activation requested: ${autoStartValue === 'yes' ? 'yes' : 'no'}`,
|
|
443
|
-
...ntfyTopicSummary,
|
|
444
|
-
setupSummary,
|
|
445
|
-
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
446
|
-
autoStartValue === 'yes'
|
|
447
|
-
? 'Agent will save the requested enabled state, but daemon lifecycle remains external.'
|
|
448
|
-
: 'Enable it later from Settings > Surfaces after the external daemon is ready.',
|
|
449
|
-
],
|
|
450
|
-
fields: [
|
|
451
|
-
{
|
|
452
|
-
kind: 'radio',
|
|
453
|
-
id: autoStartFieldId,
|
|
454
|
-
label: 'Request external activation',
|
|
455
|
-
hint: `Yes saves ${surface.enabledConfigKey}. No saves setup values but keeps the surface off until Settings > Surfaces enables it.`,
|
|
456
|
-
options: SURFACE_AUTO_START_OPTIONS,
|
|
457
|
-
defaultValue: autoStartDefault,
|
|
458
|
-
},
|
|
459
|
-
...setupFields,
|
|
460
|
-
],
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
export function buildAccessStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
465
|
-
const step = buildAccountsStep(controller);
|
|
466
|
-
return {
|
|
467
|
-
...step,
|
|
468
|
-
id: 'access',
|
|
469
|
-
title: 'Access and accounts',
|
|
470
|
-
shortLabel: 'Access',
|
|
471
|
-
};
|
|
472
|
-
}
|
|
201
|
+
{
|
|
202
|
+
kind: 'status',
|
|
203
|
+
id: 'agent-setup.profile-guide',
|
|
204
|
+
label: 'Runtime profiles',
|
|
205
|
+
hint: 'Use /agent-profile guide after setup to create household, research, travel, operations, or custom Agent profiles.',
|
|
206
|
+
defaultValue: 'Local profiles',
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
};
|
|
210
|
+
}
|
|
473
211
|
|
|
474
|
-
export function
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
212
|
+
export function buildProviderAccessStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
213
|
+
const activeSubscriptions = controller.runtimeSnapshot?.subscriptions.active ?? [];
|
|
214
|
+
const pendingSubscriptions = controller.runtimeSnapshot?.subscriptions.pending ?? [];
|
|
215
|
+
const openAiActive = activeSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
216
|
+
const openAiPending = pendingSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
217
|
+
const providerSecretCount = controller.runtimeSnapshot?.secrets.records.filter((record) => record.key.endsWith('_API_KEY') || record.key.endsWith('_TOKEN')).length ?? 0;
|
|
218
|
+
const openAiApiKeyConfigured = controller.runtimeSnapshot?.secrets.records.some((record) => record.key === 'OPENAI_API_KEY') ?? false;
|
|
219
|
+
const fields: OnboardingWizardFieldDefinition[] = [
|
|
220
|
+
{
|
|
221
|
+
kind: 'status',
|
|
222
|
+
id: 'providers.openai-subscription',
|
|
223
|
+
label: 'OpenAI subscription status',
|
|
224
|
+
hint: openAiActive
|
|
225
|
+
? 'An OpenAI subscription session is already available.'
|
|
226
|
+
: openAiPending
|
|
227
|
+
? 'An OpenAI subscription login is pending.'
|
|
228
|
+
: 'No OpenAI subscription session was found in the current Agent state.',
|
|
229
|
+
defaultValue: openAiActive ? 'Active' : openAiPending ? 'Pending' : 'Not detected',
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
kind: 'status',
|
|
233
|
+
id: 'providers.api-key-inventory',
|
|
234
|
+
label: 'Provider API key inventory',
|
|
235
|
+
hint: providerSecretCount > 0 ? `${providerSecretCount} provider credential reference(s) were found. Values stay masked.` : 'No provider API key references were detected in the current Agent state.',
|
|
236
|
+
defaultValue: providerSecretCount > 0 ? `${providerSecretCount} configured` : 'None detected',
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
kind: 'masked',
|
|
240
|
+
id: 'providers.openai-api-key',
|
|
241
|
+
label: 'OpenAI API key',
|
|
242
|
+
hint: openAiApiKeyConfigured
|
|
243
|
+
? 'An OpenAI API key is already stored. Leave blank to keep it; enter a new key to replace it through the secret manager.'
|
|
244
|
+
: 'Optional: enter an OpenAI API key now. The value is stored through the secret manager, not in config.',
|
|
245
|
+
placeholder: openAiApiKeyConfigured ? 'already configured' : 'sk-...',
|
|
246
|
+
defaultValue: '',
|
|
247
|
+
},
|
|
248
|
+
...(openAiActive ? [] : [
|
|
249
|
+
{
|
|
250
|
+
kind: 'action' as const,
|
|
251
|
+
id: 'providers.openai-subscription-start',
|
|
252
|
+
action: 'start-openai-subscription' as const,
|
|
253
|
+
label: openAiPending ? 'Restart OpenAI subscription sign-in' : 'Start OpenAI subscription sign-in',
|
|
254
|
+
hint: 'Opens the OpenAI sign-in flow from the wizard and records pending login state here.',
|
|
255
|
+
defaultValue: openAiPending ? 'Restart' : 'Start',
|
|
256
|
+
},
|
|
257
|
+
...(openAiPending ? [
|
|
487
258
|
{
|
|
488
|
-
kind: '
|
|
489
|
-
id: '
|
|
490
|
-
label: '
|
|
491
|
-
hint: '
|
|
492
|
-
|
|
493
|
-
defaultValue:
|
|
259
|
+
kind: 'text' as const,
|
|
260
|
+
id: 'providers.openai-authorization-url',
|
|
261
|
+
label: 'OpenAI authorization URL',
|
|
262
|
+
hint: 'If the browser did not open, use this URL to continue sign-in without leaving the wizard.',
|
|
263
|
+
placeholder: 'authorization URL appears after start',
|
|
264
|
+
defaultValue: '',
|
|
494
265
|
},
|
|
495
266
|
{
|
|
496
|
-
kind: '
|
|
497
|
-
id: '
|
|
498
|
-
label: '
|
|
499
|
-
hint: '
|
|
500
|
-
|
|
501
|
-
defaultValue:
|
|
267
|
+
kind: 'text' as const,
|
|
268
|
+
id: 'providers.openai-callback-code',
|
|
269
|
+
label: 'OpenAI callback code or URL',
|
|
270
|
+
hint: 'Paste the callback code or redirected URL after completing browser sign-in.',
|
|
271
|
+
placeholder: 'code or callback URL',
|
|
272
|
+
defaultValue: '',
|
|
502
273
|
},
|
|
503
274
|
{
|
|
504
|
-
kind: '
|
|
505
|
-
id: '
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
defaultValue:
|
|
275
|
+
kind: 'action' as const,
|
|
276
|
+
id: 'providers.openai-subscription-finish',
|
|
277
|
+
action: 'finish-openai-subscription' as const,
|
|
278
|
+
label: 'Finish OpenAI subscription sign-in',
|
|
279
|
+
hint: 'Completes the pending OpenAI subscription login using the code above.',
|
|
280
|
+
defaultValue: 'Finish',
|
|
510
281
|
},
|
|
511
|
-
],
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
export function buildNetworkStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
516
|
-
const bindSettings = controller.runtimeSnapshot?.bindSettings;
|
|
517
|
-
const browserEnabled = controller.shouldEnableBrowserSurface();
|
|
518
|
-
const listenerEnabled = controller.shouldExposeHttpListenerNetworkFields();
|
|
519
|
-
const listenerWillApply = controller.shouldEnableHttpListener();
|
|
520
|
-
const controlPlaneRemote = controller.shouldExposeControlPlaneNetwork();
|
|
521
|
-
const networkEnabled = {
|
|
522
|
-
controlPlane: controlPlaneRemote,
|
|
523
|
-
httpListener: listenerEnabled,
|
|
524
|
-
web: browserEnabled,
|
|
525
|
-
};
|
|
526
|
-
const mode = controller.getStringFieldValue('network.mode', controller.runtimeDerived.step1_5NetworkMode);
|
|
527
|
-
const custom = mode === 'custom';
|
|
528
|
-
const fields: OnboardingWizardFieldDefinition[] = [
|
|
529
|
-
{
|
|
530
|
-
kind: 'radio',
|
|
531
|
-
id: 'network.mode',
|
|
532
|
-
label: 'Network mode',
|
|
533
|
-
hint: 'Choose Local Network for the default LAN setup, or Custom to set IP addresses and ports.',
|
|
534
|
-
options: NETWORK_MODE_OPTIONS,
|
|
535
|
-
defaultValue: controller.runtimeDerived.step1_5NetworkMode,
|
|
536
|
-
},
|
|
537
|
-
];
|
|
538
|
-
|
|
539
|
-
if (custom) {
|
|
540
|
-
const sharedIpField: OnboardingWizardChecklistFieldDefinition = {
|
|
541
|
-
kind: 'checklist',
|
|
542
|
-
id: 'network.shared-ip',
|
|
543
|
-
label: 'Use the same IP address for all external daemon surfaces',
|
|
544
|
-
hint: 'When included, browser, external daemon control plane, and webhook listener network bindings share one IP address in the daemon host configuration.',
|
|
545
|
-
defaultValue: controller.getSharedIpDefault(networkEnabled),
|
|
546
|
-
};
|
|
547
|
-
const sharedIp = controller.getBooleanFieldValue(sharedIpField.id, sharedIpField.defaultValue);
|
|
548
|
-
fields.push(sharedIpField);
|
|
549
|
-
if (sharedIp) {
|
|
550
|
-
fields.push({
|
|
551
|
-
kind: 'text',
|
|
552
|
-
id: 'network.shared-ip-address',
|
|
553
|
-
label: 'Shared IP address',
|
|
554
|
-
hint: 'IP address used by each enabled service.',
|
|
555
|
-
placeholder: '0.0.0.0',
|
|
556
|
-
defaultValue: controller.getSharedIpHostDefault(networkEnabled),
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
if (controlPlaneRemote) {
|
|
561
|
-
fields.push({
|
|
562
|
-
kind: 'text',
|
|
563
|
-
id: 'network.service-port',
|
|
564
|
-
label: 'External daemon control-plane port',
|
|
565
|
-
hint: 'Port exposed by the external daemon control plane.',
|
|
566
|
-
placeholder: '3421',
|
|
567
|
-
defaultValue: String(bindSettings?.controlPlane.port ?? 3421),
|
|
568
|
-
});
|
|
569
|
-
if (!sharedIp) {
|
|
570
|
-
fields.push({
|
|
571
|
-
kind: 'text',
|
|
572
|
-
id: 'network.service-ip',
|
|
573
|
-
label: 'External daemon control-plane IP address',
|
|
574
|
-
hint: 'IP address exposed by the external daemon control plane.',
|
|
575
|
-
placeholder: '0.0.0.0',
|
|
576
|
-
defaultValue: normalizeText(bindSettings?.controlPlane.host) || '0.0.0.0',
|
|
577
|
-
});
|
|
578
|
-
}
|
|
579
|
-
}
|
|
282
|
+
] : []),
|
|
283
|
+
]),
|
|
284
|
+
];
|
|
580
285
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
hint: 'IP address for browser access.',
|
|
596
|
-
placeholder: '0.0.0.0',
|
|
597
|
-
defaultValue: normalizeText(bindSettings?.web.host) || '0.0.0.0',
|
|
598
|
-
});
|
|
599
|
-
}
|
|
600
|
-
}
|
|
286
|
+
return {
|
|
287
|
+
id: 'provider-access',
|
|
288
|
+
title: 'AI provider access',
|
|
289
|
+
shortLabel: 'Providers',
|
|
290
|
+
description: 'Review provider access for the Agent conversation. Credentials stay masked and are stored through the secret manager.',
|
|
291
|
+
summaryTitle: 'Provider access summary',
|
|
292
|
+
summaryLines: [
|
|
293
|
+
`OpenAI subscription: ${openAiActive ? 'active' : openAiPending ? 'pending' : 'not detected'}`,
|
|
294
|
+
`OpenAI API key: ${openAiApiKeyConfigured ? 'configured' : 'not detected'}`,
|
|
295
|
+
`Provider credential references: ${providerSecretCount}`,
|
|
296
|
+
],
|
|
297
|
+
fields,
|
|
298
|
+
};
|
|
299
|
+
}
|
|
601
300
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
301
|
+
export function buildDefaultModelStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
302
|
+
const routing = controller.runtimeSnapshot?.providerRouting;
|
|
303
|
+
const primarySelectionField: OnboardingWizardModelPickerFieldDefinition = {
|
|
304
|
+
kind: 'modelPicker',
|
|
305
|
+
id: 'default-model.primary-model',
|
|
306
|
+
label: 'Default provider + model',
|
|
307
|
+
hint: 'Open the model picker for the Agent conversation route.',
|
|
308
|
+
target: 'main',
|
|
309
|
+
defaultSelection: {
|
|
310
|
+
providerId: normalizeText(routing?.primaryProviderId),
|
|
311
|
+
modelId: normalizeText(routing?.primaryModelId),
|
|
312
|
+
enabled: true,
|
|
313
|
+
},
|
|
314
|
+
};
|
|
315
|
+
const reasoningField: OnboardingWizardRadioFieldDefinition = {
|
|
316
|
+
kind: 'radio',
|
|
317
|
+
id: 'default-model.reasoning',
|
|
318
|
+
label: 'Reasoning effort',
|
|
319
|
+
hint: 'Choose the default reasoning effort for the serial Agent conversation.',
|
|
320
|
+
options: REASONING_OPTIONS,
|
|
321
|
+
defaultValue: normalizeText(routing?.primaryReasoningEffort) || 'medium',
|
|
322
|
+
};
|
|
323
|
+
|
|
324
|
+
return {
|
|
325
|
+
id: 'default-model',
|
|
326
|
+
title: 'Default model',
|
|
327
|
+
shortLabel: 'Model',
|
|
328
|
+
description: 'Choose the default provider, model, and reasoning posture for normal Agent conversation.',
|
|
329
|
+
summaryTitle: 'Default model summary',
|
|
330
|
+
summaryLines: [
|
|
331
|
+
`Main: ${modelSelectionLabel(controller.modelSelectionState.get('main') ?? primarySelectionField.defaultSelection)}`,
|
|
332
|
+
`Reasoning: ${controller.getFieldValueLabel(reasoningField)}`,
|
|
333
|
+
],
|
|
334
|
+
fields: [primarySelectionField, reasoningField],
|
|
335
|
+
};
|
|
336
|
+
}
|
|
623
337
|
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
338
|
+
export function buildAgentKnowledgeStep(): OnboardingWizardStepDefinition {
|
|
339
|
+
return {
|
|
340
|
+
id: 'agent-knowledge',
|
|
341
|
+
title: 'Agent Knowledge',
|
|
342
|
+
shortLabel: 'Knowledge',
|
|
343
|
+
description: 'Agent Knowledge is isolated to the GoodVibes Agent product segment. It never falls back to default Knowledge/Wiki or any non-Agent product segment.',
|
|
344
|
+
summaryTitle: 'Knowledge isolation',
|
|
345
|
+
summaryLines: [
|
|
346
|
+
'Route segment: /api/goodvibes-agent/knowledge/*',
|
|
347
|
+
'Default wiki fallback: disabled',
|
|
348
|
+
'Non-Agent route fallback: disabled',
|
|
349
|
+
],
|
|
350
|
+
fields: [
|
|
351
|
+
{
|
|
352
|
+
kind: 'status',
|
|
353
|
+
id: 'agent-knowledge.route',
|
|
354
|
+
label: 'Isolated Agent Knowledge route',
|
|
355
|
+
hint: 'Ask, search, status, and ingest use /api/goodvibes-agent/knowledge/* only.',
|
|
356
|
+
defaultValue: 'Isolated',
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
kind: 'status',
|
|
360
|
+
id: 'agent-knowledge.no-default-wiki',
|
|
361
|
+
label: 'Default Knowledge/Wiki fallback',
|
|
362
|
+
hint: 'Agent setup and Agent ask/search must not query the default wiki when Agent Knowledge has no answer.',
|
|
363
|
+
defaultValue: 'Blocked',
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
kind: 'status',
|
|
367
|
+
id: 'agent-knowledge.no-non-agent-routes',
|
|
368
|
+
label: 'Non-Agent route fallback',
|
|
369
|
+
hint: 'Other product routes are not part of Agent Knowledge.',
|
|
370
|
+
defaultValue: 'Blocked',
|
|
371
|
+
},
|
|
372
|
+
],
|
|
373
|
+
};
|
|
374
|
+
}
|
|
638
375
|
|
|
639
|
-
export function
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
376
|
+
export function buildLocalStateStep(): OnboardingWizardStepDefinition {
|
|
377
|
+
return {
|
|
378
|
+
id: 'agent-local-state',
|
|
379
|
+
title: 'Local memory and behavior',
|
|
380
|
+
shortLabel: 'Memory',
|
|
381
|
+
description: 'Review the Agent-local behavior model. Memory, personas, skills, routines, and runtime profiles stay local until a stable shared registry exists.',
|
|
382
|
+
summaryTitle: 'Local Agent state',
|
|
383
|
+
summaryLines: [
|
|
384
|
+
'Memory/personas/skills/routines: local Agent registries',
|
|
385
|
+
'Secrets: rejected or stored by secret reference',
|
|
386
|
+
'Profiles: isolated Agent homes',
|
|
387
|
+
],
|
|
388
|
+
fields: [
|
|
389
|
+
{
|
|
390
|
+
kind: 'status',
|
|
391
|
+
id: 'agent-local-state.memory',
|
|
392
|
+
label: 'Local memory',
|
|
393
|
+
hint: 'Use /memory to create, review, stale, search, and delete Agent-local memory records.',
|
|
394
|
+
defaultValue: 'Local registry',
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
kind: 'status',
|
|
398
|
+
id: 'agent-local-state.personas',
|
|
399
|
+
label: 'Personas',
|
|
400
|
+
hint: 'Use /personas to create and activate serial operating modes for the main conversation.',
|
|
401
|
+
defaultValue: 'Local registry',
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
kind: 'status',
|
|
405
|
+
id: 'agent-local-state.skills',
|
|
406
|
+
label: 'Skills',
|
|
407
|
+
hint: 'Use /agent-skills and /skills local to manage reusable Agent procedures.',
|
|
408
|
+
defaultValue: 'Local registry',
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
kind: 'status',
|
|
412
|
+
id: 'agent-local-state.routines',
|
|
413
|
+
label: 'Routines',
|
|
414
|
+
hint: 'Use /routines for reusable local procedures. Starting a routine prints steps in the main conversation and does not spawn hidden work.',
|
|
415
|
+
defaultValue: 'Local registry',
|
|
416
|
+
},
|
|
417
|
+
],
|
|
418
|
+
};
|
|
419
|
+
}
|
|
649
420
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
421
|
+
export function buildAutomationStep(): OnboardingWizardStepDefinition {
|
|
422
|
+
return {
|
|
423
|
+
id: 'agent-automation',
|
|
424
|
+
title: 'Routines and automation',
|
|
425
|
+
shortLabel: 'Routines',
|
|
426
|
+
description: 'Set the Agent automation posture: local routines run in the main conversation, while daemon schedules remain externally owned and explicit.',
|
|
427
|
+
summaryTitle: 'Routine and schedule posture',
|
|
428
|
+
summaryLines: [
|
|
429
|
+
'Local routines: reusable main-conversation workflows',
|
|
430
|
+
'Daemon schedules: explicit promotion only',
|
|
431
|
+
'Runs/cancels/retries: command-confirmed side effects',
|
|
432
|
+
],
|
|
433
|
+
fields: [
|
|
434
|
+
{
|
|
435
|
+
kind: 'status',
|
|
436
|
+
id: 'agent-automation.local-routines',
|
|
437
|
+
label: 'Local routine library',
|
|
438
|
+
hint: 'Use /routines or the Agent workspace to create, review, enable, and start local routines without spawning hidden jobs.',
|
|
439
|
+
defaultValue: 'Local registry',
|
|
440
|
+
},
|
|
441
|
+
{
|
|
442
|
+
kind: 'status',
|
|
443
|
+
id: 'agent-automation.schedule-observability',
|
|
444
|
+
label: 'Schedule observability',
|
|
445
|
+
hint: 'Use /schedule list, /schedule reconcile, and automation views to inspect externally owned jobs and runs.',
|
|
446
|
+
defaultValue: 'Read first',
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
kind: 'status',
|
|
450
|
+
id: 'agent-automation.schedule-promotion',
|
|
451
|
+
label: 'Routine-to-schedule promotion',
|
|
452
|
+
hint: 'Creating daemon schedules from routines requires a reviewed routine, a real timing expression, optional delivery target, and explicit confirmation.',
|
|
453
|
+
defaultValue: 'Explicit command',
|
|
454
|
+
},
|
|
455
|
+
{
|
|
456
|
+
kind: 'status',
|
|
457
|
+
id: 'agent-automation.mutations',
|
|
458
|
+
label: 'Automation mutations',
|
|
459
|
+
hint: 'Run, pause, resume, cancel, retry, approve, and deny actions are never inferred from chat; they require exact commands and confirmation.',
|
|
460
|
+
defaultValue: 'Confirmed only',
|
|
461
|
+
},
|
|
462
|
+
],
|
|
463
|
+
};
|
|
464
|
+
}
|
|
676
465
|
|
|
677
|
-
|
|
466
|
+
export function buildVoiceMediaStep(): OnboardingWizardStepDefinition {
|
|
467
|
+
return {
|
|
468
|
+
id: 'agent-voice-media',
|
|
469
|
+
title: 'Voice and media',
|
|
470
|
+
shortLabel: 'Voice',
|
|
471
|
+
description: 'Prepare voice, speech, image input, and media understanding as Agent operator surfaces rather than daemon lifecycle features.',
|
|
472
|
+
summaryTitle: 'Voice and media posture',
|
|
473
|
+
summaryLines: [
|
|
474
|
+
'Voice and speech: optional operator surfaces',
|
|
475
|
+
'Image/audio inputs: explicit attachment workflows',
|
|
476
|
+
'Media generation and playback: provider-backed and policy-gated',
|
|
477
|
+
],
|
|
478
|
+
fields: [
|
|
678
479
|
{
|
|
679
|
-
kind: '
|
|
680
|
-
id: '
|
|
681
|
-
label: '
|
|
682
|
-
hint:
|
|
683
|
-
defaultValue:
|
|
684
|
-
required: controller.mode !== 'new' && subscriptionsAck.required,
|
|
685
|
-
reason: subscriptionsAck.reason,
|
|
686
|
-
target: 'subscriptions',
|
|
480
|
+
kind: 'status',
|
|
481
|
+
id: 'agent-voice-media.voice',
|
|
482
|
+
label: 'Voice interaction',
|
|
483
|
+
hint: 'Use the voice/media workspace and TTS settings to configure spoken responses for the Agent conversation.',
|
|
484
|
+
defaultValue: 'Optional',
|
|
687
485
|
},
|
|
688
486
|
{
|
|
689
|
-
kind: '
|
|
690
|
-
id: '
|
|
691
|
-
label: '
|
|
692
|
-
hint:
|
|
693
|
-
defaultValue:
|
|
694
|
-
required: needsExistingAuthAcknowledgement || (controller.mode !== 'new' && authAck.required),
|
|
695
|
-
reason: authAck.reason,
|
|
696
|
-
target: 'auth',
|
|
487
|
+
kind: 'status',
|
|
488
|
+
id: 'agent-voice-media.attachments',
|
|
489
|
+
label: 'Image and audio input',
|
|
490
|
+
hint: 'Attach files explicitly to a prompt or command. Agent does not ingest media into Knowledge without an Agent Knowledge ingest action.',
|
|
491
|
+
defaultValue: 'Explicit input',
|
|
697
492
|
},
|
|
698
493
|
{
|
|
699
494
|
kind: 'status',
|
|
700
|
-
id: '
|
|
701
|
-
label: '
|
|
702
|
-
hint:
|
|
703
|
-
|
|
704
|
-
: controller.hasAdminAuthUser()
|
|
705
|
-
? 'An existing local auth admin user was detected and will be kept.'
|
|
706
|
-
: controller.hasLocalAuthUser()
|
|
707
|
-
? 'Existing local auth users were detected and will be kept.'
|
|
708
|
-
: 'No server-backed surface is selected, so local auth is not required.',
|
|
709
|
-
defaultValue: needsAuthBootstrap
|
|
710
|
-
? controller.hasBootstrapCredentialPresent() ? 'Bootstrap replacement required' : 'Local admin required'
|
|
711
|
-
: controller.hasAdminAuthUser() ? 'Admin detected' : controller.hasLocalAuthUser() ? 'Local auth detected' : 'Not required',
|
|
495
|
+
id: 'agent-voice-media.output',
|
|
496
|
+
label: 'Generated media and playback',
|
|
497
|
+
hint: 'Media output uses configured providers and visible command/turn flow; external publication still requires explicit approval.',
|
|
498
|
+
defaultValue: 'Policy gated',
|
|
712
499
|
},
|
|
713
500
|
{
|
|
714
501
|
kind: 'status',
|
|
715
|
-
id: '
|
|
716
|
-
label: '
|
|
717
|
-
hint: '
|
|
718
|
-
defaultValue:
|
|
502
|
+
id: 'agent-voice-media.nodes',
|
|
503
|
+
label: 'Node and device posture',
|
|
504
|
+
hint: 'Remote devices and nodes are inspected as capability surfaces. Agent does not own runner topology or launch service processes from onboarding.',
|
|
505
|
+
defaultValue: 'External',
|
|
719
506
|
},
|
|
720
|
-
|
|
507
|
+
],
|
|
508
|
+
};
|
|
509
|
+
}
|
|
721
510
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
511
|
+
export function buildDelegationPolicyStep(): OnboardingWizardStepDefinition {
|
|
512
|
+
return {
|
|
513
|
+
id: 'agent-delegation',
|
|
514
|
+
title: 'Build delegation',
|
|
515
|
+
shortLabel: 'Delegate',
|
|
516
|
+
description: 'GoodVibes Agent is not the coding TUI. Explicit build, fix, review, or implementation work is delegated to GoodVibes TUI; ordinary assistant work stays serial in this conversation.',
|
|
517
|
+
summaryTitle: 'Delegation policy',
|
|
518
|
+
summaryLines: [
|
|
519
|
+
'Normal chat: main Agent conversation',
|
|
520
|
+
'Build/fix/review: explicit GoodVibes TUI delegation',
|
|
521
|
+
'WRFC: only when explicitly requested for build/fix/review',
|
|
522
|
+
],
|
|
523
|
+
fields: [
|
|
524
|
+
{
|
|
525
|
+
kind: 'status',
|
|
526
|
+
id: 'agent-delegation.normal-chat',
|
|
527
|
+
label: 'Normal assistant work',
|
|
528
|
+
hint: 'Planning, research, summaries, local memory updates, and safe read-only checks stay in the main Agent conversation.',
|
|
529
|
+
defaultValue: 'Serial',
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
kind: 'status',
|
|
533
|
+
id: 'agent-delegation.build-work',
|
|
534
|
+
label: 'Build/fix/review work',
|
|
535
|
+
hint: 'Use /delegate with the full original task. GoodVibes TUI owns coding execution and WRFC chains.',
|
|
536
|
+
defaultValue: 'Explicit delegation',
|
|
537
|
+
},
|
|
538
|
+
{
|
|
539
|
+
kind: 'status',
|
|
540
|
+
id: 'agent-delegation.wrfc',
|
|
541
|
+
label: 'WRFC policy',
|
|
542
|
+
hint: 'Agent never uses WRFC by default; request it only for explicit build, fix, review, or implementation work.',
|
|
543
|
+
defaultValue: 'Explicit only',
|
|
544
|
+
},
|
|
545
|
+
],
|
|
546
|
+
};
|
|
547
|
+
}
|
|
742
548
|
|
|
743
|
-
export function
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
549
|
+
export function buildExperienceStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
550
|
+
return {
|
|
551
|
+
id: 'experience',
|
|
552
|
+
title: 'Assistant experience',
|
|
553
|
+
shortLabel: 'Behavior',
|
|
554
|
+
description: 'Tune the Agent conversation style and approval posture for day-to-day operator use.',
|
|
555
|
+
summaryTitle: 'Experience posture',
|
|
556
|
+
summaryLines: [
|
|
557
|
+
`Human-in-the-Loop (HITL): ${controller.getStringFieldValue('experience.hitl', controller.runtimeSnapshot?.runtimeDefaults.behavior.hitlMode ?? 'balanced')}`,
|
|
558
|
+
`Guidance: ${controller.getStringFieldValue('experience.guidance', controller.runtimeSnapshot?.runtimeDefaults.behavior.guidanceMode ?? 'minimal')}`,
|
|
559
|
+
`Permissions: ${controller.getStringFieldValue('experience.permissions', controller.runtimeSnapshot?.runtimeDefaults.permissionsMode ?? 'prompt')}`,
|
|
560
|
+
],
|
|
561
|
+
fields: [
|
|
562
|
+
{
|
|
563
|
+
kind: 'radio',
|
|
564
|
+
id: 'experience.hitl',
|
|
565
|
+
label: 'Human-in-the-Loop (HITL) mode',
|
|
566
|
+
hint: 'Choose how much operational activity should be shown.',
|
|
567
|
+
options: HITL_MODE_OPTIONS,
|
|
568
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.behavior.hitlMode ?? 'balanced',
|
|
569
|
+
},
|
|
570
|
+
{
|
|
571
|
+
kind: 'radio',
|
|
572
|
+
id: 'experience.guidance',
|
|
573
|
+
label: 'Guidance verbosity',
|
|
574
|
+
hint: 'Choose how much explanation the Agent should provide while working.',
|
|
575
|
+
options: GUIDANCE_MODE_OPTIONS,
|
|
576
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.behavior.guidanceMode ?? 'minimal',
|
|
577
|
+
},
|
|
578
|
+
{
|
|
579
|
+
kind: 'radio',
|
|
580
|
+
id: 'experience.permissions',
|
|
581
|
+
label: 'Permission posture',
|
|
582
|
+
hint: 'Choose how aggressively the Agent should ask before powerful actions.',
|
|
583
|
+
options: PERMISSION_MODE_OPTIONS,
|
|
584
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.permissionsMode ?? 'prompt',
|
|
585
|
+
},
|
|
586
|
+
],
|
|
587
|
+
};
|
|
588
|
+
}
|
|
766
589
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
description: 'Review the selected settings and apply them directly from the wizard.',
|
|
772
|
-
summaryTitle: 'Review posture',
|
|
773
|
-
summaryLines: [
|
|
774
|
-
unsavedLabel,
|
|
775
|
-
`${controller.buildApplyRequest().operations.length} settings change(s) ready to apply`,
|
|
776
|
-
feedback ? `Last apply: ${feedback.title}` : 'No apply errors reported',
|
|
777
|
-
controller.isEditingTextField() ? `Editing: ${controller.editingFieldId}` : 'Ready to apply',
|
|
778
|
-
],
|
|
779
|
-
fields: [
|
|
780
|
-
...feedbackFields,
|
|
590
|
+
export function buildReviewStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
591
|
+
const feedback = controller.applyFeedback;
|
|
592
|
+
const feedbackFields: OnboardingWizardFieldDefinition[] = feedback
|
|
593
|
+
? [
|
|
781
594
|
{
|
|
782
595
|
kind: 'status',
|
|
783
|
-
id: 'review.
|
|
784
|
-
label:
|
|
785
|
-
hint:
|
|
786
|
-
defaultValue: '
|
|
787
|
-
},
|
|
788
|
-
{
|
|
789
|
-
kind: 'action',
|
|
790
|
-
id: 'review.apply',
|
|
791
|
-
action: 'apply',
|
|
792
|
-
label: 'Apply settings and verify',
|
|
793
|
-
hint: 'Persist the wizard settings and verify the resulting runtime state. The global onboarding check was already recorded when the wizard opened.',
|
|
794
|
-
defaultValue: 'Ready',
|
|
596
|
+
id: 'review.feedback',
|
|
597
|
+
label: feedback.title,
|
|
598
|
+
hint: feedback.summary,
|
|
599
|
+
defaultValue: feedback.severity === 'error' ? 'Needs attention' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
795
600
|
},
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
601
|
+
...feedback.messages.slice(0, 8).map((message, index): OnboardingWizardFieldDefinition => ({
|
|
602
|
+
kind: 'status',
|
|
603
|
+
id: `review.feedback.${index}`,
|
|
604
|
+
label: message,
|
|
605
|
+
hint: message,
|
|
606
|
+
defaultValue: feedback.severity === 'error' ? 'Error' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
607
|
+
})),
|
|
608
|
+
]
|
|
609
|
+
: [];
|
|
610
|
+
const unsavedLabel = controller.dirtyStepCount === 1
|
|
611
|
+
? '1 screen has unapplied changes'
|
|
612
|
+
: `${controller.dirtyStepCount} screens have unapplied changes`;
|
|
613
|
+
|
|
614
|
+
return {
|
|
615
|
+
id: 'review',
|
|
616
|
+
title: 'Review and apply',
|
|
617
|
+
shortLabel: 'Review',
|
|
618
|
+
description: 'Review Agent-owned settings and apply them directly from the wizard.',
|
|
619
|
+
summaryTitle: 'Review posture',
|
|
620
|
+
summaryLines: [
|
|
621
|
+
unsavedLabel,
|
|
622
|
+
`${controller.buildApplyRequest().operations.length} Agent setting change(s) ready to apply`,
|
|
623
|
+
feedback ? `Last apply: ${feedback.title}` : 'No apply errors reported',
|
|
624
|
+
controller.isEditingTextField() ? `Editing: ${controller.editingFieldId}` : 'Ready to apply',
|
|
625
|
+
],
|
|
626
|
+
fields: [
|
|
627
|
+
...feedbackFields,
|
|
628
|
+
{
|
|
629
|
+
kind: 'status',
|
|
630
|
+
id: 'review.global-marker',
|
|
631
|
+
label: 'Agent setup check',
|
|
632
|
+
hint: 'Opening this wizard marks Agent setup as shown for this user account, so it does not reopen automatically.',
|
|
633
|
+
defaultValue: 'Already marked as shown',
|
|
634
|
+
},
|
|
635
|
+
{
|
|
636
|
+
kind: 'action',
|
|
637
|
+
id: 'review.apply',
|
|
638
|
+
action: 'apply',
|
|
639
|
+
label: 'Apply Agent settings and verify',
|
|
640
|
+
hint: 'Persist the Agent-owned settings and verify that no service lifecycle, non-Agent entrypoint, default wiki, or non-Agent knowledge setup was requested.',
|
|
641
|
+
defaultValue: 'Ready',
|
|
642
|
+
},
|
|
643
|
+
],
|
|
644
|
+
};
|
|
645
|
+
}
|