@pellux/goodvibes-agent 1.1.7 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +170 -0
- package/README.md +46 -30
- package/dist/package/{ast-grep-napi.linux-x64-gnu-mkk8xwww.node → ast-grep-napi.linux-x64-gnu-swtppvy9.node} +0 -0
- package/dist/package/{ast-grep-napi.linux-x64-musl-ryqtgdv6.node → ast-grep-napi.linux-x64-musl-ttfcdtap.node} +0 -0
- package/dist/package/main.js +132577 -91483
- package/docs/README.md +14 -7
- package/docs/channels-remote-and-api.md +8 -5
- package/docs/connected-host.md +14 -12
- package/docs/getting-started.md +56 -30
- package/docs/knowledge-artifacts-and-multimodal.md +7 -5
- package/docs/project-planning.md +2 -2
- package/docs/providers-and-routing.md +11 -3
- package/docs/tools-and-commands.md +114 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +130 -5
- package/release/release-readiness.json +120 -90
- package/src/agent/assistant-cockpit.ts +247 -0
- package/src/agent/autonomy-schedule-format.ts +96 -0
- package/src/agent/autonomy-schedule.ts +514 -0
- package/src/agent/channel-delivery-receipts.ts +292 -0
- package/src/agent/competitive-feature-inventory.ts +296 -0
- package/src/agent/document-registry-types.ts +106 -0
- package/src/agent/document-registry.ts +734 -0
- package/src/agent/harness-control.ts +2 -2
- package/src/agent/memory-prompt.ts +2 -2
- package/src/agent/operator-actions.ts +50 -6
- package/src/agent/persona-registry.ts +8 -0
- package/src/agent/project-context-files.ts +273 -0
- package/src/agent/prompt-context-receipts.ts +502 -0
- package/src/agent/reminder-schedule-format.ts +16 -2
- package/src/agent/research-run-registry.ts +582 -0
- package/src/agent/research-source-registry.ts +441 -0
- package/src/agent/routine-registry.ts +19 -3
- package/src/agent/routine-schedule-format.ts +27 -2
- package/src/agent/runtime-profile-starters.ts +7 -0
- package/src/agent/runtime-profile.ts +106 -4
- package/src/agent/schedule-edit-format.ts +129 -0
- package/src/agent/schedule-edit.ts +496 -0
- package/src/agent/schedule-next-routes.ts +42 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +447 -0
- package/src/agent/skill-registry-types.ts +102 -0
- package/src/agent/skill-registry.ts +81 -107
- package/src/agent/vibe-confirmation-routes.ts +62 -0
- package/src/agent/vibe-file.ts +285 -0
- package/src/cli/agent-knowledge-command.ts +45 -2
- package/src/cli/help.ts +3 -0
- package/src/cli/profiles-command.ts +25 -11
- package/src/config/agent-settings-policy.ts +1 -18
- package/src/input/agent-workspace-activation.ts +53 -0
- package/src/input/agent-workspace-artifact-browser-editor.ts +494 -0
- package/src/input/agent-workspace-artifact-metadata.ts +17 -0
- package/src/input/agent-workspace-basic-command-editors.ts +5 -1
- package/src/input/agent-workspace-categories.ts +153 -155
- package/src/input/agent-workspace-channel-triage.ts +481 -0
- package/src/input/agent-workspace-channels.ts +263 -0
- package/src/input/agent-workspace-command-editor.ts +152 -0
- package/src/input/agent-workspace-context-snapshot.ts +349 -0
- package/src/input/agent-workspace-delegation-editor-submission.ts +8 -0
- package/src/input/agent-workspace-document-editor.ts +502 -0
- package/src/input/agent-workspace-document-ops-editor.ts +523 -0
- package/src/input/agent-workspace-host-category.ts +1 -1
- package/src/input/agent-workspace-local-library-snapshot.ts +167 -0
- package/src/input/agent-workspace-model-compare-editor.ts +376 -0
- package/src/input/agent-workspace-model-compare-prompt-submission.ts +552 -0
- package/src/input/agent-workspace-model-compare-types.ts +82 -0
- package/src/input/agent-workspace-model-compare-utils.ts +35 -0
- package/src/input/agent-workspace-onboarding-categories.ts +141 -0
- package/src/input/agent-workspace-operations-command-editor-submission.ts +53 -0
- package/src/input/agent-workspace-operations-command-editors.ts +22 -0
- package/src/input/agent-workspace-research-report-editor.ts +212 -0
- package/src/input/agent-workspace-research-run-editor.ts +144 -0
- package/src/input/agent-workspace-research-source-editor.ts +167 -0
- package/src/input/agent-workspace-review-packet-snapshot.ts +593 -0
- package/src/input/agent-workspace-review-packet-utils.ts +265 -0
- package/src/input/agent-workspace-settings.ts +262 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +198 -0
- package/src/input/agent-workspace-setup.ts +34 -1
- package/src/input/agent-workspace-snapshot.ts +162 -147
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +18 -0
- package/src/input/command-registry.ts +9 -2
- package/src/input/commands/agent-runtime-profile-runtime.ts +28 -13
- package/src/input/commands/channels-runtime.ts +102 -114
- package/src/input/commands/delegation-runtime.ts +87 -24
- package/src/input/commands/knowledge-browser-flags.ts +12 -0
- package/src/input/commands/knowledge.ts +28 -14
- package/src/input/commands/operator-actions-runtime.ts +6 -3
- package/src/input/commands/schedule-runtime.ts +71 -14
- package/src/input/commands/session-content.ts +2 -2
- package/src/input/commands/shell-core.ts +2 -0
- package/src/input/commands/vibe-runtime.ts +140 -0
- package/src/input/commands.ts +2 -0
- package/src/input/connected-host-routes.ts +123 -0
- package/src/input/settings-modal-types.ts +14 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +686 -0
- package/src/renderer/agent-workspace.ts +30 -419
- package/src/renderer/settings-modal-helpers.ts +12 -0
- package/src/renderer/settings-modal.ts +12 -0
- package/src/runtime/bootstrap-command-context.ts +11 -1
- package/src/runtime/bootstrap-command-parts.ts +14 -3
- package/src/runtime/bootstrap-core.ts +39 -1
- package/src/runtime/bootstrap-shell.ts +6 -0
- package/src/runtime/bootstrap.ts +113 -30
- package/src/runtime/connected-host-auth.ts +3 -2
- package/src/runtime/execution-ledger.ts +231 -0
- package/src/runtime/services.ts +88 -10
- package/src/runtime/tool-permission-safety.ts +199 -5
- package/src/shell/session-continuity-hints.ts +39 -0
- package/src/tools/agent-artifacts-tool.ts +606 -0
- package/src/tools/agent-audit-tool.ts +155 -0
- package/src/tools/agent-autonomy-schedule-tool.ts +238 -0
- package/src/tools/agent-autonomy-tool.ts +140 -0
- package/src/tools/agent-channel-send-tool.ts +24 -2
- package/src/tools/agent-channels-tool.ts +140 -0
- package/src/tools/agent-computer-tool.ts +168 -0
- package/src/tools/agent-context-policy.ts +137 -7
- package/src/tools/agent-context-tool.ts +143 -0
- package/src/tools/agent-delegation-tool.ts +128 -0
- package/src/tools/agent-device-tool.ts +240 -0
- package/src/tools/agent-documents-tool.ts +684 -0
- package/src/tools/agent-execution-tool.ts +230 -0
- package/src/tools/agent-harness-agent-orchestration.ts +703 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +588 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +560 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +794 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +219 -0
- package/src/tools/agent-harness-browser-control.ts +338 -0
- package/src/tools/agent-harness-channel-metadata.ts +168 -10
- package/src/tools/agent-harness-cli-command-policy.ts +110 -0
- package/src/tools/agent-harness-command-catalog.ts +4 -2
- package/src/tools/agent-harness-command-runner.ts +42 -0
- package/src/tools/agent-harness-connected-host-status.ts +7 -4
- package/src/tools/agent-harness-delegation-posture.ts +234 -19
- package/src/tools/agent-harness-document-ops-reviewer-readiness.ts +234 -0
- package/src/tools/agent-harness-document-ops-types.ts +72 -0
- package/src/tools/agent-harness-document-ops.ts +671 -0
- package/src/tools/agent-harness-execution-history.ts +489 -0
- package/src/tools/agent-harness-execution-posture.ts +382 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-keybinding-metadata.ts +16 -12
- package/src/tools/agent-harness-learning-curator-common.ts +102 -0
- package/src/tools/agent-harness-learning-curator-consolidation.ts +295 -0
- package/src/tools/agent-harness-learning-curator-proposals.ts +606 -0
- package/src/tools/agent-harness-learning-curator-types.ts +151 -0
- package/src/tools/agent-harness-learning-curator.ts +417 -0
- package/src/tools/agent-harness-local-model-benchmarks.ts +199 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +673 -0
- package/src/tools/agent-harness-media-posture.ts +208 -2
- package/src/tools/agent-harness-memory-posture.ts +556 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +84 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +186 -0
- package/src/tools/agent-harness-model-readiness.ts +406 -0
- package/src/tools/agent-harness-model-routing-types.ts +266 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +137 -190
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +431 -18
- package/src/tools/agent-harness-personal-ops-discovery.ts +533 -0
- package/src/tools/agent-harness-personal-ops-intake.ts +385 -0
- package/src/tools/agent-harness-personal-ops-lanes.ts +204 -0
- package/src/tools/agent-harness-personal-ops-records.ts +732 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +222 -0
- package/src/tools/agent-harness-personal-ops.ts +606 -0
- package/src/tools/agent-harness-project-context.ts +144 -0
- package/src/tools/agent-harness-prompt-context.ts +589 -0
- package/src/tools/agent-harness-provider-account-metadata.ts +2 -2
- package/src/tools/agent-harness-release-evidence.ts +9 -7
- package/src/tools/agent-harness-release-readiness.ts +9 -7
- package/src/tools/agent-harness-research-briefing.ts +427 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +295 -0
- package/src/tools/agent-harness-research-workflow.ts +322 -0
- package/src/tools/agent-harness-security-posture.ts +2 -2
- package/src/tools/agent-harness-service-posture.ts +9 -9
- package/src/tools/agent-harness-session-metadata.ts +3 -3
- package/src/tools/agent-harness-setup-connected-host.ts +501 -0
- package/src/tools/agent-harness-setup-describe.ts +557 -0
- package/src/tools/agent-harness-setup-handoffs.ts +502 -0
- package/src/tools/agent-harness-setup-model-helpers.ts +101 -0
- package/src/tools/agent-harness-setup-plan.ts +253 -0
- package/src/tools/agent-harness-setup-posture-types.ts +218 -0
- package/src/tools/agent-harness-setup-posture-utils.ts +173 -0
- package/src/tools/agent-harness-setup-posture.ts +449 -221
- package/src/tools/agent-harness-setup-smoke.ts +508 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +120 -7
- package/src/tools/agent-harness-tool-types.ts +78 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +311 -370
- package/src/tools/agent-harness-ui-surface-metadata.ts +76 -69
- package/src/tools/agent-harness-ui-surface-types.ts +46 -0
- package/src/tools/agent-harness-vibe-health.ts +105 -0
- package/src/tools/agent-harness-workspace-action-runner.ts +149 -0
- package/src/tools/agent-harness-workspace-actions.ts +114 -8
- package/src/tools/agent-harness-workspace-editor-execution.ts +214 -0
- package/src/tools/agent-harness-workspace-editor-runner.ts +755 -0
- package/src/tools/agent-host-tool.ts +159 -0
- package/src/tools/agent-knowledge-ingest-tool.ts +34 -1
- package/src/tools/agent-learning-consolidation-core.ts +327 -0
- package/src/tools/agent-learning-consolidation-tool.ts +758 -0
- package/src/tools/agent-memory-tool.ts +214 -0
- package/src/tools/agent-model-compare-export.ts +315 -0
- package/src/tools/agent-model-compare-handoff.ts +592 -0
- package/src/tools/agent-model-compare-judgment.ts +633 -0
- package/src/tools/agent-model-compare-run.ts +722 -0
- package/src/tools/agent-model-compare-tool.ts +698 -0
- package/src/tools/agent-model-compare-types.ts +191 -0
- package/src/tools/agent-model-compare-utils.ts +93 -0
- package/src/tools/agent-models-tool.ts +208 -0
- package/src/tools/agent-operator-action-tool.ts +1 -1
- package/src/tools/agent-operator-method-tool.ts +643 -0
- package/src/tools/agent-personal-ops-tool.ts +197 -0
- package/src/tools/agent-policy-explanation.ts +415 -0
- package/src/tools/agent-research-report-tool.ts +608 -0
- package/src/tools/agent-research-runs-tool.ts +434 -0
- package/src/tools/agent-research-sources-tool.ts +443 -0
- package/src/tools/agent-research-tool.ts +687 -0
- package/src/tools/agent-review-packet-presets-core.ts +757 -0
- package/src/tools/agent-review-packet-presets-tool.ts +466 -0
- package/src/tools/agent-review-packet-share-tool.ts +305 -0
- package/src/tools/agent-route-planner-candidates-setup.ts +411 -0
- package/src/tools/agent-route-planner-candidates-surfaces.ts +432 -0
- package/src/tools/agent-route-planner-candidates-work.ts +251 -0
- package/src/tools/agent-route-planner-helpers.ts +667 -0
- package/src/tools/agent-route-planner.ts +185 -0
- package/src/tools/agent-route-tool.ts +105 -0
- package/src/tools/agent-schedule-edit-tool.ts +210 -0
- package/src/tools/agent-schedule-tool.ts +282 -0
- package/src/tools/agent-security-tool.ts +145 -0
- package/src/tools/agent-sessions-tool.ts +122 -0
- package/src/tools/agent-settings-import-tool.ts +104 -0
- package/src/tools/agent-settings-tool.ts +176 -0
- package/src/tools/agent-setup-tool.ts +226 -0
- package/src/tools/agent-support-tool.ts +122 -0
- package/src/tools/agent-terminal-process-tools.ts +167 -0
- package/src/tools/agent-tool-policy-guard-types.ts +77 -0
- package/src/tools/agent-tool-policy-guard.ts +106 -85
- package/src/tools/agent-vibe-tool.ts +297 -0
- package/src/tools/agent-work-plan-tool.ts +265 -6
- package/src/tools/agent-workspace-tool.ts +305 -0
- package/src/tools/artifact-archive.ts +169 -0
- package/src/tools/tool-definition-compaction.ts +36 -0
- package/src/version.ts +1 -1
|
@@ -1,175 +1,17 @@
|
|
|
1
|
+
import { arch, cpus, freemem, platform, totalmem } from 'node:os';
|
|
2
|
+
import type { ArtifactDescriptor } from '@pellux/goodvibes-sdk/platform/artifacts';
|
|
1
3
|
import type { CommandContext } from '../input/command-registry.ts';
|
|
2
4
|
import { requireProviderApi } from '../input/commands/runtime-services.ts';
|
|
3
5
|
import { previewHarnessText } from './agent-harness-text.ts';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
type ModelRouteResolution =
|
|
14
|
-
| { readonly status: 'found'; readonly route: Record<string, unknown> }
|
|
15
|
-
| { readonly status: 'ambiguous'; readonly input: string; readonly candidates: readonly Record<string, unknown>[] }
|
|
16
|
-
| { readonly status: 'missing_lookup'; readonly usage: string };
|
|
17
|
-
|
|
18
|
-
type ModelRouteLookupSource = 'modelRouteId' | 'target' | 'query';
|
|
19
|
-
|
|
20
|
-
interface ModelCandidate {
|
|
21
|
-
readonly kind: 'model';
|
|
22
|
-
readonly id: string;
|
|
23
|
-
readonly registryKey: string;
|
|
24
|
-
readonly modelId: string;
|
|
25
|
-
readonly providerId: string;
|
|
26
|
-
readonly displayName: string;
|
|
27
|
-
readonly current: boolean;
|
|
28
|
-
readonly contextWindow: number | null;
|
|
29
|
-
readonly reasoningEffort: readonly string[];
|
|
30
|
-
readonly capabilities: unknown;
|
|
31
|
-
readonly pinned: boolean;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
interface RouteCandidate {
|
|
35
|
-
readonly kind: 'route';
|
|
36
|
-
readonly id: string;
|
|
37
|
-
readonly label: string;
|
|
38
|
-
readonly detail: string;
|
|
39
|
-
readonly currentValue: unknown;
|
|
40
|
-
readonly settingKeys: readonly string[];
|
|
41
|
-
readonly commands: readonly string[];
|
|
42
|
-
readonly uiSurfaces: readonly string[];
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
interface ProviderApiLike {
|
|
46
|
-
readonly getFavorites: () => Promise<unknown>;
|
|
47
|
-
readonly getCurrentModel: () => Promise<unknown>;
|
|
48
|
-
readonly listModels: (options?: { readonly selectableOnly?: boolean }) => Promise<readonly unknown[]>;
|
|
49
|
-
readonly listProviderIds: () => readonly string[];
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function readString(value: unknown): string {
|
|
53
|
-
return typeof value === 'string' ? value.trim() : '';
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function readLimit(value: unknown, fallback: number): number {
|
|
57
|
-
const parsed = typeof value === 'string' && value.trim() ? Number(value) : value;
|
|
58
|
-
if (typeof parsed !== 'number' || !Number.isFinite(parsed)) return fallback;
|
|
59
|
-
return Math.max(1, Math.min(500, Math.trunc(parsed)));
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function readRecord(value: unknown): Record<string, unknown> {
|
|
63
|
-
return value && typeof value === 'object' ? value as Record<string, unknown> : {};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function readStringArray(value: unknown): readonly string[] {
|
|
67
|
-
return Array.isArray(value) ? value.map((entry) => readString(entry)).filter(Boolean) : [];
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function readConfig(context: CommandContext, key: string): unknown {
|
|
71
|
-
try {
|
|
72
|
-
return (context.platform.configManager as { get(settingKey: string): unknown }).get(key);
|
|
73
|
-
} catch {
|
|
74
|
-
return undefined;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function contextWindowFor(context: CommandContext, model: unknown): number | null {
|
|
79
|
-
try {
|
|
80
|
-
const registry = context.provider.providerRegistry as { getContextWindowForModel(candidate: unknown): number };
|
|
81
|
-
const value = registry.getContextWindowForModel(model);
|
|
82
|
-
return typeof value === 'number' && Number.isFinite(value) ? value : null;
|
|
83
|
-
} catch {
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function modelRegistryKey(model: unknown): string {
|
|
89
|
-
const record = readRecord(model);
|
|
90
|
-
return readString(record.registryKey) || readString(record.id) || readString(record.modelId);
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
function modelProviderId(model: unknown): string {
|
|
94
|
-
const record = readRecord(model);
|
|
95
|
-
return readString(record.providerId) || readString(record.provider);
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
function modelModelId(model: unknown): string {
|
|
99
|
-
const record = readRecord(model);
|
|
100
|
-
return readString(record.modelId) || readString(record.id) || modelRegistryKey(model);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function modelDisplayName(model: unknown): string {
|
|
104
|
-
const record = readRecord(model);
|
|
105
|
-
return readString(record.displayName) || readString(record.name) || modelRegistryKey(model);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function modelCurrent(model: unknown): boolean {
|
|
109
|
-
const record = readRecord(model);
|
|
110
|
-
return record.current === true;
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function modelReasoning(model: unknown): readonly string[] {
|
|
114
|
-
const record = readRecord(model);
|
|
115
|
-
return readStringArray(record.reasoningEffort);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
function modelCapabilities(model: unknown): unknown {
|
|
119
|
-
return readRecord(model).capabilities ?? null;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function readProviderApi(context: CommandContext): ProviderApiLike | null {
|
|
123
|
-
try {
|
|
124
|
-
return requireProviderApi(context) as ProviderApiLike;
|
|
125
|
-
} catch {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
async function loadPinnedModelIds(context: CommandContext): Promise<ReadonlySet<string>> {
|
|
131
|
-
const providerApi = readProviderApi(context);
|
|
132
|
-
if (!providerApi) return new Set();
|
|
133
|
-
try {
|
|
134
|
-
const favorites = await providerApi.getFavorites();
|
|
135
|
-
const pinned = readRecord(favorites).pinned;
|
|
136
|
-
if (!Array.isArray(pinned)) return new Set();
|
|
137
|
-
return new Set(pinned.flatMap((entry) => {
|
|
138
|
-
const record = readRecord(entry);
|
|
139
|
-
return [readString(record.registryKey), readString(record.modelId)].filter(Boolean);
|
|
140
|
-
}));
|
|
141
|
-
} catch {
|
|
142
|
-
return new Set();
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function loadModels(context: CommandContext): Promise<readonly ModelCandidate[]> {
|
|
147
|
-
const providerApi = readProviderApi(context);
|
|
148
|
-
if (!providerApi) return [];
|
|
149
|
-
const pinned = await loadPinnedModelIds(context);
|
|
150
|
-
const models = await providerApi.listModels({ selectableOnly: true });
|
|
151
|
-
return models.map((model) => {
|
|
152
|
-
const registryKey = modelRegistryKey(model);
|
|
153
|
-
const modelId = modelModelId(model);
|
|
154
|
-
return {
|
|
155
|
-
kind: 'model',
|
|
156
|
-
id: registryKey,
|
|
157
|
-
registryKey,
|
|
158
|
-
modelId,
|
|
159
|
-
providerId: modelProviderId(model),
|
|
160
|
-
displayName: modelDisplayName(model),
|
|
161
|
-
current: modelCurrent(model) || registryKey === context.session.runtime.model,
|
|
162
|
-
contextWindow: contextWindowFor(context, model),
|
|
163
|
-
reasoningEffort: modelReasoning(model),
|
|
164
|
-
capabilities: modelCapabilities(model),
|
|
165
|
-
pinned: pinned.has(registryKey) || pinned.has(modelId),
|
|
166
|
-
};
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
function listProviderIds(context: CommandContext): readonly string[] {
|
|
171
|
-
return readProviderApi(context)?.listProviderIds() ?? [];
|
|
172
|
-
}
|
|
6
|
+
import { localModelCookbook } from './agent-harness-local-model-cookbook.ts';
|
|
7
|
+
import { collectLocalServerEndpointCandidates, describeLocalServerEndpoint, localModelDetection, localModelServerHealthMap, runLocalModelServerSmoke } from './agent-harness-local-model-endpoints.ts';
|
|
8
|
+
import { localHardwareProfile, modelReadinessScore } from './agent-harness-model-readiness.ts';
|
|
9
|
+
import { contextWindowFor, loadModels, listProviderIds, modelBenchmarkCompositeScore, modelBenchmarkQualityTier, modelCapabilities, modelCurrent, modelDisplayName, modelModelId, modelProviderId, modelReasoning, modelRegistryKey, modelTier, readConfig, readProviderApi } from './agent-harness-model-catalog.ts';
|
|
10
|
+
import type { AgentHarnessModelRoutingArgs, LocalModelServerEndpoint, ModelCandidate, ModelProviderHealthSignal, ModelRouteLookupSource, ModelRouteResolution, RouteCandidate } from './agent-harness-model-routing-types.ts';
|
|
11
|
+
import { readLimit, readString } from './agent-harness-model-routing-utils.ts';
|
|
12
|
+
export type { AgentHarnessModelRoutingArgs } from './agent-harness-model-routing-types.ts';
|
|
13
|
+
export { localModelCookbook } from './agent-harness-local-model-cookbook.ts';
|
|
14
|
+
export { runLocalModelServerSmoke } from './agent-harness-local-model-endpoints.ts';
|
|
173
15
|
|
|
174
16
|
async function readCurrentModel(context: CommandContext): Promise<unknown> {
|
|
175
17
|
try {
|
|
@@ -253,6 +95,20 @@ function routeCandidates(context: CommandContext): readonly RouteCandidate[] {
|
|
|
253
95
|
commands: ['/refresh-models'],
|
|
254
96
|
uiSurfaces: ['model-picker'],
|
|
255
97
|
},
|
|
98
|
+
{
|
|
99
|
+
kind: 'route',
|
|
100
|
+
id: 'local-model-cookbook',
|
|
101
|
+
label: 'Local model cookbook',
|
|
102
|
+
detail: 'Hardware-aware recommendations for Ollama, llama.cpp, vLLM, and local OpenAI-compatible servers.',
|
|
103
|
+
currentValue: {
|
|
104
|
+
detected: localModelDetection(context),
|
|
105
|
+
hardwareProfile: localHardwareProfile(),
|
|
106
|
+
localServerHealth: localModelServerHealthMap(context, false),
|
|
107
|
+
},
|
|
108
|
+
settingKeys: [],
|
|
109
|
+
commands: ['/provider add <name> <baseURL> [apiKey] --yes', '/refresh-models', '/model'],
|
|
110
|
+
uiSurfaces: ['provider-picker', 'model-picker', 'settings'],
|
|
111
|
+
},
|
|
256
112
|
{
|
|
257
113
|
kind: 'route',
|
|
258
114
|
id: 'pinned-models',
|
|
@@ -310,7 +166,39 @@ function modelSearchText(model: ModelCandidate): string {
|
|
|
310
166
|
].join('\n').toLowerCase();
|
|
311
167
|
}
|
|
312
168
|
|
|
313
|
-
function
|
|
169
|
+
function localEndpointSearchText(endpoint: LocalModelServerEndpoint): string {
|
|
170
|
+
return [
|
|
171
|
+
endpoint.id,
|
|
172
|
+
endpoint.providerId ?? '',
|
|
173
|
+
endpoint.stack ?? '',
|
|
174
|
+
endpoint.baseUrl,
|
|
175
|
+
endpoint.modelsUrl,
|
|
176
|
+
endpoint.diagnosticStatus,
|
|
177
|
+
...endpoint.sources,
|
|
178
|
+
...endpoint.sourceDetails,
|
|
179
|
+
...endpoint.modelRoutes,
|
|
180
|
+
...endpoint.notes,
|
|
181
|
+
].join('\n').toLowerCase();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function describeLocalServerEndpointRoute(endpoint: LocalModelServerEndpoint, lookup?: Record<string, unknown>): Record<string, unknown> {
|
|
185
|
+
return {
|
|
186
|
+
...endpoint,
|
|
187
|
+
...(lookup ? { lookup } : {}),
|
|
188
|
+
modelRouteId: endpoint.id,
|
|
189
|
+
label: `Local model server ${endpoint.baseUrl}`,
|
|
190
|
+
modelRoute: endpoint.inspectRoute,
|
|
191
|
+
modelAccess: {
|
|
192
|
+
smoke: endpoint.smokeRoute,
|
|
193
|
+
refresh: endpoint.refreshRoute,
|
|
194
|
+
addProvider: endpoint.addProviderRoute,
|
|
195
|
+
cookbook: 'models action:"local" includeParameters:true',
|
|
196
|
+
},
|
|
197
|
+
policy: endpoint.diagnostics?.policy ?? 'Read-only local model endpoint inspection. The smoke test, refresh, provider add, benchmark, and route changes remain separate visible confirmed actions.',
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
function describeRoute(route: RouteCandidate, options: { readonly context: CommandContext; readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> }): Record<string, unknown> {
|
|
314
202
|
return {
|
|
315
203
|
kind: 'route',
|
|
316
204
|
modelRouteId: route.id,
|
|
@@ -324,6 +212,7 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
324
212
|
uiSurfaces: route.uiSurfaces,
|
|
325
213
|
} : {}),
|
|
326
214
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
215
|
+
...(route.id === 'local-model-cookbook' && options.includeParameters === true ? { localCookbook: localModelCookbook(options.context, true) } : {}),
|
|
327
216
|
...(options.includeParameters ? {
|
|
328
217
|
policy: {
|
|
329
218
|
effect: 'read-only',
|
|
@@ -331,10 +220,10 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
331
220
|
mutation: 'Model/provider selection, catalog refresh, favorites, custom provider edits, and route setting changes stay explicit user-facing picker, settings, workspace, or slash-command flows.',
|
|
332
221
|
},
|
|
333
222
|
modelAccess: {
|
|
334
|
-
inspectRouting: '
|
|
223
|
+
inspectRouting: 'models action:"status"',
|
|
335
224
|
inspectRoute: 'agent_harness mode:"model_route"',
|
|
336
|
-
settingRead: '
|
|
337
|
-
settingMutation: '
|
|
225
|
+
settingRead: 'settings action:"get"',
|
|
226
|
+
settingMutation: 'settings action:"set" confirm:true explicitUserRequest:"..."',
|
|
338
227
|
openModelPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"model-picker" confirm:true explicitUserRequest:"..."',
|
|
339
228
|
openProviderPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"provider-picker" confirm:true explicitUserRequest:"..."',
|
|
340
229
|
},
|
|
@@ -342,7 +231,21 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
342
231
|
};
|
|
343
232
|
}
|
|
344
233
|
|
|
345
|
-
function
|
|
234
|
+
function compactProviderHealthSignal(signal: ModelProviderHealthSignal): Record<string, unknown> {
|
|
235
|
+
return {
|
|
236
|
+
status: signal.status,
|
|
237
|
+
sdkContract: signal.sdkContract,
|
|
238
|
+
daemonPublication: signal.daemonPublication,
|
|
239
|
+
agentConsumption: signal.agentConsumption,
|
|
240
|
+
...(signal.healthStatus ? { healthStatus: signal.healthStatus } : {}),
|
|
241
|
+
...(signal.avgLatencyMs !== undefined ? { avgLatencyMs: signal.avgLatencyMs } : {}),
|
|
242
|
+
missingSignals: signal.missingSignals,
|
|
243
|
+
policy: signal.policy,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
function describeModel(model: ModelCandidate, options: { readonly context: CommandContext; readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> }): Record<string, unknown> {
|
|
248
|
+
const readiness = modelReadinessScore(options.context, model);
|
|
346
249
|
return {
|
|
347
250
|
kind: 'model',
|
|
348
251
|
modelRouteId: model.registryKey,
|
|
@@ -354,6 +257,20 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
|
|
|
354
257
|
pinned: model.pinned,
|
|
355
258
|
contextWindow: model.contextWindow,
|
|
356
259
|
reasoningEffort: model.reasoningEffort,
|
|
260
|
+
tier: model.tier ?? null,
|
|
261
|
+
benchmarkCompositeScore: model.benchmarkCompositeScore ?? null,
|
|
262
|
+
benchmarkQualityTier: model.benchmarkQualityTier ?? null,
|
|
263
|
+
readinessScore: readiness.score,
|
|
264
|
+
readinessLevel: readiness.level,
|
|
265
|
+
readiness: options.includeParameters
|
|
266
|
+
? readiness
|
|
267
|
+
: {
|
|
268
|
+
score: readiness.score,
|
|
269
|
+
level: readiness.level,
|
|
270
|
+
confidence: readiness.confidence,
|
|
271
|
+
providerHealth: compactProviderHealthSignal(readiness.providerHealth),
|
|
272
|
+
nextStep: readiness.nextStep,
|
|
273
|
+
},
|
|
357
274
|
modelRoute: modelCandidateModelRoute(),
|
|
358
275
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
359
276
|
...(options.includeParameters ? {
|
|
@@ -367,7 +284,7 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
|
|
|
367
284
|
selectProviderCommand: `/provider ${model.providerId}`,
|
|
368
285
|
pinCommand: `/pin ${model.registryKey}`,
|
|
369
286
|
unpinCommand: `/unpin ${model.registryKey}`,
|
|
370
|
-
setMainModel: `
|
|
287
|
+
setMainModel: `settings action:"set" key:"provider.model" value:"${model.registryKey}" confirm:true explicitUserRequest:"..."`,
|
|
371
288
|
},
|
|
372
289
|
} : {}),
|
|
373
290
|
};
|
|
@@ -393,8 +310,19 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
|
|
|
393
310
|
};
|
|
394
311
|
}
|
|
395
312
|
|
|
313
|
+
function describeEndpointCandidate(endpoint: LocalModelServerEndpoint): Record<string, unknown> {
|
|
314
|
+
return {
|
|
315
|
+
kind: endpoint.kind,
|
|
316
|
+
modelRouteId: endpoint.id,
|
|
317
|
+
baseUrl: endpoint.baseUrl,
|
|
318
|
+
stack: endpoint.stack,
|
|
319
|
+
diagnosticStatus: endpoint.diagnosticStatus,
|
|
320
|
+
modelRoute: endpoint.inspectRoute,
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
|
|
396
324
|
function modelRoutingModelRoute(): string {
|
|
397
|
-
return '
|
|
325
|
+
return 'models action:"route" or action:"smoke"';
|
|
398
326
|
}
|
|
399
327
|
|
|
400
328
|
function modelCandidateModelRoute(): string {
|
|
@@ -447,12 +375,16 @@ export async function modelRoutingSummary(context: CommandContext, args: AgentHa
|
|
|
447
375
|
contextWindow: contextWindowFor(context, currentModel),
|
|
448
376
|
reasoningEffort: modelReasoning(currentModel),
|
|
449
377
|
capabilities: modelCapabilities(currentModel),
|
|
378
|
+
tier: modelTier(currentModel),
|
|
379
|
+
benchmarkCompositeScore: modelBenchmarkCompositeScore(currentModel),
|
|
380
|
+
benchmarkQualityTier: modelBenchmarkQualityTier(currentModel),
|
|
450
381
|
pinned: false,
|
|
451
|
-
}, { includeParameters }) : null,
|
|
382
|
+
}, { context, includeParameters }) : null,
|
|
452
383
|
},
|
|
453
384
|
providers: providerIds,
|
|
454
|
-
|
|
455
|
-
|
|
385
|
+
localCookbook: localModelCookbook(context, includeParameters),
|
|
386
|
+
routes: filteredRoutes.slice(0, limit).map((route) => describeRoute(route, { context, includeParameters })),
|
|
387
|
+
models: filteredModels.slice(0, limit).map((model) => describeModel(model, { context, includeParameters })),
|
|
456
388
|
returned: {
|
|
457
389
|
routes: Math.min(filteredRoutes.length, limit),
|
|
458
390
|
models: Math.min(filteredModels.length, limit),
|
|
@@ -475,42 +407,57 @@ export async function describeHarnessModelRoute(context: CommandContext, args: A
|
|
|
475
407
|
if (!lookup) {
|
|
476
408
|
return {
|
|
477
409
|
status: 'missing_lookup',
|
|
478
|
-
usage: 'model_route requires modelRouteId, target, or query.
|
|
410
|
+
usage: 'model_route requires modelRouteId, target, or query. Prefer models action:"status" to inspect route, model, and local endpoint ids.',
|
|
479
411
|
};
|
|
480
412
|
}
|
|
481
413
|
const [models] = await Promise.all([loadModels(context)]);
|
|
482
414
|
const routes = routeCandidates(context);
|
|
415
|
+
const endpoints = collectLocalServerEndpointCandidates(context).map((endpoint) => describeLocalServerEndpoint(endpoint, true));
|
|
483
416
|
const normalized = lookup.input.toLowerCase();
|
|
484
417
|
const exactRoute = routes.find((route) => route.id === lookup.input);
|
|
485
|
-
if (exactRoute) return { status: 'found', route: describeRoute(exactRoute, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'route-id' } }) };
|
|
418
|
+
if (exactRoute) return { status: 'found', route: describeRoute(exactRoute, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'route-id' } }) };
|
|
486
419
|
const exactModel = models.find((model) => model.registryKey === lookup.input || model.modelId === lookup.input);
|
|
487
|
-
if (exactModel) return { status: 'found', route: describeModel(exactModel, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'model-id' } }) };
|
|
420
|
+
if (exactModel) return { status: 'found', route: describeModel(exactModel, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'model-id' } }) };
|
|
421
|
+
const exactEndpoint = endpoints.find((endpoint) => endpoint.id === lookup.input || endpoint.baseUrl === lookup.input || endpoint.modelsUrl === lookup.input);
|
|
422
|
+
if (exactEndpoint) return { status: 'found', route: describeLocalServerEndpointRoute(exactEndpoint, { ...lookup, resolvedBy: 'local-endpoint-id' }) };
|
|
488
423
|
const insensitiveRoute = routes.find((route) => route.id.toLowerCase() === normalized);
|
|
489
|
-
if (insensitiveRoute) return { status: 'found', route: describeRoute(insensitiveRoute, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-route-id' } }) };
|
|
424
|
+
if (insensitiveRoute) return { status: 'found', route: describeRoute(insensitiveRoute, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-route-id' } }) };
|
|
490
425
|
const insensitiveModel = models.find((model) => model.registryKey.toLowerCase() === normalized || model.modelId.toLowerCase() === normalized);
|
|
491
|
-
if (insensitiveModel) return { status: 'found', route: describeModel(insensitiveModel, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-model-id' } }) };
|
|
426
|
+
if (insensitiveModel) return { status: 'found', route: describeModel(insensitiveModel, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-model-id' } }) };
|
|
427
|
+
const insensitiveEndpoint = endpoints.find((endpoint) => endpoint.id.toLowerCase() === normalized || endpoint.baseUrl.toLowerCase() === normalized || endpoint.modelsUrl.toLowerCase() === normalized);
|
|
428
|
+
if (insensitiveEndpoint) return { status: 'found', route: describeLocalServerEndpointRoute(insensitiveEndpoint, { ...lookup, resolvedBy: 'case-insensitive-local-endpoint-id' }) };
|
|
492
429
|
const searched = [
|
|
493
430
|
...routes.filter((route) => routeSearchText(route).includes(normalized)),
|
|
494
431
|
...models.filter((model) => modelSearchText(model).includes(normalized)),
|
|
495
432
|
];
|
|
496
|
-
|
|
433
|
+
const searchedEndpoints = endpoints.filter((endpoint) => localEndpointSearchText(endpoint).includes(normalized));
|
|
434
|
+
if (searched.length === 0 && searchedEndpoints.length === 1) {
|
|
435
|
+
return {
|
|
436
|
+
status: 'found',
|
|
437
|
+
route: describeLocalServerEndpointRoute(searchedEndpoints[0]!, { ...lookup, resolvedBy: 'local-endpoint-search' }),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
if (searched.length === 1 && searchedEndpoints.length === 0) {
|
|
497
441
|
const found = searched[0]!;
|
|
498
442
|
return {
|
|
499
443
|
status: 'found',
|
|
500
444
|
route: found.kind === 'route'
|
|
501
|
-
? describeRoute(found, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } })
|
|
502
|
-
: describeModel(found, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }),
|
|
445
|
+
? describeRoute(found, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } })
|
|
446
|
+
: describeModel(found, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }),
|
|
503
447
|
};
|
|
504
448
|
}
|
|
505
|
-
if (searched.length > 1) {
|
|
449
|
+
if (searched.length + searchedEndpoints.length > 1) {
|
|
506
450
|
return {
|
|
507
451
|
status: 'ambiguous',
|
|
508
452
|
input: lookup.input,
|
|
509
|
-
candidates:
|
|
453
|
+
candidates: [
|
|
454
|
+
...searched.slice(0, 8).map(describeCandidate),
|
|
455
|
+
...searchedEndpoints.slice(0, Math.max(0, 8 - searched.length)).map(describeEndpointCandidate),
|
|
456
|
+
],
|
|
510
457
|
};
|
|
511
458
|
}
|
|
512
459
|
return {
|
|
513
460
|
status: 'missing_lookup',
|
|
514
|
-
usage: `Unknown model route ${lookup.input}.
|
|
461
|
+
usage: `Unknown model route ${lookup.input}. Prefer models action:"status" to inspect route, model, and local endpoint ids.`,
|
|
515
462
|
};
|
|
516
463
|
}
|