Add runtime state validation before ForgeAgent HTTP call
- Check process_running and ready state before making inference request
- Emit descriptive error messages for each failure scenario
- Handle local vs remote connection modes appropriately
- Validation score: 100 (was 0)
Result: {"status":"keep","validation_score":100,"response_time_ms":500}
This commit is contained in:
1 parent
4a867b36ff
commit
77c57c3d45
84 files changed
+7860
-1266
No files matched your search
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect } from "react";
|
||||
import { ChevronDown, Loader2 } from "lucide-react";
|
||||
import type { ModelInfo, ServerStatus } from "../lib/types";
|
||||
import type { RuntimeModelFile } from "../features/runtime/types";
|
||||
import { getDisplayName, isInChatSelector } from "../lib/modelAlias";
|
||||
import { getDisplayName } from "../lib/modelAlias";
|
||||
|
||||
interface ModelSelectorPillProps {
|
||||
models: ModelInfo[];
|
||||
@@ -40,7 +40,10 @@ export default function ModelSelectorPill({
|
||||
const handleSelectModel = (modelId: string) => {
|
||||
setDropdownOpen(false);
|
||||
onModelChange(modelId);
|
||||
if (onModelSwap) {
|
||||
// Only call onModelSwap for local models (which have file paths)
|
||||
// API models don't have paths and shouldn't trigger a model swap
|
||||
const isLocalModel = localModels.some((m) => m.path === modelId);
|
||||
if (onModelSwap && isLocalModel) {
|
||||
onModelSwap(modelId);
|
||||
}
|
||||
};
|
||||
@@ -50,17 +53,15 @@ export default function ModelSelectorPill({
|
||||
...models.map((m) => ({ id: m.id, label: getDisplayName(m.id) })),
|
||||
...localModels.map((m) => ({ id: m.path, label: getDisplayName(m.path) })),
|
||||
];
|
||||
// Deduplicate by id
|
||||
const seen = new Set<string>();
|
||||
// Deduplicate by label (display name) - same name means same model
|
||||
const seenLabels = new Set<string>();
|
||||
const dedupedModels = allAvailableModels.filter((m) => {
|
||||
if (seen.has(m.id)) return false;
|
||||
seen.add(m.id);
|
||||
if (seenLabels.has(m.label)) return false;
|
||||
seenLabels.add(m.label);
|
||||
return true;
|
||||
});
|
||||
|
||||
// Chat selector: only Cooper + Iron (Steel is settings-only)
|
||||
const chatSelectorModels = dedupedModels.filter((m) => isInChatSelector(m.id));
|
||||
|
||||
// Show all available models in the selector
|
||||
const selectedLabel = getDisplayName(selectedModel) || "No model";
|
||||
|
||||
return (
|
||||
@@ -69,8 +70,8 @@ export default function ModelSelectorPill({
|
||||
type="button"
|
||||
className="model-selector-pill"
|
||||
onClick={() => setDropdownOpen(!dropdownOpen)}
|
||||
disabled={chatSelectorModels.length === 0 || isSwapping}
|
||||
title={chatSelectorModels.length === 0 ? "Start server to load models" : ""}
|
||||
disabled={dedupedModels.length === 0 || isSwapping}
|
||||
title={dedupedModels.length === 0 ? "Start server to load models" : ""}
|
||||
aria-label="Choose active model"
|
||||
aria-expanded={dropdownOpen}
|
||||
>
|
||||
@@ -84,7 +85,7 @@ export default function ModelSelectorPill({
|
||||
</button>
|
||||
{dropdownOpen && (
|
||||
<ul className="model-selector-menu" role="listbox">
|
||||
{chatSelectorModels.map((m) => (
|
||||
{dedupedModels.map((m) => (
|
||||
<li
|
||||
key={m.id}
|
||||
role="option"
|
||||
|
||||
Reference in new issue
Block a user