[AI-3] Let administrators add, edit and delete models by hand - #24884
[AI-3] Let administrators add, edit and delete models by hand#24884tangopium wants to merge 1 commit into
Conversation
|
Caution The provided work package version does not match the core version Details:
Please make sure that:
|
|
Caution The Enterprise plan field is not set on the work package Details:
Please make sure that:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0e6d4db2e1
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
0e6d4db to
cc8a279
Compare
cc8a279 to
1e9e5a9
Compare
1e9e5a9 to
7b53618
Compare
Not every OpenAI-compatible server exposes a model list: a gateway may route /v1/chat/completions and nothing else, in which case the operator knows the model name and OpenProject cannot discover it. This adds hand-entered LlmModel rows with their own form, including capability assertions stored as admin-sourced verdicts that survive re-detection, and an administrator-supplied context window that takes precedence over reported figures. A manual model's identifier may be corrected after the fact; the rename carries every verdict and the connection defaults along, because everything references a model by its identifier string. Discovered models are named by the server and cannot be renamed or deleted here, and a catalogue refresh never withdraws a manual entry. Part 6 of the AI-3 stack. https://community.openproject.org/work_packages/66020
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
7b53618 to
75ff06e
Compare
|
Warning Flaky specs
🤖 Ask Copilot to investigateCopy the prompt below into a new comment on this PR to delegate the investigation to GitHub Copilot. It will look into the flakiness and open a separate pull request with you as reviewer. |
thykel
left a comment
There was a problem hiding this comment.
👍 As usual, leaving you with a mixture of my own comments + robot ones (that look legible to me)
| context_window: "Context window" | ||
| context_window_caption: "How many tokens this model accepts. Leave blank if you do not know." | ||
| context_window_known: "Leave blank to use %{value}, %{source}." | ||
| create_submit: "Add model" |
There was a problem hiding this comment.
Fits our usual convention better:
| create_submit: "Add model" | |
| create_submit: "+ Model" |
| edit: | ||
| description: "Edit how OpenProject uses this model." | ||
| form: | ||
| capabilities_description: "Leave a capability unspecified to let OpenProject determine it. Marking Embeddings as supported makes this an embedding model, offered only to features that need one." |
There was a problem hiding this comment.
Ghost key? 👀 Not seeing any references even in the future PRs.
| @llm_model = @connection.models.new | ||
| end | ||
|
|
||
| def edit |
There was a problem hiding this comment.
Please rescue & add a spec for an invalid PATCH request.
|
|
||
| # Verdicts are keyed by the identifier string, not by foreign key, so they | ||
| # would silently apply to a future model re-added under the same name. | ||
| def destroy_with_verdicts(llm_model) |
There was a problem hiding this comment.
🤖 #Logic 🚨 Deleting a model leaves the connection defaults pointing at it
cascade_rename! goes to real trouble to keep references intact on a rename: it moves the verdicts and rewrites default_chat_model_id / default_embedding_model_id. This path deletes the verdicts but leaves the defaults untouched.
Confirmed on this branch: set default_chat_model_id to a manual model, delete it, and the column still holds the deleted identifier.
The dialog does warn through affected_defaults, so this may be a deliberate "the administrator was told". If so, could we say that in a comment? As it stands one method treats the defaults as references to maintain and the other does not, and it is not obvious which behaviour is intended.
| end | ||
|
|
||
| f.text_field( | ||
| name: :display_name, |
There was a problem hiding this comment.
🤖 #Logic
This PR makes display_name editable, which makes an existing behaviour in SyncModelsService#upsert reachable: it assigns display_name: card[:display_name] unconditionally, and the OpenAI adapter never supplies one.
Measured on this stack:
- manual model the server does not report - name survives
- manual model the server also reports - name lost
- discovered model whose id is in the registry - name silently replaced by the vendor's
- discovered model not in the registry - name blanked
merged_metadata already protects admin_context_window from exactly this. Would it make sense to give display_name the same treatment, so the sync keeps the stored value when the card carries none?
| # administrator knows things about their deployment that neither a published | ||
| # registry nor a probe can determine. | ||
| def apply_capabilities(llm_model) | ||
| submitted = llm_model_params |
There was a problem hiding this comment.
🤖 #Design ℹ️ apply_capabilities re-parses the request parameters
Both callers have already built this hash before calling in. Could apply_capabilities take it as an argument instead of running params.expect a second time per request?
|
|
||
| <% subheader.with_action_button( | ||
| scheme: :primary, | ||
| label: t("admin.llm_connections.show.add_model_submit"), |
There was a problem hiding this comment.
🤖 #Style ℹ️ This key names a link, not a submit, and duplicates create_submit
Two separate points on the same key, both worth a look alongside the suggestion already left on create_submit:
-
add_model_submitlabels this sub-header link, while the form's actual submit button usesadmin.llm_models.form.create_submit. Both currently read "Add model", so the same text appears on two different controls and the_submitsuffix sits on the one that is not a submit. Would it be clearer to rename this one (for exampleadd_model) and leavecreate_submitnaming the action the form performs? -
On the label itself: the closest analogues in the repo use a bare noun for a primary sub-header button with
leading_icon: :plus-+ Portfolioinportfolios/index_sub_header_component.html.erband+ Iteminadmin/custom_fields/hierarchy/items_component.html.erb. The other convention is a bare verb,+ Add, used by the projects index. Since the icon already supplies the plus, the literal "+" would not be needed in the string either.
Separately, admin.llm_connections.show.add_model_description looks like a second ghost key in this area - unreferenced since it was added, and superseded by admin.llm_models.new.description.
Ticket
AI-3
What are you trying to accomplish?
PR 6 of 11 in the AI-3 stack. Not every OpenAI-compatible server exposes a model list: a gateway may route
/v1/chat/completionsand nothing else. This part lets administrators add, edit and delete models by hand, including capability assertions stored as admin-sourced verdicts and an administrator-supplied context window that takes precedence over reported figures. A manual model's identifier can be corrected later; the rename carries every verdict and the connection defaults along. Discovered models cannot be renamed or deleted here, and a catalogue refresh never withdraws a manual entry.Merge checklist
llm_connectionfeature flagStacked on #24883.