Skip to content

feat: editable LLM prompts and per-family preferred model#951

Open
MkDev11 wants to merge 17 commits intowe-promise:mainfrom
MkDev11:feature/editable-llm-prompts-938
Open

feat: editable LLM prompts and per-family preferred model#951
MkDev11 wants to merge 17 commits intowe-promise:mainfrom
MkDev11:feature/editable-llm-prompts-938

Conversation

@MkDev11
Copy link

@MkDev11 MkDev11 commented Feb 9, 2026

What this does

The AI Prompts settings page was always read-only. This PR makes it actually useful: you can now edit the main system prompt, the intro (welcome) prompt, and choose a default AI model for your household. Each family can tune how the assistant behaves and which model new chats use.

Changes

  • Family settings — New columns: custom_system_prompt, custom_intro_prompt, preferred_ai_model. All optional; leave blank to keep the built-in defaults.
  • Assistant behavior — When you chat, the assistant uses your family’s custom prompts when set, otherwise the existing defaults (including the intro flow from PR First cut of a simplified "intro" UI layout #265).
  • Default model — New chats and messages use your family’s preferred model when set, then fall back to the existing global default (ENV / Setting / OpenAI default).
  • Settings UI — The AI Prompts page now has a form at the top to edit those three fields, with basic validation (length limits) and error handling.
  • Tests — Controller tests for the update flow; Chat tests updated so default-model behavior is stable. Added sidekiq-throttled to the Gemfile so the test suite can boot (required by IndexaCapitalActivitiesFetchJob).

Why

So each household can adjust the assistant’s personality and target model without touching code or config files. Matches the intent behind #938 and the discussion in #906.

How to verify

  1. As an admin, go to Settings → AI Prompts.
  2. Set a preferred model (e.g. gpt-4-turbo), optionally edit the main or intro prompt, and save.
  3. Start a new chat without picking a model — it should use your preferred model.
  4. The collapsible “Prompt Instructions” sections below should show the effective prompt (your custom one or the default).

Run the tests:

bin/rails test test/controllers/settings/ai_prompts_controller_test.rb test/models/chat_test.rb test/models/family_test.rb

Closes #938.

Summary by CodeRabbit

  • New Features

    • Families can set custom AI system and intro prompts, preferred AI model, and custom OpenAI endpoint.
    • Settings UI now lets admins view and update per-family AI prompt and model overrides.
    • AI model selection now honors per-family preferences when present.
  • Chores

    • Added background job throttling dependency.

mkdev11 added 4 commits February 9, 2026 15:32
- Add .cursor/rules/api-endpoint-consistency.mdc: checklist that applies
  when editing app/controllers/api/v1, spec/requests/api/v1, or
  test/controllers/api/v1. Enforces (1) Minitest-only behavioral coverage
  for new endpoints, (2) rswag docs-only (no expect/assert), (3) same
  API key auth pattern in all rswag specs.
- Reference the rule in AGENTS.md under API Development Guidelines.
- Minitest: test/api_endpoint_consistency_rule_test.rb checks rule file
  exists, globs, and all three sections (Minitest, rswag docs-only,
  API key auth) plus AGENTS.md reference.
- Standalone: test/support/verify_api_endpoint_consistency.rb runs
  same checks without loading Rails (use when app fails to boot).
- Rule: add mdc: links for Cursor, note valuations_spec OAuth outlier.
…mise#938)

- Add family columns: custom_system_prompt, custom_intro_prompt, preferred_ai_model
- Assistant::Configurable uses family overrides when present, else built-in defaults
- Chat.default_model(family) supports per-family preferred model; controllers pass family
- Settings AI Prompts page: form to edit custom prompts and preferred model, validation
- Route and Settings::AiPromptsController#update with strong params and error handling
- Family validations: prompt length cap 32k chars, preferred_ai_model 128 chars
…er tests

- Gemfile: add sidekiq-throttled (required by IndexaCapitalActivitiesFetchJob)
- ChatTest: stub ENV/Setting and clear family preferred_ai_model for default-model tests
- AiPromptsControllerTest: drop assigns/assert_template; assert response content and non-persistence
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds per-family AI prompt and model overrides, custom OpenAI endpoint support, family-aware model/provider resolution, admin-editable settings, database columns for family overrides, controller and helper updates to use family context, provider registry changes, and related tests and UI/locales.

Changes

Cohort / File(s) Summary
Database migrations & schema
db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb, db/migrate/20260209180000_add_openai_uri_base_to_families.rb, db/schema.rb
Adds family-level columns: custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base. Schema reflects added columns and other unrelated reorders/removals.
Family model & validations
app/models/family.rb
Adds length constants, validations for new prompt/model/URI fields, custom_openai_endpoint? predicate, and cross-field validation enforcing preferred_ai_model when openai_uri_base is set.
Chat default model & helpers
app/models/chat.rb, app/helpers/application_helper.rb
Chat.default_model now accepts optional family and prioritizes family.preferred_ai_model; helper default_ai_model now passes Current.user&.family.
Controllers — model resolution changes
app/controllers/chats_controller.rb, app/controllers/messages_controller.rb, app/controllers/api/v1/chats_controller.rb, app/controllers/api/v1/messages_controller.rb
Controller call sites updated to use family-aware default model (Chat.default_model(family)) when ai_model not provided.
Settings UI, controller, routes, locales
app/controllers/settings/ai_prompts_controller.rb, app/views/settings/ai_prompts/show.html.erb, config/routes.rb, config/locales/views/settings/en.yml
Adds admin-only update action, set_family and strong params, expands routes to allow show and update, adds form UI and i18n keys for editing family prompts, model, and endpoint.
Provider registry & assistant/provider plumbing
app/models/provider/registry.rb, app/models/assistant/provided.rb, app/models/assistant.rb, app/models/assistant/configurable.rb
Adds Provider::Registry.openai_for_family(family) to build family-scoped OpenAI provider; provider lookup accepts family: and prefers family-scoped provider; Assistant/Configurable use family prompts and pass family to provider lookup.
Dependencies
Gemfile
Adds sidekiq-throttled gem.
Tests
test/controllers/settings/ai_prompts_controller_test.rb, test/models/chat_test.rb, test/models/assistant_test.rb
Adds controller tests for AI prompts (authorization, persistence, validation, reset); updates tests to account for family-aware provider/model lookup and ENV/Setting fallbacks.
Other model changes
app/models/assistant/configurable.rb, app/models/assistant/provided.rb, app/models/assistant.rb
Refactors prompt selection to prefer family custom prompts and threads family through model/provider selection.

Sequence Diagram

sequenceDiagram
    participant Browser as User (Browser)
    participant Controller as ChatsController / MessagesController
    participant Chat as Chat Model
    participant Family as Family Record
    participant Registry as Provider::Registry
    participant Provider as Provider::Openai
    participant Assistant as Assistant

    Browser->>Controller: POST /chats or /messages (no ai_model)
    Controller->>Chat: Chat.default_model(Current.user.family)
    Chat->>Family: read preferred_ai_model/custom prompts
    alt family has preferred_ai_model
        Family-->>Chat: family preferred_ai_model
    else
        Chat-->>Chat: fallback to ENV/Setting/default
    end
    Chat-->>Controller: resolved ai_model

    Controller->>Assistant: create/message with ai_model and family
    Assistant->>Registry: get_model_provider(ai_model, family: family)
    Registry->>Family: check openai_uri_base & preferred_ai_model
    alt family has custom endpoint & token
        Registry->>Provider: instantiate Provider::Openai(custom uri, model)
    else
        Registry->>Provider: return default provider
    end
    Provider-->>Assistant: provider instance
    Assistant->>Assistant: apply family custom prompts if present
    Assistant-->>Browser: AI response
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~35 minutes

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • sokie

Poem

🐰 I nibble prompts with careful care,
Families choose their model, fair and square.
Endpoints tuned and settings set just right,
Custom prompts bloom in morning light.
Hop, hop — AI chats now feel delight! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Out of Scope Changes check ❓ Inconclusive The dependency addition (sidekiq-throttled) and schema cleanup (trades/holdings columns) extend beyond #938 scope but are justified as supporting infrastructure. Clarify whether trades/holdings column removal and sidekiq dependency are intentional scope or should be separated into focused PRs.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main feature: editable LLM prompts and per-family preferred model selection, matching the core changes throughout the codebase.
Linked Issues check ✅ Passed All requirements from issue #938 are met: families can customize system and intro prompts, select a default AI model, and the UI provides editing with persistence.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d33c85c384

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

… tests

- Add family.openai_uri_base; when set, chat uses this endpoint for that household
- Provider::Registry.openai_for_family(family) builds provider from family endpoint and model (public)
- Assistant uses family provider when present and supports model; validation requires model when endpoint set
- AI Prompts UI: endpoint field, locale keys; controller permits openai_uri_base
- Fix: openai_for_family moved to public class method (was private, would raise)
- Assistant tests: expect get_model_provider(ai_model, family:)
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), surfaces family-aware default model selection across controllers/helpers/models, adds provider lookup for family custom endpoints, and adds API endpoint-consistency rules, tests, and verification script.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API Endpoint Consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|New checklist documenting post-commit API v1 consistency (Minitest behavioral coverage, rswag-as-docs, uniform X-Api-Key use) plus tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Add family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base); schema/version updates and unrelated schema tidying.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds constants for max lengths, length validations for new prompt/model/URI fields, predicate `custom_openai_endpoint?`, and a validation enforcing model presence when custom endpoint set.|\n|**Default model selection (family-aware)** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Chat.default_model now accepts optional `family` and prioritizes family.preferred_ai_model; callers updated to pass family where applicable; tests adjusted.|\n|**Provider lookup / assistant changes** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Provider lookup gains optional `family:` argument and attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when present; tests updated to pass family.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds update action, strong params, set_family before_action, edit form/view, route to allow update, new locale keys, and comprehensive controller tests covering save/validation/clear behaviors.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now sources family.custom_system_prompt / custom_intro_prompt when present before falling back to defaults.|\n|**Misc — helpers/controllers** <br> `app/helpers/application_helper.rb`, `app/controllers/*` (various) |Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~25 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the API endpoint-consistency checklist and tests described in `#944`.\n- **#938**: Implements editable per-family prompts and preferred model, aligning with the editable LLM prompts feature request.\n\n## Possibly related PRs\n\n- **#225**: Related changes to default-model selection; this PR extends that logic to be family-aware and propagates it across callers.\n\n## Suggested labels\n\n`codex`\n\n## Suggested reviewers\n\n- jjmata\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked in nests for model tweaks,  \n> > Chats find their voice with tailored art,  \n> > Providers follow each family's heart,  \n> > Hopping on tests to keep rules neat and sweet. 🥕\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (2 warnings)</summary>\n\n|         Check name         | Status     | Explanation                                                                                                                                                                        | Resolution                                                                                                                                               |\n| :------------------------: | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Out of Scope Changes check | ⚠️ Warning | The PR includes one out-of-scope addition: sidekiq-throttled gem dependency was added to allow test suite boot, which is unrelated to the prompt/model editing feature objectives. | Remove sidekiq-throttled dependency or clarify its necessity; if required for tests, document this as a separate concern outside the main feature scope. |\n|     Docstring Coverage     | ⚠️ Warning | Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%.                                                                                               | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                       |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                           |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                           |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately reflects the main changes: adding editable AI prompt settings and per-family model selection features.                                               |\n| Linked Issues check | ✅ Passed | The PR implements the core objectives from `#938`: allows households to customize assistant prompts via new Family columns and editable UI, supports per-family preferred AI model selection, and provides persistence with validation. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>app/models/family.rb (1)</summary><blockquote>\n\n`42-57`: **Consider adding a format validation for `openai_uri_base`.**\n\nThe field accepts any string up to 512 characters. A basic URI format check (e.g., must start with `https://`) would prevent accidental misconfiguration and provide clearer feedback to the user.\n\n<details>\n<summary>💡 Suggested validation</summary>\n\n```diff\n  validates :openai_uri_base, length: { maximum: OPENAI_URI_BASE_MAX_LENGTH }, allow_blank: true\n+ validates :openai_uri_base, format: { with: /\\Ahttps?:\\/\\//i, message: :invalid_url }, if: -> { openai_uri_base.present? }\n  validate :openai_model_required_when_custom_endpoint\n```\n</details>\n\n</blockquote></details>\n<details>\n<summary>app/views/settings/ai_prompts/show.html.erb (1)</summary><blockquote>\n\n`54-58`: **Error block uses raw color values instead of design system tokens.**\n\nThe error container uses `border-red-200 bg-red-50 text-red-800` directly. Per the coding guidelines, prefer functional design system tokens (e.g., `text-destructive`, `bg-destructive`, `border-destructive`) from `maybe-design-system.css` instead of raw Tailwind color values.\n\nAlso, consider moving the error block **above** the form fields (after the section title) so validation errors are immediately visible to the user without scrolling past the form.\n\n</blockquote></details>\n<details>\n<summary>app/models/provider/registry.rb (1)</summary><blockquote>\n\n`21-33`: **Consider extracting shared token resolution to reduce duplication.**\n\nThe token lookup on line 25 duplicates line 80 in the private `openai` method. A small helper (e.g., `openai_access_token`) would keep both call-sites in sync and avoid drift.\n\n<details>\n<summary>♻️ Suggested helper extraction</summary>\n\n```diff\n+    def openai_access_token\n+      ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+    end\n+\n     def openai_for_family(family)\n       return nil unless family&.custom_openai_endpoint?\n       return nil unless family.preferred_ai_model.present?\n\n-      access_token = ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+      access_token = openai_access_token\n       return nil unless access_token.present?\n\n       Provider::Openai.new(\n         access_token,\n         uri_base: family.openai_uri_base,\n         model: family.preferred_ai_model\n       )\n     end\n```\n\nAnd update the private `openai` method similarly:\n\n```diff\n     def openai\n-      access_token = ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+      access_token = openai_access_token\n       return nil unless access_token.present?\n```\n</details>\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:07:38 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"388E:2AD39D:160A3C0:5CA0E74:698A0648","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4903","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"97","x-xss-protection":"0"},"data":""}}

