Commit Graph
4938 Commits
Author SHA1 Message Date
Classic298 3d630491c6 fix: re-syncing an existing model no longer fails silently (#28036)
POST /api/v1/models/sync only worked when every model in the payload was new. As soon as one id already existed, the whole call blew up and the endpoint still answered HTTP 200 with an empty list, so nothing was updated and well-behaved clients saw a success. Only a first-ever sync into an empty catalogue went through.

The update branch splatted the model dump (which already carries user_id and updated_at) and then passed both again as explicit keyword arguments, which is a duplicate-keyword TypeError before SQLAlchemy ever sees it. The insert branch right below merged the same values into a dict first, so it never collided.

Fixed by building that dict once and using it for both branches, matching how sync_functions already does it. Left the broad exception handler alone: it is the reason the failure was silent, but changing the error contract of sync_models is a separate call.

Fixes #28033
2026-08-17 01:14:11 -06:00
Classic298 b933292d63 refactor: track visited ids when resolving a chat's current message (#28035)
`delete_message_from_history` follows `childrenIds` down to the deepest leaf without recording where it has been. Record it.
2026-08-17 01:13:51 -06:00
Classic298 27402ff210 refac: issue Playwright web loader requests from the shared HTTP clients (#28634)
The Playwright loader's route interceptor now performs each intercepted request with the same requests/aiohttp clients the other web loader paths already use and fulfills the page with that response, rather than having the browser issue it. Redirect handling, header forwarding and cookie delivery to the browser are unchanged.

Two consequences worth knowing. Page requests now leave from the backend instead of the browser, so with PLAYWRIGHT_WS_URL set they originate from a different host, and TLS is verified against certifi plus AIOHTTP_CLIENT_SSL_CERT_FILE rather than the browser's own trust store. And because the synchronous interceptor blocks, sub-resources on that path fetch one at a time: 30 assets at 40ms went from 2.01s to 3.01s, and 8 assets at 500ms from 1.05s to 4.50s. The asynchronous path is unaffected, at 0.65s and 1.05s respectively.
2026-08-17 01:06:12 -06:00
Classic298 73c1f5806a refactor: match provider identity lookups via JSON subscript (#28624)
Both the OAuth and SCIM user lookups now compare the nested JSON value with SQLAlchemy's subscript operator, which emits the correct SQL for each supported database on its own. This replaces the hand-written sqlite and postgresql branches and the column-level contains() call they used.
2026-08-17 01:05:16 -06:00
G30 8fc5ffe26e fix: persist the Open Sharing permission in default user permissions (#27609) 2026-08-17 01:03:07 -06:00
Timothy Jaeryang BaekandClassic298 927ce0eae6 refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-08-16 23:58:56 -07:00
Damien SandDamien SPINELLI 54cefd2b99 fix: preserve complete user context in agentic retrieval (#27642)
* fix: preserve user info in agentic RAG tools

* fix: preserve user info in file access checks

---------

Co-authored-by: Damien SPINELLI <damien.spinelli@external.list.lu>
2026-08-17 00:56:48 -06:00
xyoniumandClaude 686d8dc54c fix: strip prefix id from model name in /responses endpoint (#28575)
The /openai/responses endpoint forwarded the prefixed model id (e.g.
"myprovider.gpt-4o") to the upstream provider instead of the stripped
native name, causing "model not found" errors when a connection has a
Prefix ID configured.

generate_chat_completion() already strips the prefix before forwarding;
apply the same strip_provider_model_prefix() call in responses() after
the urlIdx routing (which needs the prefixed id) and re-serialize the
body afterwards.

Also fixes the Azure non-v1 deployment path, which built the deployment
URL from the prefixed model name.

Co-authored-by: Claude <noreply@anthropic.com>
2026-08-17 00:53:00 -06:00
Classic298 3df485582d fix: reject skill IDs that are not URL path safe (#27660)
A skill ID goes straight into the path of every mutating skill endpoint (/api/v1/skills/id/{id}/...), but create only replaced spaces with hyphens. An ID containing a "/" was stored verbatim as the primary key, so the route never matched, the request fell through to the SPA static mount and the client got 405 Method Not Allowed. The skill could not be opened, edited, toggled or deleted, by admins either, and since skill.name is UNIQUE it could not be recreated under a corrected ID. Percent-encoding does not help: uvicorn decodes the path before Starlette routes it, so the only remaining fix was a direct database write.

Create now rejects any ID outside [a-z0-9_-] with 400 instead of silently storing an unreachable one. Two frontend paths that fed unsanitized IDs into it are fixed as well: the manual "Skill ID" field, which was bound with no sanitization at all and is the path that reproduces on every version, and the markdown import, which put the raw frontmatter name into the ID before opening the editor in clone mode, where the reactive slugify is disabled.

Existing rows with an unreachable ID are not repaired here; rewriting a primary key would also have to re-point the access grants keyed on it.

Fixes #27655
2026-08-17 00:52:16 -06:00
Timothy Jaeryang Baek 954613944b refac 2026-08-16 23:51:38 -07:00
Classic298 805bfca5af feat: emit group events on OAuth group sync (#27657)
With ENABLE_OAUTH_GROUP_MANAGEMENT enabled, every SSO login reconciles the user's group membership against the IdP claims, adding and removing them from groups and, with ENABLE_OAUTH_GROUP_CREATION, creating groups that do not exist yet. None of it emitted an event, so the same membership change was observable when an admin made it through the UI or when it arrived over SCIM, but invisible when the IdP drove it. That is the path that changes membership most often.

Emits group.member_added and group.member_removed per membership transition and group.created for each auto-created group, using the same payload keys as the groups router. The member events are published only when the write returned a group, so a failed or no-op write emits nothing, and both loops already run only on an actual transition. update_user_groups takes the request so the events can be published; it has a single caller.
2026-08-17 00:50:47 -06:00
Timothy Jaeryang BaekandClassic298 3e186abdd9 refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-08-16 23:41:58 -07:00
Timothy Jaeryang Baek 16f118d77a refac 2026-08-16 23:38:34 -07:00
Classic298 cd9db21c52 refac: bind tool server cookies per connection (#28630)
The tool callable now takes its connection's cookie jar as a parameter, matching how its headers are already passed and how the terminal tool factory in the same module builds its callables.
2026-08-17 00:25:07 -06:00
Classic298 7d392bedc9 refac: align the channel completion gate with the message update route (#28631)
The gate now applies the same authorship condition the channel message update route already uses, so both paths agree on which messages a caller may modify.
2026-08-17 00:24:49 -06:00
Timothy Jaeryang Baek 1a376ac17f refac 2026-08-16 23:21:00 -07:00
G30 1d1c14bd77 fix: compare folder names for uniqueness with lower() equality instead of a LIKE pattern (#28695) 2026-08-17 00:00:02 -06:00
Timothy Jaeryang BaekandClassic298 3258330729 refac
Co-Authored-By: Classic298 <27028174+Classic298@users.noreply.github.com>
2026-08-16 22:56:19 -07:00
Timothy Jaeryang Baek 62fc436999 refac 2026-08-16 22:52:24 -07:00
Timothy Jaeryang Baek d02b6a21fc refac 2026-08-14 00:55:21 -06:00
Timothy Jaeryang Baek c755ef60c6 refac 2026-08-14 00:54:33 -06:00
Timothy Jaeryang Baek a1579a01ff refac 2026-08-14 00:22:17 -06:00
Timothy Jaeryang Baek fa94a5ab24 refac 2026-08-13 21:36:41 -06:00
Timothy Jaeryang Baek 653562d660 refac 2026-08-13 21:15:26 -06:00
Timothy Jaeryang Baek a32a17965c refac 2026-08-13 21:06:51 -06:00
Timothy Jaeryang Baek 083e351441 refac 2026-08-13 21:02:17 -06:00
Timothy Jaeryang Baek ec36972c2b refac 2026-08-13 20:02:08 -06:00
Timothy Jaeryang Baek 7d99b2716a refac 2026-08-13 19:59:11 -06:00
Timothy Jaeryang Baek 133549a87e refac 2026-08-13 18:19:25 -06:00
Timothy Jaeryang Baek 4465f52a3e refac 2026-08-13 18:13:43 -06:00
Timothy Jaeryang Baek 2c01d59335 refac 2026-08-13 17:26:38 -06:00
Timothy Jaeryang Baek 2649e3305c refac 2026-08-13 16:42:10 -06:00
Timothy Jaeryang Baek 5c05608e3a refac 2026-08-13 15:02:18 -06:00
Timothy Jaeryang Baek 85c3d0ae2f refac 2026-08-13 00:07:31 -06:00
Timothy Jaeryang Baek 90bb94abf9 refac 2026-08-12 18:13:47 -06:00
Timothy Jaeryang BaekandG30 939bcdb79e refac
Co-Authored-By: G30 <50341825+silentoplayz@users.noreply.github.com>
2026-08-12 01:13:38 -06:00
G30 1deeaf71da fix: stop the calendar update tool from nulling every omitted field (#27777) 2026-08-12 01:09:07 -06:00
G30 2ab0311b99 fix: reject COUNT rules without DTSTART so limited automations cannot run forever (#27781) 2026-08-12 01:08:55 -06:00
G30 104a0f2f11 fix: remove vestigial api_base_url param that broke the Tavily web loader (#27636) 2026-08-12 02:05:26 -05:00
Timothy Jaeryang Baek 9c21d4ed3b refac 2026-08-11 17:42:25 -06:00
G30 e17dfae72e fix: enforce the image generation flag on the legacy chat feature path (#27759)
* fix: enforce the image generation flag on the legacy chat feature path

* fix: refresh the config store when image generation is disabled in admin settings

* fix: hide active feature pills when the feature is no longer available
2026-08-11 17:38:10 -06:00
Timothy Jaeryang Baek 4f9a0ebf71 refac 2026-08-11 17:35:05 -06:00
Timothy Jaeryang Baek 865c80c160 refac 2026-08-11 01:17:19 -06:00
Timothy Jaeryang Baek f0bfcd4097 refac 2026-08-11 01:15:05 -06:00
Timothy Jaeryang Baek 5cd9a39534 refac 2026-08-10 23:40:31 -06:00
Classic298 934802e186 fix: enforce features.memories permission on the legacy memory context path (#27668)
Revoking a user's `features.memories` permission removed their access to the memories API and to the native function-calling memory tools, but their stored memories were still injected into the system context on the legacy function-calling path.

The branch in `process_chat_payload` only checked the client-supplied `features['memory']` flag plus the global `memories.system_context.enable` switch, with no user-permission check. `add_memory_context` did not compensate: it only checks `model_allows_memory`, which is a model capability rather than a permission, and the one call inside it that does check the permission (`query_memory`) has its 403 swallowed by a `try/except`, so `Memories.get_memories_by_user_id` and the neighbourhood scan still fed the system prompt.

Gate the branch with the same permission check the native path already performs in `get_builtin_tools`, matching the neighbouring `web_search` and `image_generation` branches.

Only the caller's own memories were injected into the caller's own context, so there was no cross-user exposure. The practical effect was that the permission toggle did not do what its name implies: an admin who revoked it still got memory content injected for that user.
2026-08-10 23:36:27 -06:00
Classic298 fcc130c9bb fix: send stream_options.include_usage for backend-initiated chats (#27661)
Only the frontend added `stream_options: {include_usage: true}` to the completion payload, gated on the model's `usage` capability. Every backend-initiated run builds its own payload (automations, timers, subagents, channels) and omitted it, so those responses came back without token counts and never rendered the usage block, even with the capability enabled on the model.

Set it in `chat_completion` instead, the single handler all of those callers go through, and drop the two duplicate copies (the Anthropic-compat handler and the frontend). Capabilities are read from the resolved model before the custom-model fallback can rebind it, and the flag is applied after the model's `stream_response` override so a non-streaming model is unaffected.

Fixes #27653
2026-08-10 23:30:46 -06:00
Classic298 5c79ccc9e5 refactor: walk chat message history by map key (#28034)
`get_message_list` moves through `messages_map` by key but tracked each message's own `id` field, which the message body does not have to carry. Track the key instead.
2026-08-10 23:24:41 -06:00
G30 80d2f4154a fix: align public_tools and public_notes sharing defaults with config (#27716)
The SharingPermissions model defaulted public_tools and public_notes to
True while the config defaults (USER_PERMISSIONS_WORKSPACE_TOOLS_ALLOW_PUBLIC_SHARING
and USER_PERMISSIONS_NOTES_ALLOW_PUBLIC_SHARING) are both False.

On an instance whose stored user.permissions config predates these keys,
GET /api/v1/users/default/permissions fills the gap from the model and
reports both as enabled, while has_permission fills it from
DEFAULT_USER_PERMISSIONS and denies. Saving any unrelated permission then
persists the model's True, granting public tool and note sharing the admin
never enabled.
2026-08-10 23:24:18 -06:00
Timothy Jaeryang Baek bd8378f643 refac 2026-08-10 23:22:08 -06:00