added jenkins

This commit is contained in:
2026-06-11 11:35:46 +03:00
parent b70ac1899c
commit 1aa39fc4b2
3 changed files with 50 additions and 28 deletions
Vendored
+2 -2
View File
@@ -10,7 +10,7 @@
pipeline {
agent {
label 'Мастер'
label 'мастер'
}
options {
@@ -33,7 +33,7 @@ pipeline {
)
string(
name: 'BACKEND_HEALTH_URL',
defaultValue: 'http://127.0.0.1:8080/api/v1/health',
defaultValue: 'http://127.0.0.1:8202/api/v1/health',
description: 'Проверка после деплоя'
)
booleanParam(
+10 -2
View File
@@ -292,10 +292,14 @@ class ChatService:
reasoning_details: list[Any] | None = None
finish_reason = ""
# После tool-раунда стримим вживую; до tools — буфер (иначе текст «переписывает» notice).
stream_live = tools_executed > 0
async for event in self.llm.stream_chat(messages, tools=TOOL_DEFINITIONS):
if event["type"] == "content":
content_parts.append(event["content"])
yield self._sse("token", {"content": event["content"]})
if stream_live:
yield self._sse("token", {"content": event["content"]})
elif event["type"] == "reasoning":
reasoning = event.get("reasoning", "") or reasoning
if event.get("reasoning_details"):
@@ -390,8 +394,12 @@ class ChatService:
continue
if content_parts and not stream_live:
for part in content_parts:
yield self._sse("token", {"content": part})
final_content = "".join(content_parts).strip()
if not final_content and streamed_reply_parts:
if not final_content and streamed_reply_parts and tools_executed == 0:
final_content = "".join(streamed_reply_parts).strip()
if not final_content and reasoning:
final_content = reasoning.strip()
+38 -24
View File
@@ -48,8 +48,8 @@ export default function Chat() {
const [pendingPhase, setPendingPhase] = useState<
"thinking" | "preparing" | "generating" | "tools"
>("thinking");
const [liveNotices, setLiveNotices] = useState<string[]>([]);
const [chatError, setChatError] = useState<string | null>(null);
const tempMessageId = useRef(0);
const messagesRef = useRef<HTMLDivElement>(null);
const inputRef = useRef<HTMLTextAreaElement>(null);
const scrollRafRef = useRef<number | null>(null);
@@ -104,23 +104,38 @@ export default function Chat() {
cancelAnimationFrame(scrollRafRef.current);
}
};
}, [messages, streaming, liveNotices, loading, chatError, scrollToBottom]);
}, [messages, streaming, loading, chatError, scrollToBottom]);
const dismissKeyboard = useCallback(() => {
inputRef.current?.blur();
}, []);
const waitingForStream = loading && !streaming;
const nextTempId = () => {
tempMessageId.current -= 1;
return tempMessageId.current;
};
const appendNotice = useCallback((content: string) => {
setMessages((prev) => [
...prev,
{
id: nextTempId(),
role: "notice",
content,
created_at: new Date().toISOString(),
},
]);
}, []);
const pendingLabel =
pendingPhase === "tools"
? "Выполняю команды…"
: liveNotices.length > 0
? "Обрабатываю…"
: pendingPhase === "preparing"
? "Собираю контекст…"
: pendingPhase === "generating"
? "Генерирую ответ…"
: "Думаю…";
: pendingPhase === "preparing"
? "Собираю контекст…"
: pendingPhase === "generating"
? "Генерирую ответ…"
: "Думаю…";
useEffect(() => {
const seq = pomodoroStatus?.cycle?.chat_notify_seq ?? 0;
@@ -177,7 +192,6 @@ export default function Chat() {
await loadSessions();
setActiveId(session.id);
setMessages([]);
setLiveNotices([]);
};
const handleDelete = async (id: number) => {
@@ -187,7 +201,6 @@ export default function Chat() {
if (activeId === id) {
setActiveId(data[0]?.id ?? null);
setMessages([]);
setLiveNotices([]);
}
};
@@ -201,11 +214,10 @@ export default function Chat() {
setLoading(true);
setStreaming("");
setPendingPhase("thinking");
setLiveNotices([]);
setChatError(null);
const tempUser: ChatMessage = {
id: Date.now(),
id: nextTempId(),
role: "user",
content: text,
created_at: new Date().toISOString(),
@@ -234,7 +246,7 @@ export default function Chat() {
setStreaming(assistantText);
}
if (chunk.event === "notice") {
setLiveNotices((prev) => [...prev, chunk.data.content]);
appendNotice(chunk.data.content);
if (String(chunk.data.content).startsWith("⏱")) {
refreshPomodoro();
}
@@ -243,8 +255,19 @@ export default function Chat() {
refreshPomodoro();
}
if (chunk.event === "done") {
const tail = assistantText.trim();
if (tail) {
setMessages((prev) => [
...prev,
{
id: nextTempId(),
role: "assistant",
content: tail,
created_at: new Date().toISOString(),
},
]);
}
setStreaming("");
setLiveNotices([]);
setChatError(null);
await loadMessages(activeId);
await loadSessions();
@@ -334,15 +357,6 @@ export default function Chat() {
</div>
))}
{liveNotices.map((notice, idx) => (
<div key={`notice-${idx}`} className="message message-notice">
<div className="message-role">{noticeLabel(notice)}</div>
<div className="message-content">
<ReactMarkdown>{notice}</ReactMarkdown>
</div>
</div>
))}
{waitingForStream && (
<div className="message message-assistant message-pending" aria-live="polite">
<div className="message-role">assistant</div>