feat(kol): add SSE streaming for prompt assist

- Extract assist runtime (prompt building, response parsing, finalize)
  from the worker into kol_assist_runtime so the sync streaming path
  and the async task path share the same logic.
- Add POST /kol/manage/assist/stream as a Server-Sent Events endpoint
  emitting start/delta/completed/error events, and wire it to a
  streamAssist helper on kolManageApi that reports ApiClientError with
  the server's error envelope.
- Stream generated content live in KolPromptEditor and KolGenerateView,
  switching KolPromptEditArea to a boolean aiBusy flag and refining the
  generator page layout.
- Add KolAssistStreamEvent to shared types.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 16:17:11 +08:00
parent 79c65c1da7
commit 4bbce5f083
13 changed files with 1062 additions and 234 deletions
+12 -3
View File
@@ -27,8 +27,8 @@ import ArticleSourceMeta from "@/components/ArticleSourceMeta.vue";
import ArticleDetailDrawer from "@/components/ArticleDetailDrawer.vue";
import PublishArticleModal from "@/components/PublishArticleModal.vue";
import { articlesApi, workspaceApi } from "@/lib/api";
import { getTemplateMeta } from "@/lib/display";
import { buildArticleClipboardContent, resolveArticleActionState } from "@/lib/article-list-actions";
import { formatDateTime, getTemplateMeta } from "@/lib/display";
import { formatError } from "@/lib/errors";
const queryClient = useQueryClient();
@@ -303,6 +303,9 @@ function refreshDashboard(): void {
<h4 class="kol-card-title" :title="card.prompt_name">{{ card.prompt_name }}</h4>
<div class="kol-card-meta-row">
<span class="kol-card-prompt" :title="card.package_name">{{ card.package_name }}</span>
<span class="kol-card-updated-at">
{{ t("common.updatedAt") }}: {{ formatDateTime(card.updated_at) }}
</span>
</div>
<div class="kol-card-footer">
@@ -747,9 +750,9 @@ function refreshDashboard(): void {
.kol-card-meta-row {
display: flex;
flex-direction: column;
align-items: flex-start;
flex-wrap: wrap;
gap: 8px;
gap: 6px;
flex: 1;
}
@@ -764,6 +767,12 @@ function refreshDashboard(): void {
font-weight: 400;
}
.kol-card-updated-at {
font-size: 12px;
color: #9ca3af;
line-height: 1.4;
}
.kol-card-footer {
display: flex;
justify-content: space-between;