Skip to content

knowledge base improvements#5204

Merged
IvanIvanoff merged 4 commits into
masterfrom
knowledge-base-improvements
Jun 5, 2026
Merged

knowledge base improvements#5204
IvanIvanoff merged 4 commits into
masterfrom
knowledge-base-improvements

Conversation

@IvanIvanoff
Copy link
Copy Markdown
Member

@IvanIvanoff IvanIvanoff commented Jun 5, 2026

Changes

  • Add Knowledge Ask History context expansion badge
  • Knowledge: Support OpenRouter, record model used

Ticket

Checklist:

  • I have performed a self-review of my own code
  • I have made corresponding changes to the documentation
  • I have tried to find clearer solution before commenting hard-to-understand parts of code
  • I have added tests that prove my fix is effective or that my feature works

Summary by CodeRabbit

  • New Features

    • Answer model selection in Ask AI; OpenRouter added as an alternate AI provider
  • Behavior / UX

    • Answers now return strict structured JSON (answer, source_ids, financial_disclaimer); prompts and citation tokens standardized for reliable citation expansion
  • Admin Improvements

    • FAQ history and history view display model and context-expansion indicators
  • Database

    • Logs now persist model and context_expansion; corresponding migrations added
  • Tests

    • Expanded coverage for citation rendering, context formatting, and answer-model selection

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jun 5, 2026

Review Change Stack

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 an OpenRouter LLM client, threads optional response_format through OpenAI/OpenRouter request/retry flows, introduces Citations to render model JSON into markdown with grouped sources and sanitized links, refactors prompt assembly to use global source numbering, and persists/displays model and context-expansion metadata with migrations and UI wiring.

Changes

Knowledge Answer Citations and Multi-Model Infrastructure

Layer / File(s) Summary
LLM client infrastructure and response-format support
lib/open_router/question.ex, lib/openai/question.ex
New Sanbase.OpenRouter.Question implements OpenRouter chat-completions with retry/backoff and API-key validation. Sanbase.OpenAI.Question exposes default_model/0 and threads optional :response_format through request/retry and request body construction.
Citation rendering from JSON with safety helpers
lib/sanbase/knowledge/citations.ex, test/sanbase/knowledge/citations_test.exs
Sanbase.Knowledge.Citations provides response_format/0 (strict JSON schema) and render/2 to decode model JSON, expand [n] tokens to markdown links, compute cited ids, render grouped ### Sources, append disclaimer when requested, and sanitize URLs/labels; tests cover correctness and safety.
Context marker and prompt assembly refactor
lib/sanbase/knowledge/context.ex, lib/sanbase/knowledge/knowledge.ex, test/sanbase/knowledge/context_test.exs
Central marker/2 and source_header/2 standardize prompt headers; escape_label/1 exports safer escaping; build_question_answer_prompt/3 globally numbers sources, builds per-source hit lists, instructs models to emit strict JSON, and routes model output through Citations.render/2.
Answer model catalog and tests
lib/sanbase/knowledge/answer_model.ex, test/sanbase/knowledge/answer_model_test.exs
Adds Sanbase.Knowledge.AnswerModel catalog with selectable keys, availability gating by env, default selection, and helpers to produce :answer_client/:answer_model options; tests validate selection and resolution behavior.
Schema persistence and Ask UI wiring
lib/sanbase/knowledge/question_answer_log.ex, priv/repo/migrations/20260604*.exs, priv/repo/structure.sql, lib/sanbase_web/live/ask_live.ex, lib/sanbase_web/live/admin/faq/history_live.ex, lib/sanbase_web/live/admin/faq/history_show.ex
Adds context_expansion (boolean) and model (string) to question_answer_logs (migrations and structure.sql); AskLive initializes and persists selected answer model and context_expansion in logging; admin UI shows model and context-expansion badges/fields; structure.sql updated to match migrations.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

Suggested reviewers

  • tspenov

Poem

🐰
I number sources neat and small,
I turn model JSON into a linked hall,
I escape the traps that labels bring,
Models sing and citations spring,
Hop, render, log — knowledge for all.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The PR title 'knowledge base improvements' is vague and generic, lacking specificity about the actual changes made. Consider a more specific title that highlights the main changes, such as 'Add OpenRouter support and context expansion tracking' or 'Support multiple LLM providers and track expansion metadata'.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 93.55% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch knowledge-base-improvements

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
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/openai/question.ex (1)

