Commit Graph
18604 Commits
Author SHA1 Message Date
Timothy Jaeryang BaekandG30 67adde3193 refac
Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
2026-09-19 17:26:40 -04:00
Timothy Jaeryang Baek 10d1cfe637 refac 2026-09-19 17:26:18 -04:00
G30 c1a35b4691 fix: sort the feedback history by user when the User column is clicked (#30191) 2026-09-19 17:21:51 -04:00
G30 76bd90c832 fix: discard unsaved edits when the admin Edit User dialog is closed (#30193) 2026-09-19 17:21:44 -04:00
G30 4922b91c07 fix: stop the Model Defaults save from reverting the selected, pinned and ordered models (#30206) 2026-09-19 17:17:57 -04:00
G30 27dd191332 fix: let a calendar event's repeat, description and location be cleared again (#30204) 2026-09-19 17:17:43 -04:00
G30 757ee8132e fix: stop collapsing the task list from sending the message being typed (#30202) 2026-09-19 17:17:30 -04:00
G30 5e1f995f01 fix: show a custom gender back in the account form instead of an empty dropdown (#30215) 2026-09-19 17:16:56 -04:00
G30 b64cb06043 fix: let a user without the chat delete permission delete a folder while keeping its chats (#30163) 2026-09-19 16:07:34 -05:00
Timothy Jaeryang Baek 946be43237 refac 2026-09-19 17:05:57 -04:00
G30 25948ea213 fix: block saving a prompt's input form when a required dropdown has no option chosen (#30078) 2026-09-19 15:42:39 -05:00
G30 3fbc39a9dc fix: save a new feedback entry when rating a reply whose entry was deleted (#30077) 2026-09-19 15:42:25 -05:00
G30 a63ddb36d2 fix: clear a reply's score and reason when its rating switches thumbs (#30075) 2026-09-19 15:42:15 -05:00
G30 57063aaad8 fix: dropping a folder onto the folder it is already in no longer fails with Folder already exists (#30169) 2026-09-19 15:41:10 -05:00
G30 2690d04cac fix: clean up orphan tags for the chat's owner, not the admin, when an admin deletes another user's chat (#30171) 2026-09-19 15:40:58 -05:00
G30 af9ef1dcbc fix: hide the group picker from users who may not share with groups (#30189) 2026-09-19 15:34:33 -05:00
G30 621ed6de7f fix: export every prompt and model from the workspace, not only the page on screen (#30187) 2026-09-19 10:03:17 -05:00
G30 9e293a58ea fix: label the search modal's archive action Unarchive for archived chats and report what happened (#30177) 2026-09-19 10:02:11 -05:00
G30 dbe538c033 fix: keep a note's sharing when a collaborator saves it (#30175) 2026-09-19 10:00:39 -05:00
G30 d16fad585d fix: keep a shortcut recording from firing the action already bound to the chord (#30160) 2026-09-19 10:00:18 -05:00
G30 2af297bfcd fix: keep the pinned flag when importing a chat export (#30151) 2026-09-19 09:59:55 -05:00
G30 36276c9ead fix: keep a skill's translations and disabled state when saving it from the editor (#30185) 2026-09-19 09:59:36 -05:00
Classic298 1f8f1f61bb fix: tell ask_user models that the first option is shown as Recommended (#30196)
The ask_user card badges the first option of every question as "Recommended", but nothing ever told the model that. The model picks whatever order it likes, so the badge really means "listed first" and users act on a recommendation the model never made.

The ask_user tool description now states that the first option is labelled Recommended and that the model should list the option it recommends first, so the badge reflects an actual choice.

Kept the badge and instructed the model instead of adding a per-option "recommended" flag: the flag would need a schema change, validation in the request normalizer and a frontend change, for the same result in the common case. Dropping the badge was the other option, but it removes a useful affordance rather than fixing it.

Verified that the added line reaches the model by running the docstring through the tool-spec builder and checking the generated OpenAI function schema.

Fixes #30195
2026-09-19 09:59:18 -05:00
G30 5d7c17f41a fix: stop the Generate Message Pair shortcut from also submitting the message input form (#30167) 2026-09-18 23:54:10 -04:00
Classic298 3d29548716 fix: pgvector reads leak their connection and lose most of their neighbours (#30142)
Two defects on the pgvector read path. A search, query or get that finds nothing returns before the rollback that ends its read-only transaction, so the session keeps the connection it checked out; retrieval fans out over worker threads and the session is thread-local, so every thread that runs an empty read holds a connection for the lifetime of that thread. Users see vector search die after a while with "QueuePool limit of size 5 overflow 10 reached" and no way back other than a restart. Rolling back before the three early returns puts the connection back: measured on PostgreSQL 16, twelve empty reads on a default-shaped pool left all 12 connections checked out before and 0 after.

All collections also share one table under one vector index, and the WHERE collection_name filter is applied after the index walk, so a knowledge base holding a small share of the rows keeps only a small share of its neighbours, silently. pgvector 0.8 added iterative scans for this: the scan keeps going until enough rows pass the filter. This sets it per search so it cannot leak into other sessions, and only when the installed extension supports it, since setting it on pgvector 0.7 would make every search raise. PGVECTOR_ITERATIVE_SCAN turns it off or picks strict_order; it defaults to relaxed_order because the shipped behaviour is silently wrong results, and the cost is about a millisecond per search.

Measured through PgvectorClient.search on PostgreSQL 17 and pgvector 0.8, 101500 rows of 384 dimensions with the knowledge base at 1.5% of the table, hnsw m=16, recall@10 against an exact scan over 40 queries: 0.070 at 4.9 ms before, 0.970 at 7.2 ms after.

Fixes #30133
Fixes #30135
2026-09-18 19:31:49 -04:00
Classic298 52cd298411 fix: allow forking a chat that holds a stale unfinished message (#30131)
Forking returned 409 "Wait for the current response to finish before forking." forever once any assistant message anywhere in the chat was left at done = false, with nothing generating and even when that message sat on a branch that was not being forked. Interrupted turns leave the flag behind and nothing clears it, so an affected chat could never be forked again.

The endpoint now refuses only while a task is actually running, which is the check /compact has always relied on by itself. A message still unfinished on the forked branch is marked done in the copy so the fork does not open showing a spinner, while a turn paused waiting on tool approval keeps its unfinished state and its pending call so the fork still shows the prompt. The source chat is left untouched either way.

The client-side check had the same shape of bug: it read history.currentId instead of the message actually being forked, so a paused last turn also blocked forking earlier, finished messages. It now reads the message it is about to fork.

Fixes #30128
2026-09-18 19:31:20 -04:00
Classic298 fffcb727d2 fix: release the openGauss connection when a read returns no rows (#30144)
An openGauss query or get that finds nothing returns before the rollback that ends its read-only transaction, so the session keeps the connection it checked out of the pool. Retrieval fans out over worker threads and the session is thread-local, so every thread that runs an empty read holds a connection for the lifetime of that thread, and vector search eventually fails with a pool checkout timeout that a restart is the only way out of. Empty reads are routine: an empty knowledge base, a file whose chunks were deleted, or a metadata filter that matches nothing all produce one.

Rolling back before the two early returns puts the connection back. Measured by driving OpenGaussClient itself with a pool of 5: three empty query reads left 3 connections checked out and 0 free before the change, and 0 checked out with 3 free after, same for get. search is already correct, it has no early return.

The pgvector client had the same defect, fixed separately in #30142.
2026-09-18 19:31:01 -04:00
Classic298 6d73780fd1 fix: bundle seaborn and give black its dependencies in the Pyodide lock (#30148)
seaborn was listed among the Pyodide distribution packages, but it is not part of that distribution, so the build wrote no wheel for it. Since seaborn is on the code interpreter's package list, it was quietly downloaded from pypi.org in the user's browser instead, which is what bundling the wheels is meant to avoid. It now takes the PyPI wheel path, like openpyxl.

The code editor's Format button was broken for non-admin users, with or without internet, because black's bundled lock entry declared no dependencies and the hand-written list next to the caller was missing packaging. black's dependencies are now declared in the lock, so that list goes back to black alone and every future caller gets them too.

Both of these shipped unnoticed because nothing checked that a listed package produced a wheel. The build now fails when one did not, naming it.

Verified offline with the network cut at undici's dispatcher: seaborn, black, the Excel roundtrip and the other listed packages all install from the bundled wheels, and a deleted wheel, a missing lock entry or a non-canonical key each fail the build.

Fixes #30145
2026-09-18 19:30:54 -04:00
G30 677341578d fix: stop the model editor's Builtin Tools section from reading its labels before they exist (#30153) 2026-09-18 19:29:41 -04:00
G30 4d01f1ebed fix: keep the archived state and chat variables when importing a chat export (#30155) 2026-09-18 19:29:30 -04:00
Timothy Jaeryang Baek 64bbdf7a73 refac 2026-09-18 19:28:40 -04:00
joaoback f3cf833e54 i18n: add pt-BR translations for newly added UI items and consistency pass (#30158)
New **pt-BR** translations for items introduced in the latest releases, plus a consistency/quality pass across existing strings (grammar, tone, capitalization, pluralization). Placeholders and hotkeys preserved. No logic changes.
2026-09-18 19:18:45 -04:00
Classic298 d5cacb3c0a fix: convert forced tool_choice and non-streaming tool calls for Responses API connections (#30095)
On a connection with API type "responses", a forced tool choice sent in
the Chat Completions shape was forwarded to the provider unchanged, so
providers that validate the Responses API schema rejected the request.
A non-streaming reply that carried a function call was also flattened
to empty text with finish_reason "stop", so API clients never saw the
tool call.

The request converter now flattens a forced function choice to the
Responses API shape, and the result converter turns every function_call
output item into a Chat Completions tool_calls entry, mirroring the
existing Responses output mapping in utils/misc.py.

Fixes #30085
2026-09-18 19:18:26 -04:00
Timothy Jaeryang Baek c82634b9d0 refac 2026-09-18 11:49:56 -04:00
Timothy Jaeryang Baek b513a6ad3b refac 2026-09-18 11:40:44 -04:00
Classic298 9ee810ad09 feat: add Staan as a native web search provider (#30138)
European deployments that need EU data residency have no hosted web search option out of the box: every plug-and-play provider shipped today is US-based, and the only sovereign alternative is self-hosting SearXNG, which means running and maintaining that infrastructure yourself. Staan (staan.ai) is a European search API with EU data residency, so adding it gives those deployments a drop-in choice.

It is configured like any other provider, through the admin UI or STAAN_API_KEY, STAAN_MARKET and STAAN_MAX_SNIPPETS. Market sets the region and language of the results and defaults to en-us. Max snippets asks Staan to fetch each result page and return semantically scored chunks of it, which get merged into that result's snippet so retrieval has more to work with; leaving it at 0 uses the plain search endpoint.

Wired the same way as Tavily and Exa, with domain filtering going through the shared get_filtered_results.

Requested in #26006.
2026-09-18 10:38:36 -05:00
Classic298 655337f7bf fix: vendor openpyxl so Excel I/O works in the Pyodide code interpreter (#30140)
openpyxl has been listed as a Pyodide package since March, but it is not part of the Pyodide distribution, so the build never wrote a wheel for it and never warned about it. In the browser code interpreter every Excel operation failed with ModuleNotFoundError: import openpyxl, pd.read_excel() and DataFrame.to_excel() alike.

It now takes the PyPI wheel path together with its dependency et-xmlfile, and the code interpreter installs it when a snippet imports openpyxl or calls pandas' Excel helpers, which need it without importing it by name.

Injected lock entries are now keyed by the canonical dashed package name, the only spelling pyodide resolves them by. As a side effect black's mypy-extensions now resolves from the bundled wheel too, so formatting Python in the editor no longer reaches out to PyPI at runtime.

Verified offline against a built static/pyodide with every network call blocked: a to_excel then read_excel roundtrip loads openpyxl and et-xmlfile from the local directory and returns the frame.

Fixes #30130
2026-09-18 10:38:02 -05:00
Classic298 95406fd28d fix: build the pgvector ivfflat index once there are rows to cluster on (#30143)
ivfflat places its centroids by clustering the rows it can see when the index is built, so an index built on an empty table gets centroids that mean nothing, and everything inserted afterwards is filed against them. On a fresh install the index is created immediately after the table, before a single chunk exists, and it is never rebuilt, so that install keeps a permanently untrained index and quietly retrieves the wrong chunks. An install that upgraded into the version introducing the index is unaffected, its table already had rows.

The index is now created once the table holds 50 rows per list, the sample size ivfflat itself aims for. Below that, and until the next start, searches fall back to an exact scan, which is correct and costs about a millisecond at that size. hnsw is untouched, it builds its graph as rows are inserted and has nothing to train on. One trade-off: the build moves from the first start to that later one, so an instance that has grown large in between pays a one-time index build during startup.

Measured on PostgreSQL 17 and pgvector 0.8 with the default lists=100 and probes=1, 384 dimensions, recall@10 against an exact scan, varying only how many rows existed when the index was built:

| rows at build | 200 | 1000 | 2500 | 5000 | 20000 |
|---|---|---|---|---|---|
| recall@10 | 0.180 | 0.563 | 0.967 | 1.000 | 1.000 |

Through PgvectorClient.search on a 20000-row table, an index built as it is today scores 0.480 against 1.000 built after the rows arrive, at the same 5 ms. An existing install can repair its index with REINDEX INDEX idx_document_chunk_vector, measured to take it from 0.480 back to 1.000.

Fixes #30134
2026-09-18 10:37:25 -05:00
Timothy Jaeryang Baek 1ddba7e2c6 refac 2026-09-18 11:31:59 -04:00
Timothy Jaeryang Baek ca1eefe293 refac 2026-09-18 11:30:15 -04:00
Timothy Jaeryang Baek 9d98ffcddf refac 2026-09-18 10:55:55 -04:00
Timothy Jaeryang Baek 7cbaabe02f refac 2026-09-18 10:51:00 -04:00
Timothy Jaeryang Baek ad9da98168 refac 2026-09-17 20:11:05 -04:00
Timothy Jaeryang Baek dbb17a5725 refac 2026-09-17 19:49:35 -04:00
Classic298 9923c53c10 fix: treat SVG uploads as documents instead of vision images (#30102)
Uploading an .svg to a chat attached it as a vision image input, so the model received a data URI it could not decode. PIL-backed servers answered "cannot identify image file" and OpenAI answered "The image data you provided does not represent a valid image". No setting made it work.

SVG now takes the ordinary file upload path, so its XML source is extracted and indexed and the model can answer questions about it. Rasterizing was the alternative and it would have discarded the part of an SVG a model reads best, the source itself. Raster formats are untouched and still go up as image inputs.

A shared helper replaces the ad hoc image/ prefix checks at the points that decide image input versus document, on both ends. It normalises the content type first, because a stored "image/SVG+xml" or a trailing charset parameter slipped past a plain comparison.

One behaviour change worth knowing: an SVG now needs the model to have the file upload capability, where before it rode in as an image.

Fixes #30100
2026-09-17 17:40:07 -04:00
Classic298 d08b69025d issue-template: require reproducing on latest AND dev right before submitting (#30104)
Reports for bugs already fixed on dev, sometimes weeks earlier, are common
because reporters check an old version once and never retest. Merges the
two soft checkboxes into one strict, time-bound requirement and warns in
the template body that unreproduced reports get closed without discussion.
2026-09-17 17:39:54 -04:00
Classic298 460f2e7634 fix: surface initial chat title generation failures in the log (#30106)
When title generation for a brand new chat fails, the chat silently keeps the provisional title (the full first user message) and nothing is written to the log at the default level, so there is no way to tell that the feature is broken rather than disabled. The failure was caught by a broad `except Exception` and reported with `log.debug`, which is invisible unless GLOBAL_LOG_LEVEL is set to DEBUG. Issue #29533 describes an outage of this path that survived four releases for exactly that reason.

This logs it with `log.exception` instead, matching how the rest of main.py reports background task failures, so an admin sees one ERROR line plus the traceback naming the real cause.

Nothing else changes: the success path is untouched, the exception is still swallowed so the detached task cannot take anything down with it, and `background_tasks_handler` does not log this exception itself, so there is no duplicate traceback.

Fixes #29533
2026-09-17 17:39:43 -04:00
Classic298 0837f310be fix: reject Docling conversions that failed inside an HTTP 200 response (#30107)
Uploading a file that Docling declines or fails to convert either dies with `TypeError: argument of type 'NoneType' is not iterable`, or silently succeeds and stores the literal string `<No text content found>` as the document's text, which then gets indexed and handed to the model as if it were the file. Docling returns the conversion outcome inside the HTTP 200 body, so checking only the HTTP status made a refused conversion look identical to a successful one, and the `errors` array that says why in plain words was never read.

Failed and skipped conversions are now rejected with the messages Docling returned, so an unsupported format surfaces as "File format not allowed: example.dxf" and the traceback is gone. The markdown field is also read as nullable, because Docling returns JSON `null` for every content format it was not asked to produce, which any Docling Parameters setting `to_formats` without `md` will hit, and that null was what raised the TypeError.

Successful conversions with empty markdown keep the existing `<No text content found>` placeholder, matching what TikaLoader and the Mistral loader already do in the same package.

Fixes #29808
2026-09-17 17:39:35 -04:00
Timothy Jaeryang Baek 58b36765a7 refac 2026-09-16 22:47:37 -04:00
Classic298 fbc4897269 refac: resolve knowledge file access from the file association (#29937)
`has_access_to_file` now derives knowledge-base access purely from the knowledge-file association, instead of also consulting the `collection_name` value stored on the file record.
2026-09-16 15:59:25 -04:00