1 similar comment
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), surfaces family-aware default model selection across controllers/helpers/models, adds provider lookup for family custom endpoints, and adds API endpoint-consistency rules, tests, and verification script.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API Endpoint Consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|New checklist documenting post-commit API v1 consistency (Minitest behavioral coverage, rswag-as-docs, uniform X-Api-Key use) plus tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Add family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base); schema/version updates and unrelated schema tidying.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds constants for max lengths, length validations for new prompt/model/URI fields, predicate `custom_openai_endpoint?`, and a validation enforcing model presence when custom endpoint set.|\n|**Default model selection (family-aware)** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Chat.default_model now accepts optional `family` and prioritizes family.preferred_ai_model; callers updated to pass family where applicable; tests adjusted.|\n|**Provider lookup / assistant changes** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Provider lookup gains optional `family:` argument and attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when present; tests updated to pass family.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds update action, strong params, set_family before_action, edit form/view, route to allow update, new locale keys, and comprehensive controller tests covering save/validation/clear behaviors.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now sources family.custom_system_prompt / custom_intro_prompt when present before falling back to defaults.|\n|**Misc — helpers/controllers** <br> `app/helpers/application_helper.rb`, `app/controllers/*` (various) |Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 3 (Moderate) | ⏱️ ~25 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the API endpoint-consistency checklist and tests described in `#944`.\n- **#938**: Implements editable per-family prompts and preferred model, aligning with the editable LLM prompts feature request.\n\n## Possibly related PRs\n\n- **#225**: Related changes to default-model selection; this PR extends that logic to be family-aware and propagates it across callers.\n\n## Suggested labels\n\n`codex`\n\n## Suggested reviewers\n\n- jjmata\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked in nests for model tweaks,  \n> > Chats find their voice with tailored art,  \n> > Providers follow each family's heart,  \n> > Hopping on tests to keep rules neat and sweet. 🥕\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (2 warnings)</summary>\n\n|         Check name         | Status     | Explanation                                                                                                                                                                        | Resolution                                                                                                                                               |\n| :------------------------: | :--------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| Out of Scope Changes check | ⚠️ Warning | The PR includes one out-of-scope addition: sidekiq-throttled gem dependency was added to allow test suite boot, which is unrelated to the prompt/model editing feature objectives. | Remove sidekiq-throttled dependency or clarify its necessity; if required for tests, document this as a separate concern outside the main feature scope. |\n|     Docstring Coverage     | ⚠️ Warning | Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%.                                                                                               | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                       |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                           |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                           |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately reflects the main changes: adding editable AI prompt settings and per-family model selection features.                                               |\n| Linked Issues check | ✅ Passed | The PR implements the core objectives from `#938`: allows households to customize assistant prompts via new Family columns and editable UI, supports per-family preferred AI model selection, and provides persistence with validation. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<details>\n<summary>🧹 Recent nitpick comments</summary><blockquote>\n\n<details>\n<summary>app/models/family.rb (1)</summary><blockquote>\n\n`42-57`: **Consider adding a format validation for `openai_uri_base`.**\n\nThe field accepts any string up to 512 characters. A basic URI format check (e.g., must start with `https://`) would prevent accidental misconfiguration and provide clearer feedback to the user.\n\n<details>\n<summary>💡 Suggested validation</summary>\n\n```diff\n  validates :openai_uri_base, length: { maximum: OPENAI_URI_BASE_MAX_LENGTH }, allow_blank: true\n+ validates :openai_uri_base, format: { with: /\\Ahttps?:\\/\\//i, message: :invalid_url }, if: -> { openai_uri_base.present? }\n  validate :openai_model_required_when_custom_endpoint\n```\n</details>\n\n</blockquote></details>\n<details>\n<summary>app/views/settings/ai_prompts/show.html.erb (1)</summary><blockquote>\n\n`54-58`: **Error block uses raw color values instead of design system tokens.**\n\nThe error container uses `border-red-200 bg-red-50 text-red-800` directly. Per the coding guidelines, prefer functional design system tokens (e.g., `text-destructive`, `bg-destructive`, `border-destructive`) from `maybe-design-system.css` instead of raw Tailwind color values.\n\nAlso, consider moving the error block **above** the form fields (after the section title) so validation errors are immediately visible to the user without scrolling past the form.\n\n</blockquote></details>\n<details>\n<summary>app/models/provider/registry.rb (1)</summary><blockquote>\n\n`21-33`: **Consider extracting shared token resolution to reduce duplication.**\n\nThe token lookup on line 25 duplicates line 80 in the private `openai` method. A small helper (e.g., `openai_access_token`) would keep both call-sites in sync and avoid drift.\n\n<details>\n<summary>♻️ Suggested helper extraction</summary>\n\n```diff\n+    def openai_access_token\n+      ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+    end\n+\n     def openai_for_family(family)\n       return nil unless family&.custom_openai_endpoint?\n       return nil unless family.preferred_ai_model.present?\n\n-      access_token = ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+      access_token = openai_access_token\n       return nil unless access_token.present?\n\n       Provider::Openai.new(\n         access_token,\n         uri_base: family.openai_uri_base,\n         model: family.preferred_ai_model\n       )\n     end\n```\n\nAnd update the private `openai` method similarly:\n\n```diff\n     def openai\n-      access_token = ENV[\"OPENAI_ACCESS_TOKEN\"].presence || Setting.openai_access_token\n+      access_token = openai_access_token\n       return nil unless access_token.present?\n```\n</details>\n\n</blockquote></details>\n\n</blockquote></details>\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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= -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:07:38 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"388E:2AD39D:160A3C0:5CA0E74:698A0648","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4903","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"97","x-xss-protection":"0"},"data":""}}

