Assert uniqueMonitorDesktopTaskPlatformIDs trims and collapses duplicate
account specs, and tighten the healthier-candidate case with a target
length check. Apply gofmt alignment fixes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Keep blank lines while filtering non-answer noise instead of collapsing
every line, so multi-paragraph answers render with their structure
intact. Also reformat long box-shadow declarations and inline template
attributes for readability.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rework the AI platforms view around multiple accounts per platform:
per-account auth-state classification, status/platform filtering, and an
inline health probe (verifyAccount) with pending state. Update the nav
description to reflect multi-account binding, health checks and auto
switching.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add monitor-account-pool to select authorized, non-blocked candidates
for an AI-platform monitor task, classify failover reasons (risk
control, challenge, auth failure, empty/unknown result) and cool the
account down before rotating to the next. Wire runtime-controller to run
monitor tasks through the pool, retrying across accounts and annotating
the result with per-account attempt diagnostics and a failover count.
Expose the pool state via the runtime snapshot.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Filter captured `/api/chat/*` event-stream responses down to the one
whose request prompt matches the current question, avoiding cross-talk
between concurrent conversations. Preserve blank lines when sanitizing
answer candidates so paragraph breaks survive, and always trust the
parsed SSE answer over the DOM scrape.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Attach a response listener to the `/api/v2/chat` POST stream, parse its
SSE payloads, and reconstruct answer content/extra_info/communication
from the `multi_load/iframe` and `bar/iframe` messages. Expand embedded
`[(tab_container_N)]` references against the SSE cardMap so nested tab
content is inlined instead of leaking a raw placeholder. Prefer the API
answer, falling back to page state, and record `response_source` plus
`api_event_count` in the raw response for diagnosis.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add query-level cases asserting an internal placeholder yields
`unknown`/`qwen_incomplete_response`, and that a resolved sibling field
is used as the answer when another field is still a placeholder.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When Qwen returns an unresolved `[(tab_container_N)]` placeholder in
multiLoadIframe/barIframe content, treat it as an incomplete response:
fall back to a resolved sibling field when available, otherwise return
status `unknown` with a `qwen_incomplete_response` error so the record
is retried on a later collection pass instead of persisting garbage.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add task_plan/findings/progress notes for knowledge fact fidelity,
brand description context, media supply favorites, and the workspace
sync-to-39 deployment.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move media favorites from client state to PostgreSQL with server-side
search and pagination.
- Store favorites keyed by (tenant, user, group, resource) so a resource
can belong to multiple groups; the 500-resource cap counts distinct
resources, not memberships.
- Add favorite-group CRUD and group/global removal routes, with silent
cleanup of delisted or invisible resources on read.
- Serve favorite resource details server-side, 10 per page, with name/ID
search; favorites-page removal is group-scoped, resources-page removal
is global.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Include the current brand description in template, custom, imitation,
and KOL article-generation prompts while bounding prompt growth.
- Add a shared brand-context builder that resolves the current brand,
compacts long descriptions, and caps rendered output at 2000 runes.
- Snapshot a structured brand prompt context on queued tasks so old
jobs stay reproducible and retries stay stable.
- Route brand-profile facts through the existing typed fact guard so
founding dates and year counts get the same pre-persistence validation
as RAG facts, with brand facts outranking conflicting RAG facts.
- Fix the KOL creator to attach the brand scope its worker consumes.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Ensure numeric facts present in retrieved knowledge (especially company
founding dates) cannot be silently contradicted in generated articles.
- Add a typed fact guard that extracts constraints (dates, experience
years, etc.) from precise facts, detects source conflicts, and
validates generated content before persistence with a bounded repair
retry.
- Surface fact constraints through KnowledgeContext and render them as
a canonical, non-derivable fact block in the knowledge prompt section.
- Tighten prompt intro lines to forbid rewriting, mixing old values,
or deriving service years from founding dates.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- kimi adapter: parameterize mode switching (fast/thinking) and default to
K2.6 快速; fix snapshot filtering so fast-mode "搜索网页" chips no longer
wipe the answer body or get misclassified as reasoning/sidebar
- desktop shell: display release notes in the client update modal
- admin-web: fix publish-records table layout with fixed columns and ellipsis
- bump desktop-client to 0.1.10
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduce process-local and Redis-backed global rate limiting for the
shared LLM client, plus a dedicated generation consumer prefetch knob.
- Add request (RPM) and token (TPM) rate limits with burst controls,
process or global scope, and fail-closed/process-degraded failover
- Wire the LLM client through NewWithRedis so limits can be shared
across replicas via a Redis token bucket
- Add generation_consumer_prefetch to tune RabbitMQ generation
consumers independently of the default prefetch
- Bump generation worker_concurrency to 24 and promote golang.org/x/time
to a direct dependency
- Drop t.Parallel() from a few middleware/bootstrap tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Drive the wizard off the article locale instead of the UI locale so an
en-US article stays in English end to end, and stop Chinese values from
leaking into English drafts.
- Localize review-intro-hook copy and outline section labels to English
(with fallbacks), and use a ": " separator for en-US
- Sanitize CJK content from titles, outline, and key points when the
article locale is en-US, and re-sanitize on locale switch/draft restore
- Add knowledge-base reference labels/placeholders and the
missing-review-intro-hook validation message to both locales
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the article locale is en-US, Chinese prompt templates could leak
Chinese wording into generated titles, outlines, and article bodies.
Add high-priority language-consistency guards so the model treats the
Chinese template text as internal instructions and emits English only.
- Append per-artifact locale guards (analyze/title/outline) in template
assist prompts and an article-body guard in the generation prompt,
only when locale is en-US
- Reinforce locale consistency in the title/outline runtime prompts and
drop retained images from the rewrite prompt
- Cover the new guards with unit tests
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously AI point cost was computed from request (input) characters at
reservation time. Switch to reserving a single point up front and
settling the final cost from the generated output length on completion.
- Reserve 1 point (or FixedPoints) instead of pricing on request chars
- On completion, recompute points from output chars vs base chars,
update the reservation amounts, and post a ledger delta for the
top-up/refund; invalidate the workspace quota summary cache
- MarkCompleted now persists final request_chars/base_chars/points
- Use ceil division in calculateAIPointCost so an exact base boundary
charges one point instead of rolling over
- Thread output text through all CompleteAIPoints callers (article
selection, KOL assist, question expansion, template assist, compliance
judge) and return the settled reservation
- Add unit tests plus an integration test gated on TEST_DATABASE_URL
- Update the user manual: billing is by output characters
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the hardcoded doubao-lite model used for monitoring answer
parsing and compliance LLM judging with configurable values, resolved
from config with env overrides and a legacy default fallback.
- Add llm.monitoring_answer_parse_model and compliance.llm_judge_model
to config struct, env overrides, and all config files
- Thread the resolved model through MonitoringCallbackService via a
ConfigProvider and into parseMonitoringAnswerWithLLM
- Pass compliance.llm_judge_model into the review-job LLM request
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Remove the recentArticlesQuery fallback path so the templates record
table renders straight from the article list query, simplifying polling,
pagination and loading state.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
GetRecentArticlesByBrand now folds the latest publish record per target
into an aggregated publish_status (publishing / partial_success / success
/ failed), falling back to the stored status when no records exist.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Aggregate publish status from the latest record per publishing target
using a shared target-identity expression, so retries and multi-record
targets no longer inflate the status buckets.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unify list/detail poll intervals to 5s and skip refetch while a query is
already in flight, replacing broad invalidateQueries cascades with targeted
refetches. Poll now also triggers on active publish status via the new
hasActivePublishStatus helper. Dedupe concurrent refreshBrands calls with a
shared promise and skip the redundant AppShell refresh when already
initialized. Gate publish-record loading on popover open.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add CancelStaleQueuedPublishTasks to abort publish tasks that sit in the
queue past a configurable timeout (default 3 days) without being claimed by
a desktop client, so they no longer linger indefinitely as 'queued'. The
lease recovery worker runs the cleanup each cycle and reports a
cancelled_queued count; the timeout is configurable via job run config.
Aborted tasks carry a publish_queue_timeout error payload with a readable
Chinese duration, and the admin-web publish summary surfaces it as an
auto-cancelled queue-timeout message.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add normalizeDesktopTaskCompletionStatusForTask so an "unknown" publish
completion is downgraded to "failed" when the payload is a manual retry or
the error matches a definitive publish failure, instead of leaving it
stuck as unknown.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the in-place requeue of submit-uncertain unknown publish tasks
with an explicit supersede-and-create-new flow: manual retries mark the
old unknown task failed (manual_retry_superseded) and create a fresh task
carrying manual_retry / superseded_unknown_task_ids in its payload.
Also fold title-length validation into definitivePublishFailurePattern and
check the pattern before the publish_submit_uncertain guard so those
failures are released from the dedup set.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extract the definitive-failure regex into a named constant and add title
length/count validation patterns so submit-phase failures like
"标题长度应该在2-30字之间" stay non-retryable instead of being classified
as uncertain.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a sort_order column to brands with a migration, expose a
PUT /api/tenant/brands/order reorder endpoint, and wire the
admin-web BrandsView with drag-and-drop reordering plus i18n.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Publish records with statuses like queued, pending, running, cancelled,
or unknown fell through the display map and rendered as raw enum values.
- Add queued/pending/running/cancelled/canceled/unknown entries to the
publish status map with matching zh-CN and en-US translations
- Normalize status keys (trim + lowercase) before lookup so backend
casing variants still resolve
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Rotated refresh tokens now stay valid for a 60s grace window so
concurrent refreshes (e.g. multiple browser tabs) each obtain a valid
new pair instead of being logged out. Admin-web additionally serializes
refreshes across tabs via the Web Locks API and reuses tokens already
rotated by another tab.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>