Commit Graph
8730 Commits
Author SHA1 Message Date
GuoQing Zhang 85235780c7 Merge branch 'feat/2.6.0-beta4' of github.com:dataelement/bisheng into feat/2.6.0-beta4 2026-07-16 18:15:01 +08:00
GuoQing Zhang f6da266f4f fix(knowledge): widen file name length to 500 2026-07-16 18:11:05 +08:00
KinyooandClaude Opus 4.8 2449931971 build(client): add rspress docs site for the component library
npm run dev:docs / build:docs serve the design specs + live component demos (@rspress/plugin-preview) with the app's vite aliases and style.css mirrored into the rspack config; stubs/url-stub.ts shims Node's url module for the browser bundle. doc_build/ output gitignored.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 18:10:34 +08:00
KinyooandClaude Opus 4.8 391d6496d6 chore: gitignore the CoAligne sync config too
The tool overwrites .coaligneignore with its own default template, so tracking it means the rewrite lands in everyone's tree — keep it per-developer alongside .coaligne/.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:20:06 +08:00
KinyooandClaude Opus 4.8 f47dacfe61 chore: gitignore CoAligne local state
The .coaligne/ dir holds per-developer project bindings that the tool regenerates (it re-binds and rewrites them on its own), so it should never have been tracked — untrack the two committed state files and ignore the dir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:16:26 +08:00
KinyooandClaude Opus 4.8 bc71b7c522 chore(gallery): refresh section showcases for the re-derived green ramp
Update GalleryApp wiring and the Button/Color/ConfirmDialog/Feedback/Illustration/Modal/Responsive/Typography showcases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:04:11 +08:00
KinyooandClaude Opus 4.8 bd6b12fa5f fix(theme): re-derive the green brand ramp around the fixed #169C47 primary
The old .theme-green steps sat at hue ~157 (teal) while --brand-500 is 142, so the main color jumped out of its own ramp. Light steps keep the old saturation/brightness envelope with the hue rotated onto the 500 family (-2/step, mirroring the blue lights); dark steps mirror the blue ramp's dark-side HSV geometry. --brand-500/main unchanged; surface-active-alt re-synced to --brand-50. Values updated in BRAND-THEME-HANDOFF.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 15:04:11 +08:00
LineWalkerandClaude Opus 4.8 eff01fd31a feat(linsight): declare available libraries in code-interpreter description
The code-interpreter tool description said nothing about which Python packages
are available, so the model guessed — reaching for pdfminer.six to read PDFs (a
common default) which is NOT installed in the backend env, producing spurious
"No module named 'pdfminer'" output (it fell back to fitz, but the noise leaked
into the run).

Declare the actually-installed libraries (verified in the backend env: pandas,
numpy, matplotlib, openpyxl / XlsxWriter, python-docx, Pillow, reportlab, PyMuPDF)
and steer PDF reads to `fitz`, away from pdfminer / pdfplumber / PyPDF2. Also tell
the model not to `pip install` (shared, offline env). LocalExecutor only — e2b is
a different sandbox with a different image, not asserted here. Adds a
description-contract regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:58:09 +08:00
LineWalkerandClaude Opus 4.8 658813cdbe fix(linsight): stop partial-result salvage from leaking raw tool output
On an L3/L4 abort (tool-loop breaker / recursion ceiling), the partial-result
salvage falls back to `_last_assistant_text`, produced by
`_extract_last_message_text`. That helper returned `messages[-1]` WITHOUT
checking the role, so when a run was cut off mid tool-loop the trailing message
— typically a raw `bisheng_code_interpreter` ToolMessage such as
`{"exitcode":0,"log":"\nError: No module named 'pdfminer'\n=== PDF文本内容(fitz…"}`
— was surfaced verbatim after the apology preamble as "已完成的分析内容".