- before_action :ensure_admin for show and update; redirect non-admins with alert
- Add not_authorized locale; tests for show/update requiring admin
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), makes default model selection family-aware across controllers/helpers/models, adds family-scoped provider lookup for custom OpenAI endpoints, and introduces API endpoint-consistency rules plus tests and a verifier.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API endpoint-consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|Adds a post-commit checklist for API v1 consistency (Minitest behavioral coverage, rswag-as-docs, unified X-Api-Key pattern) plus unit tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Adds family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base) and bumps schema; other unrelated schema tidy.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds length constants and validations for new fields, predicate `custom_openai_endpoint?`, and cross-field validation requiring preferred_ai_model when openai_uri_base is set.|\n|**Family-aware default model selection** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Introduces `Chat.default_model(family = nil)` prioritizing family.preferred_ai_model; callers updated to pass family where appropriate; tests adjusted.|\n|**Provider lookup / assistant plumbing** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Adds optional `family:` arg to provider lookup, attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when configured, otherwise falls back to global providers; tests updated.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds edit/update flow for per-family AI prompts and preferred model (controller actions, strong params, view, route, locales) with comprehensive controller tests covering save, validation, and clearing overrides.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now prefers family.custom_intro_prompt / custom_system_prompt and per-family formats before falling back to defaults.|\n|**Helpers / controllers & minor updates** <br> `app/helpers/application_helper.rb`, various controller call sites|Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the post-commit API endpoint-consistency checklist, tests, and verifier described in that issue.\n\n## Possibly related PRs\n\n- **#225**: Related — modifies default-model selection; this change extends and passes family through default_model.\n- **#213**: Related — overlaps provider/registry changes to support custom endpoints and model plumbing.\n- **#223**: Related — both add per-family OpenAI endpoint/model support and touch provider/usage plumbing.\n\n## Suggested labels\n\n`enhancement`\n\n## Suggested reviewers\n\n- jjmata\n- sokie\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked neat for model tweaks,  \n> > Chats choose a voice that's set by home,  \n> > Providers follow each family's dome,  \n> > Hopping on tests to keep rules mild and sweet.\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning, 1 inconclusive)</summary>\n\n|         Check name         | Status         | Explanation                                                                                                                                                                                                                                                    | Resolution                                                                                                                                                                                                                          |\n| :------------------------: | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|     Docstring Coverage     | ⚠️ Warning     | Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                           | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                                                                                                  |\n| Out of Scope Changes check | ❓ Inconclusive | Changes are within scope of `#938`. The sidekiq-throttled dependency addition and schema changes (accounts table modifications, snaptrade_accounts, trades columns) appear necessary for the project but are not directly related to the PR's stated objectives. | Clarify whether schema changes to accounts, snaptrade_accounts, and trades tables, plus the sidekiq-throttled gem addition, are dependencies required by this PR or unrelated changes that should be separated into a different PR. |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                                             |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                                             |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately describes the main changes: adding editable prompt fields and per-family model selection in the PR.                                                                    |\n| Linked Issues check | ✅ Passed | All coding requirements from issue `#938` are met: custom prompts (system/intro) stored per-family, preferred AI model per-family with defaults, Settings UI for editing with validation, and assistant behavior respects custom prompts/models when set. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:13:22 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"4016:3F62B1:10B2454:48358D2:698A079D","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4860","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"140","x-xss-protection":"0"},"data":""}}