22-30: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Document :response_format in ask/… tracing options.

ask now supports :response_format, but the parameter list in the doc block still omits it.

Also applies to: 45-47

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/openai/question.ex` around lines 22 - 30, The doc block for tracing_opts
on the ask/… functions is missing the newly supported :response_format option;
update the documentation for ask (and the repeated block around lines 45-47) to
include `:response_format` in the tracing_opts list, describing that it selects
the expected response format (e.g., "text", "json", or a schema) and any default
behavior, so callers of ask/… and the ask function’s tracing options know this
supported key.
🧹 Nitpick comments (3)
lib/openai/question.ex (1)

16-17: ⚡ Quick win

Add a typespec for default_model/0.

The new public function is missing an explicit @spec.

As per coding guidelines, "Add typespecs (@spec) to all public functions".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/openai/question.ex` around lines 16 - 17, The public function
default_model/0 is missing an `@spec`; add a typespec for it (e.g., `@spec`
default_model() :: String.t()) immediately above def default_model(),
referencing the existing `@model` module attribute as the returned type; ensure
the spec matches the actual type of `@model` (String.t() or atom() as appropriate)
so Dialyzer and the project's coding guidelines are satisfied.
lib/open_router/question.ex (1)

41-43: ⚡ Quick win

Add @spec declarations for the new public functions.

Please add explicit specs for the exported API (ask/..., default_model/0, configured_model/0, openrouter_apikey/0) to keep contracts analyzable and consistent with project rules.

As per coding guidelines, "Add typespecs (@spec) to all public functions".

