ЮИ - Перенести настройки ассистента в управление автопрогонами и убрать верхний режим Ассистент

This commit is contained in:
2026-04-16 20:18:23 +03:00
parent f1333c457e
commit f3255cb3b8
37 changed files with 2987 additions and 166 deletions
+54 -8
View File
@@ -31,7 +31,7 @@ const SESSION_CONFIG_KEY = "ndc_normalizer_session_config_v1";
const AUTORUNS_LAYOUT_CONFIG_KEY = "ndc_autoruns_layout_config_v1";
const AUTORUNS_SAVE_EVENT = "ndc-autoruns-save";
const ASSISTANT_STAGES = ["Анализ запроса", "Получение данных", "Подготовка ответа"];
const DEFAULT_UI_MODE: UiMode = "assistant";
const DEFAULT_UI_MODE: UiMode = "autoruns";
const AUTOLOAD_PROMPT_VERSION = "normalizer_v2_0_2";
const ASSISTANT_PROMPT_VERSION = "address_query_runtime_v1";
const TAB_KEYS: TabKey[] = ["normalized", "fragments", "scope", "flags", "route", "raw", "validation", "logs"];
@@ -117,6 +117,8 @@ export default function App() {
const [lastError, setLastError] = useState("");
const [uiMode, setUiMode] = useState<UiMode>(DEFAULT_UI_MODE);
const [showAutorunsSettingsMode, setShowAutorunsSettingsMode] = useState(true);
const [showAutorunsAutoRunsMode, setShowAutorunsAutoRunsMode] = useState(true);
const [showAutorunsAssistantMode, setShowAutorunsAssistantMode] = useState(true);
const [showAutorunsDecompositionMode, setShowAutorunsDecompositionMode] = useState(true);
const [showAutorunsProgressMode, setShowAutorunsProgressMode] = useState(true);
@@ -239,6 +241,8 @@ export default function App() {
const parsed = JSON.parse(cachedAutorunsLayout) as {
uiMode?: UiMode;
activeTab?: TabKey;
showAutorunsSettingsMode?: boolean;
showAutorunsAutoRunsMode?: boolean;
showAutorunsAssistantMode?: boolean;
showAutorunsDecompositionMode?: boolean;
showAutorunsProgressMode?: boolean;
@@ -257,12 +261,20 @@ export default function App() {
showDecompositionRuntimeMode?: boolean;
prompts?: PromptState;
};
if (parsed.uiMode === "assistant" || parsed.uiMode === "decomposition" || parsed.uiMode === "autoruns") {
setUiMode(parsed.uiMode);
if (parsed.uiMode === "decomposition") {
setUiMode("decomposition");
} else if (parsed.uiMode === "assistant" || parsed.uiMode === "autoruns") {
setUiMode("autoruns");
}
if (parsed.activeTab && TAB_KEYS.includes(parsed.activeTab)) {
setActiveTab(parsed.activeTab);
}
if (typeof parsed.showAutorunsSettingsMode === "boolean") {
setShowAutorunsSettingsMode(parsed.showAutorunsSettingsMode);
}
if (typeof parsed.showAutorunsAutoRunsMode === "boolean") {
setShowAutorunsAutoRunsMode(parsed.showAutorunsAutoRunsMode);
}
if (typeof parsed.showAutorunsAssistantMode === "boolean") {
setShowAutorunsAssistantMode(parsed.showAutorunsAssistantMode);
}
@@ -430,6 +442,8 @@ export default function App() {
JSON.stringify({
uiMode,
activeTab,
showAutorunsSettingsMode,
showAutorunsAutoRunsMode,
showAutorunsAssistantMode,
showAutorunsDecompositionMode,
showAutorunsProgressMode,
@@ -946,15 +960,12 @@ export default function App() {
>
<header className="app-topbar">
<div className="mode-switch-row">
<button type="button" className={uiMode === "assistant" ? "tab active" : "tab"} onClick={() => setUiMode("assistant")}>
Ассистент
<button type="button" className={uiMode === "autoruns" ? "tab active" : "tab"} onClick={() => setUiMode("autoruns")}>
Управление ассистентом
</button>
<button type="button" className={uiMode === "decomposition" ? "tab active" : "tab"} onClick={() => setUiMode("decomposition")}>
Декомпозиция
</button>
<button type="button" className={uiMode === "autoruns" ? "tab active" : "tab"} onClick={() => setUiMode("autoruns")}>
История автопрогонов
</button>
<button type="button" className="tab" onClick={saveAutorunsLayout}>
Сохранить
</button>
@@ -1036,6 +1047,20 @@ export default function App() {
</div>
) : uiMode === "autoruns" ? (
<div className="mode-switch-row mode-switch-row-right">
<button
type="button"
className={showAutorunsSettingsMode ? "tab active" : "tab"}
onClick={() => setShowAutorunsSettingsMode((prev) => !prev)}
>
Настройки
</button>
<button
type="button"
className={showAutorunsAutoRunsMode ? "tab active" : "tab"}
onClick={() => setShowAutorunsAutoRunsMode((prev) => !prev)}
>
Автопрогоны
</button>
<button
type="button"
className={showAutorunsAssistantMode ? "tab active" : "tab"}
@@ -1300,9 +1325,30 @@ export default function App() {
<div className="layout-grid layout-grid-autoruns">
<AutoRunsHistoryPanel
connection={connection}
modelOptions={modelOptions}
modelsBusy={modelsBusy}
connectionStatus={connectionStatus}
connectionBusy={busy}
onConnectionChange={setConnection}
onReloadModels={reloadModels}
onSaveLocalConfig={saveLocalConfig}
onTestConnection={testConnection}
prompts={prompts}
onPromptsChange={setPrompts}
promptPresets={presetList}
selectedPresetId={selectedPresetId}
onSelectPreset={setSelectedPresetId}
onLoadPreset={loadSelectedPreset}
onSavePreset={savePreset}
onResetDefaults={resetDefaults}
onDiffPrevious={diffWithPrevious}
presetName={presetName}
onPresetNameChange={setPresetName}
diffSummary={diffSummary}
assistantPromptVersion={ASSISTANT_PROMPT_VERSION}
decompositionPromptVersion={AUTOLOAD_PROMPT_VERSION}
showSettingsMode={showAutorunsSettingsMode}
showAutoRunsMode={showAutorunsAutoRunsMode}
showAssistantMode={showAutorunsAssistantMode}
showDecompositionMode={showAutorunsDecompositionMode}
showProgressMode={showAutorunsProgressMode}
@@ -22,14 +22,46 @@ import type {
PromptState
} from "../state/types";
import { AssistantPanel } from "./AssistantPanel";
import { ConnectionPanel } from "./ConnectionPanel";
import { JsonView } from "./JsonView";
import { PanelFrame } from "./PanelFrame";
import { PromptPanel } from "./PromptPanel";
interface AutoRunsHistoryPanelProps {
connection: ConnectionState;
modelOptions: string[];
modelsBusy: boolean;
connectionStatus: string;
connectionBusy: boolean;
onConnectionChange: (next: ConnectionState) => void;
onReloadModels: () => Promise<void> | void;
onSaveLocalConfig: () => void;
onTestConnection: () => Promise<void> | void;
prompts: PromptState;
onPromptsChange: (next: PromptState) => void;
promptPresets: Array<{
id: string;
name: string;
prompt_version: string;
systemPrompt: string;
developerPrompt: string;
domainPrompt: string;
schemaNotes?: string;
fewShotExamples?: string;
}>;
selectedPresetId: string;
onSelectPreset: (id: string) => void;
onLoadPreset: () => void;
onSavePreset: () => void;
onResetDefaults: () => void;
onDiffPrevious: () => void;
presetName: string;
onPresetNameChange: (name: string) => void;
diffSummary: string;
assistantPromptVersion: string;
decompositionPromptVersion: string;
showSettingsMode: boolean;
showAutoRunsMode: boolean;
showAssistantMode: boolean;
showDecompositionMode: boolean;
showProgressMode: boolean;
@@ -470,9 +502,30 @@ function CopyOutlineIcon() {
export function AutoRunsHistoryPanel({
connection,
modelOptions,
modelsBusy,
connectionStatus,
connectionBusy,
onConnectionChange,
onReloadModels,
onSaveLocalConfig,
onTestConnection,
prompts,
onPromptsChange,
promptPresets,
selectedPresetId,
onSelectPreset,
onLoadPreset,
onSavePreset,
onResetDefaults,
onDiffPrevious,
presetName,
onPresetNameChange,
diffSummary,
assistantPromptVersion,
decompositionPromptVersion,
showSettingsMode,
showAutoRunsMode,
showAssistantMode,
showDecompositionMode,
showProgressMode,
@@ -1726,9 +1779,47 @@ export function AutoRunsHistoryPanel({
hideHeader
>
<div className="autoruns-columns">
<section className="autoruns-col">
{showSettingsMode ? (
<section className="autoruns-col autoruns-settings-col">
<div className="autoruns-col-header">
<h3>Настройки</h3>
</div>
<div className="autoruns-settings-stack">
<ConnectionPanel
embedded
value={connection}
modelOptions={modelOptions}
modelsBusy={modelsBusy}
onChange={onConnectionChange}
onReloadModels={onReloadModels}
onSaveLocalConfig={onSaveLocalConfig}
onTestConnection={onTestConnection}
lastStatus={connectionStatus}
busy={connectionBusy}
/>
<PromptPanel
embedded
value={prompts}
onChange={onPromptsChange}
presets={promptPresets}
selectedPresetId={selectedPresetId}
onSelectPreset={onSelectPreset}
onLoadPreset={onLoadPreset}
onSavePreset={onSavePreset}
onResetDefaults={onResetDefaults}
onDiffPrevious={onDiffPrevious}
presetName={presetName}
onPresetNameChange={onPresetNameChange}
diffSummary={diffSummary}
/>
</div>
</section>
) : null}
{showAutoRunsMode ? (
<section className="autoruns-col">
<div className="autoruns-col-header">
<h3>Настройки</h3>
<h3>Автопрогоны</h3>
</div>
<h4>Настройки выборки</h4>
@@ -2086,6 +2177,7 @@ export function AutoRunsHistoryPanel({
{errorText ? <p className="error-text">{errorText}</p> : null}
</section>
) : null}
<section className="autoruns-col">
<div className="autoruns-col-header">
@@ -63,6 +63,7 @@ interface ConnectionPanelProps {
onSaveLocalConfig: () => void;
lastStatus: string;
busy: boolean;
embedded?: boolean;
}
export function ConnectionPanel({
@@ -74,7 +75,8 @@ export function ConnectionPanel({
onTestConnection,
onSaveLocalConfig,
lastStatus,
busy
busy,
embedded = false
}: ConnectionPanelProps) {
const isLocal = value.llmProvider === "local";
const providerPreset = deriveProviderPreset(value);
@@ -121,12 +123,8 @@ export function ConnectionPanel({
setMaxOutputTokensInput(String(parsed));
};
return (
<PanelFrame
title="LLM Connection"
subtitle="Switch between OpenAI cloud and local OpenAI-compatible server."
actions={<span className="status-chip">{lastStatus || "Status: not checked"}</span>}
>
const content = (
<>
<div className="grid-two">
<label>
Provider
@@ -269,6 +267,31 @@ export function ConnectionPanel({
{busy ? "Checking..." : "Test connection"}
</button>
</div>
</>
);
if (embedded) {
return (
<section className="embedded-panel-section">
<div className="embedded-panel-section-header">
<div>
<h4>LLM Connector</h4>
<p>Switch between OpenAI cloud and local OpenAI-compatible server.</p>
</div>
<span className="status-chip">{lastStatus || "Status: not checked"}</span>
</div>
{content}
</section>
);
}
return (
<PanelFrame
title="LLM Connector"
subtitle="Switch between OpenAI cloud and local OpenAI-compatible server."
actions={<span className="status-chip">{lastStatus || "Status: not checked"}</span>}
>
{content}
</PanelFrame>
);
}
@@ -25,6 +25,7 @@ interface PromptPanelProps {
presetName: string;
onPresetNameChange: (name: string) => void;
diffSummary: string;
embedded?: boolean;
}
export function PromptPanel({
@@ -39,10 +40,11 @@ export function PromptPanel({
onDiffPrevious,
presetName,
onPresetNameChange,
diffSummary
diffSummary,
embedded = false
}: PromptPanelProps) {
return (
<PanelFrame title="Prompt Manager" subtitle="Системный, developer и domain уровни управляются отдельно.">
const content = (
<>
<div className="prompt-manager-grid">
<label>
Системный prompt
@@ -101,6 +103,26 @@ export function PromptPanel({
</button>
</div>
{diffSummary ? <p className="diff-summary">{diffSummary}</p> : null}
</>
);
if (embedded) {
return (
<section className="embedded-panel-section">
<div className="embedded-panel-section-header">
<div>
<h4>Prompt Manager</h4>
<p>Системный, developer и domain уровни управляются отдельно.</p>
</div>
</div>
{content}
</section>
);
}
return (
<PanelFrame title="Prompt Manager" subtitle="Системный, developer и domain уровни управляются отдельно.">
{content}
</PanelFrame>
);
}
+38
View File
@@ -966,6 +966,44 @@ button:disabled {
scrollbar-gutter: stable;
}
.autoruns-settings-col {
display: flex;
flex-direction: column;
}
.autoruns-settings-stack {
display: grid;
gap: 12px;
}
.embedded-panel-section {
display: grid;
gap: 12px;
border-radius: 12px;
background: rgb(var(--rgb-surface-horizontal));
padding: 12px;
}
.embedded-panel-section-header {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
}
.embedded-panel-section-header h4 {
margin: 0;
color: var(--text-main);
font-size: 0.92rem;
}
.embedded-panel-section-header p {
margin: 6px 0 0;
color: var(--text-muted);
font-size: 0.78rem;
line-height: 1.4;
}
.autoruns-assistant-live-col {
background: rgb(var(--rgb-surface-main));
padding: 12px;