Commit graph

848 commits

Author SHA1 Message Date
Roland Tannous
66a9ee258d Merge remote-tracking branch 'origin/main' into feature/rag
# Conflicts:
#	studio/backend/core/inference/tools.py
#	studio/frontend/src/components/assistant-ui/sources.tsx
#	studio/frontend/src/components/assistant-ui/thread.tsx
#	studio/frontend/src/features/chat/api/chat-adapter.ts
#	studio/frontend/src/features/chat/chat-settings-sheet.tsx
#	studio/frontend/src/features/chat/shared-composer.tsx
#	studio/frontend/src/features/chat/stores/chat-runtime-store.ts
2026-06-02 07:27:59 +04:00
Wasim Yousef Said
aee0657640
fix(chat): refine artifact panel styling (#5922)
Co-authored-by: Lee Jackson <130007945+Imagineer99@users.noreply.github.com>
2026-06-01 22:52:53 +01:00
Lee Jackson
e0ff6a1404
Studio: manage chat history with projects (#5725)
* feat: align project sidebar UX with ChatGPT

* feat: align project sidebar UX with ChatGPT

* feat(chat): load stored project list

* feat(chat): add project sidebar workflows

* fix: stabilize project page navigation

* fix: projects chat loading

* fix: show project chat thread

* style: sidebar project spacing and hover clipping

* style: add expandable project chat history and move-to-project submenu

* feat: polish project sidebar

* feat: persist project sandbox paths

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: only create sandbox project workspace dir

* feat: add optional project workspace deletion from delete dialog

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix: stabilize chat projects CI failures

* fix: polish project chat navigation

* Studio: manage chat history with projects

Group chats into projects with a dedicated projects page and route.
Sidebar shows recents with per-row actions and a vertical more-vertical
menu, and the sidebar scrollbar stays hidden so rows never shift on
hover. Includes chat settings and composer refinements.

* Studio: projects sidebar and breadcrumb polish

Sidebar:
- Remove the Compare nav item.
- Widen the sidebar to match the projects layout.
- Replace the scroll-gated bottom fade with a static fade pinned above
  the profile box, so it no longer attaches to Recents or lags the
  collapse and expand animation.

Topbar breadcrumb (chat-page):
- On a project landing show "Projects" linking to the projects list.
- Inside a project chat show the project name and chat title, with the
  project name linking back to that specific project page.
- Drop the divider between the model selector and the breadcrumb.

* Studio: make project workspace delete test cross-platform

test_chat_project_delete_files_removes_workspace rooted the project under
pytest tmp_path, which resolves to /private/tmp on macOS. The workspace
delete guard refuses paths under the system denylist by design, so the
test passed on Linux CI but failed on macOS.

Add a workspace_projects_home fixture that keeps tmp_path on Linux and
Windows (CI unchanged) and falls back to a home subdir only when the temp
root is on the platform denylist. Derive the workspace path from the
created project so it tracks the projects home.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: satisfy import-hoist check for new path re-exports

documents_root and project_workspaces_root are re-exported from
utils.paths but only referenced as __all__ string literals, which the
import-hoist safety net does not count as a use. It flagged the two newly
added re-exports as unused imports and failed Source lint.

Name-load both via a module-level _REEXPORTED tuple so the check sees
them used. No behaviour change; consumers still import them from
utils.paths.

* fix: avoid projects empty-state flash

* fix: batch chat search indexing

* Studio: polish chat sidebar, run settings, and search

- Use the native OS scrollbar for the chat sidebar, Run settings panel, and chat search list instead of a custom scrollbar
- Highlight the active run in the sidebar and keep chat search available during training
- Stop the training log view from replaying when navigating back to a run
- Rename the chat settings panel to Run settings and align its toggle icon and position
- Tighten heading and sidebar letter spacing and lighten the Train and Recents labels
- Match the search dialog corner style across light and dark and drop the stray border
- Make the MCP Servers section header plain text instead of a link
- Remove a stray .orig backup file

* studio/frontend: restore Compare entry point in the sidebar

The chat-projects sidebar redesign dropped the Compare nav item and moved
it to thread-sidebar.tsx, which is not imported or rendered anywhere. That
left no way for a user to start a new model comparison (enterCompare only
fired from the guided tour and the training handoff), and broke the
Compare/Recipes/Export UI smoke test that clicks [data-tour="chat-compare"].

Re-add the Compare NavItem to the New Chat / Search group, carrying
data-tour="chat-compare" and the same new-comparison navigation as before.

* studio/frontend: use Unsloth green for the fallback profile avatar

Switch the initials-avatar background from blue to #14b789 so the sidebar
and edit-profile avatar match the Unsloth brand colour.

* studio/frontend: turn project breadcrumb into a project switcher dropdown

* studio/frontend: stop project card kebab clicks from opening the project

* studio/frontend: hide project switcher outside projects

* studio/frontend: stabilize project switcher loading

* style: project switcher alignment

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: shimmyshimmer <107991372+shimmyshimmer@users.noreply.github.com>
Co-authored-by: Unsloth <michaelhan@Michaels-MacBook-Pro.local>
Co-authored-by: Roland Tannous <rolandtannous@gravityq.ai>
Co-authored-by: Roland Tannous <115670425+rolandtannous@users.noreply.github.com>
2026-06-01 22:09:16 +04:00
Lee Jackson
21865773a6
Studio: support connected models in compare mode (#5824)
* fix: support connected models in compare mode

* fix: support connected models in compare mode

* studio/frontend: wait for compare prompt append

---------

Co-authored-by: Roland Tannous <115670425+rolandtannous@users.noreply.github.com>
2026-06-01 20:49:27 +04:00
Daniel Han
a0b85bcc1d
Studio: move MCP to a composer button with presets (#5926)
Move MCP from the chat settings sidebar to a composer pill next to Artifacts. The dropdown lists keyless presets (Context7, Exa, Hugging Face), all off by default, created on first enable and deduped by URL. Add custom MCP opens the existing manage dialog. Enabled rows show a green underlay and a tick that becomes an X on hover to remove; enabling Exa turns off the built-in Web Search and shows a hover tooltip. Reconciles the per-chat MCP flag on load so already-enabled servers activate the pill. No backend changes.
2026-06-01 08:18:12 -07:00
Wasim Yousef Said
a895d1cab6
Use natural generated image frame (#5794)
* Use natural generated image frame

* Refine generated image caption clamp

* Fix generated image caption width

* Fix generated image natural frame sizing
2026-06-01 01:06:47 -07:00
Wasim Yousef Said
dfba4cc5ca
Studio: add HTML artifacts to chat (#5772)
* Studio: add chat HTML artifact primitives

* Studio: add local render_html tool support

* Studio: wire render_html artifacts in chat UI

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: add chat artifact surface

* Studio: mount chat artifact panel and overlay

* Studio: fix chat artifact review regressions

* Studio: fix chat artifact panel and sandbox previews

* Studio: address chat artifact review follow-ups

* Studio: polish chat artifact UI affordances

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Studio: scope artifact IDs by message to prevent cross-turn collisions

* Studio: fix artifact panel for local threads and surface tool errors

* Studio: restrict artifact frame embedding to same-origin

* Studio: stop local chat thread remount loop

* Studio: fix chat artifact store cleanup regressions

* Studio: shim artifact preview storage in sandbox

* feat(chat): add artifact rendering controls

* fix(chat): show artifact progress during tool calls

* fix(chat): refine artifact preview behavior

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* fix(chat): ignore tool markers inside arguments

* feat(chat): polish artifact preview panel

* fix(chat): stabilize artifact panel behavior

* fix(inference): merge duplicate Anthropic tool starts

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
2026-06-01 08:35:18 +02:00
Michael Han
e3b52eb98a
Use remove-circle icon for eject model button (#5906)
Co-authored-by: Unsloth <michaelhan@Michaels-MacBook-Pro.local>
2026-05-31 21:15:34 -07:00
Daniel Han
b66d35b425
Studio: stop hidden source badges from inflating chat scroll height (#5822)
The SourcesGroup measurement container renders every citation badge
off-screen with `invisible absolute` so we can measure how many fit in
two rows. Absolute descendants still contribute to the parent's
scrollable overflow region, so long source lists added hundreds of
pixels of phantom scroll space below the assistant message that the
user could scroll into.

Wrap the measurement container in an absolute, `h-0`, `overflow-hidden`
box so the off-screen pills are clipped out of the scrollable overflow
region. Measurement still works because offsetTop is read relative to
the positioned wrapper.
2026-05-31 05:55:00 -07:00
Daniel Han
ab0828b976 Studio: fix RAG correctness bugs
Backend:
- Deterministic SQLite connection cleanup. The RAG code used bare
  `with get_connection() as conn:`, which commits but never closes, leaning
  on GC to release handles (the rest of studio_db closes explicitly). Add a
  closing_connection() context manager that commits/rolls back like sqlite3's
  own manager and always closes, and route all 30 RAG call sites through it.
- filter_by_min_score no longer drops BM25-only and figure-ref hits. min_score
  is a cosine floor, so it now gates only hits that carry a dense_score;
  lexical and figure-ref hits (dense_score is None) pass through instead of
  being silently discarded when the floor is raised.
- Fix two tests that could not pass against the production code: the RRF
  fusion test asserted the wrong winner (c edges out b: 0.032266 vs 0.032258),
  and two tool-handler scope tests stubbed retrieve_hybrid without accepting
  the embedder_model kwarg the handler now passes (TypeError was swallowed,
  leaving captured["scope"] unset).

Frontend:
- Removing an in-flight upload chip now routes through the teardown thunk
  already registered for the aggregate-progress toast (abort, unsubscribe,
  release the index slot, delete the backend doc with the correct kb/thread
  scope key it closed over) and clears the toast entry. Deleting directly
  leaked the concurrency slot and hardcoded the thread scope, mis-targeting
  KB-scoped docs. Applied in both the composer hook and the compare-view
  composer; drop the now-vestigial chip-scope-key tracking and unused
  activeThreadId selectors. Add index-progress-store.remove(id).
2026-05-31 09:56:23 +00:00
Daniel Han
f3bbd53afa Studio: remove dead RAG code (AST-confirmed)
Remove code with no live references, each confirmed dead via AST reference
analysis (no production callers and no importers), not just text search:

- chunk_belongs_to_document plus its dedicated tests and the now-orphaned
  _insert_chunk test helper. The preview-target route already does a
  single-query membership check and deliberately never called this helper.
- ingestion-progress.tsx and use-ingestion-events.ts (its only importer).
  Superseded by the aggregate ingestion toast stack; zero importers.
- Unreferenced tests/fixtures/rag-preview sample files and their generator.

No behavior change. The only non-deletion edits reword two comments that
referenced the removed helper.
2026-05-31 09:35:39 +00:00
oobabooga
76574fb8da
studio/frontend: fix MCP dialog overflow on long URLs (#5864) 2026-05-31 01:55:09 -07:00
oobabooga
ff00fdd155
Studio: add stdio MCP server support (#5863)
* Studio: add stdio MCP server support

* Fix stdio command validation and Windows quoting
2026-05-31 01:54:46 -07:00
Daniel Han
d1348cac3f Studio: tighten RAG code comments
Shorten and condense comments across the RAG backend, frontend, and
tests for readability. Comment text only; no code, strings, identifiers,
or logic changed. License headers and lint/type pragmas are preserved.
2026-05-31 08:31:08 +00:00
Daniel Han
2af60c5480 Merge remote-tracking branch 'origin/main' into feature/rag
# Conflicts:
#	studio/install_python_stack.py
2026-05-31 08:15:56 +00:00
Michael Han
1016fff1d6
Update Studio sidebar logout icon to logout-05 (#5878)
Co-authored-by: Unsloth <michaelhan@Michaels-MacBook-Pro.local>
2026-05-31 00:53:40 -07:00
Roland Tannous
ff0472cfc1 Studio: hide RAG pill and Retrieval section for external providers 2026-05-30 14:34:41 +04:00
Roland Tannous
8fd0bd76f9 Revert "Studio: RAG for external model providers via prefetch"
This reverts commit b836c3c76b.
2026-05-30 14:27:05 +04:00
Roland Tannous
0e828e2c7d Revert "Studio: suppress RAG sources for uncited external prefetch"
This reverts commit 05944a1e9b.
2026-05-30 14:25:08 +04:00
Roland Tannous
538b69cf00 Revert "RAG: silence external prefetch model when chunks off-topic"
This reverts commit 1eab078311.
2026-05-30 14:25:02 +04:00
Roland Tannous
1eab078311 RAG: silence external prefetch model when chunks off-topic 2026-05-30 13:45:19 +04:00
Roland Tannous
d676cb8600 RAG: tighten local tool-loop nudge to prevent self-asked follow-ups 2026-05-30 13:12:15 +04:00
Roland Tannous
1923cb4eca
Merge branch 'main' into feature/rag 2026-05-29 21:56:55 +04:00
Roland Tannous
bab409ef84 Studio: fix KB files view widening dialog (WebKit overflow-x), use grid doc rows 2026-05-29 20:37:40 +04:00
Roland Tannous
8cc0b80704 Studio: clip KB detail slot so files view can't widen the dialog 2026-05-29 20:13:51 +04:00
Roland Tannous
978028bf82 Studio: fix KB files view overflow by using native scroll for the document list 2026-05-29 20:03:49 +04:00
Roland Tannous
1a7c1cccba Studio: stop KB preview from overflowing the settings dialog; inset counts, add header spacing 2026-05-29 19:55:53 +04:00
Roland Tannous
aa68568ff5 Studio: remove KB embedding override; prevent KB tab horizontal overflow 2026-05-29 19:39:37 +04:00
Roland Tannous
187a5853ba Studio: KB panel — embedder on its own line, uniform full-width doc pills 2026-05-29 19:20:46 +04:00
Roland Tannous
80e7ad4daf Studio: redesign KB management — per-base upload/files panels, doc pills, shared upload toast 2026-05-29 19:02:14 +04:00
Roland Tannous
6388f3f349 Studio: full-width KB list when no base is selected 2026-05-29 18:33:09 +04:00
Roland Tannous
71b5214ca7 Studio: restructure Knowledge bases tab layout; hint under header, compact when empty 2026-05-29 18:24:16 +04:00
Roland Tannous
b17b3ad727 Studio: fix overlapping sections in Knowledge bases settings tab 2026-05-29 16:25:18 +04:00
Roland Tannous
1844ec0776 Studio: clarify caption toggle text searchability 2026-05-29 16:11:17 +04:00
Roland Tannous
fc7fa0b5a7 Studio: tweak caption toggle helper text 2026-05-29 15:58:41 +04:00
Roland Tannous
1a31aa5b27 Studio: keep local RAG answers grounded; cap tools and steer off web when RAG is on 2026-05-29 15:42:32 +04:00
Roland Tannous
7335dc07a9 Studio: make figure captioning optional with a Retrieval toggle 2026-05-29 15:05:29 +04:00
Roland Tannous
c149cf58d1 Studio: place Cancel left of dismiss X, vertically centered 2026-05-29 14:11:29 +04:00
Roland Tannous
1112fc891b Studio: center Cancel in indexing toast, start file counter at 1 2026-05-29 13:18:11 +04:00
Roland Tannous
4635b0bc36 Studio: add dismiss X alongside Cancel on the indexing toast 2026-05-29 13:04:00 +04:00
Roland Tannous
db5a9880b0
Studio: keep web search/code pills off on model load if user disabled them (#5851)
* Studio: keep web search/code pills off on model load if user disabled them

* Studio: avoid redundant localStorage reads when resolving tool pills on load
2026-05-29 12:46:16 +04:00
Roland Tannous
2b0c6cf220 Studio: fix scopeKey type in RAG upload cancel wiring 2026-05-29 12:42:21 +04:00
Roland Tannous
68646a7abf Studio: cancel RAG indexing from the toast and reset the batch 2026-05-29 11:02:54 +04:00
Roland Tannous
05944a1e9b Studio: suppress RAG sources for uncited external prefetch 2026-05-28 21:06:55 +04:00
Roland Tannous
cbe4b0866a Studio: show total chunks in the aggregate indexing toast
The completion toast reported only document count. Capture each job's
num_chunks from its complete event into the index-progress store and sum
across the batch, so the toast reads 'N documents and M chunks indexed'.
Already-indexed (deduped) files contribute 0 new chunks.
2026-05-28 20:24:15 +04:00
Roland Tannous
8c6acdc6a3 Studio: aggregate RAG indexing into one toast for multi-doc uploads
Uploading several documents (or a folder) produced a separate toast per
file, which piled up. Replace the per-job toast stack with a single
aggregate toast driven by a new index-progress-store that's populated at
addDoc time — so it counts queued files (held by the concurrency
semaphore) in the denominator, which the per-job rag-store map can't see.

- index-progress-store: one entry per file in the batch
  (queued/indexing/ready/error + 0..1 progress).
- Both addDoc paths register each file on entry and update it through
  the lifecycle (setIndexing after acquiring a slot; setProgress on job
  progress events; setReady/setError on terminal).
- ingestion-toast-stack: renders ONE toast — 'Indexing document(s) · X/Y
  · Z%' with a progress bar while in flight (overall = completed files +
  in-flight fractions, over total), 'RAG index ready · N documents
  indexed' (+ failures) when the last finishes, then auto-dismisses.
  Single-file uploads still read naturally ('Indexing document' / '1
  document indexed').

IngestionProgress / rag-store jobs are untouched (still used by the
KB detail panel). Not build/UI verified here (no bun).
2026-05-28 20:22:09 +04:00
Roland Tannous
08cee7cc0a Studio: bounded parallel RAG indexing + folder upload
Uploading many docs (or a folder) previously spawned an ingestion
subprocess per file all at once, thrashing the GPU/CPU. Add a
configurable concurrency limit and a folder picker.

- ragIndexConcurrency setting (default 1) in the chat runtime store,
  persisted like the other RAG scalar settings; exposed as a 'Parallel
  indexing' slider (1-8) at the bottom of the sidebar Retrieval section.
- New rag-index-queue.ts semaphore: each document upload acquires a slot
  before it starts and releases it once its ingestion job finishes
  (complete / error / already-indexed), so bulk uploads drain at the
  configured rate. Wired into both composer upload paths
  (use-thread-doc-uploads + shared-composer).
- Folder upload: a second 'Attach a folder' button on the RAG attach
  control uses a webkitdirectory input; every compatible file is routed
  through the same queue. Multi-file select already worked (the input has
  'multiple' and loops addDoc).
- Content-hash dedup (shipped earlier) means re-scanning a folder skips
  already-indexed files.

Not build/UI verified here (no bun); needs bun typecheck + a browser
check of bulk/folder upload draining at the set concurrency.
2026-05-28 19:52:49 +04:00
Roland Tannous
b836c3c76b Studio: RAG for external model providers via prefetch
External providers (OpenAI/Anthropic/Gemini) can't run the local
search_knowledge_base tool loop, so give them RAG by prefetching:
studio retrieves before calling the provider, injects the chunks into
the user prompt, and surfaces it as a synthetic tool call. Local models
are untouched (they keep tool-based RAG + decomposition).

Backend:
- New POST /api/rag/prefetch: momentarily loads the pre-cached helper
  (gemma-4-E2B-it-GGUF) via LlamaCppBackend(kill_orphans=False) to
  decompose the question into up to 3 queries, retrieves+merges+dedups
  per query, unloads the helper. Raw single-query fallback if the helper
  can't load. New core/rag/query_decompose.py owns the helper lifecycle.
- Factored the retrieval body of /search into _execute_search, reused by
  both endpoints.

Frontend:
- prefetchRag() client.
- chat-adapter external branch: gated on isExternalRequest + ragToolEnabled
  + scope!=off + ragScopeHasDocs (no docs -> no prefetch, prior behavior
  preserved). Formats hits as <chunk id=N> (parseChunks shape), injects
  into the last user message (send-only; not shown in the user bubble),
  seeds a synthetic search_knowledge_base tool-call part so the existing
  chunk-card UI + [N] citations + source badges all work unchanged.
- Extends PR #5674's disabled-tool guard: when RAG is off, reinforce
  'no document search (RAG) capabilities'; when prefetch ran, point the
  model at the injected excerpts instead.
- RAG pill enabled for external providers regardless of supports_tools.

Not build/UI verified here (no bun/GPU/keys); needs bun typecheck+test
and a browser round-trip with real provider keys.
2026-05-28 17:18:08 +04:00
Roland Tannous
cf7dec1f13 Studio: grey out RAG pill when the model can't call tools
RAG retrieval runs entirely through the local search_knowledge_base
tool. If the loaded model doesn't support tool calling (e.g. a
safetensors model whose template advertises tools in an unparsable
emission format, so supports_tools is suppressed), enabling RAG does
nothing — the model never calls the tool. The pill stayed lit and
clickable, which was misleading.

Gate the RAG pill on supportsTools (in addition to modelLoaded), the
same condition web/code use when there's no provider builtin. Applied
to both composer surfaces (shared-composer and the in-thread
RagToggle), with a 'RAG needs a model that supports tool calling'
tooltip on the disabled state.
2026-05-28 16:02:50 +04:00
Roland Tannous
f30c0a48dd Studio: don't duplicate composer chip when re-uploading an indexed doc
The backend dedups re-uploads and the sidepanel shows the doc once, but
the composer's pending-doc chips are created per addDoc call, so each
re-upload of an already-indexed file appended another 'Ready' chip for
the same document. In the already_indexed branch, if a chip with the
returned documentId already exists, drop the chip we just added instead
of marking it ready — so the composer shows each document only once.
2026-05-28 15:33:17 +04:00