@pellux/goodvibes-agent 1.0.35 → 1.0.37
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 +20 -9
- package/README.md +8 -7
- package/dist/package/{ast-grep-napi.linux-x64-gnu-swtppvy9.node → ast-grep-napi.linux-x64-gnu-mkk8xwww.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ttfcdtap.node → ast-grep-napi.linux-x64-musl-ryqtgdv6.node} +0 -0
- package/dist/package/main.js +51495 -49329
- package/docs/README.md +6 -5
- package/docs/channels-remote-and-api.md +3 -3
- package/docs/connected-host.md +3 -3
- package/docs/getting-started.md +12 -7
- package/docs/knowledge-artifacts-and-multimodal.md +9 -4
- package/docs/project-planning.md +3 -3
- package/docs/providers-and-routing.md +2 -2
- package/docs/release-and-publishing.md +8 -8
- package/docs/tools-and-commands.md +31 -18
- package/docs/voice-and-live-tts.md +1 -1
- package/package.json +1 -1
- package/release/live-verification/live-verification.json +3 -3
- package/release/live-verification/live-verification.md +2 -4
- package/release/release-notes.md +4 -4
- package/release/release-readiness.json +46 -46
- package/src/agent/harness-control.ts +35 -9
- package/src/agent/reminder-schedule-format.ts +2 -5
- package/src/agent/reminder-schedule.ts +4 -11
- package/src/agent/routine-schedule-format.ts +3 -6
- package/src/agent/routine-schedule-promotion.ts +5 -14
- package/src/agent/routine-schedule-receipts.ts +4 -9
- package/src/cli/agent-knowledge-command.ts +6 -11
- package/src/cli/agent-knowledge-format.ts +4 -9
- package/src/cli/agent-knowledge-runtime.ts +7 -14
- package/src/cli/external-runtime.ts +3 -46
- package/src/cli/help.ts +2 -2
- package/src/cli/status.ts +6 -7
- package/src/input/agent-workspace-categories.ts +23 -23
- package/src/input/agent-workspace-channels.ts +3 -3
- package/src/input/agent-workspace-operations-command-editors.ts +1 -1
- package/src/input/command-registry.ts +1 -1
- package/src/input/commands/compat-runtime.ts +1 -1
- package/src/input/commands/planning-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +1 -1
- package/src/input/mcp-workspace.ts +1 -1
- package/src/input/submission-router.ts +1 -1
- package/src/panels/builtin/shared.ts +1 -1
- package/src/panels/project-planning-panel.ts +4 -4
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/conversation-overlays.ts +1 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +1 -2
- package/src/runtime/bootstrap-command-parts.ts +1 -1
- package/src/runtime/bootstrap-core.ts +1 -1
- package/src/runtime/bootstrap-hook-bridge.ts +1 -1
- package/src/runtime/bootstrap-shell.ts +1 -1
- package/src/runtime/bootstrap.ts +5 -4
- package/src/runtime/context.ts +2 -2
- package/src/runtime/index.ts +88 -5
- package/src/runtime/store/state.ts +1 -1
- package/src/tools/agent-channel-send-tool.ts +1 -1
- package/src/tools/agent-harness-channel-metadata.ts +36 -25
- package/src/tools/agent-harness-cli-metadata.ts +19 -1
- package/src/tools/agent-harness-command-catalog.ts +15 -4
- package/src/tools/agent-harness-connected-host-status.ts +7 -6
- package/src/tools/agent-harness-delegation-posture.ts +15 -4
- package/src/tools/agent-harness-keybinding-metadata.ts +67 -16
- package/src/tools/agent-harness-mcp-metadata.ts +11 -3
- package/src/tools/agent-harness-media-posture.ts +25 -14
- package/src/tools/agent-harness-metadata.ts +97 -6
- package/src/tools/agent-harness-mode-catalog.ts +81 -28
- package/src/tools/agent-harness-model-routing.ts +18 -3
- package/src/tools/agent-harness-model-tool-catalog.ts +85 -7
- package/src/tools/agent-harness-notification-metadata.ts +30 -19
- package/src/tools/agent-harness-operator-methods.ts +13 -8
- package/src/tools/agent-harness-pairing-posture.ts +17 -5
- package/src/tools/agent-harness-panel-metadata.ts +10 -4
- package/src/tools/agent-harness-provider-account-metadata.ts +46 -35
- package/src/tools/agent-harness-release-evidence.ts +31 -3
- package/src/tools/agent-harness-release-readiness.ts +30 -0
- package/src/tools/agent-harness-security-posture.ts +18 -4
- package/src/tools/agent-harness-service-posture.ts +8 -1
- package/src/tools/agent-harness-session-metadata.ts +24 -8
- package/src/tools/agent-harness-setup-posture.ts +32 -21
- package/src/tools/agent-harness-text.ts +6 -0
- package/src/tools/agent-harness-tool.ts +26 -34
- package/src/tools/agent-harness-ui-surface-metadata.ts +84 -84
- package/src/tools/agent-harness-workspace-actions.ts +64 -3
- package/src/tools/agent-knowledge-ingest-tool.ts +1 -1
- package/src/tools/agent-knowledge-tool.ts +1 -1
- package/src/tools/agent-media-generate-tool.ts +2 -2
- package/src/tools/agent-notify-tool.ts +1 -1
- package/src/tools/agent-reminder-schedule-tool.ts +1 -1
- package/src/tools/tool-definition-compaction.ts +35 -8
- package/src/version.ts +2 -8
|
@@ -32,21 +32,21 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
|
|
|
32
32
|
{ id: 'modes', kind: 'discover', family: 'start', summary: 'Search all agent_harness modes by task, family, effect, or id.', next: 'Use mode for one exact mode contract.', parameters: ['query', 'target', 'limit', 'includeParameters'] },
|
|
33
33
|
{ id: 'mode', kind: 'inspect', family: 'start', summary: 'Inspect one agent_harness mode contract and common next step.', next: 'Use target or query with a mode id or task phrase.', parameters: ['target', 'query'] },
|
|
34
34
|
{ id: 'cli_commands', kind: 'discover', family: 'cli', summary: 'List top-level package CLI mirrors for discovery only.', next: 'Use cli_command for one command.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
35
|
-
{ id: 'cli_command', kind: 'inspect', family: 'cli', summary: 'Inspect one
|
|
35
|
+
{ id: 'cli_command', kind: 'inspect', family: 'cli', summary: 'Inspect one CLI command parser result, policy, aliases, and model route.', parameters: ['cliCommand', 'command', 'commandName', 'target', 'query'] },
|
|
36
36
|
{ id: 'panels', kind: 'discover', family: 'ui', summary: 'List built-in panel catalog state and workspace routes.', next: 'Use panel or open_panel.', parameters: ['query', 'category', 'limit', 'includeParameters'] },
|
|
37
|
-
{ id: 'panel', kind: 'inspect', family: 'ui', summary: 'Inspect one built-in panel, open state, workspace route, and
|
|
37
|
+
{ id: 'panel', kind: 'inspect', family: 'ui', summary: 'Inspect one built-in panel, open state, workspace route, and policy.', parameters: ['panelId', 'target', 'query'] },
|
|
38
38
|
{ id: 'open_panel', kind: 'effect', family: 'ui', summary: 'Route the visible shell to one built-in panel.', requiresConfirmation: true, parameters: ['panelId', 'target', 'query', 'pane', 'confirm', 'explicitUserRequest'] },
|
|
39
39
|
{ id: 'ui_surfaces', kind: 'discover', family: 'ui', summary: 'List modal, picker, and visible UI surfaces the model can request.', next: 'Use ui_surface or open_ui_surface.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
40
40
|
{ id: 'ui_surface', kind: 'inspect', family: 'ui', summary: 'Inspect one visible modal or picker surface and route contract.', parameters: ['surfaceId', 'target', 'query'] },
|
|
41
|
-
{ id: 'open_ui_surface', kind: 'effect', family: 'ui', summary: 'Open one visible modal
|
|
41
|
+
{ id: 'open_ui_surface', kind: 'effect', family: 'ui', summary: 'Open one visible modal, picker, or operator workspace route.', requiresConfirmation: true, parameters: ['surfaceId', 'target', 'query', 'confirm', 'explicitUserRequest'] },
|
|
42
42
|
{ id: 'shortcuts', kind: 'discover', family: 'keyboard', summary: 'List fixed shortcuts and keybinding overview.', next: 'Use keybindings or keybinding for configurable actions.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
43
43
|
{ id: 'keybindings', kind: 'discover', family: 'keyboard', summary: 'List configurable keybinding actions and current/default combos.', next: 'Use keybinding, run_keybinding, set_keybinding, or reset_keybinding.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
44
|
-
{ id: 'keybinding', kind: 'inspect', family: 'keyboard', summary: 'Inspect one keybinding action,
|
|
45
|
-
{ id: 'run_keybinding', kind: 'effect', family: 'keyboard', summary: 'Run one supported keybinding action through the
|
|
44
|
+
{ id: 'keybinding', kind: 'inspect', family: 'keyboard', summary: 'Inspect one keybinding action, current combos, defaults, and policy.', parameters: ['actionId', 'key', 'target', 'query'] },
|
|
45
|
+
{ id: 'run_keybinding', kind: 'effect', family: 'keyboard', summary: 'Run one supported keybinding action through the active UI route.', requiresConfirmation: true, parameters: ['actionId', 'key', 'target', 'query', 'confirm', 'explicitUserRequest'] },
|
|
46
46
|
{ id: 'set_keybinding', kind: 'effect', family: 'keyboard', summary: 'Set one configurable keybinding action.', requiresConfirmation: true, parameters: ['actionId', 'combo', 'combos', 'confirm', 'explicitUserRequest'] },
|
|
47
47
|
{ id: 'reset_keybinding', kind: 'effect', family: 'keyboard', summary: 'Reset one configurable keybinding action to defaults.', requiresConfirmation: true, parameters: ['actionId', 'confirm', 'explicitUserRequest'] },
|
|
48
48
|
{ id: 'commands', kind: 'discover', family: 'slash', summary: 'List registered slash commands and compact policies.', next: 'Use command or run_command.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
49
|
-
{ id: 'command', kind: 'inspect', family: 'slash', summary: 'Inspect
|
|
49
|
+
{ id: 'command', kind: 'inspect', family: 'slash', summary: 'Inspect slash command, parsed args, policy, aliases, and model route.', parameters: ['command', 'commandName', 'target', 'query'] },
|
|
50
50
|
{ id: 'run_command', kind: 'effect', family: 'slash', summary: 'Run one slash command through shared command dispatch.', requiresConfirmation: true, parameters: ['command', 'commandName', 'args', 'target', 'query', 'confirm', 'explicitUserRequest'] },
|
|
51
51
|
{ id: 'channels', kind: 'discover', family: 'delivery', summary: 'List channel readiness, accounts, delivery posture, and safe setup keys.', next: 'Use channel or agent_channel_send.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
52
52
|
{ id: 'channel', kind: 'inspect', family: 'delivery', summary: 'Inspect one channel readiness entry and delivery policy.', parameters: ['channelId', 'target', 'query'] },
|
|
@@ -58,9 +58,9 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
|
|
|
58
58
|
{ id: 'mcp_server', kind: 'inspect', family: 'tools', summary: 'Inspect one MCP server, tools, schemas, auth, and trust posture.', parameters: ['mcpServerId', 'target', 'query'] },
|
|
59
59
|
{ id: 'setup_posture', kind: 'discover', family: 'setup', summary: 'Inspect first-run/setup capability posture and derived readiness flags.', next: 'Use setup_item.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
60
60
|
{ id: 'setup_item', kind: 'inspect', family: 'setup', summary: 'Inspect one setup/onboarding posture item and visible remediation route.', parameters: ['setupItemId', 'target', 'query'] },
|
|
61
|
-
{ id: 'model_routing', kind: 'discover', family: 'providers', summary: 'List
|
|
61
|
+
{ id: 'model_routing', kind: 'discover', family: 'providers', summary: 'List model/provider route, models, pins, and safe route settings.', next: 'Use model_route.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
62
62
|
{ id: 'model_route', kind: 'inspect', family: 'providers', summary: 'Inspect one model route or model candidate and visible selection paths.', parameters: ['modelRouteId', 'target', 'query'] },
|
|
63
|
-
{ id: 'pairing_posture', kind: 'discover', family: 'companion', summary: 'List
|
|
63
|
+
{ id: 'pairing_posture', kind: 'discover', family: 'companion', summary: 'List pairing routes, token posture, and safe handoff readiness.', next: 'Use pairing_route.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
64
64
|
{ id: 'pairing_route', kind: 'inspect', family: 'companion', summary: 'Inspect one companion pairing route and safe visible handoff.', parameters: ['pairingRouteId', 'target', 'query'] },
|
|
65
65
|
{ id: 'delegation_posture', kind: 'discover', family: 'delegation', summary: 'List explicit build/fix/review delegation routes and boundaries.', next: 'Use delegation_route.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
66
66
|
{ id: 'delegation_route', kind: 'inspect', family: 'delegation', summary: 'Inspect one delegation route and exact visible submission contract.', parameters: ['delegationRouteId', 'target', 'query'] },
|
|
@@ -68,34 +68,34 @@ export const HARNESS_MODE_DESCRIPTORS: readonly HarnessModeDescriptor[] = [
|
|
|
68
68
|
{ id: 'security_finding', kind: 'inspect', family: 'security', summary: 'Inspect one security posture finding and safe remediation route.', parameters: ['findingId', 'target', 'query'] },
|
|
69
69
|
{ id: 'support_bundles', kind: 'discover', family: 'support', summary: 'List support bundle artifacts and redacted export/import posture.', next: 'Use support_bundle.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
70
70
|
{ id: 'support_bundle', kind: 'inspect', family: 'support', summary: 'Inspect one support bundle artifact and redaction posture.', parameters: ['bundlePath', 'target', 'query'] },
|
|
71
|
-
{ id: 'media_posture', kind: 'discover', family: 'media', summary: 'List voice
|
|
71
|
+
{ id: 'media_posture', kind: 'discover', family: 'media', summary: 'List media/voice readiness, browser posture, and artifact routes.', next: 'Use media_provider or agent_media_generate.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
72
72
|
{ id: 'media_provider', kind: 'inspect', family: 'media', summary: 'Inspect one voice or media provider readiness entry.', parameters: ['mediaProviderId', 'target', 'query'] },
|
|
73
73
|
{ id: 'sessions', kind: 'discover', family: 'sessions', summary: 'List saved sessions, bookmarks, exports, and pending approvals posture.', next: 'Use session.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
74
74
|
{ id: 'session', kind: 'inspect', family: 'sessions', summary: 'Inspect one saved session or bookmark entry.', parameters: ['sessionId', 'target', 'query'] },
|
|
75
75
|
{ id: 'settings', kind: 'discover', family: 'settings', summary: 'Search Agent settings compactly by category, prefix, or query.', next: 'Use get_setting, set_setting, or reset_setting.', parameters: ['category', 'prefix', 'query', 'includeHidden', 'limit', 'includeParameters'] },
|
|
76
|
-
{ id: 'get_setting', kind: 'inspect', family: 'settings', summary: 'Inspect one Agent setting descriptor,
|
|
76
|
+
{ id: 'get_setting', kind: 'inspect', family: 'settings', summary: 'Inspect one Agent setting descriptor, value, default, and policy.', parameters: ['key', 'target', 'query'] },
|
|
77
77
|
{ id: 'set_setting', kind: 'effect', family: 'settings', summary: 'Set one Agent-owned setting through config/secret managers.', requiresConfirmation: true, parameters: ['key', 'target', 'query', 'value', 'confirm', 'explicitUserRequest'] },
|
|
78
78
|
{ id: 'reset_setting', kind: 'effect', family: 'settings', summary: 'Reset one Agent-owned setting and delete secret refs when needed.', requiresConfirmation: true, parameters: ['key', 'target', 'query', 'confirm', 'explicitUserRequest'] },
|
|
79
79
|
{ id: 'workspace', kind: 'discover', family: 'workspace', summary: 'List Agent workspace categories and action counts.', next: 'Use workspace_actions or workspace_action.' },
|
|
80
80
|
{ id: 'workspace_categories', kind: 'discover', family: 'workspace', summary: 'Alias of workspace for category discovery.', next: 'Use workspace_actions or workspace_action.', aliases: ['workspace'] },
|
|
81
81
|
{ id: 'workspace_actions', kind: 'discover', family: 'workspace', summary: 'Search all user-facing Agent workspace actions and compact model routes.', next: 'Use workspace_action or run_workspace_action.', parameters: ['categoryId', 'query', 'limit', 'includeParameters'] },
|
|
82
|
-
{ id: 'workspace_action', kind: 'inspect', family: 'workspace', summary: 'Inspect one workspace action, editor schema, route
|
|
83
|
-
{ id: 'run_workspace_action', kind: 'effect', family: 'workspace', summary: 'Run
|
|
82
|
+
{ id: 'workspace_action', kind: 'inspect', family: 'workspace', summary: 'Inspect one workspace action, editor schema, route, and safety policy.', parameters: ['actionId', 'command', 'target', 'query', 'recordId'] },
|
|
83
|
+
{ id: 'run_workspace_action', kind: 'effect', family: 'workspace', summary: 'Run a workspace action or return its model execution handoff.', requiresConfirmation: true, parameters: ['actionId', 'command', 'target', 'query', 'recordId', 'fields', 'confirm', 'explicitUserRequest'] },
|
|
84
84
|
{ id: 'tools', kind: 'discover', family: 'tools', summary: 'List first-class model tool definitions compactly.', next: 'Use tool for full schema.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
85
85
|
{ id: 'tool', kind: 'inspect', family: 'tools', summary: 'Inspect one first-class model tool definition and JSON schema.', parameters: ['toolName', 'target', 'query'] },
|
|
86
|
-
{ id: 'release_evidence', kind: 'discover', family: '
|
|
87
|
-
{ id: 'release_evidence_artifact', kind: 'inspect', family: '
|
|
88
|
-
{ id: 'release_readiness', kind: 'discover', family: '
|
|
89
|
-
{ id: 'release_readiness_item', kind: 'inspect', family: '
|
|
90
|
-
{ id: 'operator_methods', kind: 'discover', family: 'operator', summary: 'List
|
|
91
|
-
{ id: 'operator_method', kind: 'inspect', family: 'operator', summary: 'Inspect one
|
|
92
|
-
{ id: 'service_posture', kind: 'discover', family: 'connected-host', summary: 'Inspect
|
|
93
|
-
{ id: 'service_endpoint', kind: 'inspect', family: 'connected-host', summary: 'Inspect one
|
|
94
|
-
{ id: 'connected_host', kind: 'discover', family: 'connected-host', summary: 'Map connected-host capabilities, boundaries, and
|
|
86
|
+
{ id: 'release_evidence', kind: 'discover', family: 'operator-audit', summary: 'List packaged operator/audit release artifacts compactly.', next: 'Use release_evidence_artifact.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
87
|
+
{ id: 'release_evidence_artifact', kind: 'inspect', family: 'operator-audit', summary: 'Inspect one operator/audit release artifact and optional content.', parameters: ['artifactId', 'target', 'query'] },
|
|
88
|
+
{ id: 'release_readiness', kind: 'discover', family: 'operator-audit', summary: 'Search the operator/audit release-quality inventory.', next: 'Use release_readiness_item.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
89
|
+
{ id: 'release_readiness_item', kind: 'inspect', family: 'operator-audit', summary: 'Inspect one operator/audit readiness inventory item.', parameters: ['itemId', 'target', 'query'] },
|
|
90
|
+
{ id: 'operator_methods', kind: 'discover', family: 'operator', summary: 'List public operator/Agent Knowledge methods and owning tools.', next: 'Use operator_method.', parameters: ['query', 'limit', 'includeParameters'] },
|
|
91
|
+
{ id: 'operator_method', kind: 'inspect', family: 'operator', summary: 'Inspect one operator method and preferred first-class model tool.', parameters: ['methodId', 'target', 'query'] },
|
|
92
|
+
{ id: 'service_posture', kind: 'discover', family: 'connected-host', summary: 'Inspect service endpoint posture, binding, issues, and probes.', next: 'Use service_endpoint.', parameters: ['includeParameters'] },
|
|
93
|
+
{ id: 'service_endpoint', kind: 'inspect', family: 'connected-host', summary: 'Inspect one service endpoint binding and lifecycle boundary.', parameters: ['endpointId', 'target', 'query'] },
|
|
94
|
+
{ id: 'connected_host', kind: 'discover', family: 'connected-host', summary: 'Map connected-host capabilities, boundaries, and tool availability.', next: 'Use connected_host_capability or connected_host_status.', parameters: ['includeParameters'] },
|
|
95
95
|
{ id: 'connected_host_status', kind: 'inspect', family: 'connected-host', summary: 'Run live read-only connected-host readiness checks.', parameters: ['includeParameters'] },
|
|
96
|
-
{ id: 'connected_host_capability', kind: 'inspect', family: 'connected-host', summary: 'Inspect one connected-host capability and blocked
|
|
97
|
-
{ id: 'daemon', kind: 'alias', family: 'connected-host', summary: '
|
|
98
|
-
{ id: 'daemon_status', kind: 'alias', family: 'connected-host', summary: '
|
|
96
|
+
{ id: 'connected_host_capability', kind: 'inspect', family: 'connected-host', summary: 'Inspect one connected-host capability and blocked surfaces.', parameters: ['capabilityId', 'target', 'query'] },
|
|
97
|
+
{ id: 'daemon', kind: 'alias', family: 'connected-host', summary: 'GoodVibes daemon -> connected_host; lifecycle external.', next: 'Use connected_host for canonical naming.', aliases: ['connected_host'], parameters: ['includeParameters'] },
|
|
98
|
+
{ id: 'daemon_status', kind: 'alias', family: 'connected-host', summary: 'GoodVibes daemon status -> connected_host_status.', next: 'Use connected_host_status for canonical naming.', aliases: ['connected_host_status'], parameters: ['includeParameters'] },
|
|
99
99
|
] as const;
|
|
100
100
|
|
|
101
101
|
function readString(value: unknown): string {
|
|
@@ -117,6 +117,7 @@ function describeHarnessModeDescriptor(
|
|
|
117
117
|
kind: descriptor.kind,
|
|
118
118
|
family: descriptor.family,
|
|
119
119
|
summary: descriptor.summary,
|
|
120
|
+
modelRoute: `agent_harness mode:"${descriptor.id}"`,
|
|
120
121
|
...(descriptor.next ? { next: descriptor.next } : {}),
|
|
121
122
|
...(descriptor.requiresConfirmation ? { requiresConfirmation: true } : {}),
|
|
122
123
|
...(descriptor.aliases ? { aliases: descriptor.aliases } : {}),
|
|
@@ -141,15 +142,68 @@ function harnessModeSearchText(descriptor: HarnessModeDescriptor): string {
|
|
|
141
142
|
].filter(Boolean).join('\n').toLowerCase();
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
function searchTokens(input: string): readonly string[] {
|
|
146
|
+
return input.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
|
|
147
|
+
}
|
|
148
|
+
|
|
144
149
|
function harnessModeMatchesSearch(descriptor: HarnessModeDescriptor, input: string): boolean {
|
|
145
150
|
const text = harnessModeSearchText(descriptor);
|
|
146
151
|
const normalized = input.toLowerCase().trim();
|
|
147
152
|
if (normalized.length === 0) return true;
|
|
148
153
|
if (text.includes(normalized)) return true;
|
|
149
|
-
const tokens = normalized
|
|
154
|
+
const tokens = searchTokens(normalized);
|
|
150
155
|
return tokens.length > 0 && tokens.every((token) => text.includes(token));
|
|
151
156
|
}
|
|
152
157
|
|
|
158
|
+
function tokenScore(tokens: readonly string[], value: string | undefined, weight: number): number {
|
|
159
|
+
if (!value) return 0;
|
|
160
|
+
const text = value.toLowerCase();
|
|
161
|
+
return tokens.reduce((score, token) => score + (text.includes(token) ? weight : 0), 0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const ACTION_VERBS = new Set(['run', 'set', 'reset', 'open', 'create', 'send', 'schedule']);
|
|
165
|
+
|
|
166
|
+
function harnessModeRelevance(descriptor: HarnessModeDescriptor, input: string): number {
|
|
167
|
+
const normalized = input.toLowerCase().trim();
|
|
168
|
+
if (!normalized) return 0;
|
|
169
|
+
|
|
170
|
+
const tokens = searchTokens(normalized);
|
|
171
|
+
const id = descriptor.id.toLowerCase();
|
|
172
|
+
const idPhrase = id.replace(/_/g, ' ');
|
|
173
|
+
const idLookup = normalized.replace(/\s+/g, '_');
|
|
174
|
+
let score = 0;
|
|
175
|
+
|
|
176
|
+
if (id === normalized || idPhrase === normalized) score += 10_000;
|
|
177
|
+
if (id.startsWith(idLookup) || idPhrase.startsWith(normalized)) score += 5_000;
|
|
178
|
+
if (id.includes(idLookup) || idPhrase.includes(normalized)) score += 2_500;
|
|
179
|
+
|
|
180
|
+
score += tokenScore(tokens, [id, idPhrase, ...(descriptor.aliases ?? [])].join('\n'), 1_000);
|
|
181
|
+
score += tokenScore(tokens, descriptor.family, 500);
|
|
182
|
+
score += tokenScore(tokens, descriptor.kind, 500);
|
|
183
|
+
score += tokenScore(tokens, (descriptor.parameters ?? []).join('\n'), 350);
|
|
184
|
+
score += tokenScore(tokens, descriptor.summary, 200);
|
|
185
|
+
score += tokenScore(tokens, descriptor.next, 100);
|
|
186
|
+
|
|
187
|
+
const actionVerb = tokens.find((token) => ACTION_VERBS.has(token));
|
|
188
|
+
if (actionVerb) {
|
|
189
|
+
const idTokens = searchTokens(id);
|
|
190
|
+
if (idTokens[0] === actionVerb) score += 2_000;
|
|
191
|
+
if (descriptor.kind === 'effect' && idTokens.includes(actionVerb)) score += 1_000;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return score;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function matchingHarnessModes(input: string): readonly HarnessModeDescriptor[] {
|
|
198
|
+
const matches = HARNESS_MODE_DESCRIPTORS
|
|
199
|
+
.map((descriptor, index) => ({ descriptor, index, score: harnessModeRelevance(descriptor, input) }))
|
|
200
|
+
.filter(({ descriptor }) => harnessModeMatchesSearch(descriptor, input));
|
|
201
|
+
if (!input) return matches.map(({ descriptor }) => descriptor);
|
|
202
|
+
return matches
|
|
203
|
+
.sort((left, right) => right.score - left.score || left.index - right.index)
|
|
204
|
+
.map(({ descriptor }) => descriptor);
|
|
205
|
+
}
|
|
206
|
+
|
|
153
207
|
function modeLookupInput(args: HarnessModeCatalogArgs): { readonly source: 'target' | 'query'; readonly input: string } | null {
|
|
154
208
|
const target = readString(args.target);
|
|
155
209
|
if (target) return { source: 'target', input: target };
|
|
@@ -161,8 +215,7 @@ export function listHarnessModes(args: HarnessModeCatalogArgs): Record<string, u
|
|
|
161
215
|
const lookup = modeLookupInput(args);
|
|
162
216
|
const limit = readLimit(args.limit, 120);
|
|
163
217
|
const normalized = lookup?.input.toLowerCase() ?? '';
|
|
164
|
-
const modes =
|
|
165
|
-
.filter((descriptor) => harnessModeMatchesSearch(descriptor, normalized))
|
|
218
|
+
const modes = matchingHarnessModes(normalized)
|
|
166
219
|
.map((descriptor) => describeHarnessModeDescriptor(descriptor, { includeParameters: args.includeParameters === true }))
|
|
167
220
|
.slice(0, limit);
|
|
168
221
|
return {
|
|
@@ -187,7 +240,7 @@ export function describeHarnessMode(args: HarnessModeCatalogArgs): HarnessModeRe
|
|
|
187
240
|
if (exact) return { status: 'found', mode: describeHarnessModeDescriptor(exact, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'id' } }) };
|
|
188
241
|
const insensitive = HARNESS_MODE_DESCRIPTORS.find((descriptor) => descriptor.id.toLowerCase() === normalized);
|
|
189
242
|
if (insensitive) return { status: 'found', mode: describeHarnessModeDescriptor(insensitive, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-id' } }) };
|
|
190
|
-
const searched =
|
|
243
|
+
const searched = matchingHarnessModes(normalized);
|
|
191
244
|
if (searched.length === 1) {
|
|
192
245
|
return { status: 'found', mode: describeHarnessModeDescriptor(searched[0]!, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }) };
|
|
193
246
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
2
|
import { requireProviderApi } from '../input/commands/runtime-services.ts';
|
|
3
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
3
4
|
|
|
4
5
|
export interface AgentHarnessModelRoutingArgs {
|
|
5
6
|
readonly modelRouteId?: unknown;
|
|
@@ -314,11 +315,14 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
314
315
|
kind: 'route',
|
|
315
316
|
modelRouteId: route.id,
|
|
316
317
|
label: route.label,
|
|
317
|
-
detail: route.detail,
|
|
318
|
+
...(options.includeParameters ? { detail: route.detail } : { summary: previewHarnessText(route.detail) }),
|
|
318
319
|
currentValue: route.currentValue,
|
|
319
320
|
settingKeys: route.settingKeys,
|
|
320
|
-
|
|
321
|
-
|
|
321
|
+
modelRoute: modelRoutingModelRoute(),
|
|
322
|
+
...(options.includeParameters ? {
|
|
323
|
+
commands: route.commands,
|
|
324
|
+
uiSurfaces: route.uiSurfaces,
|
|
325
|
+
} : {}),
|
|
322
326
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
323
327
|
...(options.includeParameters ? {
|
|
324
328
|
policy: {
|
|
@@ -350,6 +354,7 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
|
|
|
350
354
|
pinned: model.pinned,
|
|
351
355
|
contextWindow: model.contextWindow,
|
|
352
356
|
reasoningEffort: model.reasoningEffort,
|
|
357
|
+
modelRoute: modelCandidateModelRoute(),
|
|
353
358
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
354
359
|
...(options.includeParameters ? {
|
|
355
360
|
capabilities: model.capabilities,
|
|
@@ -374,6 +379,7 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
|
|
|
374
379
|
kind: 'route',
|
|
375
380
|
modelRouteId: entry.id,
|
|
376
381
|
label: entry.label,
|
|
382
|
+
modelRoute: modelRoutingModelRoute(),
|
|
377
383
|
};
|
|
378
384
|
}
|
|
379
385
|
return {
|
|
@@ -383,9 +389,18 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
|
|
|
383
389
|
displayName: entry.displayName,
|
|
384
390
|
current: entry.current,
|
|
385
391
|
pinned: entry.pinned,
|
|
392
|
+
modelRoute: modelCandidateModelRoute(),
|
|
386
393
|
};
|
|
387
394
|
}
|
|
388
395
|
|
|
396
|
+
function modelRoutingModelRoute(): string {
|
|
397
|
+
return 'agent_harness mode:"model_route" or mode:"run_command"';
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function modelCandidateModelRoute(): string {
|
|
401
|
+
return 'agent_harness mode:"run_command" command:"/model"';
|
|
402
|
+
}
|
|
403
|
+
|
|
389
404
|
export async function modelRoutingCatalogStatus(context: CommandContext): Promise<Record<string, unknown>> {
|
|
390
405
|
const [models, providerIds] = await Promise.all([
|
|
391
406
|
loadModels(context),
|
|
@@ -25,19 +25,91 @@ function readLimit(value: unknown, fallback: number): number {
|
|
|
25
25
|
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
-
function previewText(value: string, maxLength =
|
|
28
|
+
function previewText(value: string, maxLength = 56): string {
|
|
29
29
|
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
30
|
-
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength -
|
|
30
|
+
return normalized.length <= maxLength ? normalized : `${normalized.slice(0, maxLength - 3).trimEnd()}...`;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function searchTokens(input: string): readonly string[] {
|
|
34
|
+
return input.toLowerCase().split(/[^a-z0-9]+/).filter((token) => token.length > 0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function schemaSearchText(value: unknown): string {
|
|
38
|
+
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') return String(value);
|
|
39
|
+
if (Array.isArray(value)) return value.map(schemaSearchText).filter(Boolean).join('\n');
|
|
40
|
+
if (!value || typeof value !== 'object') return '';
|
|
41
|
+
return Object.entries(value)
|
|
42
|
+
.map(([key, entry]) => `${key}\n${schemaSearchText(entry)}`)
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.join('\n');
|
|
31
45
|
}
|
|
32
46
|
|
|
33
47
|
function modelToolSearchText(tool: HarnessModelToolDefinition): string {
|
|
34
48
|
return [
|
|
35
49
|
tool.name,
|
|
50
|
+
tool.name.replace(/_/g, ' '),
|
|
36
51
|
tool.description,
|
|
37
52
|
...(tool.sideEffects ?? []),
|
|
53
|
+
schemaSearchText(tool.parameters),
|
|
38
54
|
].join('\n').toLowerCase();
|
|
39
55
|
}
|
|
40
56
|
|
|
57
|
+
function modelToolMatchesSearch(tool: HarnessModelToolDefinition, input: string): boolean {
|
|
58
|
+
const text = modelToolSearchText(tool);
|
|
59
|
+
const normalized = input.toLowerCase().trim();
|
|
60
|
+
if (!normalized) return true;
|
|
61
|
+
if (text.includes(normalized)) return true;
|
|
62
|
+
const tokens = searchTokens(normalized);
|
|
63
|
+
return tokens.length > 0 && tokens.every((token) => text.includes(token));
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function tokenScore(tokens: readonly string[], value: string | undefined, weight: number): number {
|
|
67
|
+
if (!value) return 0;
|
|
68
|
+
const text = value.toLowerCase();
|
|
69
|
+
return tokens.reduce((score, token) => score + (text.includes(token) ? weight : 0), 0);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const ACTION_VERBS = new Set(['run', 'set', 'reset', 'open', 'create', 'send', 'schedule', 'generate', 'read', 'search', 'ingest']);
|
|
73
|
+
|
|
74
|
+
function modelToolRelevance(tool: HarnessModelToolDefinition, input: string): number {
|
|
75
|
+
const normalized = input.toLowerCase().trim();
|
|
76
|
+
if (!normalized) return 0;
|
|
77
|
+
|
|
78
|
+
const tokens = searchTokens(normalized);
|
|
79
|
+
const name = tool.name.toLowerCase();
|
|
80
|
+
const namePhrase = name.replace(/_/g, ' ');
|
|
81
|
+
const nameLookup = normalized.replace(/\s+/g, '_');
|
|
82
|
+
const parameterText = schemaSearchText(tool.parameters);
|
|
83
|
+
let score = 0;
|
|
84
|
+
|
|
85
|
+
if (name === normalized || namePhrase === normalized) score += 10_000;
|
|
86
|
+
if (name.startsWith(nameLookup) || namePhrase.startsWith(normalized)) score += 5_000;
|
|
87
|
+
if (name.includes(nameLookup) || namePhrase.includes(normalized)) score += 2_500;
|
|
88
|
+
|
|
89
|
+
score += tokenScore(tokens, `${name}\n${namePhrase}`, 1_000);
|
|
90
|
+
score += tokenScore(tokens, tool.description, 300);
|
|
91
|
+
score += tokenScore(tokens, (tool.sideEffects ?? []).join('\n'), 250);
|
|
92
|
+
score += tokenScore(tokens, parameterText, 150);
|
|
93
|
+
|
|
94
|
+
const actionVerb = tokens.find((token) => ACTION_VERBS.has(token));
|
|
95
|
+
if (actionVerb && searchTokens(name).includes(actionVerb)) score += 1_500;
|
|
96
|
+
|
|
97
|
+
return score;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function matchingModelTools(tools: readonly HarnessModelToolDefinition[], input: string): readonly HarnessModelToolDefinition[] {
|
|
101
|
+
const query = input.toLowerCase().trim();
|
|
102
|
+
const matches = tools
|
|
103
|
+
.map((tool, index) => ({ tool, index, score: modelToolRelevance(tool, query) }))
|
|
104
|
+
.filter(({ tool }) => modelToolMatchesSearch(tool, query));
|
|
105
|
+
return matches
|
|
106
|
+
.sort((left, right) => {
|
|
107
|
+
if (!query) return left.tool.name.localeCompare(right.tool.name);
|
|
108
|
+
return right.score - left.score || left.tool.name.localeCompare(right.tool.name) || left.index - right.index;
|
|
109
|
+
})
|
|
110
|
+
.map(({ tool }) => tool);
|
|
111
|
+
}
|
|
112
|
+
|
|
41
113
|
function modelToolLookupFromArgs(args: AgentHarnessModelToolCatalogArgs): { readonly source: ModelToolLookupSource; readonly input: string } | null {
|
|
42
114
|
const toolName = readString(args.toolName);
|
|
43
115
|
if (toolName) return { source: 'toolName', input: toolName };
|
|
@@ -51,6 +123,11 @@ function describeModelTool(tool: HarnessModelToolDefinition, options: { readonly
|
|
|
51
123
|
return {
|
|
52
124
|
name: tool.name,
|
|
53
125
|
...(options.includeParameters ? { description: tool.description } : { summary: previewText(tool.description) }),
|
|
126
|
+
modelRoute: tool.name,
|
|
127
|
+
modelAccess: {
|
|
128
|
+
inspect: `agent_harness mode:"tool" toolName:"${tool.name}"`,
|
|
129
|
+
invoke: tool.name,
|
|
130
|
+
},
|
|
54
131
|
sideEffects: tool.sideEffects ?? [],
|
|
55
132
|
concurrency: tool.concurrency ?? 'parallel',
|
|
56
133
|
supportsProgress: tool.supportsProgress ?? false,
|
|
@@ -64,6 +141,8 @@ function describeModelToolCandidates(tools: readonly HarnessModelToolDefinition[
|
|
|
64
141
|
return tools.slice(0, 8).map((tool) => ({
|
|
65
142
|
toolName: tool.name,
|
|
66
143
|
summary: previewText(tool.description),
|
|
144
|
+
modelRoute: tool.name,
|
|
145
|
+
inspectRoute: `agent_harness mode:"tool" toolName:"${tool.name}"`,
|
|
67
146
|
sideEffects: tool.sideEffects ?? [],
|
|
68
147
|
}));
|
|
69
148
|
}
|
|
@@ -71,10 +150,8 @@ function describeModelToolCandidates(tools: readonly HarnessModelToolDefinition[
|
|
|
71
150
|
export function listHarnessModelTools(toolRegistry: ToolRegistry, args: AgentHarnessModelToolCatalogArgs): readonly Record<string, unknown>[] {
|
|
72
151
|
const query = readString(args.query).toLowerCase();
|
|
73
152
|
const includeParameters = args.includeParameters === true;
|
|
74
|
-
const limit = readLimit(args.limit,
|
|
75
|
-
return toolRegistry.getToolDefinitions()
|
|
76
|
-
.filter((tool) => !query || modelToolSearchText(tool).includes(query))
|
|
77
|
-
.sort((a, b) => a.name.localeCompare(b.name))
|
|
153
|
+
const limit = readLimit(args.limit, 500);
|
|
154
|
+
return matchingModelTools(toolRegistry.getToolDefinitions(), query)
|
|
78
155
|
.slice(0, limit)
|
|
79
156
|
.map((tool) => describeModelTool(tool, { includeParameters }));
|
|
80
157
|
}
|
|
@@ -90,7 +167,8 @@ export function describeHarnessModelTool(toolRegistry: ToolRegistry, args: Agent
|
|
|
90
167
|
: (() => {
|
|
91
168
|
const insensitive = tools.find((tool) => tool.name.toLowerCase() === normalized);
|
|
92
169
|
if (insensitive) return { tool: insensitive, resolvedBy: 'case-insensitive-name' };
|
|
93
|
-
|
|
170
|
+
if (lookup.source === 'toolName') return null;
|
|
171
|
+
const searched = matchingModelTools(tools, normalized);
|
|
94
172
|
if (searched.length === 1) return { tool: searched[0]!, resolvedBy: 'search' };
|
|
95
173
|
if (searched.length > 1) return { candidates: searched };
|
|
96
174
|
return null;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
3
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
3
4
|
|
|
4
5
|
export interface AgentHarnessNotificationArgs {
|
|
5
6
|
readonly notificationTargetId?: unknown;
|
|
@@ -114,9 +115,14 @@ function describeTargetCandidate(target: NotificationTargetDescriptor): Record<s
|
|
|
114
115
|
fingerprint: target.fingerprint,
|
|
115
116
|
validUrl: target.validUrl,
|
|
116
117
|
...(target.host ? { host: target.host } : {}),
|
|
118
|
+
modelRoute: notificationTargetModelRoute(),
|
|
117
119
|
};
|
|
118
120
|
}
|
|
119
121
|
|
|
122
|
+
function notificationTargetModelRoute(): string {
|
|
123
|
+
return 'agent_notify or agent_harness mode:"notification_target"';
|
|
124
|
+
}
|
|
125
|
+
|
|
120
126
|
function describeTarget(
|
|
121
127
|
target: NotificationTargetDescriptor,
|
|
122
128
|
options: { readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> } = {},
|
|
@@ -131,26 +137,31 @@ function describeTarget(
|
|
|
131
137
|
...(target.pathDepth !== undefined ? { pathDepth: target.pathDepth } : {}),
|
|
132
138
|
...(target.hasQuery !== undefined ? { hasQuery: target.hasQuery } : {}),
|
|
133
139
|
value: '<redacted>',
|
|
140
|
+
modelRoute: notificationTargetModelRoute(),
|
|
134
141
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
135
|
-
...(options.includeParameters
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
142
|
+
...(options.includeParameters
|
|
143
|
+
? {
|
|
144
|
+
policy: {
|
|
145
|
+
effect: 'read-only',
|
|
146
|
+
values: 'Full webhook URLs are not returned because they can contain bearer tokens or secret path/query values.',
|
|
147
|
+
delivery: 'Use agent_notify only for one explicit, confirmed notification requested by the user.',
|
|
148
|
+
management: 'Use confirmed /notify mirrors only when the user explicitly asks to add, remove, clear, test, or send notification targets.',
|
|
149
|
+
},
|
|
150
|
+
modelAccess: {
|
|
151
|
+
sendTool: 'agent_notify',
|
|
152
|
+
listCommand: '/notify list',
|
|
153
|
+
addCommand: '/notify add <url> --yes',
|
|
154
|
+
removeCommand: '/notify remove <url> --yes',
|
|
155
|
+
clearCommand: '/notify clear --yes',
|
|
156
|
+
testCommand: '/notify test --yes',
|
|
157
|
+
settingsCategory: 'notifications.webhookUrls',
|
|
158
|
+
targetValueRequiredForRemove: true,
|
|
159
|
+
targetValuePolicy: 'Ask the user for the exact webhook URL before removing one target; do not infer it from redacted metadata.',
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
: {
|
|
163
|
+
summary: previewHarnessText(`${target.validUrl ? 'valid' : 'invalid'} notification webhook target ${target.index}`),
|
|
164
|
+
}),
|
|
154
165
|
};
|
|
155
166
|
}
|
|
156
167
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { AGENT_KNOWLEDGE_METHODS } from '../cli/agent-knowledge-methods.ts';
|
|
2
2
|
import { OPERATOR_ACTIONS } from '../agent/operator-actions.ts';
|
|
3
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
3
4
|
|
|
4
5
|
export interface AgentHarnessOperatorMethodArgs {
|
|
5
6
|
readonly methodId?: unknown;
|
|
@@ -120,7 +121,7 @@ function agentKnowledgeMethods(): readonly OperatorMethodDescriptor[] {
|
|
|
120
121
|
effect: readOnly ? 'read-only-network' : 'confirmed-agent-knowledge-write',
|
|
121
122
|
owner: 'connected-host',
|
|
122
123
|
preferredModelTool: readOnly ? 'agent_knowledge' : key === 'reindex' ? 'agent_harness mode:"run_command"' : 'agent_knowledge_ingest',
|
|
123
|
-
confirmation: readOnly ? 'Read-only; use the owning first-class tool.' : 'Requires explicit user request and confirmation through the owning tool or command
|
|
124
|
+
confirmation: readOnly ? 'Read-only; use the owning first-class tool.' : 'Requires explicit user request and confirmation through the owning tool or command route.',
|
|
124
125
|
boundary: 'Isolated Agent Knowledge route family only; default knowledge and non-Agent knowledge segments are forbidden.',
|
|
125
126
|
...(readOnly ? {} : {
|
|
126
127
|
parameters: [
|
|
@@ -193,23 +194,27 @@ function describeMethod(
|
|
|
193
194
|
return {
|
|
194
195
|
id: method.id,
|
|
195
196
|
label: method.label,
|
|
196
|
-
route: method.route,
|
|
197
197
|
effect: method.effect,
|
|
198
198
|
owner: method.owner,
|
|
199
|
-
|
|
200
|
-
confirmation: method.confirmation,
|
|
201
|
-
boundary: method.boundary,
|
|
199
|
+
modelRoute: previewHarnessText(method.preferredModelTool),
|
|
202
200
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
203
|
-
...(options.includeParameters ? {
|
|
201
|
+
...(options.includeParameters ? {
|
|
202
|
+
route: method.route,
|
|
203
|
+
preferredModelTool: method.preferredModelTool,
|
|
204
|
+
confirmation: method.confirmation,
|
|
205
|
+
boundary: method.boundary,
|
|
206
|
+
parameters: method.parameters ?? [],
|
|
207
|
+
} : {
|
|
208
|
+
summary: previewHarnessText(method.boundary),
|
|
209
|
+
}),
|
|
204
210
|
};
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
function describeCandidate(method: OperatorMethodDescriptor): Record<string, unknown> {
|
|
208
214
|
return {
|
|
209
215
|
methodId: method.id,
|
|
210
|
-
route: method.route,
|
|
211
216
|
effect: method.effect,
|
|
212
|
-
|
|
217
|
+
modelRoute: previewHarnessText(method.preferredModelTool),
|
|
213
218
|
};
|
|
214
219
|
}
|
|
215
220
|
|
|
@@ -4,6 +4,7 @@ import { GOODVIBES_AGENT_PAIRING_SURFACE } from '../config/surface.ts';
|
|
|
4
4
|
import { resolveRuntimeEndpointBinding } from '../cli/endpoints.ts';
|
|
5
5
|
import { connectedHostOperatorTokenFingerprint, readConnectedHostOperatorToken } from '../runtime/connected-host-auth.ts';
|
|
6
6
|
import { requirePlatform, requireShellPaths } from '../input/commands/runtime-services.ts';
|
|
7
|
+
import { previewHarnessText } from './agent-harness-text.ts';
|
|
7
8
|
|
|
8
9
|
export interface AgentHarnessPairingArgs {
|
|
9
10
|
readonly pairingRouteId?: unknown;
|
|
@@ -101,7 +102,7 @@ function pairingRoutes(): readonly PairingRoute[] {
|
|
|
101
102
|
{
|
|
102
103
|
id: 'connected-host-status',
|
|
103
104
|
label: 'Connected host live posture',
|
|
104
|
-
detail: 'Read-only reachability, token posture,
|
|
105
|
+
detail: 'Read-only reachability, token posture, and route readiness used before companion setup.',
|
|
105
106
|
effect: 'read-only',
|
|
106
107
|
harnessRoute: 'agent_harness mode:"connected_host_status"',
|
|
107
108
|
capabilityIds: ['connected-host-status'],
|
|
@@ -152,6 +153,7 @@ function describeCandidate(route: PairingRoute): Record<string, unknown> {
|
|
|
152
153
|
label: route.label,
|
|
153
154
|
effect: route.effect,
|
|
154
155
|
requiresConfirmation: route.requiresConfirmation === true,
|
|
156
|
+
modelRoute: pairingRouteModelRoute(route),
|
|
155
157
|
};
|
|
156
158
|
}
|
|
157
159
|
|
|
@@ -159,12 +161,15 @@ function describeRoute(route: PairingRoute, options: { readonly includeParameter
|
|
|
159
161
|
return {
|
|
160
162
|
pairingRouteId: route.id,
|
|
161
163
|
label: route.label,
|
|
162
|
-
detail: route.detail,
|
|
164
|
+
...(options.includeParameters ? { detail: route.detail } : { summary: previewHarnessText(route.detail) }),
|
|
163
165
|
effect: route.effect,
|
|
164
|
-
...(route.command ? { command: route.command } : {}),
|
|
165
|
-
...(route.harnessRoute ? { harnessRoute: route.harnessRoute } : {}),
|
|
166
|
-
...(route.capabilityIds ? { capabilityIds: route.capabilityIds } : {}),
|
|
167
166
|
requiresConfirmation: route.requiresConfirmation === true,
|
|
167
|
+
modelRoute: pairingRouteModelRoute(route),
|
|
168
|
+
...(options.includeParameters ? {
|
|
169
|
+
...(route.command ? { command: route.command } : {}),
|
|
170
|
+
...(route.harnessRoute ? { harnessRoute: route.harnessRoute } : {}),
|
|
171
|
+
...(route.capabilityIds ? { capabilityIds: route.capabilityIds } : {}),
|
|
172
|
+
} : {}),
|
|
168
173
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
169
174
|
...(options.includeParameters ? {
|
|
170
175
|
policy: {
|
|
@@ -183,6 +188,13 @@ function describeRoute(route: PairingRoute, options: { readonly includeParameter
|
|
|
183
188
|
};
|
|
184
189
|
}
|
|
185
190
|
|
|
191
|
+
function pairingRouteModelRoute(route: PairingRoute): string {
|
|
192
|
+
if (route.command === '/pair') return 'agent_harness mode:"run_command" command:"/pair"';
|
|
193
|
+
if (route.command === '/pair --show-token --yes') return 'agent_harness mode:"run_command" command:"/pair --show-token --yes"';
|
|
194
|
+
if (route.id === 'pairing-ui') return 'agent_harness mode:"workspace_action" target:"pair"';
|
|
195
|
+
return previewHarnessText(route.harnessRoute ?? 'agent_harness mode:"pairing_route"');
|
|
196
|
+
}
|
|
197
|
+
|
|
186
198
|
function pairingState(context: CommandContext): Record<string, unknown> {
|
|
187
199
|
const shellPaths = requireShellPaths(context);
|
|
188
200
|
const configManager = requirePlatform(context).configManager;
|