3 similar comments
@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), makes default model selection family-aware across controllers/helpers/models, adds family-scoped provider lookup for custom OpenAI endpoints, and introduces API endpoint-consistency rules plus tests and a verifier.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API endpoint-consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|Adds a post-commit checklist for API v1 consistency (Minitest behavioral coverage, rswag-as-docs, unified X-Api-Key pattern) plus unit tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Adds family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base) and bumps schema; other unrelated schema tidy.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds length constants and validations for new fields, predicate `custom_openai_endpoint?`, and cross-field validation requiring preferred_ai_model when openai_uri_base is set.|\n|**Family-aware default model selection** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Introduces `Chat.default_model(family = nil)` prioritizing family.preferred_ai_model; callers updated to pass family where appropriate; tests adjusted.|\n|**Provider lookup / assistant plumbing** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Adds optional `family:` arg to provider lookup, attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when configured, otherwise falls back to global providers; tests updated.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds edit/update flow for per-family AI prompts and preferred model (controller actions, strong params, view, route, locales) with comprehensive controller tests covering save, validation, and clearing overrides.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now prefers family.custom_intro_prompt / custom_system_prompt and per-family formats before falling back to defaults.|\n|**Helpers / controllers & minor updates** <br> `app/helpers/application_helper.rb`, various controller call sites|Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the post-commit API endpoint-consistency checklist, tests, and verifier described in that issue.\n\n## Possibly related PRs\n\n- **#225**: Related — modifies default-model selection; this change extends and passes family through default_model.\n- **#213**: Related — overlaps provider/registry changes to support custom endpoints and model plumbing.\n- **#223**: Related — both add per-family OpenAI endpoint/model support and touch provider/usage plumbing.\n\n## Suggested labels\n\n`enhancement`\n\n## Suggested reviewers\n\n- jjmata\n- sokie\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked neat for model tweaks,  \n> > Chats choose a voice that's set by home,  \n> > Providers follow each family's dome,  \n> > Hopping on tests to keep rules mild and sweet.\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning, 1 inconclusive)</summary>\n\n|         Check name         | Status         | Explanation                                                                                                                                                                                                                                                    | Resolution                                                                                                                                                                                                                          |\n| :------------------------: | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|     Docstring Coverage     | ⚠️ Warning     | Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                           | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                                                                                                  |\n| Out of Scope Changes check | ❓ Inconclusive | Changes are within scope of `#938`. The sidekiq-throttled dependency addition and schema changes (accounts table modifications, snaptrade_accounts, trades columns) appear necessary for the project but are not directly related to the PR's stated objectives. | Clarify whether schema changes to accounts, snaptrade_accounts, and trades tables, plus the sidekiq-throttled gem addition, are dependencies required by this PR or unrelated changes that should be separated into a different PR. |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                                             |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                                             |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately describes the main changes: adding editable prompt fields and per-family model selection in the PR.                                                                    |\n| Linked Issues check | ✅ Passed | All coding requirements from issue `#938` are met: custom prompts (system/intro) stored per-family, preferred AI model per-family with defaults, Settings UI for editing with validation, and assistant behavior respects custom prompts/models when set. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:13:22 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"4016:3F62B1:10B2454:48358D2:698A079D","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4860","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"140","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), makes default model selection family-aware across controllers/helpers/models, adds family-scoped provider lookup for custom OpenAI endpoints, and introduces API endpoint-consistency rules plus tests and a verifier.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API endpoint-consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|Adds a post-commit checklist for API v1 consistency (Minitest behavioral coverage, rswag-as-docs, unified X-Api-Key pattern) plus unit tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Adds family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base) and bumps schema; other unrelated schema tidy.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds length constants and validations for new fields, predicate `custom_openai_endpoint?`, and cross-field validation requiring preferred_ai_model when openai_uri_base is set.|\n|**Family-aware default model selection** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Introduces `Chat.default_model(family = nil)` prioritizing family.preferred_ai_model; callers updated to pass family where appropriate; tests adjusted.|\n|**Provider lookup / assistant plumbing** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Adds optional `family:` arg to provider lookup, attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when configured, otherwise falls back to global providers; tests updated.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds edit/update flow for per-family AI prompts and preferred model (controller actions, strong params, view, route, locales) with comprehensive controller tests covering save, validation, and clearing overrides.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now prefers family.custom_intro_prompt / custom_system_prompt and per-family formats before falling back to defaults.|\n|**Helpers / controllers & minor updates** <br> `app/helpers/application_helper.rb`, various controller call sites|Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the post-commit API endpoint-consistency checklist, tests, and verifier described in that issue.\n\n## Possibly related PRs\n\n- **#225**: Related — modifies default-model selection; this change extends and passes family through default_model.\n- **#213**: Related — overlaps provider/registry changes to support custom endpoints and model plumbing.\n- **#223**: Related — both add per-family OpenAI endpoint/model support and touch provider/usage plumbing.\n\n## Suggested labels\n\n`enhancement`\n\n## Suggested reviewers\n\n- jjmata\n- sokie\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked neat for model tweaks,  \n> > Chats choose a voice that's set by home,  \n> > Providers follow each family's dome,  \n> > Hopping on tests to keep rules mild and sweet.\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning, 1 inconclusive)</summary>\n\n|         Check name         | Status         | Explanation                                                                                                                                                                                                                                                    | Resolution                                                                                                                                                                                                                          |\n| :------------------------: | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|     Docstring Coverage     | ⚠️ Warning     | Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                           | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                                                                                                  |\n| Out of Scope Changes check | ❓ Inconclusive | Changes are within scope of `#938`. The sidekiq-throttled dependency addition and schema changes (accounts table modifications, snaptrade_accounts, trades columns) appear necessary for the project but are not directly related to the PR's stated objectives. | Clarify whether schema changes to accounts, snaptrade_accounts, and trades tables, plus the sidekiq-throttled gem addition, are dependencies required by this PR or unrelated changes that should be separated into a different PR. |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                                             |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                                             |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately describes the main changes: adding editable prompt fields and per-family model selection in the PR.                                                                    |\n| Linked Issues check | ✅ Passed | All coding requirements from issue `#938` are met: custom prompts (system/intro) stored per-family, preferred AI model per-family with defaults, Settings UI for editing with validation, and assistant behavior respects custom prompts/models when set. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:13:22 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"4016:3F62B1:10B2454:48358D2:698A079D","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4860","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"140","x-xss-protection":"0"},"data":""}}