Also applies to: 139-151

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/open_router/question.ex` around lines 41 - 43, Add explicit `@spec`
declarations for the exported API: add `@spec` ask(question :: String.t()) ::
{:ok, map()} | {:error, term()} for the ask/1 function, add `@spec`
default_model() :: String.t(), `@spec` configured_model() :: String.t(), and `@spec`
openrouter_apikey() :: String.t() | nil for the respective zero-arity helpers;
also ensure any other public functions around lines 139-151 have matching `@specs`
following the same style so the module's public contracts are fully annotated.
lib/sanbase_web/live/ask_live.ex (1)

227-244: 🏗️ Heavy lift

Migrate the new model selector to the to_form/2 + <.input> form pipeline.

This new control is wired as raw <select> + event handling, which diverges from the project’s required LiveView form pattern and makes this screen harder to keep consistent with the rest of the app.

As per coding guidelines: "When building forms, always use the already imported Phoenix.Component.to_form/2... Never pass raw changesets to templates." and "Always use a form assigned via to_form/2 in the LiveView, and the <.input> component in the template."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/sanbase_web/live/ask_live.ex` around lines 227 - 244, The
answer_model_select/1 component currently renders a raw <select> and manual
phx-change handling; refactor it to use Phoenix.Component.to_form/2 and the
project's <.input> form component: in answer_model_select/1 assign a form (e.g.,
assign(assigns, :form, to_form(assigns.form_changeset_or_params, name: "ask")))
and assign :models from Sanbase.Knowledge.answer_models(); then replace the raw
select with <.input type="select" field={:answer_model} form={`@form`}
options={Enum.map(`@models`, &{&1.label, &1.key})} /> (remove the manual
phx-change and selected logic). Keep the same field name "answer_model" so
existing handlers continue to work and ensure the LiveView sets/updates the form
assign used by to_form/2.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/sanbase/knowledge/citations.ex`:
- Around line 170-177: The markdown link interpolation in link/1 and
labelled_link/1 currently injects raw url into "[label](url)"; validate and
sanitize the URL before interpolation by parsing it (e.g., via URI.parse),
ensuring the scheme is "http" or "https", and rejecting or skipping entries with
other schemes, and escape/percent-encode any characters that could break
markdown (parentheses, angle brackets, spaces) so the final string uses a safe,
canonical URL; keep using Context.escape_label(label) for the label and only
interpolate the sanitized/validated URL into the returned string.

In `@lib/sanbase/knowledge/knowledge.ex`:
- Around line 288-301: The function answer_academy_hits currently swallows
non-{:ok, _} results from Sanbase.Knowledge.Academy.search_chunks by returning
{:ok, []}; change it to propagate errors instead: use a with to call
Sanbase.Knowledge.Academy.search_chunks(embedding, `@retrieval_top_k`) and only on
{:ok, raw_chunks} run the pipeline (filter_by_similarity, rerank,
diversify_by_document, maybe_expand_context) and return {:ok, hits}, but on any
non-{:ok, reason} return that {:error, reason} so backend failures are not
masked.

In
`@priv/repo/migrations/20260604120000_add_context_expansion_to_question_answer_logs.exs`:
- Around line 5-7: Update the migration so the new column is non-null with a
default false: in the alter table(:question_answer_logs) block change
add(:context_expansion, :boolean) to add(:context_expansion, :boolean, default:
false, null: false) so existing rows become false and the DB enforces a boolean
(no nil); reference the :question_answer_logs table and :context_expansion
column in the migration file to locate the change.

---

Outside diff comments:
In `@lib/openai/question.ex`:
- Around line 22-30: The doc block for tracing_opts on the ask/… functions is
missing the newly supported :response_format option; update the documentation
for ask (and the repeated block around lines 45-47) to include
`:response_format` in the tracing_opts list, describing that it selects the
expected response format (e.g., "text", "json", or a schema) and any default
behavior, so callers of ask/… and the ask function’s tracing options know this
supported key.

---

Nitpick comments:
In `@lib/open_router/question.ex`:
- Around line 41-43: Add explicit `@spec` declarations for the exported API: add
`@spec` ask(question :: String.t()) :: {:ok, map()} | {:error, term()} for the
ask/1 function, add `@spec` default_model() :: String.t(), `@spec`
configured_model() :: String.t(), and `@spec` openrouter_apikey() :: String.t() |
nil for the respective zero-arity helpers; also ensure any other public
functions around lines 139-151 have matching `@specs` following the same style so
the module's public contracts are fully annotated.

In `@lib/openai/question.ex`:
- Around line 16-17: The public function default_model/0 is missing an `@spec`;
add a typespec for it (e.g., `@spec` default_model() :: String.t()) immediately
above def default_model(), referencing the existing `@model` module attribute as
the returned type; ensure the spec matches the actual type of `@model` (String.t()
or atom() as appropriate) so Dialyzer and the project's coding guidelines are
satisfied.

In `@lib/sanbase_web/live/ask_live.ex`:
- Around line 227-244: The answer_model_select/1 component currently renders a
raw <select> and manual phx-change handling; refactor it to use
Phoenix.Component.to_form/2 and the project's <.input> form component: in
answer_model_select/1 assign a form (e.g., assign(assigns, :form,
to_form(assigns.form_changeset_or_params, name: "ask"))) and assign :models from
Sanbase.Knowledge.answer_models(); then replace the raw select with <.input
type="select" field={:answer_model} form={`@form`} options={Enum.map(`@models`,
&{&1.label, &1.key})} /> (remove the manual phx-change and selected logic). Keep
the same field name "answer_model" so existing handlers continue to work and
ensure the LiveView sets/updates the form assign used by to_form/2.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 207ef979-921d-4992-bd2a-f6eb018186a0

📥 Commits

Reviewing files that changed from the base of the PR and between 61333db and 8705fc7.

📒 Files selected for processing (14)
  • lib/open_router/question.ex
  • lib/openai/question.ex
  • lib/sanbase/knowledge/citations.ex
  • lib/sanbase/knowledge/context.ex
  • lib/sanbase/knowledge/knowledge.ex
  • lib/sanbase/knowledge/question_answer_log.ex
  • lib/sanbase_web/live/admin/faq/history_live.ex
  • lib/sanbase_web/live/admin/faq/history_show.ex
  • lib/sanbase_web/live/ask_live.ex
  • priv/repo/migrations/20260604120000_add_context_expansion_to_question_answer_logs.exs
  • priv/repo/migrations/20260604130000_add_model_to_question_answer_logs.exs
  • priv/repo/structure.sql
  • test/sanbase/knowledge/citations_test.exs
  • test/sanbase/knowledge/context_test.exs

Comment thread lib/sanbase/knowledge/citations.ex Outdated
Comment thread lib/sanbase/knowledge/knowledge.ex
@IvanIvanoff IvanIvanoff force-pushed the knowledge-base-improvements branch from 8705fc7 to f4fb672 Compare June 5, 2026 08:52
@IvanIvanoff IvanIvanoff force-pushed the knowledge-base-improvements branch from f4fb672 to 4e01873 Compare June 5, 2026 09:38
@IvanIvanoff IvanIvanoff force-pushed the knowledge-base-improvements branch from 1b1c3c0 to 972d3ba Compare June 5, 2026 11:42
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/sanbase_web/live/ask_live.ex (1)

95-97: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate the selected model key in the event handler.

The "select_answer_model" event handler accepts any string from the client without validation. If a user sends an invalid or malicious key (e.g., via browser devtools), it will be stored in the socket and later passed to AnswerModel.options_for/1, which returns [] for unknown keys (falling back to the default). While this is safe, explicitly validating the key provides better defense-in-depth and clearer error handling.

🔒 Proposed fix to validate the model key
   `@impl` true
   def handle_event("select_answer_model", %{"answer_model" => key}, socket) do
-    {:noreply, assign(socket, :answer_model, key)}
+    valid_keys = Enum.map(AnswerModel.selectable(), & &1.key)
+    
+    if key in valid_keys do
+      {:noreply, assign(socket, :answer_model, key)}
+    else
+      {:noreply, socket}
+    end
   end

Alternatively, add a flash message for invalid selections.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/sanbase_web/live/ask_live.ex` around lines 95 - 97, The handler
handle_event("select_answer_model", %{"answer_model" => key}, socket) currently
assigns any client-provided string; update it to validate the key against the
known set of models (e.g., via AnswerModel.options_for/1 or a new
AnswerModel.valid?/1 or list of allowed keys) before assigning to :answer_model,
and if invalid either ignore the change (keep existing
socket.assigns.answer_model) or set a safe default and optionally push a
flash/error; ensure the validation logic lives in the handler so malicious or
unknown keys are never directly stored in the socket.
🧹 Nitpick comments (2)
lib/sanbase_web/live/ask_live.ex (1)

