diff --git a/apps/internal-ui/src/features/ai/AgentsTable.tsx b/apps/internal-ui/src/features/ai/AgentsTable.tsx
index 8738e71..f3fde19 100644
--- a/apps/internal-ui/src/features/ai/AgentsTable.tsx
+++ b/apps/internal-ui/src/features/ai/AgentsTable.tsx
@@ -1,9 +1,8 @@
import { Dropdown } from "antd";
-import type { RouteKey } from "../../types";
import { Icon } from "../../shared/icons";
import { StatusPill } from "../../shared/ui";
-import { Button, MonoLink, ToneBadge } from "../../shared/ui-controls";
+import { MonoLink, ToneBadge } from "../../shared/ui-controls";
import { productAccent } from "../../shared/utils";
import { publishedRelease, releaseName, type AiAgent, type AiRelease } from "./model";
@@ -13,7 +12,6 @@ export function AgentsTable({
menuId,
setMenuId,
toggleActive,
- setRoute,
openAgent,
openRelease,
}: {
@@ -22,7 +20,6 @@ export function AgentsTable({
menuId: number | null;
setMenuId: (id: number | null) => void;
toggleActive: (agent: AiAgent) => void;
- setRoute: (route: RouteKey) => void;
openAgent: (agentId: number) => void;
openRelease: (releaseId: number) => void;
}) {
@@ -84,7 +81,6 @@ export function AgentsTable({
—
-
setRoute("aiTestChat")}>Тест-чат
void; setRoute: (route: RouteKey) => void; openAgentCreate: (productCode: string | null) => void; openAgent: (agentId: number) => void; openRelease: (releaseId: number) => void }) {
+export function AiAgentsPage({ agents, releases, reload, openAgentCreate, openAgent, openRelease }: { agents: AiAgent[]; releases: AiRelease[]; reload: () => void; openAgentCreate: (productCode: string | null) => void; openAgent: (agentId: number) => void; openRelease: (releaseId: number) => void }) {
const [menuId, setMenuId] = useState(null);
async function toggleActive(agent: AiAgent) {
@@ -22,7 +21,7 @@ export function AiAgentsPage({ agents, releases, reload, setRoute, openAgentCrea
openAgentCreate(null)}>Создать агента} />
-
+
);
}
diff --git a/apps/internal-ui/src/features/ai/AiSubnav.tsx b/apps/internal-ui/src/features/ai/AiSubnav.tsx
index 73059bf..70f46d4 100644
--- a/apps/internal-ui/src/features/ai/AiSubnav.tsx
+++ b/apps/internal-ui/src/features/ai/AiSubnav.tsx
@@ -3,7 +3,6 @@ import { UnderlineTabs } from "../../shared/ui-controls";
const ITEMS: Array<{ key: RouteKey; label: string; disabled?: boolean }> = [
{ key: "aiAgents", label: "AI-агенты" },
- { key: "aiTestChat", label: "Тестовый чат" },
{ key: "aiUsage", label: "Использование AI", disabled: true },
];
diff --git a/apps/internal-ui/src/features/ai/detail/AiAgentDetailHeader.tsx b/apps/internal-ui/src/features/ai/detail/AiAgentDetailHeader.tsx
index 9dd8dcb..3e39bff 100644
--- a/apps/internal-ui/src/features/ai/detail/AiAgentDetailHeader.tsx
+++ b/apps/internal-ui/src/features/ai/detail/AiAgentDetailHeader.tsx
@@ -2,20 +2,17 @@ import { Icon } from "../../../shared/icons";
import { StatusPill } from "../../../shared/ui";
import { Button } from "../../../shared/ui-controls";
import { productAccent } from "../../../shared/utils";
-import type { RouteKey } from "../../../types";
import { dailyBudget, publishedRelease, releaseDisplayName, type AiAgentDetail, type AiReleaseFull } from "./model";
export function AiAgentDetailHeader({
agent,
releases,
- setRoute,
openRelease,
createRelease,
onEditChannel,
}: {
agent: AiAgentDetail;
releases: AiReleaseFull[];
- setRoute: (route: RouteKey) => void;
openRelease: (releaseId: number) => void;
createRelease: () => void;
onEditChannel: () => void;
@@ -40,7 +37,6 @@ export function AiAgentDetailHeader({
- setRoute("aiTestChat")}>Тест-чат
Создать черновик версии
diff --git a/apps/internal-ui/src/features/ai/detail/AiAgentDetailPage.tsx b/apps/internal-ui/src/features/ai/detail/AiAgentDetailPage.tsx
index 459744c..11aca0d 100644
--- a/apps/internal-ui/src/features/ai/detail/AiAgentDetailPage.tsx
+++ b/apps/internal-ui/src/features/ai/detail/AiAgentDetailPage.tsx
@@ -4,7 +4,6 @@ import { api } from "../../../api/client";
import { Icon } from "../../../shared/icons";
import { EmptyState, LoadingState } from "../../../shared/ui";
import { Button, UnderlineTabs } from "../../../shared/ui-controls";
-import type { RouteKey } from "../../../types";
import { AiAgentDetailHeader } from "./AiAgentDetailHeader";
import { AgentEditForm } from "./AgentEditForm";
import { ChannelEditForm } from "./ChannelEditForm";
@@ -16,7 +15,7 @@ import { AiAgentReleasesTab } from "./AiAgentReleasesTab";
import { agentTabs, type AgentTab, type AiReleaseFull } from "./model";
import { useAiAgentDetail } from "./useAiAgentDetail";
-export function AiAgentDetailPage({ agentId, setRoute, openRelease, onAgentLoaded }: { agentId: number | null; setRoute: (route: RouteKey) => void; openRelease: (releaseId: number) => void; onAgentLoaded: (name: string | null) => void }) {
+export function AiAgentDetailPage({ agentId, openRelease, onAgentLoaded }: { agentId: number | null; openRelease: (releaseId: number) => void; onAgentLoaded: (name: string | null) => void }) {
const { agent, releases, knowledge, prompts, loading, error, reload } = useAiAgentDetail(agentId);
const [tab, setTab] = useState("overview");
const [editOpen, setEditOpen] = useState(false);
@@ -50,7 +49,7 @@ export function AiAgentDetailPage({ agentId, setRoute, openRelease, onAgentLoade
return (
-
setChannelEdit(true)} />
+ setChannelEdit(true)} />
{(tab === "instructions" || tab === "knowledge") && (
diff --git a/apps/internal-ui/src/features/ai/release/ProductAIReleaseHeader.tsx b/apps/internal-ui/src/features/ai/release/ProductAIReleaseHeader.tsx
index 48a3fc4..aadd185 100644
--- a/apps/internal-ui/src/features/ai/release/ProductAIReleaseHeader.tsx
+++ b/apps/internal-ui/src/features/ai/release/ProductAIReleaseHeader.tsx
@@ -1,6 +1,5 @@
import { Icon } from "../../../shared/icons";
import { Button } from "../../../shared/ui-controls";
-import type { RouteKey } from "../../../types";
import type { AiReleaseFull } from "../detail/model";
import { formatDateTime, releaseLabel, releaseState, type ReleaseCheck } from "./model";
@@ -8,13 +7,11 @@ export function ProductAIReleaseHeader({
canPublish,
checks,
release,
- setRoute,
startPublish,
}: {
canPublish: boolean;
checks: ReleaseCheck[];
release: AiReleaseFull;
- setRoute: (route: RouteKey) => void;
startPublish: () => void;
}) {
const state = releaseState(checks, release.status === "PUBLISHED");
@@ -38,7 +35,6 @@ export function ProductAIReleaseHeader({
Сравнить с опубликованной
-
setRoute("aiTestChat")}>Тест-чат
{release.status === "PUBLISHED" ? "Опубликована" : "Опубликовать"}
diff --git a/apps/internal-ui/src/features/ai/release/ProductAIReleasePage.tsx b/apps/internal-ui/src/features/ai/release/ProductAIReleasePage.tsx
index 0bf55d8..875deb6 100644
--- a/apps/internal-ui/src/features/ai/release/ProductAIReleasePage.tsx
+++ b/apps/internal-ui/src/features/ai/release/ProductAIReleasePage.tsx
@@ -2,7 +2,6 @@ import { useEffect, useMemo, useState } from "react";
import { api } from "../../../api/client";
import { EmptyState, LoadingState } from "../../../shared/ui";
-import type { RouteKey } from "../../../types";
import { ProductAIReleaseHeader } from "./ProductAIReleaseHeader";
import { PublishReleaseModal } from "./PublishReleaseModal";
import { ReleaseComposition } from "./ReleaseComposition";
@@ -13,11 +12,9 @@ import { useProductAIRelease } from "./useProductAIRelease";
export function ProductAIReleasePage({
onReleaseLoaded,
releaseId,
- setRoute,
}: {
onReleaseLoaded: (name: string | null) => void;
releaseId: number | null;
- setRoute: (route: RouteKey) => void;
}) {
const { release, releases, knowledge, prompts, loading, error, reload } = useProductAIRelease(releaseId);
const [modalOpen, setModalOpen] = useState(false);
@@ -54,7 +51,7 @@ export function ProductAIReleasePage({
return (
-
setModalOpen(true)} />
+ setModalOpen(true)} />
diff --git a/apps/internal-ui/src/features/ai/release/model.ts b/apps/internal-ui/src/features/ai/release/model.ts
index 1ef383e..a5f95fa 100644
--- a/apps/internal-ui/src/features/ai/release/model.ts
+++ b/apps/internal-ui/src/features/ai/release/model.ts
@@ -79,20 +79,18 @@ export function canPublishRelease(release: AiReleaseFull, checks: ReleaseCheck[]
return release.status === "DRAFT" && checks.every((check) => check.tone === "ok");
}
-export function validationBanner(checks: ReleaseCheck[], tested = true) {
+export function validationBanner(checks: ReleaseCheck[]) {
const summary = checksSummary(checks);
if (summary.tone === "error") return { title: "Найдены ошибки валидации", note: "Исправьте отмеченные пункты в составе версии, затем перезапустите проверку.", tone: "error" as const };
if (summary.tone === "warn") return { title: "Черновик версии неполный", note: "Заполните обязательные разделы, чтобы перейти к проверке.", tone: "warn" as const };
- if (!tested) return { title: "Готово к тестированию", note: "Проверки пройдены. Запустите тест-чат перед публикацией.", tone: "ok" as const };
- return { title: "Готово к публикации", note: "Все проверки пройдены, протестировано в тест-чате. Можно публиковать.", tone: "ok" as const };
+ return { title: "Готово к публикации", note: "Все проверки пройдены. Можно публиковать.", tone: "ok" as const };
}
-export function releaseState(checks: ReleaseCheck[], published: boolean, tested = true): { className: string; label: string } {
+export function releaseState(checks: ReleaseCheck[], published: boolean): { className: string; label: string } {
const summary = checksSummary(checks);
if (published) return { className: "published", label: "Опубликован" };
if (summary.tone === "error") return { className: "errors", label: "Ошибки валидации" };
if (summary.tone === "warn") return { className: "incomplete", label: "Неполный черновик" };
- if (!tested) return { className: "ready-test", label: "Готов к тестированию" };
return { className: "ready-publish", label: "Готов к публикации" };
}
diff --git a/apps/internal-ui/src/features/ai/release/styles.css b/apps/internal-ui/src/features/ai/release/styles.css
index 5194c6c..d39d36c 100644
--- a/apps/internal-ui/src/features/ai/release/styles.css
+++ b/apps/internal-ui/src/features/ai/release/styles.css
@@ -86,16 +86,6 @@
background: #52c41a;
}
-.release-status-badge.ready-test {
- color: #0958d9;
- background: #e6f4ff;
- border-color: #91caff;
-}
-
-.release-status-badge.ready-test span {
- background: #1677ff;
-}
-
.release-status-badge.incomplete {
color: #8c8c8c;
background: #f5f5f5;
diff --git a/apps/internal-ui/src/features/ai/styles.css b/apps/internal-ui/src/features/ai/styles.css
index 4a2e3c7..0ed486a 100644
--- a/apps/internal-ui/src/features/ai/styles.css
+++ b/apps/internal-ui/src/features/ai/styles.css
@@ -101,13 +101,6 @@
gap: 7px;
}
-.ai-test-chat-btn {
- height: 32px;
- padding: 0 12px;
- font-size: 12.5px;
- white-space: nowrap;
-}
-
.ai-table-footer {
display: flex;
align-items: center;
diff --git a/apps/internal-ui/src/features/ai/test-chat/AiTestChatPage.tsx b/apps/internal-ui/src/features/ai/test-chat/AiTestChatPage.tsx
deleted file mode 100644
index 71440b7..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/AiTestChatPage.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import { useState } from "react";
-
-import type { TestChannel } from "./model";
-import { TestChatDiagnostics } from "./TestChatDiagnostics";
-import { TestChatSidebar } from "./TestChatSidebar";
-import { TestConversation } from "./TestConversation";
-
-export function AiTestChatPage() {
- const [channel, setChannel] = useState
("MAX");
- const [scenario, setScenario] = useState("box");
-
- return (
-
-
-
-
-
- );
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/TestChatDiagnostics.tsx b/apps/internal-ui/src/features/ai/test-chat/TestChatDiagnostics.tsx
deleted file mode 100644
index 99eaa18..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/TestChatDiagnostics.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import { Icon } from "../../../shared/icons";
-import { diagnosticChunks } from "./model";
-
-export function TestChatDiagnostics() {
- return (
-
-
-
Диагностика
- Последний ответ AI
-
-
-
-
Tokens 1 284 in 940 · out 344
-
Cost ₽0,42 latency 3,1с
-
-
-
ИСПОЛЬЗОВАННЫЕ ФРАГМЕНТЫ
-
- {diagnosticChunks.map((chunk) => (
-
-
{chunk.source} {chunk.score}
-
{chunk.text}
-
- ))}
-
-
-
ВЫЗВАННЫЕ ИНСТРУМЕНТЫ
-
-
-
-
-
-
ПЕРЕДАЧА ОПЕРАТОРУ
-
Передачи оператору не было — сценарий в рамках агента.
-
-
- );
-}
-
-function PanelTitle({ children }: { children: string }) {
- return {children}
;
-}
-
-function ToolCall({ meta, name, time }: { meta: string; name: string; time: string }) {
- return (
-
-
-
{name} {meta}
-
{time}
-
- );
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/TestChatSidebar.tsx b/apps/internal-ui/src/features/ai/test-chat/TestChatSidebar.tsx
deleted file mode 100644
index e0f698f..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/TestChatSidebar.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import { Icon } from "../../../shared/icons";
-import { testChannels, testScenarios, type TestChannel } from "./model";
-
-export function TestChatSidebar({
- channel,
- scenario,
- setChannel,
- setScenario,
-}: {
- channel: TestChannel;
- scenario: string;
- setChannel: (channel: TestChannel) => void;
- setScenario: (scenario: string) => void;
-}) {
- return (
-
-
-
ЧЕРНОВИК ВЕРСИИ
-
-
- REL-FP-v5 · Черновик версии
- REL-FP-v4 · Опубликована
-
-
-
-
-
- FirePage Sales · gpt-4o-mini · temp 0.4
-
-
-
КАНАЛ СИМУЛЯЦИИ
-
- {testChannels.map((item) => (
- setChannel(item.key)} key={item.key}>
-
- {item.label}
-
- ))}
-
-
-
ГОТОВЫЕ СЦЕНАРИИ
-
- {testScenarios.map((item) => (
- setScenario(item.id)} key={item.id}>
- {item.title}
- {item.desc}
-
- ))}
-
-
-
- Очистить тестовую сессию
-
-
- );
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/TestConversation.tsx b/apps/internal-ui/src/features/ai/test-chat/TestConversation.tsx
deleted file mode 100644
index d4cac3a..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/TestConversation.tsx
+++ /dev/null
@@ -1,97 +0,0 @@
-import { useLayoutEffect, useRef, useState, type ChangeEvent, type ReactNode } from "react";
-
-import { Icon } from "../../../shared/icons";
-import type { TestChannel } from "./model";
-
-const channelLabel: Record = {
- MAX: "MAX",
- TG: "Telegram",
- WEB: "Web Chat",
-};
-
-export function TestConversation({ channel }: { channel: TestChannel }) {
- const [message, setMessage] = useState("");
- const textareaRef = useRef(null);
-
- const resizeMessageInput = () => {
- const textarea = textareaRef.current;
- if (!textarea) return;
- const styles = window.getComputedStyle(textarea);
- const lineHeight = Number.parseFloat(styles.lineHeight);
- const paddingTop = Number.parseFloat(styles.paddingTop);
- const paddingBottom = Number.parseFloat(styles.paddingBottom);
- const maxHeight = lineHeight * 12 + paddingTop + paddingBottom;
-
- textarea.style.height = "auto";
- const nextHeight = Math.min(textarea.scrollHeight, maxHeight);
- textarea.style.height = `${nextHeight}px`;
- textarea.style.overflowY = textarea.scrollHeight > maxHeight ? "auto" : "hidden";
- };
-
- useLayoutEffect(() => {
- resizeMessageInput();
- }, [message]);
-
- const handleMessageChange = (event: ChangeEvent) => {
- setMessage(event.target.value);
- };
-
- return (
-
-
-
-
-
- Test conversation
- Симуляция клиента · сообщений: 4
-
-
-
Не создаёт Contact, Order или Payment
-
-
-
-
Сценарий: «Покупка коробки» · канал {channelLabel[channel]}
-
-
- Здравствуйте! FirePage — это готовый нишевой сайт под ключ. Коробка стоит ₽4 900 единоразово. Дополнительно можно подключить годовую поддержку за ₽1 470. Под визитку отлично подходит — оформить?
-
-
-
- Отлично! Подготовил оформление коробки FirePage за ₽4 900. Вызываю оформление покупки — в реальном диалоге клиент получил бы ссылку на оплату.
-
-
-
-
-
- );
-}
-
-function ClientMessage({ note, text }: { note?: string; text: string }) {
- return (
-
-
Т
-
-
{text}
- {note &&
{note} }
-
-
- );
-}
-
-function AiMessage({ children, tool }: { children: ReactNode; tool?: string }) {
- return (
-
-
-
-
AI · REL-FP-v5
-
{children}
- {tool &&
tool: {tool} }
-
-
- );
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/conversation.css b/apps/internal-ui/src/features/ai/test-chat/conversation.css
deleted file mode 100644
index 8b57d26..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/conversation.css
+++ /dev/null
@@ -1,201 +0,0 @@
-.test-conversation-head {
- flex: none;
- display: flex;
- align-items: center;
- justify-content: space-between;
- padding: 11px 20px;
- background: #fff;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.test-conversation-title {
- display: flex;
- align-items: center;
- gap: 11px;
-}
-
-.test-conversation-title > span,
-.test-ai-avatar {
- display: flex;
- align-items: center;
- justify-content: center;
- background: #f9f0ff;
- border: 1px solid #efdbff;
- color: #722ed1;
-}
-
-.test-conversation-title > span {
- width: 34px;
- height: 34px;
- border-radius: 9px;
-}
-
-.test-conversation-title strong {
- display: block;
- color: #1f1f1f;
- font-size: 14px;
-}
-
-.test-conversation-title small,
-.test-conversation-head em {
- color: #8c8c8c;
- font-size: 11.5px;
- font-style: normal;
-}
-
-.test-conversation-head em {
- display: inline-flex;
- align-items: center;
- gap: 5px;
- color: #bfbfbf;
-}
-
-.test-messages {
- flex: 1;
- overflow-y: auto;
- padding: 18px 24px 8px;
-}
-
-.test-messages::before,
-.test-messages::after {
- display: table;
- content: "";
-}
-
-.test-scenario-pill {
- width: max-content;
- margin: 0 auto 16px;
- padding: 4px 12px;
- color: #8c8c8c;
- background: #eef0f2;
- border-radius: 20px;
- font-size: 11.5px;
-}
-
-.test-message {
- display: flex;
- gap: 10px;
- max-width: 680px;
- margin: 0 auto 14px;
-}
-
-.test-message.ai {
- flex-direction: row-reverse;
-}
-
-.test-client-avatar,
-.test-ai-avatar {
- width: 30px;
- height: 30px;
- flex: none;
- border-radius: 50%;
-}
-
-.test-client-avatar {
- display: flex;
- align-items: center;
- justify-content: center;
- color: #fff;
- background: #8c8c8c;
- font-size: 11px;
- font-weight: 600;
-}
-
-.test-message > div {
- max-width: 78%;
-}
-
-.test-message p {
- margin: 0;
- padding: 10px 14px;
- color: #262626;
- background: #fff;
- border: 1px solid #eee;
- border-radius: 4px 14px 14px 14px;
- font-size: 13.5px;
- line-height: 1.5;
-}
-
-.test-message.ai p {
- background: #f9f0ff;
- border-color: #efdbff;
- border-radius: 14px 4px 14px 14px;
-}
-
-.test-message small {
- display: block;
- margin: 4px 0 0 4px;
- color: #bfbfbf;
- font-size: 11px;
-}
-
-.test-message.ai strong {
- display: block;
- margin-bottom: 4px;
- color: #722ed1;
- font-size: 11px;
- text-align: right;
-}
-
-.test-message.ai em {
- display: inline-flex;
- float: right;
- margin: 6px 4px 0 0;
- padding: 2px 8px;
- color: #0958d9;
- background: #e6f4ff;
- border-radius: 5px;
- font-family: "SF Mono", ui-monospace, Menlo, monospace;
- font-size: 10.5px;
- font-style: normal;
- font-weight: 600;
-}
-
-.test-composer {
- flex: none;
- padding: 14px 24px 16px;
- background: #fff;
- border-top: 1px solid #f0f0f0;
-}
-
-.test-composer > div {
- max-width: 680px;
- display: flex;
- align-items: flex-end;
- gap: 10px;
- margin: 0 auto;
- padding: 8px 8px 8px 14px;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 12px;
-}
-
-.test-composer textarea {
- flex: 1;
- min-height: 38px;
- min-width: 0;
- padding: 9px 0;
- overflow-y: hidden;
- resize: none;
- border: 0;
- outline: 0;
- color: #262626;
- font: inherit;
- font-size: 13.5px;
- line-height: 1.5;
-}
-
-.test-composer button {
- height: 38px;
- display: inline-flex;
- align-items: center;
- gap: 7px;
- flex: none;
- padding: 0 16px;
- color: #fff;
- background: #1677ff;
- border: 0;
- border-radius: 9px;
- font-size: 13px;
- font-weight: 600;
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/diagnostics.css b/apps/internal-ui/src/features/ai/test-chat/diagnostics.css
deleted file mode 100644
index 8f97254..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/diagnostics.css
+++ /dev/null
@@ -1,155 +0,0 @@
-.test-diagnostics {
- width: 340px;
- flex: none;
- display: flex;
- flex-direction: column;
- min-height: 0;
- background: #fff;
- border-left: 1px solid #f0f0f0;
-}
-
-.test-diagnostics-head {
- flex: none;
- padding: 15px 18px 12px;
- border-bottom: 1px solid #f0f0f0;
-}
-
-.test-diagnostics-head h3 {
- margin: 0;
- color: #1f1f1f;
- font-size: 14px;
-}
-
-.test-diagnostics-head span {
- display: block;
- margin-top: 2px;
- color: #bfbfbf;
- font-size: 11.5px;
-}
-
-.test-cost-grid {
- display: grid;
- grid-template-columns: 1fr 1fr;
- gap: 1px;
- margin-bottom: 18px;
- overflow: hidden;
- background: #f0f0f0;
- border: 1px solid #f0f0f0;
- border-radius: 9px;
-}
-
-.test-cost-grid div {
- padding: 12px 14px;
- background: #fff;
-}
-
-.test-cost-grid span,
-.test-cost-grid small {
- display: block;
- color: #8c8c8c;
- font-size: 11px;
-}
-
-.test-cost-grid strong {
- display: block;
- margin-top: 3px;
- color: #262626;
- font-size: 17px;
-}
-
-.test-cost-grid small {
- margin-top: 1px;
- color: #bfbfbf;
- font-size: 10.5px;
-}
-
-.test-diagnostic-list {
- display: flex;
- flex-direction: column;
- gap: 8px;
- margin-bottom: 20px;
-}
-
-.test-chunk,
-.test-tool-call,
-.test-handoff {
- border: 1px solid #f0f0f0;
- border-radius: 9px;
-}
-
-.test-chunk {
- padding: 10px 12px;
-}
-
-.test-chunk div,
-.test-tool-call {
- display: flex;
- align-items: center;
- gap: 10px;
-}
-
-.test-chunk div {
- justify-content: space-between;
- gap: 8px;
-}
-
-.test-chunk strong,
-.test-tool-call strong {
- color: #262626;
- font-size: 12px;
-}
-
-.test-chunk b {
- padding: 1px 6px;
- color: #389e0d;
- background: #f6ffed;
- border-radius: 5px;
- font-size: 10.5px;
-}
-
-.test-chunk p,
-.test-tool-call span,
-.test-handoff {
- color: #8c8c8c;
- font-size: 11.5px;
- line-height: 1.45;
-}
-
-.test-chunk p {
- margin: 4px 0 0;
-}
-
-.test-tool-call {
- padding: 10px 12px;
-}
-
-.test-tool-call svg,
-.test-handoff svg {
- flex: none;
- color: #389e0d;
-}
-
-.test-tool-call div {
- flex: 1;
- min-width: 0;
-}
-
-.test-tool-call strong,
-.test-tool-call span {
- display: block;
- font-family: "SF Mono", ui-monospace, Menlo, monospace;
-}
-
-.test-tool-call small {
- flex: none;
- color: #bfbfbf;
- font-size: 10.5px;
-}
-
-.test-handoff {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 11px 13px;
- background: #fafafa;
-}
diff --git a/apps/internal-ui/src/features/ai/test-chat/model.ts b/apps/internal-ui/src/features/ai/test-chat/model.ts
deleted file mode 100644
index e13fa4e..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/model.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-export type TestChannel = "MAX" | "TG" | "WEB";
-
-export const testChannels: Array<{ key: TestChannel; label: string; dot: string }> = [
- { key: "MAX", label: "MAX", dot: "#6b5be0" },
- { key: "TG", label: "TG", dot: "#2f8fd0" },
- { key: "WEB", label: "Web", dot: "#0f9b8e" },
-];
-
-export const testScenarios = [
- { id: "box", title: "Покупка коробки", desc: "Клиент хочет купить FirePage под визитку." },
- { id: "support", title: "Вопрос про поддержку", desc: "Уточняет условия годовой поддержки." },
- { id: "handoff", title: "Запрос человека", desc: "Просит соединить с менеджером." },
-];
-
-export const diagnosticChunks = [
- { source: "Что входит в коробку FirePage", score: "0.91", text: "Коробка FirePage — готовый нишевой сайт под ключ, единоразовая оплата ₽4 900." },
- { source: "Условия годовой поддержки", score: "0.84", text: "Годовая поддержка — 30% от цены коробки, ₽1 470 в год, продление по желанию." },
-];
diff --git a/apps/internal-ui/src/features/ai/test-chat/styles.css b/apps/internal-ui/src/features/ai/test-chat/styles.css
deleted file mode 100644
index 5985159..0000000
--- a/apps/internal-ui/src/features/ai/test-chat/styles.css
+++ /dev/null
@@ -1,167 +0,0 @@
-.ai-test-chat-page {
- height: calc(100vh - 56px);
- display: flex;
- overflow: hidden;
-}
-
-.test-chat-sidebar {
- width: 300px;
- flex: none;
- display: flex;
- flex-direction: column;
- min-height: 0;
- background: #fff;
- border-right: 1px solid #f0f0f0;
-}
-
-.test-chat-sidebar-scroll,
-.test-diagnostics-scroll {
- flex: 1;
- overflow-y: auto;
- padding: 18px;
-}
-
-.test-chat-label,
-.test-panel-title {
- margin-bottom: 10px;
- color: #bfbfbf;
- font-size: 11px;
- font-weight: 600;
- letter-spacing: 0.05em;
-}
-
-.test-release-select {
- position: relative;
- display: block;
- margin-bottom: 8px;
-}
-
-.test-release-select select {
- width: 100%;
- height: 40px;
- padding: 0 32px 0 12px;
- color: #262626;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 9px;
- appearance: none;
- font: inherit;
- font-size: 13px;
- font-weight: 500;
-}
-
-.test-release-select svg {
- position: absolute;
- top: 13px;
- right: 11px;
- color: #8c8c8c;
- pointer-events: none;
-}
-
-.test-agent-chip {
- display: flex;
- align-items: center;
- gap: 8px;
- padding: 9px 12px;
- margin-bottom: 18px;
- color: #722ed1;
- background: #f9f0ff;
- border: 1px solid #efdbff;
- border-radius: 8px;
- font-size: 11.5px;
-}
-
-.test-channel-row {
- display: flex;
- gap: 6px;
- margin-bottom: 18px;
-}
-
-.test-channel-row button {
- height: 32px;
- flex: 1;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 6px;
- color: #595959;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 8px;
- font-size: 12px;
- font-weight: 500;
-}
-
-.test-channel-row button.active {
- color: #0958d9;
- background: #e6f4ff;
- border-color: #1677ff;
- font-weight: 600;
-}
-
-.test-channel-row span {
- width: 6px;
- height: 6px;
- border-radius: 50%;
-}
-
-.test-scenarios {
- display: flex;
- flex-direction: column;
- gap: 8px;
-}
-
-.test-scenarios button {
- padding: 11px 13px;
- text-align: left;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 10px;
-}
-
-.test-scenarios button.active {
- background: #f7fbff;
- border-color: #1677ff;
-}
-
-.test-scenarios strong {
- display: block;
- color: #262626;
- font-size: 13px;
-}
-
-.test-scenarios span {
- display: block;
- margin-top: 2px;
- color: #8c8c8c;
- font-size: 11.5px;
- line-height: 1.4;
-}
-
-.test-chat-sidebar-footer {
- padding: 12px 18px;
- border-top: 1px solid #f5f5f5;
-}
-
-.test-chat-sidebar-footer button {
- width: 100%;
- height: 38px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- gap: 8px;
- color: #595959;
- background: #fff;
- border: 1px solid #e8e8e8;
- border-radius: 9px;
- font-size: 13px;
- font-weight: 500;
-}
-
-.test-conversation {
- min-width: 0;
- flex: 1;
- display: flex;
- flex-direction: column;
- background: #f7f8fa;
-}
diff --git a/apps/internal-ui/src/layout/Shell.tsx b/apps/internal-ui/src/layout/Shell.tsx
index 587439b..fbcf5a2 100644
--- a/apps/internal-ui/src/layout/Shell.tsx
+++ b/apps/internal-ui/src/layout/Shell.tsx
@@ -93,7 +93,7 @@ export function Shell({ route, setRoute, selectedEmployeeId, selectedProductId,
const isSalesOrders = route === "salesOrderDetail" || route === "salesOrders";
// Подменю AI показываем только там, где оно есть в baseline.
const isAiSection = route === "aiAgents" || route === "aiUsage";
- const isAiFullWidth = route === "aiAgentCreate" || route === "aiRelease" || route === "aiTestChat";
+ const isAiFullWidth = route === "aiAgentCreate" || route === "aiRelease";
// OPERATOR работает в пространстве своего отдела (SPEC-HUB-0004 §9 + §0010 §10):
// sales operator → sales-sidebar, support operator → support-sidebar.
const showSalesSidebar = isSalesWorkspace || (user.role === "OPERATOR" && user.department !== "support" && !isSupportWorkspace);
diff --git a/apps/internal-ui/src/layout/ShellRouteContent.tsx b/apps/internal-ui/src/layout/ShellRouteContent.tsx
index f5ee45c..9c58339 100644
--- a/apps/internal-ui/src/layout/ShellRouteContent.tsx
+++ b/apps/internal-ui/src/layout/ShellRouteContent.tsx
@@ -2,7 +2,6 @@ import { AiAgentsPage } from "../features/ai/AiAgentsPage";
import { AiAgentCreatePage } from "../features/ai/create/AiAgentCreatePage";
import { AiAgentDetailPage } from "../features/ai/detail/AiAgentDetailPage";
import { ProductAIReleasePage } from "../features/ai/release/ProductAIReleasePage";
-import { AiTestChatPage } from "../features/ai/test-chat/AiTestChatPage";
import { CommandCenter } from "../features/command/CommandCenter";
import { IntegrationsPage } from "../features/integrations/IntegrationsPage";
import { DepartmentsPage } from "../features/departments/DepartmentsPage";
@@ -40,11 +39,10 @@ export function ShellRouteContent({ route, data, currentEmployee, currentProduct
{route === "salesDialogs" && }
{route === "salesOrderDetail" && }
{route === "salesOrders" && }
- {route === "aiAgents" && }
+ {route === "aiAgents" && }
{route === "aiAgentCreate" && }
- {route === "aiAgentDetail" && }
- {route === "aiRelease" && }
- {route === "aiTestChat" && }
+ {route === "aiAgentDetail" && }
+ {route === "aiRelease" && }
{route === "integrations" && }
>
);
diff --git a/apps/internal-ui/src/router.ts b/apps/internal-ui/src/router.ts
index 487dd88..2a08b93 100644
--- a/apps/internal-ui/src/router.ts
+++ b/apps/internal-ui/src/router.ts
@@ -53,7 +53,6 @@ export function routeFromPath(pathname: string, search = ""): RouteState {
const id = Number(path.split("/")[3]);
return Number.isInteger(id) && id > 0 ? { ...base, route: "aiRelease", releaseId: id } : { route: "aiAgents", ...base };
}
- if (path === "/ai/test-chat") return { route: "aiTestChat", ...base };
if (path === "/ai/usage") return { route: "aiUsage", ...base };
if (path === "/integrations") return { route: "integrations", ...base };
if (path === "/profile") return { route: "profile", ...base };
@@ -77,7 +76,6 @@ export function pathFromRoute(route: RouteKey, entityId: number | null = null, p
if (route === "productDetail") return entityId ? `/products/${entityId}` : "/products";
if (route === "aiAgents") return "/ai/agents";
if (route === "aiAgentCreate") return productCode ? `/ai/agents/new?product=${encodeURIComponent(productCode)}` : "/ai/agents/new";
- if (route === "aiTestChat") return "/ai/test-chat";
if (route === "aiUsage") return "/ai/usage";
if (route === "aiAgentDetail") return entityId ? `/ai/agents/${entityId}` : "/ai/agents";
if (route === "aiRelease") return entityId ? `/ai/releases/${entityId}` : "/ai/agents";
diff --git a/apps/internal-ui/src/routes.ts b/apps/internal-ui/src/routes.ts
index 7742e86..3be86ce 100644
--- a/apps/internal-ui/src/routes.ts
+++ b/apps/internal-ui/src/routes.ts
@@ -20,7 +20,6 @@ export const routes: Record = {
aiAgentCreate: "Создание агента",
aiAgentDetail: "Карточка агента",
aiRelease: "Версия продукта",
- aiTestChat: "Тестовый чат",
aiUsage: "Использование AI",
integrations: "Интеграции",
};
diff --git a/apps/internal-ui/src/styles.css b/apps/internal-ui/src/styles.css
index 922eb76..52bfce2 100644
--- a/apps/internal-ui/src/styles.css
+++ b/apps/internal-ui/src/styles.css
@@ -24,9 +24,6 @@
@import "./features/ai/release/composition.css";
@import "./features/ai/release/side.css";
@import "./features/ai/release/modal.css";
-@import "./features/ai/test-chat/styles.css";
-@import "./features/ai/test-chat/conversation.css";
-@import "./features/ai/test-chat/diagnostics.css";
@import "./features/integrations/styles.css";
@import "./features/notifications/styles.css";
@import "./shared/state.css";
diff --git a/apps/internal-ui/src/types.ts b/apps/internal-ui/src/types.ts
index b060a2a..bd2d14b 100644
--- a/apps/internal-ui/src/types.ts
+++ b/apps/internal-ui/src/types.ts
@@ -92,7 +92,7 @@ export type ProductOffer = {
prices: ProductPrice[];
};
-export type RouteKey = "command" | "departments" | "employeeDetail" | "employees" | "productDetail" | "products" | "profile" | "salesClientDetail" | "salesClients" | "salesDialogs" | "salesOrderDetail" | "salesOrders" | "salesOverview" | "supportOverview" | "supportDialogs" | "aiAgents" | "aiAgentCreate" | "aiAgentDetail" | "aiRelease" | "aiTestChat" | "aiUsage" | "integrations";
+export type RouteKey = "command" | "departments" | "employeeDetail" | "employees" | "productDetail" | "products" | "profile" | "salesClientDetail" | "salesClients" | "salesDialogs" | "salesOrderDetail" | "salesOrders" | "salesOverview" | "supportOverview" | "supportDialogs" | "aiAgents" | "aiAgentCreate" | "aiAgentDetail" | "aiRelease" | "aiUsage" | "integrations";
export type AppData = {
employees: Employee[];
diff --git a/design/baseline/Тестовый чат.dc.html b/design/baseline/Тестовый чат.dc.html
deleted file mode 100644
index 968ccc9..0000000
--- a/design/baseline/Тестовый чат.dc.html
+++ /dev/null
@@ -1,218 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Тестовая песочница
-
-
ИП
-
-
-
-
-
-
-
-
-
-
ЧЕРНОВИК ВЕРСИИ
-
-
REL-FP-v5 · Черновик версии REL-FP-v4 · Опубликована
-
-
-
-
-
FirePage Sales · gpt-4o-mini · temp 0.4
-
-
-
КАНАЛ СИМУЛЯЦИИ
-
- MAX
- TG
- Web
-
-
-
ГОТОВЫЕ СЦЕНАРИИ
-
-
-
- {{ s.title }}
- {{ s.desc }}
-
-
-
-
-
-
Очистить тестовую сессию
-
-
-
-
-
-
-
-
-
Test conversation
Симуляция клиента · сообщений: 4
-
-
Не создаёт Contact, Order или Payment
-
-
-
-
-
Сценарий: «Покупка коробки» · канал {{ channelLabel }}
-
-
-
Т
Здравствуйте, интересует FirePage для сайта-визитки. Сколько стоит?
тестовый клиент
-
-
-
AI · REL-FP-v5
Здравствуйте! FirePage — это готовый нишевой сайт под ключ. Коробка стоит ₽4 900 единоразово. Дополнительно можно подключить годовую поддержку за ₽1 470. Под визитку отлично подходит — оформить?
debug ниже →
-
-
-
Т
Да, давайте оформим коробку.
-
-
-
Отлично! Подготовил оформление коробки FirePage за ₽4 900. Вызываю checkout — в реальном диалоге клиент получил бы ссылку на оплату.
tool: create_checkout
-
-
-
-
-
-
-
-
-
- Диагностика Последний ответ AI
-
-
-
-
-
Tokens
1 284
in 940 · out 344
-
-
-
-
-
ИСПОЛЬЗОВАННЫЕ CHUNKS
-
-
-
-
{{ c.source }} {{ c.score }}
-
{{ c.text }}
-
-
-
-
-
-
ВЫЗВАННЫЕ TOOLS
-
-
get_offers
product=firepage → 2 offers
120мс
-
create_checkout
offer=OFR-FP-BOX · ₽4 900 (симуляция)
88мс
-
-
-
-
HANDOFF
-
Передачи оператору не было — сценарий в рамках агента.
-
-
-
-
-
-
-
-
-
-
-