@coderabbitai
Copy link

coderabbitai bot commented Feb 9, 2026

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- walkthrough_start -->\n\n<details>\n<summary>📝 Walkthrough</summary>\n\n## Walkthrough\n\nAdds per-family AI prompt and model overrides (DB, validations, UI, routes, controller), makes default model selection family-aware across controllers/helpers/models, adds family-scoped provider lookup for custom OpenAI endpoints, and introduces API endpoint-consistency rules plus tests and a verifier.\n\n## Changes\n\n|Cohort / File(s)|Summary|\n|---|---|\n|**API endpoint-consistency rules & tests** <br> ` .cursor/rules/api-endpoint-consistency.mdc`, `AGENTS.md`, `test/api_endpoint_consistency_rule_test.rb`, `test/support/verify_api_endpoint_consistency.rb`|Adds a post-commit checklist for API v1 consistency (Minitest behavioral coverage, rswag-as-docs, unified X-Api-Key pattern) plus unit tests and a standalone verifier.|\n|**DB migrations & schema** <br> `db/migrate/20260209120000_add_ai_prompt_overrides_to_families.rb`, `db/migrate/20260209180000_add_openai_uri_base_to_families.rb`, `db/schema.rb`|Adds family-level columns (custom_system_prompt, custom_intro_prompt, preferred_ai_model, openai_uri_base) and bumps schema; other unrelated schema tidy.|\n|**Family model & validations** <br> `app/models/family.rb`|Adds length constants and validations for new fields, predicate `custom_openai_endpoint?`, and cross-field validation requiring preferred_ai_model when openai_uri_base is set.|\n|**Family-aware default model selection** <br> `app/models/chat.rb`, `app/helpers/application_helper.rb`, `app/controllers/api/v1/chats_controller.rb`, `app/controllers/api/v1/messages_controller.rb`, `app/controllers/chats_controller.rb`, `app/controllers/messages_controller.rb`, `test/models/chat_test.rb`|Introduces `Chat.default_model(family = nil)` prioritizing family.preferred_ai_model; callers updated to pass family where appropriate; tests adjusted.|\n|**Provider lookup / assistant plumbing** <br> `app/models/assistant.rb`, `app/models/assistant/provided.rb`, `app/models/provider/registry.rb`, `test/models/assistant_test.rb`|Adds optional `family:` arg to provider lookup, attempts to instantiate an OpenAI provider from family.openai_uri_base + preferred_ai_model when configured, otherwise falls back to global providers; tests updated.|\n|**AI Prompts settings UI & controller** <br> `app/controllers/settings/ai_prompts_controller.rb`, `app/views/settings/ai_prompts/show.html.erb`, `config/routes.rb`, `config/locales/views/settings/en.yml`, `test/controllers/settings/ai_prompts_controller_test.rb`|Adds edit/update flow for per-family AI prompts and preferred model (controller actions, strong params, view, route, locales) with comprehensive controller tests covering save, validation, and clearing overrides.|\n|**Assistant configuration usage** <br> `app/models/assistant/configurable.rb`|config_for now prefers family.custom_intro_prompt / custom_system_prompt and per-family formats before falling back to defaults.|\n|**Helpers / controllers & minor updates** <br> `app/helpers/application_helper.rb`, various controller call sites|Helpers and controllers updated to use family-aware default model selection.|\n|**Dependencies** <br> `Gemfile`|Adds `sidekiq-throttled` gem.|\n\n## Sequence Diagram(s)\n\n```mermaid\nsequenceDiagram\n    participant User\n    participant Controller\n    participant ChatModel as Chat Model\n    participant Family\n    participant ProviderRegistry as Provider Registry\n    participant Assistant\n\n    User->>Controller: create chat / send message\n    Controller->>ChatModel: default_model(family)\n    ChatModel->>Family: read preferred_ai_model\n    alt family.preferred_ai_model present\n        Family-->>ChatModel: return preferred_ai_model\n        ChatModel-->>Controller: selected model\n    else\n        ChatModel->>ProviderRegistry: check ENV / Setting / default\n        ProviderRegistry-->>ChatModel: return default model\n        ChatModel-->>Controller: selected model\n    end\n    Controller->>ProviderRegistry: get_model_provider(model, family: family)\n    alt family has custom endpoint + token\n        ProviderRegistry-->>Assistant: instantiate Provider::Openai with family's uri_base & model\n    else\n        ProviderRegistry-->>Assistant: return global provider for model\n    end\n    Assistant-->>Controller: assistant configured / response\n```\n\n## Estimated code review effort\n\n🎯 4 (Complex) | ⏱️ ~45 minutes\n\n## Possibly related issues\n\n- **#944**: Implements the post-commit API endpoint-consistency checklist, tests, and verifier described in that issue.\n\n## Possibly related PRs\n\n- **#225**: Related — modifies default-model selection; this change extends and passes family through default_model.\n- **#213**: Related — overlaps provider/registry changes to support custom endpoints and model plumbing.\n- **#223**: Related — both add per-family OpenAI endpoint/model support and touch provider/usage plumbing.\n\n## Suggested labels\n\n`enhancement`\n\n## Suggested reviewers\n\n- jjmata\n- sokie\n\n## Poem\n\n> 🐰 In burrows of code the family speaks,  \n> > Prompts tucked neat for model tweaks,  \n> > Chats choose a voice that's set by home,  \n> > Providers follow each family's dome,  \n> > Hopping on tests to keep rules mild and sweet.\n\n</details>\n\n<!-- walkthrough_end -->\n\n\n<!-- pre_merge_checks_walkthrough_start -->\n\n<details>\n<summary>🚥 Pre-merge checks | ✅ 3 | ❌ 2</summary>\n\n<details>\n<summary>❌ Failed checks (1 warning, 1 inconclusive)</summary>\n\n|         Check name         | Status         | Explanation                                                                                                                                                                                                                                                    | Resolution                                                                                                                                                                                                                          |\n| :------------------------: | :------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |\n|     Docstring Coverage     | ⚠️ Warning     | Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%.                                                                                                                                                                           | Write docstrings for the functions missing them to satisfy the coverage threshold.                                                                                                                                                  |\n| Out of Scope Changes check | ❓ Inconclusive | Changes are within scope of `#938`. The sidekiq-throttled dependency addition and schema changes (accounts table modifications, snaptrade_accounts, trades columns) appear necessary for the project but are not directly related to the PR's stated objectives. | Clarify whether schema changes to accounts, snaptrade_accounts, and trades tables, plus the sidekiq-throttled gem addition, are dependencies required by this PR or unrelated changes that should be separated into a different PR. |\n\n</details>\n<details>\n<summary>✅ Passed checks (3 passed)</summary>\n\n|      Check name     | Status   | Explanation                                                                                                                                                                                                                                             |\n| :-----------------: | :------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |\n|  Description Check  | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled.                                                                                                                                                                                             |\n|     Title check     | ✅ Passed | The title 'feat: editable LLM prompts and per-family preferred model' accurately describes the main changes: adding editable prompt fields and per-family model selection in the PR.                                                                    |\n| Linked Issues check | ✅ Passed | All coding requirements from issue `#938` are met: custom prompts (system/intro) stored per-family, preferred AI model per-family with defaults, Settings UI for editing with validation, and assistant behavior respects custom prompts/models when set. |\n\n</details>\n\n<sub>✏️ Tip: You can configure your own custom pre-merge checks in the settings.</sub>\n\n</details>\n\n<!-- pre_merge_checks_walkthrough_end -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing touches</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> 📝 Generate docstrings\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"07f1e7d6-8a8e-4e23-9900-8731c2c87f58\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Post copyable unit tests in a comment\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n\n\n---\n\nNo actionable comments were generated in the recent review. 🎉\n\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=we-promise/sure&utm_content=951)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n<sub>Comment `@coderabbitai help` to get the list of available commands and usage tips.</sub>\n\n<!-- tips_end -->\n\n<!-- internal state start -->\n\n\n<!-- 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 -->\n\n<!-- internal state end -->"},"request":{"retryCount":3,"retries":3,"retryAfter":16}},"response":{"url":"https://api.github.com/repos/we-promise/sure/issues/comments/3872466911","status":500,"headers":{"access-control-allow-origin":"*","access-control-expose-headers":"ETag, Link, Location, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Used, X-RateLimit-Resource, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval, X-GitHub-Media-Type, X-GitHub-SSO, X-GitHub-Request-Id, Deprecation, Sunset","content-length":"0","content-security-policy":"default-src 'none'","content-type":"application/json; charset=utf-8","date":"Mon, 09 Feb 2026 16:13:22 GMT","referrer-policy":"origin-when-cross-origin, strict-origin-when-cross-origin","server":"github.com","strict-transport-security":"max-age=31536000; includeSubdomains; preload","vary":"Accept-Encoding, Accept, X-Requested-With","x-accepted-github-permissions":"issues=write; pull_requests=write","x-content-type-options":"nosniff","x-frame-options":"deny","x-github-api-version-selected":"2022-11-28","x-github-media-type":"github.v3; format=json","x-github-request-id":"4016:3F62B1:10B2454:48358D2:698A079D","x-ratelimit-limit":"5000","x-ratelimit-remaining":"4860","x-ratelimit-reset":"1770655833","x-ratelimit-resource":"core","x-ratelimit-used":"140","x-xss-protection":"0"},"data":""}}

