@pellux/goodvibes-agent 1.1.7 → 1.3.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 +329 -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 +138903 -91477
- 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 +58 -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 +116 -45
- package/docs/voice-and-live-tts.md +3 -1
- package/package.json +3 -2
- package/release/release-notes.md +142 -5
- package/release/release-readiness.json +124 -94
- 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 +294 -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-artifact-receipts.ts +366 -0
- package/src/agent/setup-wizard-checkpoint.ts +140 -0
- package/src/agent/setup-wizard.ts +683 -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 +313 -30
- package/src/input/agent-workspace-setup-checkpoint-action.ts +127 -0
- package/src/input/agent-workspace-setup-snapshot.ts +217 -0
- package/src/input/agent-workspace-setup.ts +61 -1
- package/src/input/agent-workspace-snapshot.ts +184 -149
- package/src/input/agent-workspace-types.ts +287 -2
- package/src/input/agent-workspace.ts +23 -1
- 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/input/setup-wizard-live-receipts.ts +76 -0
- package/src/main.ts +15 -15
- package/src/panels/qr-panel.ts +2 -2
- package/src/renderer/agent-workspace-context-lines.ts +701 -0
- package/src/renderer/agent-workspace.ts +68 -421
- 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-policy.ts +75 -0
- package/src/tools/agent-harness-agent-orchestration.ts +791 -0
- package/src/tools/agent-harness-autonomy-intake.ts +785 -0
- package/src/tools/agent-harness-autonomy-live-records.ts +742 -0
- package/src/tools/agent-harness-autonomy-queue-types.ts +88 -0
- package/src/tools/agent-harness-autonomy-queue.ts +571 -0
- package/src/tools/agent-harness-autonomy-watcher-read-models.ts +509 -0
- package/src/tools/agent-harness-background-processes-types.ts +35 -0
- package/src/tools/agent-harness-background-processes.ts +798 -0
- package/src/tools/agent-harness-browser-cockpit-route.ts +373 -0
- package/src/tools/agent-harness-browser-control.ts +346 -0
- package/src/tools/agent-harness-browser-pwa-read-models.ts +622 -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-device-live-read-models.ts +366 -0
- 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 +385 -0
- package/src/tools/agent-harness-file-recovery.ts +135 -0
- package/src/tools/agent-harness-interactive-runtime-records.ts +421 -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 +269 -0
- package/src/tools/agent-harness-local-model-cookbook.ts +238 -0
- package/src/tools/agent-harness-local-model-endpoints.ts +788 -0
- package/src/tools/agent-harness-local-model-smoke.ts +277 -0
- package/src/tools/agent-harness-local-model-url.ts +78 -0
- package/src/tools/agent-harness-media-posture.ts +223 -2
- package/src/tools/agent-harness-memory-external-providers.ts +796 -0
- package/src/tools/agent-harness-memory-posture.ts +672 -0
- package/src/tools/agent-harness-memory-provider-certification.ts +219 -0
- package/src/tools/agent-harness-memory-refinement.ts +340 -0
- package/src/tools/agent-harness-metadata.ts +100 -168
- package/src/tools/agent-harness-mode-catalog.ts +86 -33
- package/src/tools/agent-harness-model-catalog.ts +162 -0
- package/src/tools/agent-harness-model-provider-health.ts +283 -0
- package/src/tools/agent-harness-model-readiness.ts +432 -0
- package/src/tools/agent-harness-model-routing-types.ts +327 -0
- package/src/tools/agent-harness-model-routing-utils.ts +30 -0
- package/src/tools/agent-harness-model-routing.ts +165 -193
- package/src/tools/agent-harness-operator-methods.ts +115 -133
- package/src/tools/agent-harness-pairing-posture.ts +452 -18
- package/src/tools/agent-harness-personal-ops-certification.ts +116 -0
- 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 +270 -0
- package/src/tools/agent-harness-personal-ops-operations.ts +225 -0
- package/src/tools/agent-harness-personal-ops-provider-records.ts +358 -0
- package/src/tools/agent-harness-personal-ops-provider-task-records.ts +321 -0
- package/src/tools/agent-harness-personal-ops-records.ts +684 -0
- package/src/tools/agent-harness-personal-ops-runner.ts +637 -0
- package/src/tools/agent-harness-personal-ops-types.ts +240 -0
- package/src/tools/agent-harness-personal-ops.ts +613 -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-remote-read-models.ts +541 -0
- package/src/tools/agent-harness-research-briefing.ts +446 -0
- package/src/tools/agent-harness-research-live-read-models.ts +500 -0
- package/src/tools/agent-harness-research-queue.ts +250 -0
- package/src/tools/agent-harness-research-runs.ts +307 -0
- package/src/tools/agent-harness-research-workflow.ts +395 -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 +102 -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 +533 -0
- package/src/tools/agent-harness-sudo-posture.ts +114 -0
- package/src/tools/agent-harness-tool-schema.ts +142 -7
- package/src/tools/agent-harness-tool-types.ts +83 -0
- package/src/tools/agent-harness-tool-utils.ts +43 -0
- package/src/tools/agent-harness-tool.ts +319 -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 +253 -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 +735 -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-runner.ts +367 -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 +515 -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,19 @@
|
|
|
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
|
-
|
|
14
|
-
|
|
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 { localBenchmarkRouteLatencyMap } from './agent-harness-local-model-benchmarks.ts';
|
|
8
|
+
import { localModelDetection, localModelServerEndpoints, localModelServerHealthMap } from './agent-harness-local-model-endpoints.ts';
|
|
9
|
+
import { runLocalModelServerSmoke } from './agent-harness-local-model-smoke.ts';
|
|
10
|
+
import { localHardwareProfile, modelReadinessScore } from './agent-harness-model-readiness.ts';
|
|
11
|
+
import { contextWindowFor, loadModels, listProviderIds, modelBenchmarkCompositeScore, modelBenchmarkQualityTier, modelCapabilities, modelCurrent, modelDisplayName, modelModelId, modelProviderId, modelReasoning, modelRegistryKey, modelTier, readConfig, readProviderApi } from './agent-harness-model-catalog.ts';
|
|
12
|
+
import type { AgentHarnessModelRoutingArgs, LocalModelServerEndpoint, ModelCandidate, ModelProviderHealthSignal, ModelRouteLookupSource, ModelRouteResolution, RouteCandidate } from './agent-harness-model-routing-types.ts';
|
|
13
|
+
import { readLimit, readString } from './agent-harness-model-routing-utils.ts';
|
|
14
|
+
export type { AgentHarnessModelRoutingArgs } from './agent-harness-model-routing-types.ts';
|
|
15
|
+
export { localModelCookbook } from './agent-harness-local-model-cookbook.ts';
|
|
16
|
+
export { runLocalModelServerSmoke } from './agent-harness-local-model-smoke.ts';
|
|
173
17
|
|
|
174
18
|
async function readCurrentModel(context: CommandContext): Promise<unknown> {
|
|
175
19
|
try {
|
|
@@ -179,6 +23,15 @@ async function readCurrentModel(context: CommandContext): Promise<unknown> {
|
|
|
179
23
|
}
|
|
180
24
|
}
|
|
181
25
|
|
|
26
|
+
function attachLocalBenchmarkLatencies(context: CommandContext, models: readonly ModelCandidate[]): readonly ModelCandidate[] {
|
|
27
|
+
const latencies = localBenchmarkRouteLatencyMap(context);
|
|
28
|
+
if (latencies.size === 0) return models;
|
|
29
|
+
return models.map((model) => ({
|
|
30
|
+
...model,
|
|
31
|
+
localBenchmarkLatency: latencies.get(model.registryKey) ?? null,
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
|
|
182
35
|
function routeCandidates(context: CommandContext): readonly RouteCandidate[] {
|
|
183
36
|
return [
|
|
184
37
|
{
|
|
@@ -253,6 +106,20 @@ function routeCandidates(context: CommandContext): readonly RouteCandidate[] {
|
|
|
253
106
|
commands: ['/refresh-models'],
|
|
254
107
|
uiSurfaces: ['model-picker'],
|
|
255
108
|
},
|
|
109
|
+
{
|
|
110
|
+
kind: 'route',
|
|
111
|
+
id: 'local-model-cookbook',
|
|
112
|
+
label: 'Local model cookbook',
|
|
113
|
+
detail: 'Hardware-aware recommendations for Ollama, llama.cpp, vLLM, and local OpenAI-compatible servers.',
|
|
114
|
+
currentValue: {
|
|
115
|
+
detected: localModelDetection(context),
|
|
116
|
+
hardwareProfile: localHardwareProfile(),
|
|
117
|
+
localServerHealth: localModelServerHealthMap(context, false),
|
|
118
|
+
},
|
|
119
|
+
settingKeys: [],
|
|
120
|
+
commands: ['/provider add <name> <baseURL> [apiKey] --yes', '/refresh-models', '/model'],
|
|
121
|
+
uiSurfaces: ['provider-picker', 'model-picker', 'settings'],
|
|
122
|
+
},
|
|
256
123
|
{
|
|
257
124
|
kind: 'route',
|
|
258
125
|
id: 'pinned-models',
|
|
@@ -310,7 +177,39 @@ function modelSearchText(model: ModelCandidate): string {
|
|
|
310
177
|
].join('\n').toLowerCase();
|
|
311
178
|
}
|
|
312
179
|
|
|
313
|
-
function
|
|
180
|
+
function localEndpointSearchText(endpoint: LocalModelServerEndpoint): string {
|
|
181
|
+
return [
|
|
182
|
+
endpoint.id,
|
|
183
|
+
endpoint.providerId ?? '',
|
|
184
|
+
endpoint.stack ?? '',
|
|
185
|
+
endpoint.baseUrl,
|
|
186
|
+
endpoint.modelsUrl,
|
|
187
|
+
endpoint.diagnosticStatus,
|
|
188
|
+
...endpoint.sources,
|
|
189
|
+
...endpoint.sourceDetails,
|
|
190
|
+
...endpoint.modelRoutes,
|
|
191
|
+
...endpoint.notes,
|
|
192
|
+
].join('\n').toLowerCase();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function describeLocalServerEndpointRoute(endpoint: LocalModelServerEndpoint, lookup?: Record<string, unknown>): Record<string, unknown> {
|
|
196
|
+
return {
|
|
197
|
+
...endpoint,
|
|
198
|
+
...(lookup ? { lookup } : {}),
|
|
199
|
+
modelRouteId: endpoint.id,
|
|
200
|
+
label: `Local model server ${endpoint.baseUrl}`,
|
|
201
|
+
modelRoute: endpoint.inspectRoute,
|
|
202
|
+
modelAccess: {
|
|
203
|
+
smoke: endpoint.smokeRoute,
|
|
204
|
+
refresh: endpoint.refreshRoute,
|
|
205
|
+
addProvider: endpoint.addProviderRoute,
|
|
206
|
+
cookbook: 'models action:"local" includeParameters:true',
|
|
207
|
+
},
|
|
208
|
+
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.',
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function describeRoute(route: RouteCandidate, options: { readonly context: CommandContext; readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> }): Record<string, unknown> {
|
|
314
213
|
return {
|
|
315
214
|
kind: 'route',
|
|
316
215
|
modelRouteId: route.id,
|
|
@@ -324,6 +223,7 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
324
223
|
uiSurfaces: route.uiSurfaces,
|
|
325
224
|
} : {}),
|
|
326
225
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
226
|
+
...(route.id === 'local-model-cookbook' && options.includeParameters === true ? { localCookbook: localModelCookbook(options.context, true) } : {}),
|
|
327
227
|
...(options.includeParameters ? {
|
|
328
228
|
policy: {
|
|
329
229
|
effect: 'read-only',
|
|
@@ -331,10 +231,10 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
331
231
|
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
232
|
},
|
|
333
233
|
modelAccess: {
|
|
334
|
-
inspectRouting: '
|
|
234
|
+
inspectRouting: 'models action:"status"',
|
|
335
235
|
inspectRoute: 'agent_harness mode:"model_route"',
|
|
336
|
-
settingRead: '
|
|
337
|
-
settingMutation: '
|
|
236
|
+
settingRead: 'settings action:"get"',
|
|
237
|
+
settingMutation: 'settings action:"set" confirm:true explicitUserRequest:"..."',
|
|
338
238
|
openModelPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"model-picker" confirm:true explicitUserRequest:"..."',
|
|
339
239
|
openProviderPicker: 'agent_harness mode:"open_ui_surface" surfaceId:"provider-picker" confirm:true explicitUserRequest:"..."',
|
|
340
240
|
},
|
|
@@ -342,7 +242,26 @@ function describeRoute(route: RouteCandidate, options: { readonly includeParamet
|
|
|
342
242
|
};
|
|
343
243
|
}
|
|
344
244
|
|
|
345
|
-
function
|
|
245
|
+
function compactProviderHealthSignal(signal: ModelProviderHealthSignal): Record<string, unknown> {
|
|
246
|
+
return {
|
|
247
|
+
status: signal.status,
|
|
248
|
+
sdkContract: signal.sdkContract,
|
|
249
|
+
daemonPublication: signal.daemonPublication,
|
|
250
|
+
agentConsumption: signal.agentConsumption,
|
|
251
|
+
...(signal.healthStatus ? { healthStatus: signal.healthStatus } : {}),
|
|
252
|
+
...(signal.modelRouteId ? { modelRouteId: signal.modelRouteId } : {}),
|
|
253
|
+
...(signal.sourceRecordId ? { sourceRecordId: signal.sourceRecordId } : {}),
|
|
254
|
+
...(signal.avgLatencyMs !== undefined ? { avgLatencyMs: signal.avgLatencyMs } : {}),
|
|
255
|
+
...(signal.rateLimitRemaining !== undefined ? { rateLimitRemaining: signal.rateLimitRemaining } : {}),
|
|
256
|
+
...(signal.rateLimitResetAt ? { rateLimitResetAt: signal.rateLimitResetAt } : {}),
|
|
257
|
+
...(signal.lastErrorMessage ? { lastErrorMessage: signal.lastErrorMessage } : {}),
|
|
258
|
+
missingSignals: signal.missingSignals,
|
|
259
|
+
policy: signal.policy,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function describeModel(model: ModelCandidate, options: { readonly context: CommandContext; readonly includeParameters?: boolean; readonly lookup?: Record<string, unknown> }): Record<string, unknown> {
|
|
264
|
+
const readiness = modelReadinessScore(options.context, model);
|
|
346
265
|
return {
|
|
347
266
|
kind: 'model',
|
|
348
267
|
modelRouteId: model.registryKey,
|
|
@@ -354,6 +273,21 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
|
|
|
354
273
|
pinned: model.pinned,
|
|
355
274
|
contextWindow: model.contextWindow,
|
|
356
275
|
reasoningEffort: model.reasoningEffort,
|
|
276
|
+
tier: model.tier ?? null,
|
|
277
|
+
benchmarkCompositeScore: model.benchmarkCompositeScore ?? null,
|
|
278
|
+
benchmarkQualityTier: model.benchmarkQualityTier ?? null,
|
|
279
|
+
localBenchmarkLatency: model.localBenchmarkLatency ?? null,
|
|
280
|
+
readinessScore: readiness.score,
|
|
281
|
+
readinessLevel: readiness.level,
|
|
282
|
+
readiness: options.includeParameters
|
|
283
|
+
? readiness
|
|
284
|
+
: {
|
|
285
|
+
score: readiness.score,
|
|
286
|
+
level: readiness.level,
|
|
287
|
+
confidence: readiness.confidence,
|
|
288
|
+
providerHealth: compactProviderHealthSignal(readiness.providerHealth),
|
|
289
|
+
nextStep: readiness.nextStep,
|
|
290
|
+
},
|
|
357
291
|
modelRoute: modelCandidateModelRoute(),
|
|
358
292
|
...(options.lookup ? { lookup: options.lookup } : {}),
|
|
359
293
|
...(options.includeParameters ? {
|
|
@@ -367,7 +301,7 @@ function describeModel(model: ModelCandidate, options: { readonly includeParamet
|
|
|
367
301
|
selectProviderCommand: `/provider ${model.providerId}`,
|
|
368
302
|
pinCommand: `/pin ${model.registryKey}`,
|
|
369
303
|
unpinCommand: `/unpin ${model.registryKey}`,
|
|
370
|
-
setMainModel: `
|
|
304
|
+
setMainModel: `settings action:"set" key:"provider.model" value:"${model.registryKey}" confirm:true explicitUserRequest:"..."`,
|
|
371
305
|
},
|
|
372
306
|
} : {}),
|
|
373
307
|
};
|
|
@@ -393,8 +327,19 @@ function describeCandidate(entry: RouteCandidate | ModelCandidate): Record<strin
|
|
|
393
327
|
};
|
|
394
328
|
}
|
|
395
329
|
|
|
330
|
+
function describeEndpointCandidate(endpoint: LocalModelServerEndpoint): Record<string, unknown> {
|
|
331
|
+
return {
|
|
332
|
+
kind: endpoint.kind,
|
|
333
|
+
modelRouteId: endpoint.id,
|
|
334
|
+
baseUrl: endpoint.baseUrl,
|
|
335
|
+
stack: endpoint.stack,
|
|
336
|
+
diagnosticStatus: endpoint.diagnosticStatus,
|
|
337
|
+
modelRoute: endpoint.inspectRoute,
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
396
341
|
function modelRoutingModelRoute(): string {
|
|
397
|
-
return '
|
|
342
|
+
return 'models action:"route" or action:"smoke"';
|
|
398
343
|
}
|
|
399
344
|
|
|
400
345
|
function modelCandidateModelRoute(): string {
|
|
@@ -402,10 +347,11 @@ function modelCandidateModelRoute(): string {
|
|
|
402
347
|
}
|
|
403
348
|
|
|
404
349
|
export async function modelRoutingCatalogStatus(context: CommandContext): Promise<Record<string, unknown>> {
|
|
405
|
-
const [
|
|
350
|
+
const [rawModels, providerIds] = await Promise.all([
|
|
406
351
|
loadModels(context),
|
|
407
352
|
Promise.resolve(listProviderIds(context)),
|
|
408
353
|
]);
|
|
354
|
+
const models = attachLocalBenchmarkLatencies(context, rawModels);
|
|
409
355
|
return {
|
|
410
356
|
modes: ['model_routing', 'model_route'],
|
|
411
357
|
status: readProviderApi(context) ? 'available' : 'degraded',
|
|
@@ -421,15 +367,20 @@ export async function modelRoutingCatalogStatus(context: CommandContext): Promis
|
|
|
421
367
|
export async function modelRoutingSummary(context: CommandContext, args: AgentHarnessModelRoutingArgs): Promise<Record<string, unknown>> {
|
|
422
368
|
const query = readString(args.query).toLowerCase();
|
|
423
369
|
const includeParameters = args.includeParameters === true;
|
|
424
|
-
const [
|
|
370
|
+
const [rawModels, providerIds, currentModel] = await Promise.all([
|
|
425
371
|
loadModels(context),
|
|
426
372
|
Promise.resolve(listProviderIds(context)),
|
|
427
373
|
readCurrentModel(context),
|
|
428
374
|
]);
|
|
375
|
+
const models = attachLocalBenchmarkLatencies(context, rawModels);
|
|
429
376
|
const routes = routeCandidates(context);
|
|
430
377
|
const filteredRoutes = routes.filter((route) => !query || routeSearchText(route).includes(query));
|
|
431
378
|
const filteredModels = models.filter((model) => !query || modelSearchText(model).includes(query));
|
|
432
379
|
const limit = readLimit(args.limit, 100);
|
|
380
|
+
const currentRegistryKey = currentModel ? modelRegistryKey(currentModel) : '';
|
|
381
|
+
const loadedCurrentModel = currentRegistryKey
|
|
382
|
+
? models.find((model) => model.registryKey === currentRegistryKey || model.modelId === modelModelId(currentModel))
|
|
383
|
+
: null;
|
|
433
384
|
return {
|
|
434
385
|
status: readProviderApi(context) ? 'available' : 'degraded',
|
|
435
386
|
current: {
|
|
@@ -447,12 +398,17 @@ export async function modelRoutingSummary(context: CommandContext, args: AgentHa
|
|
|
447
398
|
contextWindow: contextWindowFor(context, currentModel),
|
|
448
399
|
reasoningEffort: modelReasoning(currentModel),
|
|
449
400
|
capabilities: modelCapabilities(currentModel),
|
|
401
|
+
tier: modelTier(currentModel),
|
|
402
|
+
benchmarkCompositeScore: modelBenchmarkCompositeScore(currentModel),
|
|
403
|
+
benchmarkQualityTier: modelBenchmarkQualityTier(currentModel),
|
|
404
|
+
localBenchmarkLatency: loadedCurrentModel?.localBenchmarkLatency ?? null,
|
|
450
405
|
pinned: false,
|
|
451
|
-
}, { includeParameters }) : null,
|
|
406
|
+
}, { context, includeParameters }) : null,
|
|
452
407
|
},
|
|
453
408
|
providers: providerIds,
|
|
454
|
-
|
|
455
|
-
|
|
409
|
+
localCookbook: localModelCookbook(context, includeParameters),
|
|
410
|
+
routes: filteredRoutes.slice(0, limit).map((route) => describeRoute(route, { context, includeParameters })),
|
|
411
|
+
models: filteredModels.slice(0, limit).map((model) => describeModel(model, { context, includeParameters })),
|
|
456
412
|
returned: {
|
|
457
413
|
routes: Math.min(filteredRoutes.length, limit),
|
|
458
414
|
models: Math.min(filteredModels.length, limit),
|
|
@@ -475,42 +431,58 @@ export async function describeHarnessModelRoute(context: CommandContext, args: A
|
|
|
475
431
|
if (!lookup) {
|
|
476
432
|
return {
|
|
477
433
|
status: 'missing_lookup',
|
|
478
|
-
usage: 'model_route requires modelRouteId, target, or query.
|
|
434
|
+
usage: 'model_route requires modelRouteId, target, or query. Prefer models action:"status" to inspect route, model, and local endpoint ids.',
|
|
479
435
|
};
|
|
480
436
|
}
|
|
481
|
-
const [
|
|
437
|
+
const [rawModels] = await Promise.all([loadModels(context)]);
|
|
438
|
+
const models = attachLocalBenchmarkLatencies(context, rawModels);
|
|
482
439
|
const routes = routeCandidates(context);
|
|
440
|
+
const endpoints = localModelServerEndpoints(context, true);
|
|
483
441
|
const normalized = lookup.input.toLowerCase();
|
|
484
442
|
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' } }) };
|
|
443
|
+
if (exactRoute) return { status: 'found', route: describeRoute(exactRoute, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'route-id' } }) };
|
|
486
444
|
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' } }) };
|
|
445
|
+
if (exactModel) return { status: 'found', route: describeModel(exactModel, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'model-id' } }) };
|
|
446
|
+
const exactEndpoint = endpoints.find((endpoint) => endpoint.id === lookup.input || endpoint.baseUrl === lookup.input || endpoint.modelsUrl === lookup.input);
|
|
447
|
+
if (exactEndpoint) return { status: 'found', route: describeLocalServerEndpointRoute(exactEndpoint, { ...lookup, resolvedBy: 'local-endpoint-id' }) };
|
|
488
448
|
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' } }) };
|
|
449
|
+
if (insensitiveRoute) return { status: 'found', route: describeRoute(insensitiveRoute, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-route-id' } }) };
|
|
490
450
|
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' } }) };
|
|
451
|
+
if (insensitiveModel) return { status: 'found', route: describeModel(insensitiveModel, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'case-insensitive-model-id' } }) };
|
|
452
|
+
const insensitiveEndpoint = endpoints.find((endpoint) => endpoint.id.toLowerCase() === normalized || endpoint.baseUrl.toLowerCase() === normalized || endpoint.modelsUrl.toLowerCase() === normalized);
|
|
453
|
+
if (insensitiveEndpoint) return { status: 'found', route: describeLocalServerEndpointRoute(insensitiveEndpoint, { ...lookup, resolvedBy: 'case-insensitive-local-endpoint-id' }) };
|
|
492
454
|
const searched = [
|
|
493
455
|
...routes.filter((route) => routeSearchText(route).includes(normalized)),
|
|
494
456
|
...models.filter((model) => modelSearchText(model).includes(normalized)),
|
|
495
457
|
];
|
|
496
|
-
|
|
458
|
+
const searchedEndpoints = endpoints.filter((endpoint) => localEndpointSearchText(endpoint).includes(normalized));
|
|
459
|
+
if (searched.length === 0 && searchedEndpoints.length === 1) {
|
|
460
|
+
return {
|
|
461
|
+
status: 'found',
|
|
462
|
+
route: describeLocalServerEndpointRoute(searchedEndpoints[0]!, { ...lookup, resolvedBy: 'local-endpoint-search' }),
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
if (searched.length === 1 && searchedEndpoints.length === 0) {
|
|
497
466
|
const found = searched[0]!;
|
|
498
467
|
return {
|
|
499
468
|
status: 'found',
|
|
500
469
|
route: found.kind === 'route'
|
|
501
|
-
? describeRoute(found, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } })
|
|
502
|
-
: describeModel(found, { includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }),
|
|
470
|
+
? describeRoute(found, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } })
|
|
471
|
+
: describeModel(found, { context, includeParameters: true, lookup: { ...lookup, resolvedBy: 'search' } }),
|
|
503
472
|
};
|
|
504
473
|
}
|
|
505
|
-
if (searched.length > 1) {
|
|
474
|
+
if (searched.length + searchedEndpoints.length > 1) {
|
|
506
475
|
return {
|
|
507
476
|
status: 'ambiguous',
|
|
508
477
|
input: lookup.input,
|
|
509
|
-
candidates:
|
|
478
|
+
candidates: [
|
|
479
|
+
...searched.slice(0, 8).map(describeCandidate),
|
|
480
|
+
...searchedEndpoints.slice(0, Math.max(0, 8 - searched.length)).map(describeEndpointCandidate),
|
|
481
|
+
],
|
|
510
482
|
};
|
|
511
483
|
}
|
|
512
484
|
return {
|
|
513
485
|
status: 'missing_lookup',
|
|
514
|
-
usage: `Unknown model route ${lookup.input}.
|
|
486
|
+
usage: `Unknown model route ${lookup.input}. Prefer models action:"status" to inspect route, model, and local endpoint ids.`,
|
|
515
487
|
};
|
|
516
488
|
}
|