Walk backward to the last AIMessage carrying text instead; skip Tool/Human/
System messages. When the model never produced any text, return None so the
caller degrades to a friendly failure rather than dumping tool JSON. Split out
`_is_assistant_message` / `_message_text` helpers and cover with unit tests.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 17:33:28 +08:00
LineWalkerandClaude Opus 4.8 9376bee814 fix(linsight): resolve deliverable images & drop raw-HTML noise in md preview
The task-mode report md preview (PreviewBody → shared react-markdown) had two
independent rendering failures:

1. Relative image refs `![](charts/x.png)` never resolved — the renderer has no
   relative→absolute rewrite, so the browser resolved them against the SPA route
   and got the index.html fallback (200 text/html) → broken image. Fix: a custom
   async <img> renderer (MarkdownImage) resolves relative refs against the session
   file_list (matchArtifactByRelPath → file_url → resolveArtifactUrl presigned
   URL). Enabled only when a resolver is injected, so chat bubbles are unchanged.

2. Empty raw-HTML placeholder boxes (`<div style=...></div>` comment/figure
   scaffolding) leaked as literal text because rehype-raw is deliberately off
   (XSS guard). Fix: stripEmptyHtmlPlaceholders removes only *empty* paired block
   tags in the md preview (preview-only; stored .md is untouched so HTML/PDF
   derivation is unaffected).

Also nudge generation: the task-mode system prompt now tells the model to use
markdown image syntax and avoid raw HTML in the canonical md deliverable.