jjmata and others added 5 commits February 10, 2026 23:44
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
Signed-off-by: Juan José Mata <juanjo.mata@gmail.com>
…int_consistency.rb

- family.rb: keep AI prompt/endpoint validations and custom_openai_endpoint?; add moniker validation and moniker_label/moniker_label_plural from main
- db/schema.rb: keep schema version from main; families table includes both AI columns and vector_store_id/moniker
- verify_api_endpoint_consistency.rb: add --compliance option and comment from main
@MkDev11 MkDev11 force-pushed the feature/editable-llm-prompts-938 branch from 9d5a7de to fdbf0da Compare February 15, 2026 02:17
mkdev11 added 6 commits February 18, 2026 19:21
- assistant.rb: keep upstream module + registry; family-aware lookup in Builtin
- builtin.rb: pass family: chat.user&.family to get_model_provider
- schema.rb: keep both vector_store_id and assistant_type on families
…tantConfig

- Add builtin_assistant_configs table and BuiltinAssistantConfig model
- Backfill from families, remove custom_system_prompt, custom_intro_prompt,
  preferred_ai_model, openai_uri_base from families
- Family has_one :builtin_assistant_config; remove prompt validations from Family
- Assistant::Configurable, Provider::Registry.openai_for_family, Chat.default_model
  read from family.builtin_assistant_config
- Settings::AiPromptsController and views use builtin_assistant_config params
- Update tests and make AddAssistantTypeToFamilies migration idempotent
- Add docs/assistant_config_refactor.md and refactor review
- Add turbo_frame_tag 'modal' to properties/edit so response targets modal frame
- Fixes PropertiesEditTest#test_can_persist_property_subtype (selector not found)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Editable LLM Prompts / target model

2 participants