11-23: Depends on AnswerModel.default_key/0 fix.

Line 18 calls AnswerModel.default_key() during mount. If the fix for the empty-list crash in answer_model.ex is not applied, this LiveView will crash on mount when no models are selectable.

Ensure the fix for AnswerModel.default_key/0 is applied before deploying this LiveView change, or add defensive handling here:

answer_model: AnswerModel.default_key() || "gpt-5-nano"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/sanbase_web/live/ask_live.ex` around lines 11 - 23, The mount assigns
answer_model via AnswerModel.default_key() which can crash if that function
returns nil/raises; either ensure the fix is applied inside
AnswerModel.default_key/0 so it never returns nil, or change the LiveView mount
to defensively set answer_model to a safe fallback (e.g. use
AnswerModel.default_key() || "gpt-5-nano") before assigning; update the mount
function (the assign call that sets :answer_model) to use this fallback or
verify AnswerModel.default_key/0 behavior to prevent mount crashes.
test/sanbase/knowledge/answer_model_test.exs (1)

26-30: ⚡ Quick win

Add test coverage for default_key/0 when no models are available.

The current test only validates the happy path. Add a test case that verifies behavior when selectable/0 returns an empty list (e.g., when all requires_env conditions fail). Given the main module currently uses hd/1 unsafely, this test would help document the expected behavior once that issue is fixed.

🧪 Proposed test for edge case
   describe "default_key/0" do
     test "is the first available entry (always present gpt-5-nano)" do
       assert AnswerModel.default_key() == "gpt-5-nano"
     end
+
+    # This test would require the ability to clear env vars in test, or mock selectable/0
+    # Uncomment once default_key/0 handles empty list gracefully
+    # test "raises when no models are available" do
+    #   # Would need to mock System.get_env to return nil for all requires_env checks
+    #   assert_raise RuntimeError, ~r/No selectable answer models/, fn ->
+    #     AnswerModel.default_key()
+    #   end
+    # end
   end

Based on learnings: Focus on testing public context APIs and structure tests with Arrange-Act-Assert pattern.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/sanbase/knowledge/answer_model_test.exs` around lines 26 - 30, Add a
test in test/sanbase/knowledge/answer_model_test.exs that simulates
AnswerModel.selectable/0 returning an empty list and asserts the current
behavior of AnswerModel.default_key/0 in that case; specifically, stub or
temporarily override selectable/0 to return [] and assert that calling
default_key/0 raises an ArgumentError (hd/1 on empty list) so the edge case is
covered and documented until the hd/1 usage in default_key/0 is made safe.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@lib/sanbase/knowledge/answer_model.ex`:
- Around line 54-56: Replace the unsafe hd(selectable()) in default_key/0 with a
safe lookup using List.first(selectable()) and return a safe result (e.g. {:ok,
key} when a model exists or {:error, :no_models_available} when the list is
empty); update callers (notably the LiveView mount in ask_live.ex) to
pattern-match on the tuple and handle the {:error, :no_models_available} case
gracefully instead of crashing.
- Around line 24-44: The `@models` list contains invalid OpenAI model IDs for the
entries with key "gpt-5-nano" and "gpt-5-mini"; update the model fields in those
map entries (referenced in the module's `@models`) to the correct OpenAI
identifiers (for example replace "gpt-5-nano" -> "gpt-5.4-nano" and "gpt-5-mini"
-> "gpt-5.4-mini" or another supported ID like "gpt-5.5" as appropriate), or
alternatively read the desired model from configuration/env and use that value
as the model field to provide a safe fallback; ensure the client remains
Sanbase.OpenAI.Question and keep the keys/labels intact.
- Around line 46-89: Add doctest-style usage examples to each public function's
`@doc`: include minimal example calls and expected return forms for selectable/0,
default_key/0, options_for/1, client/1 and resolve/1 so docs compile as tests;
update the `@doc` for selectable(), default_key(), options_for(key),
client(options) and resolve(options \\ []) to show one concrete call (e.g.
calling selectable() and showing a list/map shape, calling
options_for("some_key") returning a keyword list or [], client/1 returning a
module, resolve/1 returning a string) while keeping examples simple and not
relying on external state (use pattern that works in tests or guard with
explanatory comment).

---

Outside diff comments:
In `@lib/sanbase_web/live/ask_live.ex`:
- Around line 95-97: The handler handle_event("select_answer_model",
%{"answer_model" => key}, socket) currently assigns any client-provided string;
update it to validate the key against the known set of models (e.g., via
AnswerModel.options_for/1 or a new AnswerModel.valid?/1 or list of allowed keys)
before assigning to :answer_model, and if invalid either ignore the change (keep
existing socket.assigns.answer_model) or set a safe default and optionally push
a flash/error; ensure the validation logic lives in the handler so malicious or
unknown keys are never directly stored in the socket.

---

Nitpick comments:
In `@lib/sanbase_web/live/ask_live.ex`:
- Around line 11-23: The mount assigns answer_model via
AnswerModel.default_key() which can crash if that function returns nil/raises;
either ensure the fix is applied inside AnswerModel.default_key/0 so it never
returns nil, or change the LiveView mount to defensively set answer_model to a
safe fallback (e.g. use AnswerModel.default_key() || "gpt-5-nano") before
assigning; update the mount function (the assign call that sets :answer_model)
to use this fallback or verify AnswerModel.default_key/0 behavior to prevent
mount crashes.

In `@test/sanbase/knowledge/answer_model_test.exs`:
- Around line 26-30: Add a test in test/sanbase/knowledge/answer_model_test.exs
that simulates AnswerModel.selectable/0 returning an empty list and asserts the
current behavior of AnswerModel.default_key/0 in that case; specifically, stub
or temporarily override selectable/0 to return [] and assert that calling
default_key/0 raises an ArgumentError (hd/1 on empty list) so the edge case is
covered and documented until the hd/1 usage in default_key/0 is made safe.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 73927631-d583-403a-86f5-10baa777598c

📥 Commits

Reviewing files that changed from the base of the PR and between 1b1c3c0 and 972d3ba.

📒 Files selected for processing (6)
  • lib/sanbase/knowledge/answer_model.ex
  • lib/sanbase/knowledge/citations.ex
  • lib/sanbase/knowledge/knowledge.ex
  • lib/sanbase_web/live/ask_live.ex
  • priv/repo/structure.sql
  • test/sanbase/knowledge/answer_model_test.exs
🚧 Files skipped from review as they are similar to previous changes (2)
  • lib/sanbase/knowledge/citations.ex
  • lib/sanbase/knowledge/knowledge.ex

Comment thread lib/sanbase/knowledge/answer_model.ex
Comment thread lib/sanbase/knowledge/answer_model.ex
Comment thread lib/sanbase/knowledge/answer_model.ex Outdated
@IvanIvanoff IvanIvanoff merged commit f05011d into master Jun 5, 2026
3 checks passed
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.

1 participant