fileList is threaded through WorkspacePanel / FilePreviewPanel (via ExecutionFlow).
15 unit tests cover matching (path-suffix / basename / URL-encoded CN names) and
empty-box stripping. HTML (iframe srcDoc) preview has the same image gap — not
covered here.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 16:15:50 +08:00
KinyooandClaude Opus 4.8 19eb33d6ba chore(gallery): fold scrollbar into color section + refresh progress tracker
Remove the standalone ScrollbarSection (scrollbar guidance folded elsewhere), update GalleryApp wiring, and refresh Color/Button/ConfirmDialog/Modal/Overview/Responsive/Typography showcases + ColorProgress/ProgressOverview.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:31:18 +08:00
KinyooandClaude Opus 4.8 78abdc4307 style(client): normalize empty-state illustration usage across pages
Drop the now-redundant opacity-90 on EmptyStateIllustration (the grey/mid-tone was darkened at the source, so the dimming hack is no longer needed) and normalize sizing to size-[120px] mb-4 across channel/subscription/knowledge/apps empty states.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:31:18 +08:00
LineWalkerandClaude Opus 4.8 ac01a94d18 fix(linsight): keep code-interpreter deliverables inside the harvested output dir
Task-mode results claimed a deliverable (e.g. a generated PDF) that never
appeared in the workspace panel. Root cause: the model wrote the file to an
ABSOLUTE path (/output/report.pdf, /scratch/*.png) which resolves to the
container filesystem root -- outside the per-task working dir the LocalExecutor
harvests. The file was never uploaded (file_list=[]) nor synced, so
get_final_result_file found no deliverable and the panel fell back to a
synthesized fallback report. The shared LocalExecutor cannot safely rescue
container-root files (cross-task leak), so the fix steers the model to relative
paths:

- Harden the code-interpreter tool description (local + e2b) to require the
  RELATIVE output/ (scratch/) dir and forbid absolute /output|/scratch, noting
  files outside the working dir are discarded.
- Add a deterministic, non-blocking corrective notice: when a run's code wrote
  to an absolute /output|/scratch path, append a system notice to the tool
  result so the model self-corrects on the next step
  (BaseExecutor.absolute_path_advisory + wiring in LocalExecutor.run).
- Tests: test/linsight/test_code_interpreter_output_path.py (18 cases).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 14:51:43 +08:00
KinyooandClaude Opus 4.8 64c6568954 chore(gallery): wire up color/scrollbar/illustration sections + progress tracker
DEV-only gallery: register the new Color/Scrollbar/Illustration sections in GalleryApp, add a progress/ tracker (per-component migration status), and refresh the Button/ConfirmDialog/Modal/Overview/Responsive/Typography showcases.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:58 +08:00
KinyooandClaude Opus 4.8 c7dc47ee5d fix(client): darken grey-mode illustration mid-tone so halos don't wash out on white
illus-grey --illus-300 #FFFFFF→#E5E5E5 (grey mode only; green/blue keep the mid tone) — pure white made e.g. the CrawlingIllustration magnifier halo disappear on white backgrounds. New gallery IllustrationSection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:58 +08:00
KinyooandClaude Opus 4.8 2fb731ecbd refactor(client): scrollbars follow the OS setting (drop global forced-slim bar)
Per 基础-滚动条规范.md: remove the global :not(.scrollbar-os) forced-slim ::-webkit-scrollbar rule plus the .excel-scroll / .scrollbar-transparent overrides so OS auto-hide/always-on is respected; drop the now-dead excel-scroll class from ExcelPreview. New gallery ScrollbarSection. The .scrollbar-os opt-out is now a no-op, cleaned up as files get touched.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:58 +08:00
KinyooandClaude Opus 4.8 911f384346 feat(client): add Arco semantic color tokens (text/fill/border/functional)
Two-layer color tokens per 基础-色彩规范.md: primitive --arco-gray-1..10 + semantic --text-1..4 / --fill-1..4 / --border-base|-deep / --success|warning|danger(+hover/active/tint) in style.css, wired to Tailwind (text-1.. / fill-1.. / border-base / bg-success ...). Functional colors are theme-independent. New gallery ColorSection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:42:58 +08:00
LineWalkerandClaude Opus 4.8 97d43716a2 fix(linsight): thread task-mode skill selection to the submit
Follow-up to the None≡[] skill gate: with skills now strictly opt-in, the
daily task-mode path (ChatView → useAiChat → unified /chat/completions →
_to_linsight_submit) exposed a latent gap — it never carried the picked
skills, so the stored SV had skills=None and NOTHING was materialized. The
picker looked broken ("workspace has no such skill file"). Previously this
was masked because None loaded every enabled skill.

Thread the selection end-to-end:
- APIChatCompletion gains `skills` (Track H); _to_linsight_submit maps it
  onto the linsight submit schema (None/[] = no skills, opt-in list = those).
- useAiChat sends the picked skill names (taskModeSkillsState('new')) on
  task-mode turns only; the daily chain ignores the field.
- tests: _to_linsight_submit forwards a selection / stays None when absent.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:48:00 +08:00
LineWalkerandClaude Opus 4.8 58325411d1 fix(linsight): recover ask_user questions crammed into a dict's question value
Live case (session b28d0dc6, model deepseek-v4-flash, input "skill test"):
the task-mode ask_user clarify card rendered a raw-JSON blob as its single
question title with zero options. Root cause is model-side — deepseek-v4-flash
did NOT escape the inner quotes in a question text (你想要的"skill test"是指什么?),
so its OpenAI-compatible function-call serializer corrupted the whole `questions`
array. The arg parser then produced a WELL-FORMED outer list/dict but crammed the
entire 3-question array into the FIRST dict's `question` VALUE (dropping the
opening `[{"question"` while keeping the `: "` separator). The trigger is
intermittent: it only fires when a question's text itself contains quotes (here
echoed from the literal user input) — which is why prior DeepSeek clarifications
without quotes rendered fine.

The existing recovery (854d45974) only re-parsed malformed STRING list-elements,
so this dict-value shape fell through unchanged. Extend the recovery to:
- re-expand a dict whose `question` value is itself a serialized questions array
  (gated by a quoted-JSON-key signature so ordinary prose is never mangled);
- reconstruct a blob that RETAINED the `: "` separator via `[{"question"` so the
  first question comes back clean (no leading `: "` noise);
- run the same crammed-array recovery on a malformed TOP-LEVEL string (still
  degrades to [] for arbitrary prose — reason-only park).

Frontend needs no change (one clarify tool_call per recovered question already
renders the multi-page card). 22 unit tests green, incl. the exact live blob as
a fixture and regression guards for prose/placeholder questions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 11:35:21 +08:00
KinyooandClaude Opus 4.8 6bfedd60f4 fix(client): register semantic font-size tokens in tailwind-merge (cn)
extendTailwindMerge teaches cn() the custom text-caption/body/h1... tokens as a font-size group (v1.x config shape) so a size + a color in the same cn() call no longer drop the size; gallery Modal/ConfirmDialog sections + kit updates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:36:45 +08:00
LineWalkerandClaude Opus 4.8 9faf41afd5 fix(linsight): treat absent skills selection as none, not all
Task mode was running skills the user never picked. Root cause: the submit
persisted `skills=NULL` (the field was absent — a stale/cached client or a
non-UI caller), and `materialize_session_skills` treated `None` as
"copy every governance-enabled skill" — the exact opposite of an empty
selection. Every enabled skill was then materialized into the workspace
`/skills/` subtree, advertised to the model, and executed, silently
defeating the picker.

- skill_provisioning: `None ≡ [] ≡ "no skills this run"` (guard on `not
  selected`); skills are strictly opt-in via an explicit non-empty list,
  still intersected with the tenant's governance-enabled set.
- useSubmitMessage (client): the daily-chat task-mode entry now sends an
  explicit `skills: []` instead of omitting the field, so the contract no
  longer depends on the downstream `|| []` guard.
- test + docstrings updated; `test_none_selection_copies_nothing` is a
  regression guard against the footgun.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-15 10:33:17 +08:00
KinyooandClaude Opus 4.8 bd874d4aff feat(client): gate Button press feedback to touch + gallery responsive section
Button active states now use coarse-pointer:active (hover-capable devices keep the hover color on press, no click flash); theme-green btn-brand-primary :active wrapped in a touch-only media query to match; new gallery ResponsiveSection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 18:09:20 +08:00
KinyooandClaude Opus 4.8 7a7eba5cd3 fix(theme): brighten the green brand color to #169C47
Bump the green theme's --brand-500/main, --illus-500 (+ lighter 100/300), --primary and the btn-brand-primary green ramp from the darker #187C54/#19B476 to #169C47; TaskModeToggle active state uses the brand blue-500 token. Update the values in BRAND-THEME-HANDOFF.md.

(cherry picked from commit 1d2757797 on hotfix/2.6.0-beta4-cofco; style.css hunk re-placed into beta4's .theme-green block since beta4 defaults to the blue theme.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 17:08:33 +08:00
Kinyoo 142a128c4c fix(client): align folder icon & knowledge-space illustration with green illus palette
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit cbe08a8de4)
2026-07-14 17:07:31 +08:00
Kinyoo 347ca4effc fix(client): drop redundant mobile negative-margin/padding on input toolbar
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 790a14da64)
2026-07-14 17:07:15 +08:00
KinyooandClaude Opus 4.8 9a9e9331e7 feat(client): dual-axis Button design-system component + btn-* tokens
New color×variant×size Button API (solid/outlined/filled/text/link) with legacy shadcn variants auto-mapped; btn-* semantic tokens + touch hit-area in style.css/tailwind; app-wide hoverOnlyWhenSupported; gallery ButtonSection; migrate KnowledgeSpaceSidebar create button to the new API.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 16:58:32 +08:00
KinyooandClaude Opus 4.8 324f299ffd feat(client): add semantic typography scale + gallery typography section
Two-layer type tokens (primitive --font-size-N + semantic --text-*) in style.css with a mobile remap, wired to Tailwind fontSize; system font stack; new gallery TypographySection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 15:05:28 +08:00
LineWalkerandClaude Opus 4.8 715ebaf991 fix(channel): sync information articles under per-tenant context
sync_information_article iterated channel_info_source (a tenant-aware table)
with no tenant context set, so on a multi-tenant deploy the first SELECT raised
NoTenantContextError and the daily article sync never ran — subscribed sources'
content never updated.

Mirror reconcile_all_tenants: enumerate active tenants (root + active children,
or the default tenant when multi-tenancy is off) and run the sync under each
tenant's context, isolating per-tenant failures. Add a sync counterpart
TenantDao.get_children_ids_active for the sync worker path, and fix a latent
missing `import asyncio` in the knowledge-space dispatch hook.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-11 21:41:36 +08:00
LineWalkerandClaude Opus 4.8 c42a3edc08 fix(workbench): drop unused char-whitelist pattern on app-center text
Follow-up to 1208fa158: instead of only relaxing the pattern to allow the
empty string, remove it entirely to align with feat/2.6.0 (72fd1e8f0
"fix: unused pattern"). The whitelist could not stop XSS (it allowed <>/"'&)
yet rejected the empty default plus emoji / non-CJK text; real escaping is
done by the frontend (React text nodes, no dangerouslySetInnerHTML). Keeping
all three branches identical avoids a future merge conflict on these lines.

Update regression tests accordingly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:31:51 +08:00
LineWalkerandClaude Opus 4.8 1208fa1580 fix(workbench): accept empty application-center text in WorkstationConfig
applicationCenterWelcomeMessage / applicationCenterDescription were declared
with default="" but a pattern requiring >=1 char (^[...]+$). Any tenant whose
stored workstation config left these fields empty or unset (the default) made
WorkstationConfig(**raw) raise a pydantic ValidationError, so GET
/api/v1/workstation/config returned 500 and the client rendered its full-screen
"system maintenance" overlay — /workspace/c/new appeared broken.

Relax both patterns from + to * so the empty string is accepted while keeping
the character whitelist for non-empty input. Add regression tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 18:02:36 +08:00
dolphin 32ee955eac fix(feedback): keep task-mode like highlight across conversation switch
The task result panel reads its liked verdict from the linsight store, which is
seeded once on hydration. An optimistic like updated only the button's local
state + backend, not the store — so switching away and back re-mounted the panel
with the stale store value and the highlight vanished (a full page reload fixed
it, since that re-hydrates the store from the server).

Sync the verdict back to the store on click via a new onLikedChange callback
(TaskTurnPanel + ExecutionFlow pass updateLinsight), so the store stays current
and the highlight survives switch-away/switch-back.
2026-07-11 11:13:02 +08:00
dolphin ae636b7a36 fix(feedback): task-mode like targets the real answer id, not the placeholder
In task mode the result panel's like/dislike showed as soon as the run hit
'completed', but the task turn still carried its streaming placeholder id
(userMessageId + '_') — the real persisted category="task" ChatMessage id only
arrived on a page reload. A like clicked the moment the panel appeared wrote to
a non-existent row and silently vanished (occasional, timing-dependent).

Source the feedback id from the linsight store instead of the conversation
message, and populate the store's real message_id at completion by reusing the
existing session-version-list enrichment (no new endpoint/field):
- Websocket final_result: fetch the version list, copy this version's real
  message_id + liked into the store
- TaskTurnPanel: ResultPanel reads linsight.message_id (history hydration
  already seeds it via the same endpoint); add allowFeedback prop for the
  share-view opt-out
- AiMessageBubble: pass allowFeedback instead of encoding it via messageId

The button now appears only once the real id is in the store, so show-time and
id-availability are aligned and the placeholder can never reach /liked.
2026-07-11 10:44:58 +08:00
LineWalkerandClaude Opus 4.8 ed0d4a0fca fix(llm): preserve workbench models when a partial POST omits them
update_workbench_llm persisted the incoming WorkbenchModelConfig wholesale, so a
body without `models` (Pydantic defaults it to None) nulled the entire configured
dialogue-model list — the way a stale admin page wiped the Root config in prod.
Treat a missing/None `models` as "no change" and keep the stored list; an explicit
`models: []` still clears. asr/tts/chat_title keep their None-clears semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:48:37 +08:00
LineWalkerandClaude Opus 4.8 13f1a28c27 fix(model): guard empty-id workbench models from crashing the picker
A blank dialogue-model row ({id:''}) saved from the workbench model config
flows into the workspace model pickers as <SelectItem value="">, which Radix
forbids — it throws and crashes the whole /workspace/c/new page.

- client: drop empty/invalid-id options in AiModelSelect and the Linsight
  ModelSelector so a stale/blank model never renders an empty-string
  SelectItem value (defense that doesn't rely on backend sanitizing).
- platform: reject saving a blank model row in WorkbenchModel — validation
  only checked models.length, letting {id:''} through and overwriting the
  configured dialogue models with an empty row.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 20:26:49 +08:00
dolphin 3cbd4461d4 fix(channel): carry the real answer message_id on the stream end event
Channel article chat yielded the 'end' event BEFORE persisting the answer
ChatMessage, so the client never got the real id — the streamed answer kept its
temporary placeholder id and a like clicked before switching away wrote to a
non-existent row and vanished (same class of bug as the knowledge-space fix).

Persist the answer first, then emit the end event with its message_id so the
client can swap the placeholder out immediately (frontend useChannelChat already
consumes it).
2026-07-10 19:07:03 +08:00
dolphin 8964cbd134 fix(llm): TTS synthesis failure returns a business error, not HTTP 500
A TTS provider failure (e.g. empty audio) raised a bare exception that
propagated as HTTP 500, which the client's global interceptor treats as a
service outage and redirects to the maintenance overlay — a poor experience
for what is just 'this one utterance failed to synthesize'.

- backend: wrap the synthesis call, raise a dedicated TtsSynthesisFailedError
  (code 10026) instead of letting it bubble up as 500
- frontend: textToSpeech opts into the interceptor's translate-and-toast path
  (skip403Redirect) instead of the 500 escape hatch; TextToSpeechButton no
  longer masks the real error or double-toasts once the interceptor already
  showed the localized message
- add api_errors.10026 to zh-Hans/en/ja
2026-07-10 18:42:30 +08:00
dolphin e3d2ed803d fix(feedback): swap streamed-answer placeholder id for the real one on stream end
Knowledge-space chat (single-file / folder) rendered the streaming answer under
a temporary client-side placeholder id (userMessageId + '_') and never swapped
it for the real persisted ChatMessage id, so a like clicked before the first
page reload wrote to a row that never existed — it silently vanished. Reload
loaded the real id from history and worked fine, masking the bug as 'only
fails right after sending, fixed by refresh'.

- backend: the 'end' stream event now carries the persisted answer message_id
- frontend: useStreamChatSSE forwards it through onFinal; useFolderChat /
  useFileChat / useChannelChat swap their placeholder messageId for it so
  like/dislike (and any other per-message action) targets the right row
  immediately, not just after a reload
2026-07-10 18:42:30 +08:00
KinyooandClaude Opus 4.8 71d7a3cbe2 style(client): tighten top padding to pt-4 across chat nav + knowledge headers
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:11:25 +08:00
KinyooandClaude Opus 4.8 67c92b1b5a refactor(client): unified CommentDialog for feedback + menu-apply reason (UI unification infra)
Add a shared CommentDialog (optional-comment / reason dialog) + gallery FeedbackSection; migrate the message 点赞/点踩 feedback (dropping the bespoke MessageFeedbackForm) and the menu-unavailable apply-reason dialog onto it; feedback comment is now optional (com_feedback_placeholder, en/zh/ja).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:11:25 +08:00
dolphin ec99d17d43 feat(feedback): unify task-mode 点赞/点踩 on the task-result ChatMessage
The linsight task result is already persisted as a category="task" ChatMessage
in the unified daily conversation, so rate it through the shared chatmessage
feedback (/liked + /chat/comment) instead of a linsight_session_version-specific
column/endpoint. All four AI Q&A surfaces now share one storage + rollup path.

Backend:
- chat_helpers: agent history formatter returns liked + remark (fixes daily +
  in-conversation task-turn highlight on reload)
- workstation_schema: WorkstationMessage carries liked + remark (channel surface)
- linsight utils: get_task_feedback_by_version maps session_version -> its task
  ChatMessage {message_id, liked}
- linsight endpoint: session-version-list enriches each version with message_id +
  liked for the standalone linsight page

Frontend:
- ResultPanel: rate by messageId via likeChatApi / disLikeCommentApi
- TaskTurnPanel forwards messageId + liked; AiMessageBubble passes the task row's
  message.messageId (hidden on the read-only share view); ExecutionFlow reads them
  from the enriched session-version store field
- drop the now-unused likeLinsightVersion / commentLinsightVersion
2026-07-10 01:31:08 +08:00
LineWalkerandClaude Opus 4.8 18adc59068 docs(feedback): remove message 点赞/点踩 feedback PRD
The PRD doc is no longer needed; the 点赞/点踩 feature itself (98b48c93a) is
unaffected — only its now-redundant design doc is removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-09 23:35:26 +08:00
GuoQing Zhang 871e830ca5 Merge branch 'feat/2.6.0-beta4' of github.com:dataelement/bisheng into feat/2.6.0-beta4 2026-07-09 20:57:36 +08:00
GuoQing Zhang 5c2802e9a4 fix: tool sse event twice 2026-07-09 20:57:27 +08:00
Sarah b35f390dd2 fix(llm): sanitize stale workbench model refs 2026-07-09 18:08:39 +08:00
KinyooandClaude Opus 4.8 05260ec837 style(knowledge): edit-tags modal spacing, focus ring, neutral placeholder colors
Tighten padding (px-6 -> px-5), add a focus ring (border + 2px shadow) on the tag input, disable autocomplete, and normalize placeholder / no-tags text to #999.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 17:47:26 +08:00
KinyooandClaude Opus 4.8 9e3f7518ae style(knowledge): edit-tags modal goes full-screen on mobile via max-md breakpoints
Swap the touch-mobile: variant for max-md: so the edit-tags dialog uses the standard breakpoint-based mobile full-screen sheet (rounded corners only from md up).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:30:38 +08:00
KinyooandClaude Opus 4.8 1166f52aa1 refactor(client): migrate SharedLinks + guest-convo delete to the unified ConfirmDialog (UI unification infra)
Replace OGDialog/OGDialogTemplate delete confirmations in SharedLinks and the standalone guest-convo item with useConfirm; touch up the ConfirmDialog + Modal gallery sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:30:38 +08:00
dolphin 0836db4b6f fix(knowledge): sidebar tree — select never reloads, expand only via chevron
- Root-list loading no longer depends on currentFolderId, so selecting a
  folder (click or route change) never rebuilds this or any other space's
  tree; switching the active space leaves background trees untouched.
- Clicking a folder row (or a space row) only selects/navigates; expanding
  and collapsing is exclusively the chevron's job.
- Deep links (direct URL into a nested folder) still auto-expand the
  ancestor chain, fetching only levels not already cached, gated on the
  root list being genuinely loaded (fixes the reload race that left the
  tree half-expanded).
2026-07-09 11:14:09 +08:00
LineWalkerandClaude Opus 4.8 98b48c93a7 feat(client): add 点赞/点踩 feedback to the four AI Q&A surfaces
Share a MessageFeedbackButtons control (thumbs + dislike-comment modal) across
two insertion points:
- AiMessageBubble action row -> workstation daily, knowledge-space 知源,
  channel subscription (reuse existing /api/v1/liked + /chat/comment,
  message_session rollup already maintained backend-side).
- Linsight ResultPanel -> task mode (inline + full-page /linsight), via new
  likeLinsightVersion / commentLinsightVersion (backend endpoint + liked
  column pending per PRD; optimistic UI for now).

Seed the highlight from chatmessage.liked on history reload (ChatMessage.liked
+ both mappers). Hidden on the read-only share view (allowFeedback=!shareToken).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:59:08 +08:00
LineWalkerandClaude Opus 4.8 532597a226 docs(feedback): add message 点赞/点踩 feedback PRD
Product PRD (pyramid structure) for adding thumbs up/down feedback to the
four AI Q&A surfaces (workstation daily, linsight task mode, knowledge-space
知源, channel subscription). Feedback persists on the answer row and rolls up
into message_session for single-table, per-surface analytics.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-08 23:59:08 +08:00